漏洞原因

程序使用了格式化字符串作为参数,并且格式化字符串为用户可控。其中触发格式化字符串漏洞函数主要是printf、sprintf、fprintf等C库中print家族的函数。

出现漏洞的代码

正常的代码:

//gcc test.c -o test -m32
#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
/*int test(int a,int b){
        //int len = 0;
        //len = strlen(a);
        return a+b;
}*/
int main()
{
        char a[100];
        int passwd = 1234;
        //int a = 0;
        //scanf("%s",a);

        printf("%d",1);
        return 0;
}

如果将printf写成下面的样子:

//gcc test.c -o test -m32
#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
/*int test(int a,int b){
        //int len = 0;
        //len = strlen(a);
        return a+b;
}*/
int main()
{
        char a[100];
        int passwd = 1234;
        //int a = 0;
        //scanf("%s",a);

        printf("%d %d %d %d %d",1);
        return 0;
}

则出现如下的运行结果:

burning@burning-RedmiBook-14-APCS:~/linux$ ./a.out
1 -135348599 1448830356 -117540 1234

passwd变量的值居然被打印出来了。

原因

printf会打印堆栈上面的内容。堆栈内容如下所示, 第一个%d打印的是1,第5个%d打印的便是12345( 0x00003039)

格式化字符串漏洞-手动触发_格式化字符串

[0x00000f5a]> ? 0x00003039
12345 0x3039 030071 12.0K 0000:0039 12345 00111001 12345.0 0.000000
OpenSSL的心脏流血漏洞基于的就是这个原理。

公众号

更多漏洞信息可关注公众号:

格式化字符串漏洞-手动触发_格式化字符串_02