Team nilarmstrong<br>(BoB 10th)
by Team nilarmstrong
(BoB 10th)
12 min read

Categories

Tags

From the implemented fuzzer, thousands of crash files were generated. Since we are just a small team and we had limited time for this project, we needed some strategy to classify our crash files. Also, as crash files were .lua script files, we spent much time on analyzing root cause of crash files. We believe this post would be helpful to those who are trying to analyze lua script that causes crash on Lua interprerter.

1. Classifying crash files

1) Comparing hash value of call stack’s PC

Under the same environment, we made an assumption that if hash values of call stack’s PC(from call stack #0 to call stack #4) of two crash files are same, they are overlapped. We made script files to automate comparing process. You can refer the script files from this link. Using this method the number of crash files was reduced from thousands to hundreds.

2) Checking crash type

Hundreds of crash files are still a long way to go. There were various kinds of crash files. Crash files caused use-after-free, heap overflow, stack overflow, segmentation violation, etc. Not qqqqqqqqqqall crash files are related to worthwhile vulnerability. Our mentor recommended us to give precedence to crash type. We first analyzed use-after-free, segmentation violation, then heap overflow, and so on. Recently, we could find an exploitable vulnerability from use-after-free crash file. It would be helpful to first analyze suspicious crash files before trivial ones.



2. Tips for analyzing the crash

makefile

  • AddressSanitizer If you want to use AddressSanitizer, you need to add -fsanitize=address option to the makefile.

  • GDB debugging with source code If you want to debug with source code, you need to add -g -O0 options to the makefile.


  • A makefile with nothing applied

    # skipped
    # enable Linux goodies
    MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUA_USE_READLINE
    MYLDFLAGS= $(LOCAL) -Wl,-E
    MYLIBS= -ldl -lreadline
    
    
    CC= gcc
    CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common -march=native
    AR= ar rc
    RANLIB= ranlib
    RM= rm -f
    # skipped
    



  • ASAN, debug wth source code applied makefile

    # skipped
    # enable Linux goodies
    MYCFLAGS= $(LOCAL) -g -O0 -std=c99 -DLUA_USE_LINUX -DLUA_USE_READLINE -fsanitize=address #-DLUAI_ASSERT -DLUA_USE_APICHECK
    MYLDFLAGS= $(LOCAL) -Wl,-E
    MYLIBS= -ldl -lreadline -fsanitize=address
    
    
    CC= gcc
    CFLAGS= -Wall $(MYCFLAGS) -fno-stack-protector -fno-common -march=native
    AR= ar rc
    RANLIB= ranlib
    RM= rm -f
    # skipped
    



Crash Minimization

It is efficient to reduce the code of the crash to analyze the root cause of the crash. Below is an example of actually reducing the crashes from the project’s fuzzer.



  • example original crash
  local function c(a,b) local label = string.gsub("0123456789", 40) end
    local function v(f, ...) string.packsize"XXxX" end
    setmetatable({}, {__gc = function () string.packsize(type"", "^([^\n]+)\n") end})
    local b,c = next(string)
    local function v(f, ...) local function c(x)
    os.exit(err, "[^\n]", "")
  end
    local function v(x)
    os.exit(err, "[^\n]", "")
  end
    local a <close> = setmetatable({}, {__close = c})
    return v(function() return x end) end
    local a <close> = setmetatable({}, {__close = c})
    return v(function() return x end)


  • example minimal crash
  local function v(a, b, c, ...)
    return os.exit(0, true)
  end

  local function a()
    return h()
  end

  local e <close> = setmetatable({}, {__close = string.rep})

  v()



ByteCode


Due to the characteristics of the lua interpreter, the parsed code is converted into bytecode and executed. Therefore, in order to analyze the root cause of a minimized crash, it is necessary to know which bytecode the crash code is converted to. So, we analyzed the crash by referring to the luac.nl web page that converts lua code into bytecode.

The converted bytecode is operated in the luaV_execute function inside Lua. After checking which bytecode among the bytecodes generated by the crash code causes the crash to occur, we focused on that part to find out the root cause.