今天做Dest0g3 520迎新赛的dest_love,发现是格式化字符串问题,但是由于其内容保存在了bss区,导致无法像过去那样简单利用,坐牢半天没做出来,但恰巧遇到了,就复习一下格式化字符串漏洞的基本原理吧,顺便补一下过去基本功不扎实的问题
首先是格式化字符串漏洞长啥样子
printf(format); //format是一个字符串
如何触发?
一般来说通过%p泄露内容,通过%n来写内容。
%p也可用%08x(32位)替代,不过还是推荐%p,因为%p无需考虑32还是64的问题。
tip:可以通过“%p-%p-%p”来断开,方便看。
%n可以把已输出字符数目存到指定地点。比如:
printf("123%n",&a); //a=3
通过这个方式,就可以修改指定的值了,那么%3$n是什么意思?这是一种定位方式,效果类似%n%n%n,只不过前面两个%n不起效果。除此以外,%n有如下拓展:
%hhn 写一字节
%hn 写两字节
%n 写四字节
%ln 32位写四字节,64位写八字节
%lln 写八字节
常用触发方式,printf(“AAAA%p-%p-%p-%p”);
先不说AAAA。%p会打印出什么?
这一块内容需要已经理解用户态函数参数传递方式。
32位:
我输入了%p%p%p,上图是效果,我断点设在printf了。众所周知32位用栈传参用栈,此时因为call了printf,所以返回地址已经被存在栈里了。0xffffcf80是第一个参数,它指向了“ %p%p%p ”(它显示两个%p,可能是显示错误)这块字符串的地址。相应的下面0xffffcf84、0x…88、0x…90被当作了第二第三第四个参数,注意这个“被”字,重点理解。所以我们可以看到,下面%p%p%p输出效果伪为0xffffcfa8,0x63,nil(0无法显示),对应第二第三第四个参数。这是32位的效果。
再看64位
64位用户态函数传参规则:
从左到右rdi,rsi,rdx,r8,r9,剩下的从右到左依次压入栈。
我们可以对照一下这张图,寄存器和输出的值,栈和输出的值对照一下,完全吻合。
上面这个就是基本原理。
那么有的博客,直接告诉你用printf(“AAAA%p%p…”)是什么意思呢?这是这类题的另一种做法,不用gdb看,直接通过打出来的对照,只要出现AAAA的ascii值基本就确定了该字符串的位置了(不过我觉得还有一种方法,就是看ida静态分析,不过这种方法实际效果肯定不如上面俩,就不展示了)
还有一个重点,64位的地址常常存在零(看看上面那张图中的地址,实际上只用了6个字节),所以想要利用偏移来泄露地址内容或者改写其内容的话,目的地址不能放在格式化符号之前,否则printf在遇到零字节时会被截断,此时应将目的地址放在格式化符号后面。
利用案例:
http://t.csdn.cn/cLGnT