Building a Live PHP CVE Honeypot: From Internet Scan to Full Forensic Telemetry
A practical walkthrough on exposing an isolated PHP 8.3.35 honeypot for CVE-2026-109618 and CVE-2026-109619, capturing live reconnaissance with tcpdump, automating scanner threat intelligence, and building Microsoft Sentinel detections.
Why We Built a Honeypot for CVE-2026-109618 and CVE-2026-109619
On 21 October 2026, two critical remote code execution vulnerabilities (CVSS 9.2) were disclosed affecting core PHP versions dating back to PHP 5.4. Dubbed PHP2Shell, the flaws stem from improper memory management during out-of-memory (OOM) errors and fatal runtime cleanups via longjmp().
Because exploitation can occur pre-authentication during early request startup (such as parsing multipart form-data or session upload progress headers), automated internet scanning began within hours. To understand scanning patterns, capture live payloads, and validate detection rules, GlobalSOC deployed a high-interaction, heavily instrumented honeypot on Microsoft Azure.
1. Honeypot Architecture & Reverse Proxy Design
The honeypot presents an unpatched PHP service on the public internet, while isolating container and virtual machine processes:
[ Public Internet / Scanner ]
│
│ TCP 80 (HTTP) & TCP 22 (SSH)
▼
[ Azure NSG: nsg-php-lab ]
│
▼
[ Linux VM: vm-php-cve-lab (13.75.195.138) ]
├── Nginx Reverse Proxy (0.0.0.0:80)
│ ├── Structured JSON Logging (method, request, status, body) -> Syslog local6
│ └── Upstream Docker Bridge (172.18.0.2:80)
├── Docker: php-vulnerable (php:8.3.35-apache, unpatched)
├── Docker: php-patched (php:8.3.36-apache on 127.0.0.1:8081 for comparison)
├── tcpdump Daemon: Full snaplen (-s 0) rolling PCAP on eth0 & Docker bridges
├── Host Harvester: Inotify watcher copying dropped binaries to secure staging
└── Azure Monitor Linux Agent (AMA) -> Microsoft Sentinel (Testyainstance)
Nginx Configuration (Exposing the PHP Banner)
Nginx intercepts incoming HTTP traffic, routes it to the unpatched container, and serializes every request into JSON for our SIEM:
log_format lab_json escape=json '{"event":"php_http","client":"$remote_addr","host":"$host","method":"$request_method","request":"$request","uri":"$request_uri","status":$status,"bytes_in":$request_length,"bytes_out":$bytes_sent,"user_agent":"$http_user_agent","content_type":"$http_content_type","body":"$request_body"}';
server {
listen 0.0.0.0:80 default_server;
listen 127.0.0.1:8080;
server_name _;
client_max_body_size 32m;
access_log syslog:server=unix:/dev/log,facility=local6,tag=php_http lab_json;
access_log /var/log/php-lab.log lab_json;
location / {
proxy_pass http://172.18.0.2:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
2. Simulating Reconnaissance: The Nmap Probes
To verify that threat hunters and automated engines see our server as vulnerable, we executed service detection and script scanning:
# Version detection
nmap -Pn -sV -p 22,80,443,8080 13.75.195.138
# HTTP header and method enumeration
nmap -Pn -p 80 --script http-headers,http-methods 13.75.195.138
What the Scanner Discovered:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu (Protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)
443/tcp filtered https
8080/tcp filtered http-proxy
| http-headers:
| Server: nginx/1.18.0 (Ubuntu)
| X-Powered-By: PHP/8.3.35
|_ (Request type: HEAD)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
X-Powered-By: PHP/8.3.35 and supported POST method immediately trigger automated exploitation frameworks scanning for CVE-2026-109618.
3. What the Network Packet Capture (tcpdump) Recorded
Our background capture service (php-lab-capture.service) records full frames without truncation (-s 0). Inspecting the PCAP revealed the exact mechanics of the scan:
A. Complete TCP 3-Way Handshake
05:31:53.367690 IP 203.221.137.241.54054 > 10.203.1.4.80: Flags [S], seq 1632411086, win 65535, length 0
05:31:53.367738 IP 10.203.1.4.80 > 203.221.137.241.54054: Flags [S.], seq 4218490308, ack 1632411087, win 64240, length 0
05:31:53.392917 IP 203.221.137.241.54054 > 10.203.1.4.80: Flags [.], ack 1, win 255, length 0
B. Decoded Nmap Script Payloads
Nmap's Scripting Engine sent discovery checks and SOAP/XML requests:
GET /nmaplowercheck1792647659 HTTP/1.1
Host: 13.75.195.138
User-Agent: Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/nse.html)
POST /sdk HTTP/1.1
Host: 13.75.195.138
Content-Length: 441
User-Agent: Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/nse.html)
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<RetrieveServiceContent xmlns="urn:internalvim25">
<_this xsi:type="ManagedObjectReference" type="ServiceInstance">ServiceInstance</_this>
</RetrieveServiceContent>
</soap:Body>
</soap:Envelope>
4. Automated Scanner Threat Intelligence
Whenever an external IP touches our honeypot ports, our local enrichment script (/usr/local/bin/honeypot-intel.sh) resolves attribution data:
| Attribute | Extracted Value |
|---|---|
| Scanner IP | 203.221.137.241 |
| Reverse DNS (PTR) | 203-221-137-241.tpgi.com.au |
| Network & ASN | TPG Internet Pty Ltd (AS4804 / AS7545) |
| Country | Australia |
| HTTP Methods Tested | HEAD, GET, POST, OPTIONS, YEQW (fuzzer verb) |
5. Microsoft Sentinel Detection Rules
To detect similar activity across enterprise networks, we created two Sentinel analytic rules:
A. Suspicious Multipart / OOM Runtime Failure (KQL)
Syslog
| where TimeGenerated > ago(15m)
| where _ResourceId has "vm-php-cve-lab" and Facility == "local6"
| extend Http = parse_json(extract(@"(\{.*\})", 1, SyslogMessage))
| extend IsMultipart = tostring(Http.content_type) contains "multipart/form-data" and tostring(Http.method) =~ "POST",
IsRuntimeFailure = SyslogMessage matches regex @"(?i)(allowed memory size.*exhausted|segmentation fault|child pid.*exit signal|PHP Fatal error|upstream prematurely closed)"
| where IsMultipart or IsRuntimeFailure
| project TimeGenerated, HostName=Computer, Request=tostring(Http.request), HttpStatus=tostring(Http.status), SyslogMessage
B. Multi-Port Scan Identification (KQL)
NTANetAnalytics
| where TimeGenerated > ago(1h)
| where TargetResourceId has "rg-php-cve-lab-east-20261022"
| where FlowDirection in~ ("I", "Inbound")
| summarize DistinctPorts = dcount(DestPort), Ports = make_set(DestPort, 100) by SrcIp, bin(TimeGenerated, 10m)
| where DistinctPorts >= 5
6. Mandatory Honeypot Security Controls
- Storage Account Isolation: The honeypot VM holds zero storage keys and has no Azure RBAC roles. Production storage accounts (e.g.
metriconbak3055) have their network firewalls locked todefaultAction: Deny. - Egress Metadata Blocking: An
iptables DOCKER-USERrule drops all container traffic to the Azure Instance Metadata Service (169.254.169.254) and private subnets (10.0.0.0/8). - Outbound Reverse Shell Capture: The container can access the internet to allow second-stage malware downloads and reverse shells, but all traffic passes through our full PCAP capture and file harvester.
Conclusion
Deploying a controlled, high-interaction honeypot provides practical threat telemetry. By capturing raw packets, monitoring container modifications, and shipping structured JSON logs to Microsoft Sentinel, security teams can observe real-world attacker techniques without endangering enterprise assets.