Case evidence dataset: Per-case HTTP packet captures and selected Apache, PHP, Tetragon, and signal records for all 35 confirmed shells ( A01 – A03 , B01 – B32 ) are published in 2026-10-24-rce-evidence/ .
Target-side packet captures and Tetragon process events correlate 35 complete execution-stage HTTP POSTs with 35 /bin/sh starts directly parented by Apache workers ( uid=33 ) across three PHP targets. Three shell events followed traffic from 15.204.59.70 on T1; 32 followed traffic from 162.35.99.94 on T1, T2, and T3. These are two source-address clusters, not an attribution to two actors.
The requests used a four-stage multipart chain, sometimes with retries: memory pressure, memory disclosure through an oversized PHPSESSID , further memory pressure, then a target-adjusted execution stage. Fifty-two disclosure-sized cookies were logged; 51 complete responses were reconstructed in packet captures and acknowledged by the client. Representative complete chains from both source clusters and all three successful targets shared byte-identical A1/B1/A2 bodies. The B2 body varied with the target's leaked address range and the shell command, supporting the published leak-guided ASLR technique rather than a new primitive. The traffic closely matches the public HTTP-only PoC family; packet evidence does not identify the exact client or revision used.
The reviewed targets ran PHP 8.4.26 under single-worker Apache mod_php with a 128 MiB PHP memory limit. The relevant PHP errors occurred during request startup ( Unknown on line 0 ), before application code, consistent with a PHP-engine vulnerability rather than a flaw in a particular CMS. All confirmed execution-stage requests used plaintext HTTP/80. T1 – T3 label the three targets throughout this report.
The targets were disposable phpot honeypots presenting ordinary PHP-backed pages. The sensor records bidirectional network packets, Apache requests and worker PIDs, PHP errors, and Tetragon process/kernel events. We joined the packet flows to application and process records by source port, time, worker identity, and request sequence; no single alert or HTTP status was treated as proof of execution.
The acquired snapshot contains 3,459 sealed segments and 10,948 manifest-listed files (11.21 GB); all listed sizes and SHA-256 values matched their local copies, and the parsed Apache/Tetragon JSONL records had no malformed lines. The latest sealed window on each sensor ended between 19:26 and 19:31 UTC. Counts below refer to this fixed snapshot.
Two observed exploitation episodes
Episode A — 15.204.59.70
The source began path probing at 13:47, sent memory-pressure requests by approximately 15:16, and produced its first confirmed Apache-parent shell at 15:35. Two further shells followed at 16:04. All three used the same final-stage request-body hash and shell command. Three disclosure-sized cookies were recorded on T1, all reconstructed as complete and TCP-acknowledged in packet capture. The command tried to write id output to a temporary proof file and web roots, then invoke wget ; the web-root writes met a read-only filesystem and wget was absent. The first full packet-to-process timeline appears below.
Episode B — 162.35.99.94
The source appeared at 16:36 with disclosure-sized responses, cycled through repeated OOM/leak/crash attempts around 16:44–16:46, and produced its first confirmed shell at 16:46. Tetragon recorded 32 Apache-parent shell starts through 18:57: 19 on T2, ten on T3, and three on T1. Commands changed among PHP CLI, curl , and wget variants; later proof URLs embedded shell command substitutions for id -un , hostname , and uname -m . Forty-nine disclosure-sized cookies were recorded across those targets; 48 were reconstructed as complete and TCP-acknowledged. The target-dependent final-stage bodies and command changes distinguish this episode from A operationally, while the byte-identical first three request bodies link both episodes to the same exploit template.
Relationship between episodes: The shared template, boundary, body hashes, and stage order do not establish shared control. Nor do different source IPs and proof commands establish separate actors. The defensible finding is two source-address episodes using closely related tooling.
Separately, 104.28.208.84 and 144.48.4.242 sent exploit-shaped requests associated with PHP errors or worker crashes in the reviewed snapshot. Neither had an observed Apache-parent shell or disclosure-sized cookie; they are attempt indicators, not confirmed RCE sources .
The two confirmed source addresses were registered to hosting networks when checked on 24 October: 15.204.59.70 to OVH US LLC ( 15.204.0.0/16 ) and 162.35.99.94 to Interserver, Inc ( 162.35.96.0/19 ). The former's PTR, vps-b225fb62.vps.ovh.us , resolved back to its IP. The latter's PTR, vps3749638.trouble-free.net , had no confirming A record in the lookup. Network registration and PTRs describe infrastructure, not the operators behind it.
Shared request fingerprint and exploit sequence
The successful chains used HTTP/1.1 multipart POSTs to / and /index.php , no User-Agent , and a ten-character C multipart boundary. Request-header order was Host → Content-Type → Transfer-Encoding → Connection for chunked stages and Host → Content-Type → Content-Length → Connection for fixed-length stages. The first memory-pressure request had five numbered q...=v query parameters. These characteristics were checked in representative complete packet captures from both source clusters.
Four request stages on the wire
The table uses complete target-side TCP reassembly from a successful T1 chain at 15:35 UTC. Decoded sizes exclude HTTP chunk framing. The same first three decoded request-body hashes were found in complete successful-chain captures from both sources and all three targets.
Body anatomy: The captured A1 body was dominated by files* fields (859 of 973 multipart parts); B1 had 900 x* fields among 918 parts; A2 had 880 files* fields among 997; B2 had 500 s* and 495 t* fields among 998. All four included PHPSESSID and PHP_SESSION_UPLOAD_PROGRESS fields. B2 also contained target-dependent address-like words and a command string; its digest changed when those values or the command changed. The fixed-body SHA-256 indicators are:
These digests are over the decoded body , not the complete TCP stream or the chunked wire representation. A1 and B1 used Transfer-Encoding: chunked ; A2 and B2 used Content-Length . The attacker sometimes repeated A1/B1 before advancing. The first and third stages produced pre-script PHP errors, while B1 could produce a large cookie or crash the worker. The final request could crash the worker after starting a shell, leaving no completed Apache access entry. HTTP 200 on A1/B1/A2 is therefore not the success criterion.
The B1 digest also appears in the initial attempt-only capture report , where identical B1 bodies preceded worker crashes without confirmed RCE. It identifies a payload family, not an execution outcome by itself.
Memory disclosure and ASLR adjustment
Apache recorded 52 disclosure-sized cookies: three for A on T1 and, for B, four on T1, 29 on T2, and 16 on T3. Each decoded to 819,200 bytes. The decoded values were not ordinary session IDs: they contained repeated aligned, pointer-like 64-bit words, including a dominant word repeated 1,095 times in representative leaks. Matching the cookie's SHA-256 from Apache to target-side PCAPs gave 51 complete responses with zero captured response gaps and a client ACK through the response end (T1 7/7, T2 28/29, T3 16/16). The remaining T2 capture begins mid-response; Apache recorded the cookie, but its complete packet delivery is not established by that file.
The dominant disclosed pointer differed in absolute value across representative T1, T2, and T3 leaks. An address-like word in their corresponding B2 bodies maintained the same relative difference from that value across the three targets. Along with the request sequence, this supports leak-guided adjustment to each target's randomized memory layout rather than one hard-coded address accidentally working everywhere. The public 9bie HTTP-only PoC uses the same type of relative calculation and request roles; Wiz's PHP2Shell research describes the underlying PHP upload-progress/disclosure family. The observed chain is consistent with CVE-2026-109618 ; these records do not establish use of a distinct CVE-2026-109619 path.
The public exploit.py revision examined on 24 October filters disclosed pointers below 0x7f0000000000 . The early successful chains had no pointer-like words above that threshold in their observed cookies, so an unchanged run of that revision would not parse those leaks. Two later T3 cookies did contain qualifying pointers. The traffic therefore does not support a blanket claim that every successful run required a modified PoC; a small change, another revision, or a different client could explain the early chains. Packet captures cannot identify which implementation was used.
Case evidence: HTTP request to Apache child process
Episode A: first confirmed execution
The first T1 execution illustrates the evidence chain without relying on a 500 response or an alert label:
Apache logged A1, B1, and A2 on the same worker (container PID 31). Its normal B2 access line is absent because the worker died. Packet source ports and worker socket events link the sequence to the host PID that Tetragon recorded as the shell's Apache parent. The shell attempted an id proof file and web-root writes; Apache recorded Read-only file system for the web-root attempts and wget: not found for the attempted fetch. Those errors are additional evidence that the command reached a shell, while the process_exec parentage is the decisive execution observation.
Episode B: first confirmed execution
The first T2 chain shows the same transition with a different command:
Later T2 shells used curl and wget variants. For example, at 16:50:49 Tetragon recorded apache2 → /bin/sh → /usr/bin/curl after B2, then a tcp_connect for 162.35.99.94:8080 in TCP_SYN_SENT . At 17:27:25 on T3 it recorded apache2 → /bin/sh with a wget command; Apache then emitted wget: not found and the worker crashed. At 18:55:02, the same source reached T1: the complete B2 request began at 18:55:02.387 and an Apache-parent shell followed at 18:55:02.429. Two more T1 shells followed at 18:57. These are distinct process-level observations on independent targets, not repeated parsing of one HTTP error.
Selected runtime records
These normalized records retain the observed command content, including proof paths. [T1-honeypot-IP] through [T3-honeypot-IP] replace addresses of the three targets, not the attacker endpoints. PHP and Apache lines are correlated by the request window; Tetragon records process parentage directly.
Complete case index: 35 confirmed shell events
Every row below has a complete 451,384-B B2 request in target-side PCAP immediately before a Tetragon /bin/sh process_exec with parent.binary=/usr/sbin/apache2 and uid=33 (released per case under 2026-10-24-rce-evidence/ ). B2 port is the attacker's TCP source port . Event ref identifies the target alias, sealed-segment sequence, and line of its Tetragon JSONL; it does not expose a target address. A source port and time identify the matching PCAP flow. Command descriptions summarize the observed process arguments, not hypothetical intent.
Episode A: three shells on T1
Episode B: 32 shells across T1, T2, and T3
Some final requests have no completed Apache access entry because their worker crashed; the packet flow and process event provide the evidence for those rows. Successful RCE is not inferred from a PHP OOM, a PHPSESSID alone, or AH00051 alone. The decisive difference is the unexpected Apache-parent shell, followed in several cases by independently observed id , PHP CLI, or curl child processes.
Complete observed shell commands
Tetragon captured one Apache-parent /bin/sh event for each case above. These are the 14 distinct original commands after the shell's -c -- wrapper; each case maps to exactly one row. Embedded target addresses are replaced with the corresponding [T1-honeypot-IP] , [T2-honeypot-IP] , or [T3-honeypot-IP] label; other command text is retained. The execution-stage HTTP payload is the corresponding 451,384-byte B2 body, indexed by SHA-256 below.
Apache logged sh: 1: wget: not found for the wget commands; /ok33 was observed in the command line, not recovered as a fetched file. Tetragon recorded id , PHP CLI, and curl child processes; the PHP CLI request timed out. No downloaded second-stage file was observed in the reviewed evidence.
Execution-stage body digests
These SHA-256 values cover the complete 451,384-byte B2 bodies matched to the case index. B2 changes with the target-specific address-like values and command; repeated digests identify exact body reuse.
For the observed activity, the strongest cross-source sequence is: HTTP/1.1 chunked multipart memory pressure with pre-script Unknown on line 0 OOM; a ~33.1-MB chunked multipart request followed by an unusually large PHPSESSID ; a ~279-KB fixed-length multipart request and another OOM; then a ~451-KB fixed-length multipart request followed by an Apache-parent shell. The fixed decoded-body hashes above, absent User-Agent , repeated multipart boundary, and consistent header order provide additional clustering features. A worker crash may occur between stages or immediately after process creation.
The fixed bodies and request roles align closely with the public 9bie exploit.py . The evidence demonstrates this chain on the intentionally favorable single-worker mod_php profile; it is not a measurement of exploit reliability on other worker counts, PHP builds, or applications.
Appendix: representative request excerpts
These are shortened excerpts from complete TCP-reassembled requests in confirmed chains. Host is replaced with example.invalid ; chunk framing is omitted from the displayed body, and ellipses or bracketed text mark omitted bytes. Body lengths and SHA-256 values refer to the complete decoded multipart bodies.
A1 — memory-pressure request, episode A
15.204.59.70:54952 → T1, 15:35:32.793 UTC; decoded body 1,060,211 bytes.
B1 — memory-disclosure request, episode B
162.35.99.94:36844 → T2, 16:46:50.785 UTC; decoded body 33,128,677 bytes, SHA-256 b6c547e0e9a2bb26607df1521de96f4d5c9adf4621c28b7ab491587b21ae40f2 .
B2 — execution-stage request, episode B
162.35.99.94:47720 → T2, 16:46:58.166 UTC; body 451,384 bytes, SHA-256 aab24fa5ec0df76f731c1ea4bac9fd36aa350eef9a42c33315e485178e1e5892 .
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
