格式化字符串漏洞
前提知识储备:
概念
格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根据其来解析之后的参数。一般来说,格式化字符串在利用的时候主要分为三个部分
- 格式化字符串函数
- 格式化字符串
- 后续参数,就是下图中逗号后的变量(可以不要)
上述可转为该图:
将相关正式概念代入图片更好理解
相关函数
输入:
- scanf
输出函数
函数 | 基本介绍 |
---|---|
printf | 输出到stdout |
fprintf | 输出到指定FILE流 |
vprintf | 根据参数列表格式化输出到 stdout |
vfprintf | 根据参数列表格式化输出到指定FILE流 |
sprintf | 输出到字符串 |
snprintf | 输出指定字节数到字符串 |
vsprintf | 根据参数列表格式化输出到字符串 |
vsnprintf | 根据参数列表格式化输出指定字节到字符串 |
setproctitle | 设置argv |
syslog | 输出日志 |
err, verr, warn, vwarn等 | 。。。 |
printf函数的字符串漏洞
此漏洞如(来自攻防世界的CGfsb):
在格式化字符串函数中%n,作用是把在%n前输出的字符个数赋值给对应的整型指针参数所指的变量
%hh的作用是限定输出格式为8位,即一个字节;
%h的作用是限定输出格式为16位,即两个字节;
%l的作用是限定输出格式为32位,即四个字节;
%ll的作用是限定输出格式为64位,即八个字节;
%L的作用是输出实数,支持long double类型;
sprintf原型int sprintf(char *string, char *format [,argument,…])
string– 这是指向一个字符数组的指针,该数组存储了 C 字符串。
format– 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是**%[flags] (width)[.precision] (length)specifier**
**[argument]…**:根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。
把格式化的数据写入某个字符串缓冲区。如果成功,则返回写入的字符总数(不包括’\0’),不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。
原理
x86系统下:
以printf为例
假设printf函数将以图中方式进行输出。那么作为一个函数,首先就是将参数入栈,又按照从右到左的方式。那么将按以下的情况入栈:
1 |
|
执行printf函数后,函数会获取第一个参数,也就是格式化字符串。函数将会一个个的读取字符串中的字符,有以下情况:
- 当前字符不是%,直接输出到相应标准输出。
- 当前字符是%, 继续读取下一个字符
- 如果没有字符,报错
- 如果下一个字符是%,输出%;否则根据相应字符对应的数据类型,获取相应的参数,将其输出
那么漏洞将会发生在哪呢?
假设我们将程序写成这样
1 |
|
我们并没有提供printf函数中%后对应的参数,此时程序并不会报错停止,而是继续执行,会在栈中存储着格式化字符串地址上面的三个高地址变量解析,作为输出:
%s则解析其地址对应的字符串
%d解析内容对应的整型值
%f解析内容对应的浮点值
第一个,注意!解析地址!如果是一个无法访问的地址比如0,那么程序将崩溃,这也是我们利用的点,比如注入不限量个%s,总有一个能让程序崩溃的。而其余两个我们也可以借此而使得栈上的内容泄露出来
这里补充一点:我们是可以获取栈中被视为第n+1个参数的值方法为:
1
%n$p
n代表该格式化字符串对应的第n个输出参数,那相对于输出函数来说,就是第n+1个参数了。
x64系统下:
原理与x86并无不同,唯一需要注意的就是x64系统下,函数的前六位参数是使用寄存器存放的,顺序为RDI,RSI,RDX,RCX,R8,R9对应前六位参数,所以在gdb中相对偏移时,要把栈上的偏移加上相差寄存器的数量的才是n的值
参考:
ctf-wiki格式化字符串漏洞
- 本文作者:ShouCheng
- 本文链接:http://shoucheng3.github.io/2020/12/05/2020-12-05-%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%BC%8F%E6%B4%9E/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!