首页
论坛
课程
招聘
[原创]格式化字符串漏洞
2021-6-12 11:17 3232

[原创]格式化字符串漏洞

2021-6-12 11:17
3232

格式化函数

格式化字符串漏洞本身并不算缓冲区溢出漏洞,主要是针对一些格式化函数,如printf、sprintf、vsprintf等。这些格式化函数利用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后面的变参列表中提供相应的变量,最终函数就会使用相应位置的变量来代替那个说明符,产生一个调用者想要的字符串。

下面列出几个比较关键的参数格式:
·%x(%lx):替换为参数的值(十六进制)。
·%p:替换为参数的值(指针形式)。
·%s:替换为参数所指向内存的字符串。
.%n:参数对应整型指针,将该参数之前输出的字符数量写入参数指向的地址中。

参数定位

在C语言程序中,多数含有可变参数的函数都使用stdarg.h头文件中定义的宏stdarg来访问它们的可变参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdarg.h>
 
int myprint(int Narg,...)
{
        int i;
        va_list ap;
 
        va_start(ap,Narg);
        for(int i=0; i<Narg;i++)
        {
                printf("%d\t",va_arg(ap,int));
                printf("%f\n",va_arg(ap,double));
        }
        va_end(ap);
}
int main()
{
        myprint(1,2,3.5);
        myprint(2,2,3.5,3,4.5);
}
  1. 初始va_list:myprint()函数中定义了一个va_list指针,用于访问可变参数。
  2. 宏va_start根据传入的第二个参数来计算va_list的起始位置,宏va_start获得Narg的地址(设为A),根据其类型(int)计算它的长度(设为B),然后设置va_list指针(变量ap)指向A+B,实际上就是指向Narg正上面的内存位置。
  3. 移动va_list指针:宏va_arg()返回va_list指针指向的值,并使指针指向下一个可变参数的位置,这个指针应该移动多少取决于宏的类型参数,int移动4个字节,double移动8个字节。
  4. va_end():来做必要的清理工作。
 

printf()函数扫描格式化字符串,直到遇到一个格式说明符'%',此时,printf()函数调用va_arg()来获得当前va_list指针指向的可变参数,同时va_arg()把指针移到下一个可变参数,把获得的参数看成什么类型的数和把va_list指针移动多少距离取决于格式规定符的类型。

 

在正常的情况下,格式化字符串所需的参数是依次往后索引的,如“%p,%x”,其对应于第1、2个参数。

也有一些特殊情况,如
“%d$m”形式:
其中,d代表数字(1,2,.…),用来定位参数列表中的第d个参数(从1开始算);
m为前面所述的关键参数格式之一(x,p,s,n,...).

原理

通常,格式化函数是一种变长参数函数,后面的参数需要根据栈的参数传递来进行释放,x86的参数全在栈上,x64的参数从第4个开始放在栈上。这些格式化函数遇到格式说明符的关键字符之后,会按照传参规则去寻找参数来进行替换或者修改,并不会关心真实的传参情况。所以如果实际参数数量小于所需的参数数量,则其依然会将对应位置的数值当成参数进行转换,从而引发格式化字符串漏洞。由此可见,利用格式化字符串漏洞既能够泄露信息,又能够修改信息,功能比较强大。

未检查真实的参数列表
“nil”表示无值,任何变量在没有被赋值之前的值都为nil,对于真假判断,只有nil与false、0表示假,其余均为真。

 

信息修改主要是利用格式化字符串中的‘%n’对参数进行写入,写入的值是格式化字符串中%n之前的字符数量。

修改宽度控制具体如下:
·%n:修改4字节。
.%hn:修改2字节。
.%hhn:修改1字节。


[培训] 优秀毕业生寄语:恭喜id咸鱼炒白菜拿到远超3W月薪的offer,《安卓高级研修班》火热招生!!!

最后于 2021-6-12 20:22 被wx_堃编辑 ,原因:
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回