smartloader: same luajit binary in 17 repos across 14 cves

2026-03-14 · malware · github · smartloader · stealc · luajit

Out of 2,712 PoC repository archives scanned by rdintel, 76 scored as malicious. 17 of those repos share the same two file hashes, spread across 15 GitHub accounts and 14 unrelated CVEs. All 17 scored 1.0 (maximum malware confidence).

The binaries are luajit.exe (99 KB) and lua51.dll (3,449 KB). The payload is SmartLoader, which delivers StealC via process hollowing.

what rdintel flagged

Our scanner fires on seven distinct signals for these repos. Here is the output from KvzinNcpx7/kvzinncpx7.github.io:

[renamed_interpreter]        lua51.dll is a renamed LuaJIT binary (3449 KB)
[interpreter_with_payload]   lua51.dll (LuaJIT) loads payload: arch.txt (347 KB)
[interpreter_with_payload]   luajit.exe (LuaJIT) loads payload: arch.txt (347 KB)
[nested_archive_with_exe]    io_github_kvzinncpx_v2.3.zip contains executables: lua51.dll, luajit.exe
[nested_archive_with_scripts] io_github_kvzinncpx_v2.3.zip contains scripts: Launcher.cmd
[bat_launches_exe]           Launcher.cmd launches: luajit.exe
[obfuscated_payload]         arch.txt (347 KB) contains obfuscated code:
                             lua varargs pattern, single-line packed code, high special-char ratio

The same pattern repeats across all 17 repos: a ZIP containing luajit.exe + lua51.dll + an obfuscated .txt file + a .cmd launcher. The exe hashes are identical. The bytecode payload names change per repo.

the archive contents

file sha256 size
luajit.exe 5343326fb0b4f79c32276f08ffcc36bd88cde23aa19962bd1e8d8b80f5d33953 99 KB
lua51.dll c7a657af5455812fb215a8888b7e3fd8fa1ba27672a3ed9021eb6004eff271ac 3,449 KB
bytecode payload varies per repo 335-347 KB
Launcher.cmd 627b500fc6ae782368f39fc36e7ac5f3da38b962070a07f71782526e548dac03 <1 KB

luajit.exe scores 31/76 on VirusTotal. BitDefender detects it as Gen:Heur.FakeGit.1. lua51.dll scores 0/76 because it is a legitimate Lua 5.1 runtime. The bytecode file (arch.txt, ico.txt, clib.txt, etc.) looks like random text to static analysis.

all 17 repositories

The ZIP name, bytecode filename, and repo description vary per repo, but the executables are identical.

# account repository cve zip name payload file
1 KvzinNcpx7 kvzinncpx7.github.io CVE-2025-9074 io_github_kvzinncpx_v2.3.zip arch.txt
2 freiwi CVE-2025-8110 CVE-2025-8110 CV-2.0.zip arch.txt
3 kikiuuw kikiuuw.github.io CVE-2025-68921 github_io_kikiuuw_1.0-alpha.1.zip ico.txt
4 kikiuuw CVE-2025-68921 CVE-2025-68921 CV_3.6.zip ico.txt
5 juccoblak CVE-2025-6554 CVE-2025-6554 CVE-2025-6554_1.6.zip clib.txt
6 siddu7575 CVE-2025-61882-CVE-2025-61884 CVE-2025-61882 CVE-2025-61882-CVE-2025-61884.zip vm.txt
7 yogeshkumar09 yogeshkumar09.github.io CVE-2025-55184 yogeshkumar-io-github-v2.9.zip arch.txt
8 yogeshkumar09 CVE-2025-55184_Testing CVE-2025-55184 CV-Testing-v3.9.zip arch.txt
9 Black-and-reds reactguard CVE-2025-55183 Software-3.8.zip cdef.txt
10 Asder10 asder10.github.io CVE-2025-55182 github_io_asder_v2.0.zip license.txt
11 vick333-peniel vick333-peniel.github.io CVE-2025-55182 peniel-io-github-vick-v3.5.zip cdef.txt
12 sakyu7 sakyu7.github.io CVE-2025-43529 io-github-sakyu-1.9.zip clx.txt
13 Nikopmpm nikopmpm.github.io CVE-2024-0670 github_nikopmpm_io_v1.9-alpha.4.zip arch.txt
14 Hitplus hitplus.github.io CVE-2023-39910 github_io_hitplus_1.2.zip arch.txt
15 Boydunbarred375 gi-cv CVE-2020-14144 gi-cv-3.4.zip license.txt
16 Riocipta75 lab-cve-2020-0610 CVE-2020-0610 lab-cve-2020-0610.zip -
17 mzuhair9933 PoPE-pytorch CVE-2016-0856 pytorch-P-Po-v3.5-alpha.2.zip icon.txt

First seen: 2022-01-12. Last seen: 2026-01-26.

repo descriptions are ai-generated

Every repo has an AI-generated description and README. Examples from our scan data:

  • reactguard: “Detect vulnerabilities in React Server Components with ReactGuard”
  • PoPE-pytorch: “Implement polar coordinate positional embedding in PyTorch for efficient attention”
  • gi-cv: “Create a documentation-as-code CV showcasing your skills and experience”
  • CVE-2025-9074: “Exploit CVE-2025-9074 using this API exploitation framework designed for Docker environments”
  • CVE-2025-6554: “Demonstrate and validate the addressof and fakeobj primitives in the V8 sandbox”

All descriptions start with an emoji. Three repos (reactguard, PoPE-pytorch, gi-cv) disguise themselves as legitimate projects. The rest name-drop the CVE they are impersonating.

Several READMEs link directly to the malicious archive hosted in the repo or in a related account’s repo. Our scanner flagged these as doc_links_to_archive.

overlapping accounts across clusters

rdintel tracks 18 malware clusters total. Three accounts from this cluster also appear in separate clusters with different binaries:

account this cluster also in
sakyu7 luajit.exe (CVE-2025-43529) reinit.exe cluster (sha256:5b6f8ee0..., 4 repos, 4 CVEs)
mzuhair9933 luajit.exe (CVE-2016-0856) reinit.exe cluster
Asder10 luajit.exe (CVE-2025-55182) unc.exe cluster (sha256:30694a01..., 2 repos, 2 CVEs)

These accounts distribute multiple unrelated malware binaries. This confirms they are not compromised accounts with a single injected repo; they are operated as part of the campaign.

delivery via github pages

8 of 17 repos are GitHub Pages sites (*.github.io). This means the malware is served both to people who clone the repo and to anyone who visits the page URL. The Pages sites use the repo description as page content, creating a landing page that links to the archive download.

execution chain

Launcher.cmd runs start luajit.exe conf.txt (or arch.txt, ico.txt, etc. depending on the repo). The console window is hidden immediately via GetConsoleWindow + ShowWindow(SW_HIDE).

luajit.exe loads lua51.dll and interprets the bytecode. The Lua payload declares an 8,514-byte FFI C definition block and calls Windows APIs directly:

Process injection:

CreateProcessA(CREATE_SUSPENDED) -> NtUnmapViewOfSection -> VirtualAllocEx
-> WriteProcessMemory -> SetThreadContext -> ResumeThread

Targets: openwith.exe, dialer.exe, dllhost.exe, rundll32.exe.

Alternative path: VirtualAlloc(PAGE_EXECUTE_READWRITE) + CreateThread.

Reconnaissance: GetComputerNameW, IsWow64Process, GetSystemMetrics, screenshot via GDI chain (GetDC / CreateCompatibleDC / CreateDIBSection / BitBlt), then http://ip-api.com/json/ for geolocation. Exfiltrated with static user-agent s3klqc1wa6ntg1szvckzi0nt9oumpwy6hhq.

FFI structures: IMAGE_DOS_HEADER, IMAGE_NT_HEADERS32/64, IMAGE_EXPORT_DIRECTORY, TOKEN_ELEVATION, OSVERSIONINFOEXW, PEB/LDR (manual API resolution to avoid import table analysis).

C2 resolution

SmartLoader resolves C2 by calling a Solidity getter on Polygon Mainnet:

contract function selector deployed
0xd68910ED4D4A5A9bAdF9ec95604CAE0f3378479B getDomain() 0xb68d1809 2025-02-21
0x2cbd2464dd749f5c0034fc9cddc6db2d53dea400 getDomain() 0xb68d1809 -
0x1823A9a0Ec8e0C25dD957D0841e3D41a4474bAdc getData() 0x3bc5de30 2025-11-15

RPC: polygon-rpc.com. The operator called destroyContract() on the V1 contract on 2026-01-26; it failed because EIP-6780 (post-Dencun) prevents selfdestruct from clearing contract state.

Resolved domains: layer1.icu (registered 2025-02-21), aproxy.app (registered 2025-03-10).

Fallback: hex-encoded blobs fetched from GitHub dead drop repos (github.com/rd898/package, github.com/Mahmudul-Riad/www, github.com/aidagluglu/files, github.com/AKboss1221/fortigate-belsen-leak). Decrypted with 32-byte XOR key ECe6VGLRJum2qYtl79OiOU7aHot7Zhbn.

obfuscation

Lua bytecode uses the Prometheus obfuscator. ESET tracks 16 distinct generations (Lua/Agent.Z through .BT).

  • Custom Base64 alphabet: L07ker/2Jn4Z+b6y8hfXYVpTiDCvQKc3qRjUEBdo9MzHxtGNgWuA1FSmlaPO5wIs
  • P table: 1,078 entries of encrypted constants (~114KB per payload)
  • Three-pass shuffle on P table: {1,1064}, {1,658}, {659,1064}
  • State machine dispatcher over encrypted bytecode
  • All strings assembled from P table at runtime; zero plaintext
  • Addition cipher: (plaintext + key) mod 256, key 89pCO1NlLRkTZgb8DtZmKwC42AQcUeXF

PE crypter and stealc

The crypter loads AES-256-ECB-encrypted payload from PE resource RCDATA (ID 101). Two hardcoded 32-byte constants XORed via AVX2 (vpxor ymm1, ymm0, [rbp+0x20]) produce the AES key. Base64url decode precedes decryption. Output: 779,808 bytes.

AES keys: YOYd5_dZpfW_nmA-rTxg61gpdbu_26-u (build0, 2025-02-27), 51AabzlG90_c_K9JZ8YXRGTOFralTd8k (build6, 2025-03-02).

StealC (TrojanPSW:Win64/StealC) resolves 120+ Win32 APIs via PEB walking. Config encrypted with RC4 (keys: qAw6EF2z3ycMeACsJA, dVhllnj7MBHRDVTFDT).

Targets: Chromium Login Data/Cookies/Web Data/History/IndexedDB/App-Bound Encryption, Firefox logins.json/cookies.sqlite via NSS3 (PK11SDR_Decrypt), Outlook (Office 13.0-16.0), Steam (ssfn*, config.vdf), WinSCP sessions, FoxMail.

persistence

%AppData%\ODE3\ODE3.exe          (renamed luajit.exe)
%AppData%\ODE3\module.class      (bytecode)
%AppData%\ODE3\lua51.dll         (runtime)
%USERPROFILE%\Pictures\<MachineGUID>  (task cache)
%TEMP%\session.lua / debug.lua   (secondary payloads)

Scheduled tasks:
  SecurityHealthService_ODE3
  ApplicationExperienceAnalyzeris_ODE4
  WindowsErrorReporting_<Base64EncodedLoaderID>

Registry: HKCU:\SOFTWARE\SibCode\

C2 IPs

89.169.13.215    95.164.53.26     150.241.108.62
77.105.164.178   89.169.12.179    87.120.36.50
178.236.243.5    80.66.81.11      150.241.105.82
213.176.73.80    91.196.34.40     89.169.12.173
89.169.12.241    217.119.129.110  213.176.72.200

detection

Test-Path "$env:APPDATA\ODE3"
Get-ScheduledTask | Where-Object {
  $_.TaskName -match 'SecurityHealthService_ODE|ApplicationExperienceAnalyzeris_ODE|WindowsErrorReporting_ODE'
}
Get-ItemProperty "HKCU:\SOFTWARE\SibCode\" -ErrorAction SilentlyContinue
Get-ChildItem "$env:USERPROFILE\Pictures" -Filter "*-*-*-*-*" -Directory

AV: BitDefender Gen:Heur.FakeGit.1, ESET Lua/Agent.Z through .BT, Microsoft TrojanPSW:Win64/StealC.

If executed: rotate browser passwords, session cookies, crypto wallet keys, Outlook credentials, Steam sessions, WinSCP saved sessions, any API keys on the machine.

mitre att&ck

id technique
T1566.002 Spearphishing Link
T1204.002 User Execution: Malicious File
T1059.007 Scripting Interpreter (Lua)
T1036.005 Masquerading
T1027 Obfuscated Files
T1140 Deobfuscate/Decode
T1102.001 Dead Drop Resolver
T1055.012 Process Hollowing
T1113 Screen Capture
T1555.003 Credentials from Browsers
T1539 Steal Web Session Cookie

additional hashes

# stealc
ca42898e885979196647b6e5c469461a25870c1f15ef5910d531f37f8f3f147f  build0
63c8cedc49339dd788dbc25f851dfce5219045aef80dd9bd17343948fb73f954  build6

# related luajit variants
1cf20b8449ea84c684822a5e8ab3672213072db8267061537d1ce4ec2c30c42a  lua.exe
ff976f6e965e3793e278fa9bf5e80b9b226a0b3932b9da764bffc8e41e6cdb60  lua51.dll variant

# bytecode payloads
4b1ba932f06251267820b1af5f0a533f869e809bb9c6a1729a8097553d2f874e  conf.txt
57df281639cfd3245818757cd30887b1128153b8d3d2e013166a362acd0ec72a  import.ui

# archives
ebb0c76a03b8bb0ba246b8b31143f4462b4c3b0b3b5d581c499b4c3a484fd792  Application.zip
81580758604dff8b2b8f9126645e4a897e9b86b63bede420a07b1a6b3a973638  Application.zip variant

# related clusters (shared accounts)
5b6f8ee0072386b4b63cbcb8f83ef010005d4b6ed3cbd906a094a69726475d62  reinit.exe
30694a0101abfeea642cb9de7fb7eb66789eea74d8d7257b39822d7dab59445d  unc.exe

references

← all posts