{
	"id": "74f794d4-82bd-47a6-88a6-4d5316f34816",
	"created_at": "2026-04-06T00:07:06.43886Z",
	"updated_at": "2026-04-10T03:19:57.789236Z",
	"deleted_at": null,
	"sha1_hash": "68628fa55fc66a52cf15670c92405f44c44b894e",
	"title": "GitHub Bug Used to Infect Game Hackers With Lua Malware",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 198458,
	"plain_text": "GitHub Bug Used to Infect Game Hackers With Lua Malware\r\nPublished: 2024-03-03 · Archived: 2026-04-05 15:45:45 UTC\r\nOverview\r\nMalware operators are using a cloned game cheat website, SEO poisoning, and a bug in GitHub to trick would-be-game-hackers into running Lua malware. Our notes are divided into two sections, the first part is focuses on the\r\nGitHub bug the enables the malware delivery and the second part covers our attempt to analyze the Lua JIT\r\nmalware.\r\nSpecial Thanks\r\n@JustasMasiulis\r\n0AVX\r\nFish-Sticks\r\nJollyc\r\n@xusheng6\r\nThemida for the sample 😉\r\nDelivery\r\nThe game cheat that has been targeted is an open source aim bot called AIMMY which is maintained in the\r\nfollowing GitHub repository Babyhamsta/Aimmy with the website aimmy.dev.\r\nThe malware operators have made a clone of the GitHub repository here\r\nhttps[:]//github[.]com/nehuenbohm/Aimmy and setup a malicious website https[:]//aimmy[.]app which\r\nlinks to the cloned GitHub repository. The website also has a modified download link which links to malware\r\nhosted at https[:]//github[.]com/Babyhamsta/Aimmy/files/14475029/Aimmy.zip . Note that this download link\r\nis for a ZIP file that is hosted on the original benign GitHub repository.\r\nThe malicious website has a high Google rank (likely due to SEO poisoning) and is ranked above the legitimate\r\naim bot website. Users searching for the aim bot are likely to be tricked into visiting the malicious site and\r\ndownloading the malware.\r\nhttps://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html\r\nPage 1 of 7\n\nA key element in the attack involves hosting that malware payload on the original benign repository. This both\r\ndistances the operators from the payload host and also may enable the download URL to blend in with normal\r\ntraffic. Using this trick makes it difficult for the victim to identify that they are clicking a malicious link. But how\r\nare the operators able to host their malware on another GitHub repository? This had us stumped until\r\n@JustasMasiulis discovered the bug … feature?\r\nWhen opening an issue on a repository any file uploaded to the issue is stored under the GitHub repository\r\nwhere the issue when opened. These files persist even if the issue is never saved. This means that anyone can\r\nupload a file to any git repository on GitHub an not leave any trace that the file exists except for the direct link.\r\nCick New Issue on the target GitHub repository\r\nDrag and drop malware into issue description\r\nCopy generated link for malware from description\r\nClose issue without submitting/saving\r\nThe link to the uploaded malware remains active even though the issue was never saved\r\n@JustasMasiulis posted a POC of this to X last night.\r\nMalicous GitHub Cloning\r\nhttps://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html\r\nPage 2 of 7\n\nThe malware operators also used a clever technique to obscure the fact that they have cloned the original GitHub\r\nrepository. ArsTechnica recently detailed similar malicious cloning attacks but in this case we were able to\r\nobserve the attack in real time, and can report some additional details.\r\nThe target repository is downloaded then uploaded to a new account, it is not forked.\r\nThough the git commit history is maintained in the newly uploaded repository it does not display as a fork\r\nof the original repository.\r\nThe operator then makes thousands of empty commits to the repository, likely scripted, making it appear\r\nas though they are main contributor to the project. In the case of the aim bot the operator made over seven\r\nthousand commits in a 24h hour period.\r\nThe final commit is made to the project README changing the project download links to the malware\r\nURL. This commit is made as a GitHub verified user as the user is verified for the repo.\r\nLua Malware Analysis\r\nThe malware itself is very unique. It consists of a Lua JIT file, a compiled LuaJIT executable used to interpret the\r\nJIT file, and a batch script used to elevate permissions and run the JIT in the interpreter.\r\nSample\r\nThe malware is delivered in a ZIP file malshare\r\nc912762952152c40646a61d7cc80a74f61ddd7aad292a1812f66e76b405f9660 Aimmy.bat\r\nBatch script used to run the lua code in the interpreter\r\n1cf20b8449ea84c684822a5e8ab3672213072db8267061537d1ce4ec2c30c42a AimmyLauncher.exe\r\nLuaJIT intepreter\r\nd6d3c8ea51a025b3abeb70c9c8a17ac46cf82e5a46a259e9aaa9d245212d9e17 README.txt\r\nfa3224ec83c69883519941c0e010697bcdc0518a3d9e2c081cd54f5e9458b253 data\r\nMalicious compiled Lua JIT code, magic bytes 1B 4C 4A\r\nhttps://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html\r\nPage 3 of 7\n\nff976f6e965e3793e278fa9bf5e80b9b226a0b3932b9da764bffc8e41e6cdb60 lua51.dll\r\nAnalysis\r\nUsing the LuaJIT Decompiler v2 we were able to decompile the JIT and recover the Lua code only find that it had\r\nbeen heavily obfuscated.\r\nlocal var_0_19 = {\r\n var_0_17[var_0_18(\"\\xA7Z$\\\\oӈ.\", 8170536974433)],\r\n var_0_17[var_0_18(\"\\x83\\xEB\\xC1\\xEC\\xAER\\x0E\\xCB\", 32340223605166)],\r\n var_0_17[var_0_18(\"\\x98E\\r\\f\", 18847752807337)],\r\n var_0_17[var_0_18(\"Z\\x16g\\xD2\", 17704612011450)],\r\n var_0_17[var_0_18(\"K۽\\^xAE\\xF8_\\xFF\", 2538651564100)],\r\n var_0_17[var_0_18(\"\\x1Bdo\\xF6B\\xF3\\x92\\xC0\\x84^zg\\x8B\\xB1\\x95\\xC3\", 17854945091482)],\r\n var_0_17[var_0_18(\"\\xFFYk\\xF5\\xAB37\\x83\", 21489022010759)],\r\n var_0_17[var_0_18(\"\\x8Eq\\x85\\x93yJ.\\xD8\", 17231694304248)],\r\n var_0_17[var_0_18(\"\\xDD,G\\x17\\xEBg#h\", 1115184245546)],\r\n var_0_17[var_0_18(\"DE\\x10D\", 12159446557750)],\r\n var_0_17[var_0_18(\"(\\x92\\xE7\\xB9X\\xEE8C޵\\x19Z\\xBE\\x8Fq\\xBF\", 24217461828912)],\r\n var_0_17[var_0_18(\"\\xF8cQsU\\xAF\\x9C\\x9C\", 12518619714798)],\r\n var_0_17[var_0_18(\"o\\x01\\xC1\\xC7\\xE7$(\\x84\", 29604450893836)],\r\n . . .\r\nThe obfuscation was matched to an open source Lua obfuscator called Prometheus. This obfuscator bot encrypts\r\nstrings, and employs a virtual machine to protect the Lua code.\r\nLua Environment Instrumentation\r\nRather than attempting to break the VM directly we attempted to trace the Lua code dynamically. Because the\r\nmalicious Lua code is passed as an argument to the LuaJIT interpreter we first attempted to instrument the Lua\r\nenvironment by loading tracing code prior to running the JIT, a concept based on the ideas outlined in Nick’s blog\r\nHooking LuaJIT. Using the following script passed with the -e argument to the interpreter.\r\nAimmyLauncher.exe -e \u003cscript\u003e data\r\njit.off()\r\nFILE_PATH = \"C:\\\\LuaJitHookLogs\\\\\"\r\nSTARTING_TIME = os.clock()\r\nGDUMPED = false\r\nfunction table.show(t)\r\nhttps://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html\r\nPage 4 of 7\n\nlocal function serialize(arr, level)\r\n local str = \"\"\r\n local indent = string.rep(\" \", level*2)\r\n for i, v in pairs(arr) do\r\n if type(v) == \"table\" then\r\n str = str .. indent .. i .. \":\\n\" .. serialize(v, level+1)\r\n else\r\n str = str .. indent .. i .. \": \" .. tostring(v) .. \"\\n\"\r\n end\r\n end\r\n return str\r\n end\r\n return serialize(t, 0)\r\nend\r\nfunction dumpGlobals()\r\n local fname = FILE_PATH .. \"globals_\" .. STARTING_TIME .. \".txt\"\r\n local globalsFile = io.open(fname, \"w\")\r\n globalsFile:write(table.show(_G, \"_G\"))\r\n globalsFile:flush()\r\n globalsFile:close()\r\nend\r\nfunction trace(event, line)\r\n local info = debug.getinfo(2)\r\n if not info then return end\r\n if not info.name then return end\r\n if string.len(info.name) \u003c= 1 then return end\r\n if (not GDUMPED) then\r\n dumpGlobals()\r\n GDUMPED = true\r\n end\r\n local fname = FILE_PATH .. \"trace_\" .. STARTING_TIME .. \".txt\"\r\n local traceFile = io.open(fname, \"a\")\r\n traceFile:write(info.name .. \"()\\n\")\r\n local a = 1\r\n while true do\r\n local name, value = debug.getlocal(2, a)\r\n if not name then break end\r\n if not value then break end\r\nhttps://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html\r\nPage 5 of 7\n\ntraceFile:write(tostring(name) .. \": \" .. tostring(value) .. \"\\n\")\r\n a = a + 1\r\n end\r\n traceFile:flush()\r\n traceFile:close()\r\nend\r\ndebug.sethook(trace, \"c\")\r\nThis had some limited success, there is an anti-tamper feature in the VM (which was eventually bypassed by\r\nJollyc) but I ran into some issues... mainly I don’t know anything about Lua and troubleshooting the errors was\r\ntime consuming.\r\nLua Garbage - Dumping Encrypted Strings\r\nThis idea belongs to Jolyc, Fishy-Sticks, and 0AVX. As Fishy-Sticks put it...\r\nLua is a managed language which has a garbage collector, me and AVX are looking for where they\r\ncollect strings so we can dump all string info before it gets collected thus holding decrypted strings :)\r\nLuaJIT is a little bit diff from normal Lua so it takes us a bit to find All that was needed was to clone\r\nthe LuaJIT repository, locate the garbage collector for the strings in the LuaJIT code, and add our own\r\nhook to dump them before they were freed. We could then compile our custom version of LuaJIT and\r\nuse this to run the malicious Lua code and dump the strings.\r\nHook lj_str_free\r\nThe lj_str_free function in lj_str.c is responsible for freeing the string memory. By adding some simple\r\nlog code here and recompiling\r\nvoid LJ_FASTCALL lj_str_free(global_State *g, GCstr *s)\r\n{\r\n const char* myStr = strdata(s);\r\n if (myStr) {\r\n printf(\"STRING: %s\\n\", myStr);\r\n FILE* newfile = fopen(\"log.txt\", \"a\");\r\n fprintf(newfile, \"STRING: %s\\n\", myStr);\r\n fclose(newfile);\r\n }\r\n g-\u003estr.num--;\r\n lj_mem_free(g, s, lj_str_size(s-\u003elen));\r\n}\r\nAdditional hooks can be added in lib_os.c on the os functions to dump interactions between the Lua and the\r\nhost.\r\nhttps://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html\r\nPage 6 of 7\n\nLJLIB_CF(os_execute)\r\n{\r\n const char* cmd2 = luaL_optstring(L, 1, NULL);\r\n if (cmd2) {\r\n printf(\"OS_EXECUTE: %s\\n\", cmd2);\r\n FILE* newfile = fopen(\"log.txt\", \"a\");\r\n fprintf(newfile, \"OS_EXECUTE: %s\\n\", cmd2);\r\n fclose(newfile);\r\n }\r\nBecause many string operators result in partial strings being allocated to memory there is a lot of noise in the\r\ndump but we were able to recover full structs, function definition, as well as strings used for the C2\r\ncommunication and persistence of the malware.\r\nTODO - this approach could be combined with more classic API tracing to provide an more holistic view of the\r\nmalware.\r\nSource: https://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html\r\nhttps://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html\r\nPage 7 of 7",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://research.openanalysis.net/github/lua/2024/03/03/lua-malware.html"
	],
	"report_names": [
		"lua-malware.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775434026,
	"ts_updated_at": 1775791197,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/68628fa55fc66a52cf15670c92405f44c44b894e.pdf",
		"text": "https://archive.orkl.eu/68628fa55fc66a52cf15670c92405f44c44b894e.txt",
		"img": "https://archive.orkl.eu/68628fa55fc66a52cf15670c92405f44c44b894e.jpg"
	}
}