Malicious Packagist Packages Masquerade as Laravel Tools, Drop RAT
Socket’s Threat Research Team has uncovered a sophisticated supply chain attack targeting PHP developers via Packagist, the primary Composer package repository for PHP.
Malicious packages published under the account “nhattuanbl” disguise themselves as legitimate Laravel utilities while delivering a fully featured remote access trojan (RAT). This campaign highlights the growing risks of transitive dependencies in open-source ecosystems.
Revealing three implicated packages from the nhattuanbl account, registered on Packagist since December 12, 2015.
The primary vectors are nhattuanbl/lara-helper (version 5.4.7) and nhattuanbl/simple-queue (version 1.5), both of which embed an identical malicious payload in src/helper.php (SHA-256: a493ce9509c5180e997a04cab2006a48202afbb8edfa15149a4521067191ead7).
A third package, nhattuanbl/lara-swagger (version 2.0), appears benign but enforces a hard dependency on lara-helper@dev-master, automatically installing the RAT during Composer resolution.
The threat actor maintains private profiles on GitLab and GitHub, limiting visibility into their activity. All six packages under nhattuanbl, three clean (lara-syslog, lara-media, and one other), and three malicious were published between June and December 2024.
The clean packages likely served to build credibility, accumulating modest install counts before the RAT-laden ones dropped last. Cross-references, such as dangling imports in lara-syslog and lara-mediathat point to lara-helper, indicate that the malware was baked into the actor’s local development workflow.
The 27,340-byte helper.php file employs aggressive obfuscation to evade detection: randomized goto labels (e.g., tc0pE, IlaiV), hex/octal-encoded strings for domains and paths, and garbage variable names ($riz07, BsYhQ()). This “goto spaghetti” flattens control flow, rendering static analysis ineffective without dynamic execution.
Upon inclusion via Laravel service provider autoloading in lara-helper or class autoload in simple-queue, the payload first checks for CLI arguments.
In web contexts, it spawns a detached background process (php helper.php helper on Unix/Windows) using a 15-minute lockfile ({sys_get_temp_dir()}/wvIjjnDMRaomchPprDBzzVSpzh61RCar.lock) to prevent duplicates. The parent process exits cleanly, masking the compromise from application logs.
The RAT establishes a persistent TCP connection to helper.leuleu.net:2096 using stream_socket_client(), retrying every 15 seconds indefinitely.
Communication uses AES-128-CTR encryption with a hardcoded 16-byte key (esCAmxUoJkIjTV0n) and per-message random IVs. Messages follow a wire format: a 4-byte length prefix, a 16-byte IV, and an encrypted JSON payload. This allows decryption by anyone who extracts the key, underscoring the payload’s relative simplicity despite the obfuscation.
Initial beaconing transmits reconnaissance JSON: os_type (PHP_OS), version (OS-specific), hostname (php_uname(‘n’)), unique machine ID (e.g., Windows registry GUID, Linux /etc/machine-id), user permissions, payload directory, and RAT version (1.2). Heartbeats (“ping”) follow every 60 seconds.
The RAT supports a versatile command set (JSON “s” field), resilient to PHP hardening:
| Command | Behavior |
|---|---|
| ping | Heartbeat every 60s |
| info | Full system recon dump |
| cmd | Shell command (stdout return) |
| powershell | PowerShell one-liner (stdout) |
| run | Background shell, no output |
| screenshot | Base64 PNG screengrab |
| download | Base64 file read |
| upload | Base64 file write (0777 perms) |
| stop | Disconnect and exit |
Shell execution probes disable_functions, falling back across popen, proc_open, exec, etc. This grants attackers arbitrary RCE, file I/O, persistence, and exfiltration in the web app’s context, exposing .env secrets, database creds, and API keys.
Lara-swagger exemplifies dependency-chain abuse: its composer.json mandates lara-helper@dev-master, pulling the latest (potentially updated) RAT without a direct malicious dev-master bypass, thereby bypassing versioning and enabling silent payload evolution. Activation via boot-time includes or autoload triggers silently, even from class_exists() checks.
The C2 domain was unresponsive at disclosure, but the RAT persists on disk and redials indefinitely. Packages remain live on Packagist despite takedown requests.
According to the report, affected Laravel apps run persistent backdoors with web server privileges on Windows, macOS, and Linux. Compromise enables data theft, ransomware staging, or lateral movement.
Immediate Steps:
- Quarantine hosts; rotate all app secrets.
- composer remove nhattuanbl/*; rm -rf vendor/nhattuanbl; delete helper.php and lockfile.
- Scan for 0777 uploads; audit traffic to leuleu.net:2096.
Defensive Best Practices:
- Scan transitive dependencies (e.g., Firewall blocks known malware).
- Ban dev-master in prod; audit boot/autoload PHP includes.
- Use tools like GitHub App/CLI for PR/CI gating.
This fits T1195.001 (Compromise Software Dependencies), echoing npm/PyPI campaigns. Obfuscation (T1027), non-standard port (T1571), shell (T1059), and C2 exfil (T1041/T1105) align with commodity malware trends.
Packagist’s 2015 account dormancy until 2024 suggests opportunistic reuse. As supply chain attacks proliferate, npm saw Lazarus RATs in 2025. PHP devs must prioritize visibility into the dependency graph. Detection prevented production deploys; broader adoption could curb these threats.
Site: cybersecuritypath.com