Bug 697136 (CVE-2016-7563)

Summary: mujs str Out-of-Bound read 1 byte in function chartorune
Product: MuJS Reporter: Shi Ji <puzzorsj>
Component: generalAssignee: Tor Andersson <tor.andersson>
Status: RESOLVED FIXED    
Severity: normal CC: gustavo.grieco
Priority: P4    
Version: unspecified   
Hardware: PC   
OS: Linux   
Customer: Word Size: ---
Attachments: poc and stack trace

Description Shi Ji 2016-09-20 06:49:02 UTC
Created attachment 12958 [details]
poc and stack trace

# Vulnerability
mujs str Out-of-Bound read 1 byte in function chartorune

# Version
github head version (2016-09-20 21:22:10)

# Address Sanitizer Output
=================================================================
==22011== ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb5c01e25 at pc 0x80680ed bp 0xbffff178 sp 0xbffff16c
READ of size 1 at 0xb5c01e25 thread T0
    #0 0x80680ec in jsU_chartorune /home/fuzzing/fuzzing/mujs/utf.c:55
    #1 0x808c79c in jsY_next /home/fuzzing/fuzzing/mujs/jslex.c:155
    #2 0x808d168 in lexcomment /home/fuzzing/fuzzing/mujs/jslex.c:228
    #3 0x808ec66 in jsY_lexx /home/fuzzing/fuzzing/mujs/jslex.c:550
    #4 0x808fca1 in jsY_lex /home/fuzzing/fuzzing/mujs/jslex.c:721
    #5 0x8096be1 in jsP_next /home/fuzzing/fuzzing/mujs/jsparse.c:132
    #6 0x809f22a in jsP_parse /home/fuzzing/fuzzing/mujs/jsparse.c:944
    #7 0x805edd1 in js_loadstringx /home/fuzzing/fuzzing/mujs/jsstate.c:55
    #8 0x805ef3a in js_loadstring /home/fuzzing/fuzzing/mujs/jsstate.c:70
    #9 0x805f197 in js_loadfile /home/fuzzing/fuzzing/mujs/jsstate.c:121
    #10 0x805f2fd in js_dofile /home/fuzzing/fuzzing/mujs/jsstate.c:150
    #11 0x8049fbb in main /home/fuzzing/fuzzing/mujs/main.c:175
    #12 0xb6805a82 (/lib/i386-linux-gnu/libc.so.6+0x19a82)
    #13 0x8049560 in _start (/home/fuzzing/fuzzing/mujs/build/mujs+0x8049560)
0xb5c01e25 is located 0 bytes to the right of 21-byte region [0xb5c01e10,0xb5c01e25)
allocated by thread T0 here:
    #0 0xb69f8854 (/usr/lib/i386-linux-gnu/libasan.so.0+0x16854)
    #1 0x805ec9d in js_defaultalloc /home/fuzzing/fuzzing/mujs/jsstate.c:17
    #2 0x8051a79 in js_malloc /home/fuzzing/fuzzing/mujs/jsrun.c:34
    #3 0x805f064 in js_loadfile /home/fuzzing/fuzzing/mujs/jsstate.c:100
    #4 0x805f2fd in js_dofile /home/fuzzing/fuzzing/mujs/jsstate.c:150
    #5 0x8049fbb in main /home/fuzzing/fuzzing/mujs/main.c:175
    #6 0xb6805a82 (/lib/i386-linux-gnu/libc.so.6+0x19a82)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/fuzzing/fuzzing/mujs/utf.c:55 jsU_chartorune
Shadow bytes around the buggy address:
  0x36b80370: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36b80380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36b80390: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36b803a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36b803b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x36b803c0: fa fa 00 00[05]fa fa fa 00 00 05 fa fa fa 00 00
  0x36b803d0: 04 fa fa fa 00 00 02 fa fa fa 00 00 04 fa fa fa
  0x36b803e0: 00 00 01 fa fa fa 00 00 05 fa fa fa 00 00 01 fa
  0x36b803f0: fa fa 00 00 02 fa fa fa 00 00 02 fa fa fa 00 00
  0x36b80400: 01 fa fa fa 00 00 00 07 fa fa 00 00 06 fa fa fa
  0x36b80410: 00 00 00 07 fa fa 00 00 06 fa fa fa 00 00 05 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
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==22011== ABORTING


# PoC
See poc

# Analysis
From the call stack, we get to know this oob was caused by str ptr in chartorune function.
When we analyzed further, we found the lexcomment function may be the root cause. If a js ends with "*", then jsY-accpet(Y,'*') will return true, and jsY_next will be called, and finally will cause an OOB.

# Report Timeline
2016.09.20: Shi Ji(@Puzzor) discovered this issue

# Credit
Shi Ji(@Puzzor)

# Repro
./build/mujs poc
Comment 1 Tor Andersson 2016-09-20 08:21:15 UTC
commit f8234d830e17fc5e8fe09eb76d86dad3f6233c59
Author: Tor Andersson <tor.andersson@artifex.com>
Date:   Tue Sep 20 17:11:32 2016 +0200

    Fix bug 697136.
    
    We were unconditionally reading the next character if we encountered
    a '*' in a multi-line comment; possibly reading past the end of
    the input.
Comment 2 Shi Ji 2016-09-20 18:51:16 UTC
(In reply to Tor Andersson from comment #1)
> commit f8234d830e17fc5e8fe09eb76d86dad3f6233c59
> Author: Tor Andersson <tor.andersson@artifex.com>
> Date:   Tue Sep 20 17:11:32 2016 +0200
> 
>     Fix bug 697136.
>     
>     We were unconditionally reading the next character if we encountered
>     a '*' in a multi-line comment; possibly reading past the end of
>     the input.

Could you please apply CVE ID for this issue?
Comment 3 Shi Ji 2016-09-27 06:42:21 UTC
Use CVE-2016-7563
Comment 4 gustavo.grieco 2016-10-04 11:46:16 UTC
Hi, i think this bug is not fixed (tested in a3a4fe840b80706c706e86160352af5936f292d8):

$ echo "c2UoJyI/czFJXA==" | base64 -d > oob.js
$ mujs oob.js
...
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60040000dffb at pc 0x41f0a7 bp 0x7fffffffd580 sp 0x7fffffffd578
READ of size 1 at 0x60040000dffb thread T0
    #0 0x41f0a6 (/home/g/Codigo/mujs/build/mujs+0x41f0a6)
    #1 0x43f065 (/home/g/Codigo/mujs/build/mujs+0x43f065)
    #2 0x43f5fa (/home/g/Codigo/mujs/build/mujs+0x43f5fa)
    #3 0x441472 (/home/g/Codigo/mujs/build/mujs+0x441472)
    #4 0x44d7b6 (/home/g/Codigo/mujs/build/mujs+0x44d7b6)
    #5 0x44e465 (/home/g/Codigo/mujs/build/mujs+0x44e465)
    #6 0x44e745 (/home/g/Codigo/mujs/build/mujs+0x44e745)
    #7 0x44e985 (/home/g/Codigo/mujs/build/mujs+0x44e985)
    #8 0x44ec79 (/home/g/Codigo/mujs/build/mujs+0x44ec79)
    #9 0x44f198 (/home/g/Codigo/mujs/build/mujs+0x44f198)
    #10 0x44f548 (/home/g/Codigo/mujs/build/mujs+0x44f548)
    #11 0x44f6c8 (/home/g/Codigo/mujs/build/mujs+0x44f6c8)
    #12 0x44f849 (/home/g/Codigo/mujs/build/mujs+0x44f849)
    #13 0x44fada (/home/g/Codigo/mujs/build/mujs+0x44fada)
    #14 0x44fc0c (/home/g/Codigo/mujs/build/mujs+0x44fc0c)
    #15 0x450858 (/home/g/Codigo/mujs/build/mujs+0x450858)
    #16 0x449a92 (/home/g/Codigo/mujs/build/mujs+0x449a92)
    #17 0x44b016 (/home/g/Codigo/mujs/build/mujs+0x44b016)
    #18 0x451bf0 (/home/g/Codigo/mujs/build/mujs+0x451bf0)
    #19 0x417603 (/home/g/Codigo/mujs/build/mujs+0x417603)
    #20 0x4178da (/home/g/Codigo/mujs/build/mujs+0x4178da)
    #21 0x417b55 (/home/g/Codigo/mujs/build/mujs+0x417b55)
    #22 0x4025a6 (/home/g/Codigo/mujs/build/mujs+0x4025a6)
    #23 0x7ffff47a1ec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
    #24 0x402a04 (/home/g/Codigo/mujs/build/mujs+0x402a04)
0x60040000dffb is located 0 bytes to the right of 11-byte region [0x60040000dff0,0x60040000dffb)
allocated by thread T0 here:
    #0 0x7ffff4e6041a (/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0+0x1541a)
    #1 0x40d934 (/home/g/Codigo/mujs/build/mujs+0x40d934)
Shadow bytes around the buggy address:
  0x0c00ffff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c00ffff9bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 00[03]
  0x0c00ffff9c00:fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9c40: 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
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==1132== ABORTING

Program received signal SIGABRT, Aborted.
0x00007ffff47b6cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56	../nptl/sysdeps/unix/sysv/linux/raise.c: No existe el archivo o el directorio.
(gdb) bt
#0  0x00007ffff47b6cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff47ba0d8 in __GI_abort () at abort.c:89
#2  0x00007ffff4e66829 in ?? () from /usr/lib/x86_64-linux-gnu/libasan.so.0
#3  0x00007ffff4e5d3ec in ?? () from /usr/lib/x86_64-linux-gnu/libasan.so.0
#4  0x00007ffff4e64012 in ?? () from /usr/lib/x86_64-linux-gnu/libasan.so.0
#5  0x00007ffff4e63121 in __asan_report_error () from /usr/lib/x86_64-linux-gnu/libasan.so.0
#6  0x00007ffff4e5d6a4 in __asan_report_load1 () from /usr/lib/x86_64-linux-gnu/libasan.so.0
#7  0x000000000041f0a7 in jsU_chartorune (rune=rune@entry=0x7fffffffd5c0, str=str@entry=0x60040000dffb "") at utf.c:55
#8  0x000000000043f066 in jsY_next (J=J@entry=0x608200004a00) at jslex.c:155
#9  0x000000000043f5fb in lexescape (J=<optimized out>) at jslex.c:404
#10 lexstring (J=J@entry=0x608200004a00) at jslex.c:422
#11 0x0000000000441473 in jsY_lexx (J=0x608200004a00, J@entry=0xc10bfff894b) at jslex.c:582
#12 jsY_lex (J=J@entry=0x608200004a00) at jslex.c:722
#13 0x000000000044d7b7 in jsP_next (J=0x608200004a00) at jsparse.c:132
#14 callexp (J=0x608200004a00) at jsparse.c:411
#15 postfix (J=0x608200004a00) at jsparse.c:417
#16 unary (J=J@entry=0x608200004a00) at jsparse.c:434
#17 0x000000000044e466 in multiplicative (J=J@entry=0x608200004a00) at jsparse.c:439
#18 0x000000000044e746 in additive (J=J@entry=0x608200004a00) at jsparse.c:449
#19 0x000000000044e986 in shift (J=J@entry=0x608200004a00) at jsparse.c:458
#20 0x000000000044ec7a in relational (J=J@entry=0x608200004a00, notin=notin@entry=0) at jsparse.c:468
#21 0x000000000044f199 in equality (J=J@entry=0x608200004a00, notin=notin@entry=0) at jsparse.c:481
#22 0x000000000044f549 in bitand (J=J@entry=0x608200004a00, notin=notin@entry=0) at jsparse.c:492
#23 0x000000000044f6c9 in bitxor (J=J@entry=0x608200004a00, notin=notin@entry=0) at jsparse.c:500
#24 0x000000000044f84a in bitor (notin=notin@entry=0, J=J@entry=0x608200004a00) at jsparse.c:508
#25 logand (J=J@entry=0x608200004a00, notin=notin@entry=0) at jsparse.c:516
#26 0x000000000044fadb in logor (J=J@entry=0x608200004a00, notin=notin@entry=0) at jsparse.c:524
#27 0x000000000044fc0d in conditional (notin=0, notin@entry=1102416563, J=J@entry=0x608200004a00) at jsparse.c:533
#28 assignment (J=J@entry=0x608200004a00, notin=notin@entry=0) at jsparse.c:545
#29 0x0000000000450859 in expression (J=J@entry=0x608200004a00, notin=notin@entry=0) at jsparse.c:563
#30 0x0000000000449a93 in statement (J=J@entry=0x608200004a00) at jsparse.c:817
#31 0x000000000044acb6 in scriptelement (J=J@entry=0x608200004a00) at jsparse.c:839
#32 0x000000000044b017 in script (J=J@entry=0x608200004a00, terminator=terminator@entry=0) at jsparse.c:847
#33 0x0000000000451bf1 in jsP_parse (J=J@entry=0x608200004a00, filename=filename@entry=0x7fffffffe362 "oob.js", 
    source=source@entry=0x60040000dff0 "se('\"?s1I\\") at jsparse.c:945
#34 0x0000000000417604 in js_loadstringx (J=J@entry=0x608200004a00, filename=filename@entry=0x7fffffffe362 "oob.js", 
    source=source@entry=0x60040000dff0 "se('\"?s1I\\", iseval=iseval@entry=0) at jsstate.c:55
#35 0x00000000004178db in js_loadstring (source=0x60040000dff0 "se('\"?s1I\\", filename=0x7fffffffe362 "oob.js", J=0x608200004a00) at jsstate.c:70
#36 js_loadfile (J=J@entry=0x608200004a00, filename=filename@entry=0x7fffffffe362 "oob.js") at jsstate.c:121
#37 0x0000000000417b56 in js_dofile (J=J@entry=0x608200004a00, filename=0x7fffffffe362 "oob.js") at jsstate.c:150
#38 0x00000000004025a7 in main (argc=<optimized out>, argv=0x7fffffffdfd8) at main.c:175

This test case was found using QuickFuzz.

Regards,
Gustavo.
Comment 5 Tor Andersson 2016-11-04 09:12:15 UTC
Gustavo,

With the latest git code your example runs as follows:

$ echo "c2UoJyI/czFJXA==" | base64 -d > oob.js
$ ./build/mujs oob.js
SyntaxError: o:1: unterminated escape sequence

I believe this was fixed in a later commit a0ceaf5050faf419401fe1b83acfa950ec8a8a89 to check for incomplete escape sequences.
Comment 6 gustavo.grieco 2016-11-06 16:34:56 UTC
Great. I will re-test and let you know if i can find any other related memory issue.