格式化字符串漏洞

概述

格式化字符串漏洞最早是在1999年被Tymm Twillman发现的,他在著名的BugTrag邮件列表中公布了一篇关于proftpd软件漏洞的文章Exploit for proftpd 1.2.0pre6,这就是最早关于格式化字符串漏洞的公开描述。

由于程序使用了格式化字符串作为参数,并且格式化字符串是用户可以控制的。触发格式化字符串漏洞的主要函数就是printf、sprintf、fprint、vprintfptintf家族函数。恶意用户可以使用%s%x等格式符,从堆栈或其他内存位置输出数据,也可以使用%n向任意地址写入被格式化的字节数,可能造成任意代码的执行,或者从漏洞程序中读取铭感信息。

printf为例:

 printf("<式样化字符串>",<参数表>);

函数printf从右到左压栈,然后将先读取放到栈底,最后读取的放在栈顶,处理时候是从栈顶开始的,所以我们看见的结果是,从右边开始处理的。

printf("Number %d has no address,number %d has:%08x\n",i,a,&a);
        栈顶 
    +--------+ 
    |  ...   | 
    |  &a    | 
    |   a    | 
    |   i    |
    |   A    | 
    |  ...   |
    +--------+
       栈底

其中A是格式化字符串的地址,i是变量i的值,a是变量a的值,&a是变量a的地址

一些格式化参数

格式化字符串%n

功能:将%n之前打印出来的字符个数,赋值给一个变量

如上所示,在%n之前打印了5个字符a,所以最后n的值为5;

格式化字符串%s

任意的内存的读取需要用到格式化字符串 %s,其对应的参量是一个指向字符串首地址的指针,作用是输出这个字符串

格式化字符串%x

漏洞成因

先看下面这段代码:

#include<stdio.h>
int main(){
    char str[100];
    scanf("%s",&str);
    printf("%s",str);
    printf(str); //触发漏洞
    return 0;
}

针对于上面的列子,第一个printf的调用时正确的,第二个printf的调用是错误的。

漏洞形成原因:程序将格式化字符串的输入权交给用户,printf函数并不知道参数个数,它的内部有个指针,用来索检格式化字符串。对于特定类型%,就去取相应参数的值,直到索检到格式化字符串结束。所以没有参数,代码也会将format string 后面的内存当做参数以16进制输出。这样就会造成内存泄露。

对于上面的例子,输入:

aaaa%x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x

程序输出:

aaaabfe582ec,b7f6f950,004b61c0,00000000,00c30000,00000001,61616161,252c7825,2c783830,78383025,3830252cr

参考

(1)https://www.freebuf.com/column/207425.html

(2)https://blog.csdn.net/qq_43394612/article/details/84900668

(3)《漏洞战争——软件漏洞分析精要》

(4)《0day安全:软件漏洞分析技术》

拓展阅读

https://bbs.ichunqiu.com/thread-42943-1-1.html?from=bkyl

猜你喜欢

转载自www.cnblogs.com/CH42e/p/11978281.html