Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heap Overflow in json_parse_string() #92

Closed
hyrathon opened this issue Nov 14, 2022 · 2 comments · Fixed by #98
Closed

Heap Overflow in json_parse_string() #92

hyrathon opened this issue Nov 14, 2022 · 2 comments · Fixed by #98

Comments

@hyrathon
Copy link

Heap Overflow in json_parse_string()

In json_parse_string(), there is a heap out-of-bound write. The bug can be triggered with an invocation of json_parse_ex() with specific flags combination. The root cause of the vulnerability is when copy from src to data, the length of data(state.data_size) is not taken consideration of. Here is the output of Google ASAN when the vulnerability is triggerred:

The flags is 0x5fd6d7d6d6247bff
=================================================================
==4928==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x613000000189 at pc 0x55b62d1096ee bp 0x7ffdc2d4b010 sp 0x7ffdc2d4b008
WRITE of size 1 at 0x613000000189 thread T0
    #0 0x55b62d1096ed in json_parse_string /home/hyrathon/Desktop/jsonh/./json.h:1540:29
    #1 0x55b62d10d6db in json_parse_value /home/hyrathon/Desktop/jsonh/./json.h:1949:7
    #2 0x55b62d10c8f0 in json_parse_object /home/hyrathon/Desktop/jsonh/./json.h:1719:5
    #3 0x55b62d10d1c8 in json_parse_value /home/hyrathon/Desktop/jsonh/./json.h:1940:5
    #4 0x55b62d115c85 in json_parse_ex /home/hyrathon/Desktop/jsonh/./json.h:2129:3
    #5 0x55b62d12c192 in main /home/hyrathon/Desktop/jsonh/fuzz.c:29:5
    #6 0x7fb9e4174d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #7 0x7fb9e4174e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #8 0x55b62d03a314 in _start (/home/hyrathon/Desktop/jsonh/san+0x33314) (BuildId: a0e983e1c9c38a8763824dc5481f79d22fe8c82a)

0x613000000189 is located 0 bytes to the right of 329-byte region [0x613000000040,0x613000000189)
allocated by thread T0 here:
    #0 0x55b62d0bd15e in __interceptor_malloc (/home/hyrathon/Desktop/jsonh/san+0xb615e) (BuildId: a0e983e1c9c38a8763824dc5481f79d22fe8c82a)
    #1 0x55b62d114f15 in json_parse_ex /home/hyrathon/Desktop/jsonh/./json.h:2088:18
    #2 0x55b62d12c192 in main /home/hyrathon/Desktop/jsonh/fuzz.c:29:5
    #3 0x7fb9e4174d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/hyrathon/Desktop/jsonh/./json.h:1540:29 in json_parse_string
Shadow bytes around the buggy address:
  0x0c267fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c267fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c267fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c267fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c267fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c267fff8030: 00[01]fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c267fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c267fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c267fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c267fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c267fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==4928==ABORTING

And the backtrace info from gdb:

#0  json_parse_string (state=0x7fffffffc700, string=0x613000000158) at ./json.h:1540
#1  0x000055555565a6dc in json_parse_value (state=0x7fffffffc700, is_global_object=0, value=0x613000000130) at ./json.h:1949
#2  0x00005555556598f1 in json_parse_object (state=0x7fffffffc700, is_global_object=1, object=0x613000000068) at ./json.h:1719
#3  0x000055555565a1c9 in json_parse_value (state=0x7fffffffc700, is_global_object=4, value=0x613000000040) at ./json.h:1940
#4  0x0000555555662c86 in json_parse_ex (src=0x7fffffffcb48, src_size=35, flags_bitset=6905944396334922751, alloc_func_ptr=0x0, user_data=0x0, result=0x7fffffffdbc0) at ./json.h:2129
#5  0x0000555555679193 in main (argc=2, argv=0x7fffffffde08) at fuzz.c:29
#6  0x00007ffff7ca3d90 in __libc_start_call_main (main=main@entry=0x555555678e30 <main>, argc=argc@entry=2, argv=argv@entry=0x7fffffffde08) at ../sysdeps/nptl/libc_start_call_main.h:58
#7  0x00007ffff7ca3e40 in __libc_start_main_impl (main=0x555555678e30 <main>, argc=2, argv=0x7fffffffde08, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffddf8) at ../csu/libc-start.c:392
#8  0x0000555555587315 in _start ()

The input to trigger this bug is attached. The first 8 bytes are the flags for json_parse_ex() and the rest is the content(src). Please use address sanitizer to reproduce the bug, as non-crash overflow is hard to detect or locate without shadow memory.

Version: latest commit (bdcf2e1)

Also, you can always use the code below to reproduce the vulnerabilities I reported(and I won't attach it in each report for simplicity:

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "json.h"

#define BUFF_SIZE 0x1000

int main(int argc, char** argv){
    if(argc != 2){
        printf("Wrong number of arguments\n");
        exit(0);
    }

    char data[BUFF_SIZE];
    FILE *f = fopen(argv[1], "r");
    size_t size = fread(data, 1, BUFF_SIZE, f);

    if(size < sizeof(size_t)){
        // to short input, exit
        exit(0);
    }
    size_t flags = *((size_t *)data);

    printf("The flags is 0x%zx\n", flags);

    struct json_parse_result_s result;

    json_parse_ex(data + sizeof(size_t), size - sizeof(size_t), flags, NULL, NULL, &result);
}

clang fuzz.c -o san -O0 -g -fsanitize=address,undefined

crash-input.zip

@sheredom
Copy link
Owner

Thanks for these bugs - working through them at present!

sheredom added a commit that referenced this issue Nov 14, 2022
The issue was caused by "NaNE1" - EG. I was accidentally accepting the 'E' as being valid after a NaN was processed, which it wasn't.

Fixes #92.
Fixes #93.
Fixes #94.
Fixes #95.
Fixes #96.
Fixes #97.
sheredom added a commit that referenced this issue Nov 14, 2022
The issue was caused by "NaNE1" - EG. I was accidentally accepting the 'E' as being valid after a NaN was processed, which it wasn't.

Fixes #92.
Fixes #93.
Fixes #94.
Fixes #95.
Fixes #96.
Fixes #97.
sheredom added a commit that referenced this issue Nov 14, 2022
The issue was caused by "NaNE1" - EG. I was accidentally accepting the 'E' as being valid after a NaN was processed, which it wasn't.

Fixes #92.
Fixes #93.
Fixes #94.
Fixes #95.
Fixes #96.
Fixes #97.
@hyrathon
Copy link
Author

Very quick response, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants