Pwn格式化字符漏洞详细分析(第五空间2019决赛PWN5)
本帖最后由 HNHuangJingYU 于 2021-11-12 21:25 编辑拿到题目(第五空间2019决赛PWN5)分析如图:(以下都是针对32位)
首先看了看栈溢出漏洞,read做了限制字符大小利用不了,但是看到了一个printf(buf)这就是一个明显的格式化字符漏洞,再结合题目分析一波,大概流程是随机生成一个数字存入到地址为dword_804C044的全局变量中,最后对输入的passwd字符进行比较,这里注意下atoi这个函数它只会提取正整数,除此之外都是返回0,因为dword变量是随机数,所以控制不了(之前见过一题也是随机数,但是它的随机种子在栈里面是可控的,然后用栈溢出,再引用ctypes库,加载libc.so.6然后就可以获得系统一样的随机数了),但是这题很明显就是通过printf(buf)这个漏洞去更改dword变量的值,所谓格式化漏洞。。。阿巴阿巴。。。。之前看格式化漏洞相关的wp大佬们都要讲一遍格式化字符漏洞知识,看基础还是自行看资料吧,比我这详细,,其实就几个核心点:
1. %2$s 以字符串格式输出参数二
2. %n ,如 printf("abcdefg%n"); ,%n前面写了7个字符,所以向ESP(栈顶指针)所指向的地址处所指向的地址处(ESP指向了栈顶,此处存储着一个地址)写入7。
3. %10$n ,与 %n 类似,不过是向处指向的内存处写入7。%n:将%n 之前 printf 已经打印的字符个数赋值给偏移处指针所指向的地址位置
这里的格式符是一定要理解清楚的,理解了这里做题就不难。最后payload如下:
玩点花样
当然就算当输入password时我们输入字符串使atpi函数返回0也能做,可以利用整型溢出的方法,将我们格式化字符的数值变为溢出状态并控制为0
在默认是最小值4的情况下它的栈情况:
这里可以看到它处于偏移为10的位置处(fmtarg这里显示10行、第9个参数估计是把第一和第二行识别为一行)但是手动数一下是第11行。
再变换一下如果要控制小于4的数是不是就看’%index$n’它处于payload的第几个。
假设变换后是这样
payload =b'%10$n' + p32(bss_addr)
理解下代码,这样确实让%n为0了,但是写入的参数是格式化字符,然后printf执行会报找栈对齐错误,再者毕竟也没有’%10$n’这个地址把。此时栈如图:
之前是不是取偏移为10的参数就取到了自己,加上一个栈对齐错误,‘%10$n’这里是不是占了5个字节,5字节加上后面的p32()是不是就是9字节。。。栈对齐错误,那么给’%10$n’再加上3个字节,使它对齐栈,这时候加上了一个填充字节,那么我们取的地址应该就在偏移为12处的位置,那么改良变换后的代码:
payload =b'%12$n'+b’aaa’ + p32(bss_addr)
然后看看栈空间:
第十二位参数刚刚是符号地址,并且栈对齐了。这里就完成了对符号地址处赋值为0的操作
0-3之间就是依葫芦画瓢反之就是在’%index$n’前后进行增减就好了,保证栈对齐就行
当要写入比较大的数据时运行程序会报错,因为填充的栈数据过大会覆盖其他重要的地址导致栈奔溃。
这之前要需要了解如下格式符:
%$hhn 表示写入的地址空间为 1字节
%$hn -> 2 字节
%$n -> 4 字节
%$ln -> 8 字节,在 32bit 和 64bit 环境下一样。有时,直接写 4 字节会导致程序崩溃或等候时间过长,可以通过%$hn 或%$hhn 来适时调整。
%$lln -> 16字节
嗯,来到题目中如何给上面的符号地址赋值0x00abcdef呢?
因为如果填充这么大的长度数据进栈显然是不可能的,但是数据是以最小单位byte单位存储的并以地址连接方式组成数据,比如0x080492bc里面存储的值是0xb4853881那么按照小端存储(一般都是小端,我知道的单片机就是大端模式,之前老师上课讲过。。)来说它是这样的
假设想让0x804c044这里的值为0x00abcdef,那么也就是说需要在对应位置赋予对应的值,所以payload的前部分就是这样
payload =p32(bss_addr) + p32(bss_addr+1) + p32(bss_addr + 2) + p32(bss_addr +3 )
那后部分就是对应参数位的值,嗯,那么先看看效果代码、运行效果如下:
payload =p32(bss_addr) + p32(bss_addr+1) + p32(bss_addr + 2) + p32(bss_addr +3 )
payload += b'%10$n' + b'%11$n' + b'%12$n' + b'%13$n'
嗯,感觉好像差不多,因为我们前面有4个p32的数据,刚好就是0x10大小,那么修改一下他的值为0xef,那么就是说在前面填充223个字节,更新代码查看结果:
payload =p32(bss_addr) + p32(bss_addr+1) + p32(bss_addr + 2) + p32(bss_addr +3 )
payload += b'%223c%10$n' + b'%11$n' + b'%12$n' + b'%13$n'
ok,再来第二个也就是0xcd,因为前面已经填充了0xef个长度了,所以只能继续扩大然后用hhn取最后一个字节得到0xcd
payload =p32(bss_addr) + p32(bss_addr+1) + p32(bss_addr + 2) + p32(bss_addr +3 )
payload += b'%223c%10$n' + b'%222c%11$hhn' + b'%12$n' + b'%13$n'
依照上面可以得出如下:
payload =p32(bss_addr) + p32(bss_addr+1) + p32(bss_addr + 2) + p32(bss_addr +3 )
payload += b'%223c%10$n' + b'%222c%11$hhn' + b'%222c%12$hhn' + b'%85c%13$hhn'
ok最后成功赋值0x00ABCDEF
牛,先收藏一波 学海无涯,学的东西还很多啊 看不懂啊这{:1_896:} suiyuewudi 发表于 2021-11-12 21:38
看不懂啊这
适合有点pwn基础的看。。 值得学习 哈哈,正好需要! 学习了,感谢分享 感谢,有用 GeekPwn 发表于 2021-11-13 12:04
感谢,有用
看不懂,真的看不懂。