PWN的格式化字符串漏洞初探
本文主要参考了CTF-WIKI的pwn部分:原理介绍 - CTF Wiki
以及部分Bilibili教学资源如XMCVE 2020 CTF Pwn入门课程_哔哩哔哩_bilibili
我一直想要学习格式化字符串漏洞,至少搁置了半年吧,这次重新学习Pwn,也要重拾之前的知识了!
介绍
格式化字符串是将一些数据按照固定格式输出的控制字符串,比如一串字符串aaaa,可能在内存就是0x610x610x610x00,我们想要打印出这串字符,就得用%s,若是打印出数字格式,可能需要使用%x,打印出地址则是其他的如%p(使用%p需要跟&+变量名)这个地址得是有效地址
C/C++遇到以下函数,基本都是采用格式化字符串了。当然,虽然看起来格式化字符串这么威力巨大,实际上CTF赛题专门考察格式化字符串的情况却不多,大多数情况以堆为主,或者结合一些考点来考察。尽管如此,格式化字符串漏洞仍然是我们需要掌握的。
格式化字符串一般结构可参考wiki:格式化字符串 - 维基百科,自由的百科全书
注意:type的不同,%后部分参数所代表的含义也是不同的。但是所谓大同小异,掌握一种之后吸收起来会特别快,具体的例子是%x和%f的%.x含义就是不同的。
到后面还会根据场景不同进行介绍。下面的demo则是几个简单的实例
1 |
|
这里也展示了%p接受参数的要求,即必须是有效地址。
在做题中,一般见到的也就是printf这个格式化字符串函数,实际上还有其他的,比如scanf是输入格式化但是这个不常用,以及printf的其他“近亲”比如sprintf等。
对于printf函数来说,他其实接受参数是一个格式化字符串+其余变量。比如上文的printf("%p\n", &a)其实就是两个参数,一个是格式化字符串,一个是变量a的地址。对于x32程序来说,显然这些东西都是存储在栈之上。printf解析的时候,会读取第一个参数,假如有%,就认为其为一个格式化控制字符,再找对应位置的参数进行解析,如果没有%就好办了,直接把这个字符送到缓冲区即可。
这就是我们所说的printf函数的基本原理,唯一的和其他函数参数不同的就是他是接受参数内容不固定,而且会根据格式化字符串来执行。
更深层次的实现,则是写在了c语言某个头文件之中,大家感兴趣可自行查看源码,是根据va_list、va_start、va_arg、va_end 这一组宏来读取可变参数。
利用
格式化字符串存在多种利用姿势,从CTF出发,我们可能更关注它泄露栈上内容和任意地址写。从简单的手法来说,我们可以让一个程序崩溃。
程序崩溃
相信大家都知道,%s就是将一个值解析为字符串,而且是遇到0才停止。然鹅这是理想情况下的%s,现在就来讨论非理想情况下的%s:即格式化字符串接受了无数个%s。。。。。如下所示:
%s%s%s%s%s%s%s%s%s%s%s%s%s%s
程序不可能所有地址都能正确解析为字符串,何况部分内存还有一些保护权限等,总之就是会出现各种异常情况。假如程序没有做异常处理,那自然就会崩溃,崩溃的后果即是业务瘫痪了。假如抢票系统出现这个问题崩溃了,甚至银行系统出现问题了,后果可想而知。然而坏消息是我们在CTF竞赛中不能用这个来getflag。