格式化字符串漏洞?
存在场景:存在格式化输出函数
如果输入正常的字符,程序就不会有问题。
格式字符串漏洞发生的条件就是格式字符串要求的参数和实际提供的参数不匹配。
为什么可以通过编译?
因为 printf() 函数的参数被定义为可变的。
为了发现不匹配的情况,编译器需要理解 printf() 是怎么工作的和格式字符串是什么。然而,编译器并不知道这些。
有时格式字符串并不是固定的,它可能在程序执行中动态生成。
printf() 函数自己可以发现不匹配吗?
printf() 函数从栈中取出参数,如果它需要 3 个,那它就取出 3 个。除非栈的边界被标记了,否则 printf() 是不会知道它取出的参数比提供给它的参数多了。然而并没有这样的标记。
一、查看文件信息
先file ./pwn查看文件类型再checksec --file=pwn检查一下文件保护情况。
我们发现:32位程序,设置了canary,无法栈溢出。
二、IDA反编译
我们这里使用ida 32位打开文件。
我们查看mian函数,发现几个比较可疑的地方:
源程序大意是把随机数放入到0x804c044处,用户输入用户名和密码,如果密码和随机数相等,则拿到权限。
看到了printf,又加了canary权限,可以想到考查格式化字符串漏洞。
首先我们先利用利用AAAA %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x的形式来计算偏移量:
因为A的Ascll码中为41,四个A就是41414141,我们可以在图片里看到第十个输出正是41414141所以偏移量为10。
之后只要修改dword_804c044的值,让输入和dword_804c044的值一样就可以了。
而这个函数:
代表向这个地址中写入四个字节。
举个例子:
当payload为aaaa%7$n时,输出的字符数量为4,程序会将4写入0x61616161指向的内存中。
所以我们要用% 10 $ n来修改的话,我们写入的也是4,因为read(fd, &dword_804C044, 4u);中读入的是4个字节。
所以我们的代码为:
from pwn import *
## remote()建立远程连接,指明ip和port
io = remote('node4.buuoj.cn', 26427)
leak_addr = 0x804C044
io.recvuntil('your name:')
payload1 = p32(leak_addr) + b'%10$n'
io.sendline(payload1)#发送数据
io.recvuntil('your passwd:') #与shell进行交互
io.sendline(b'4')
io.interactive()
因为密码要和该地址存储的值一样,所以我们把密码改为b’4’.
总结
这里用到的一些知识:
1.任意地址读:
根据0x01中的知识,我们只需要把最后一个%08x换成%s就可以读取0x61616161地址的数据,注意这个0x61616161是我们可以控制的内容,就是我们输入的前四个字节且这四个字节就是读取的地址。所以,可以通过替换这个payload的前四个字节完成任意地址读。
这个payload也可以简化为aaaa%7 s ,这里的 7 s,这里的7 s,这里的7的意思就是取printf的第七个参数(0x61616161),如果这里要用等宽输出的话payload就变成这样了aaaa%7$08x,结果会输出aaaa61616161。
2.任意地址写:
我们先了解一下%n的作用。%n是将输出的字符的个数写入到内存中。
根据上述知识,当payload为aaaa%7$n时,输出的字符数量为4,程序会将4写入0x61616161指向的内存中。如果我们需要写更大的数就得用等宽输出来实现了。假设,我们需要向0x61616161写入100,则payload就变成了aaaa%7$0100n。
任意地址写还有一个问题就是,如果我们要写一个很大的数,比如要将0x8048320写入0x61616161,这个16进制对应的十进制数为134513440,也就是说需要在输出134513440个字符。不用多想,程序肯定会崩溃。
如果遇到这种情况怎么办呢?我们可以通过%hn来两字节两字节写入。在上面的例子中,我们将0x8048320拆分为高两字节0x804和低两字节0x8320,将0x804也就是十进制2052写入0x61616161 – 0x61616162;将0x8320也就是十进制33568写入0x61616163 – 0x61616164。分两次写入就可以完成大数的写入了。
参考链接
第一次碰见这种题,我看了好多大佬的解说,甚至有很多方法,我这里只采用了修改值的办法。没办法啊,菜狗子们还得多做做,我这里很抱歉并没有讲的很清楚,所以再附一下我的参考链接: