格式化字符串漏洞通常情况下是由printf函数产生的;
正常情况下我们用printf函数输出字符串时是这样的:
char a[100]="fmtstr";
int b=12,c=666;
printf("%s %d %x",a,b,c);
但是有时是出于方便会直接输出字符串:
char str[12]="fmtstr";
printf(str);
这时,如果这个str是我们用户输入可控的,那么这就存在了一个格式化字符串漏洞,这时攻击者将有机会对任意内存地址进行读写操作;
printf的读写操作:
我们都知道printf函数可以打印出一段内容,比如:
printf("%d",a); //打印一个整型a
printf("%s",b); //打印一个字符串b
printf("%c",c); //打印一个字符c
printf("%x",d); //以十六进制数的格式打印d
但是printf里面还有一个%n的格式可以用来对一段地址写值;
#include<stdio.h>
int main()
{
int a,b,c;
printf("ABC%nEFG%n\n",a,b);
printf("%123c%n\n",'a',c)
printf("a=%d b=%d c=%d\n",a,b,c);
return 0;
}
输出结果:a=3 b=6 c=123
我们并没有对a,b,c进行初始化和赋值,但我们通过%n来写入了一个值,这就是printf写的操作,具体的还可以往某一个字节写值(%hnn);
危害:
用一个简单的列子来说明:
#include<stdio.h>
int main()
{
char str[100];
scanf("%s",str); //用户可控的字符串
printf(str); //格式化字符串漏洞
printf("\n");
return 0;
}
如果我们将我们输入一些特殊的字符串比如%x会怎么样呢;
我们发现,它将栈中的数据打印出来了,而我们输入的第一个数据在第6个;
如果我们将我们输入是‘aaaa'换成某一个地址,然后找到它在栈中的位置,我们是不是就可以获得一些敏感信息了呢,
比如我们可以打印出开了canary的cookie,某一个函数在got表中的地址然后找到函数的真实的地址,然后减去偏移获得基地址;
具体的方法我们在另外一篇中,用一个具体的列子来讲。。。。。