格式化字符串漏洞原理 ¶
一、 栈结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cZv7cQTB-1681099438782)(file:///C:/Users/杨建哲/AppData/Local/Temp/msohtmlclip1/01/clip_image002.gif)]
由图可知,在运行到add(i, j)函数时,先压入参数j,i再压入返回地址,再压入ebp,最后压入局部变量。(字节对齐)
二、格式化字符串漏洞基本原理
printf(&fom,&chr)
在一开始,我们就给出格式化字符串的基本介绍,这里再说一些比较细致的内容。我们上面说,格式化字符串函数是根据格式化字符串函数来进行解析的。那么相应的要被解析的参数的个数也自然是由这个格式化字符串所控制。比如说’%s’表明我们会输出一个字符串参数。
我们再继续以上面的为例子进行介绍
对于这样的例子,在进入 printf 函数的之前 (即还没有调用 printf),栈上的布局由高地址到低地址依次如下
some value
3.14
123456
addr of "red" #注意存放的位字符串的地址
addr of format string: Color %s...
注:这里我们假设 3.14 上面的值为某个未知的值。
在进入 printf 之后,函数首先获取第一个参数,一个一个读取其字符会遇到两种情况
- 当前字符不是 %,直接输出到相应标准输出。
- 当前字符是 %, 继续读取下一个字符
- 如果没有字符,报错
- 如果下一个字符是 %, 输出 %
- 否则根据相应的字符,获取相应的参数,对其进行解析并输出
那么假设,此时我们在编写程序时候,写成了下面的样子
printf("Color %s, Number %d, Float %4.2f");
此时我们可以发现我们并没有提供参数,那么程序会如何运行呢?程序照样会运行,会将栈上存储格式化字符串地址上面的三个变量分别解析为
-
%s: 打印偏移处内容(内容作为地址)指向的字符串
输入:%s
分析打印:esp+4所内容所指向的字符串,即0xffffd5e4所指向的字符串,即%s
输出:%s
故:可将%s指向一个内容为非法地址的空间使得程序崩溃
-
%d: 解析偏移处内容对应的整形值
输入:%d
分析输出:相对格式化字符串偏移为1处的内容,以有符号整数打印,0xffffd5e4对应的有符号十进制,即-10780
实际输出:-10780
-
%f: 解析偏移处内容对应的浮点值
-
%n$x:以十六进制的形式打印相对格式化字符串偏移n处的内容
输入:%6$xaaaabbbb
分析输出:即以十六进制形式打印相对格式化字符串(位于栈顶处)偏移为6的内容,该图中打印0xfffd5e8处的内容(aaaa),输出61616161
实际输出:61616161aaaabbbb
三、具体利用
(一)、程序崩溃
通常来说,利用格式化字符串漏洞使得程序崩溃是最为简单的利用方式,因为我们只需要输入若干个 %s 即可
%s%s%s%s%s%s%s%s%s%s%s%s%s%s
这是因为栈上不可能每个值都对应了合法的地址,所以总是会有某个地址可以使得程序崩溃。这一利用,虽然攻击者本身似乎并不能控制程序,但是这样却可以造成程序不可用。比如说,如果远程服务有一个格式化字符串漏洞,那么我们就可以攻击其可用性,使服务崩溃,进而使得用户不能够访问。
(二)、泄露内存 ¶
利用格式化字符串漏洞,我们还可以获取我们所想要输出的内容。一般会有如下几种操作
- 泄露栈内存
- 获取某个变量的值
- 获取某个变量对应地址的内存
- 泄露任意地址内存
- 利用 GOT 表得到 libc 函数地址,进而获取 libc,进而获取其它 libc 函数地址
- 盲打,dump 整个程序,获取有用信息。
1.获取栈的数值
%p: 以十六进制打印偏移处的内容,前面不足8位(在32位机器上地址为8位)补0
%x: 以十六进制打印偏移处的内容,前面不足8位,不补0
%o: 八进制
%d: 十进制
(1)方法一
(三)、任意地址写(劫持got表)
机器上地址为8位)补0
%x: 以十六进制打印偏移处的内容,前面不足8位,不补0
%o: 八进制
%d: 十进制