hijacking picoCTF 2023 Solution

Published: April 26, 2023

Description

SSH into the server and discover a hidden Python script you can run with sudo. The script imports base64, and you have write permission on base64.py in the Python library. Edit that file to inject a system call, then run the script with sudo to read the flag.

SSH into the provided server using the given credentials.

List hidden files in your home directory to find the server script.

Check what sudo allows you to run.

bash
ssh <USER>@<HOST> -p <PORT>
bash
ls -la
bash
sudo -l
  1. Step 1Discover the hidden script and sudo permissions
    After logging in, list all files including hidden ones. There is a hidden file called .server.py in the home directory. Running sudo -l shows you can run python3 .server.py as root without a password.
    bash
    ls -la
    bash
    cat .server.py
    bash
    sudo -l
    Learn more

    sudo -l lists the commands the current user can run with elevated privileges. The output shows something like (root) NOPASSWD: /usr/bin/python3 /home/user/.server.py, meaning you can run that specific Python script as root without entering a password.

    The script itself imports base64 and os, and does something innocuous. The key is that it imports Python standard library modules, and those module files might be writable by your user.

  2. Step 2Find the writable Python library file
    Check the permissions on the base64.py file in the Python standard library. It turns out to be writable by your user, which means you can inject code that will run when the script imports it.
    python
    python3 -c 'import base64; print(base64.__file__)'
    bash
    ls -la /usr/lib/python3.*/base64.py
    Learn more

    Python's import statement searches directories in order and executes the module file when it is first imported. If a module file is world-writable, any user can add arbitrary code to it. That code runs with whatever privileges the importing script has.

    This is a Python library hijacking attack. The misconfiguration is leaving a standard library file world-writable, which lets an unprivileged user inject code that runs as root when a sudo-enabled script imports that module.

  3. Step 3Inject code into base64.py
    Add an os.system() call at the top of base64.py to read and print the flag file. The existing code must remain intact so the import does not fail.
    python
    python3 -c 'import base64; print(base64.__file__)'
    bash
    # Prepend a system call to base64.py
    bash
    echo 'import os; os.system("cat /challenge/metadata.json")' >> /usr/lib/python3.10/base64.py
    Learn more

    Appending code to the end of the module works because Python executes the module file from top to bottom on import. Adding a line at the end is safer than inserting at the beginning, since it does not break the existing function definitions that the script may rely on.

    The flag is stored in /challenge/metadata.json. That file is owned by root and not readable by your user directly, which is why privilege escalation is needed.

  4. Step 4Run the script with sudo to trigger the injection
    Run the server script with sudo. Python imports base64, executes your injected os.system() call as root, and the flag is printed to stdout.
    bash
    sudo python3 .server.py
    Learn more

    When Python runs the sudo script, it imports base64. The import mechanism executes base64.py, which now contains your injected call. Since the script runs as root via sudo, the os.system() call also runs as root, and cat /challenge/metadata.json reads and prints the flag.

    The fix for this misconfiguration: never leave Python standard library files writable by unprivileged users. Standard library permissions should be root-owned and not world-writable. For more on Linux privilege escalation see Linux CLI for CTF.

Flag

picoCTF{pYth0n_lIb_hIj4ck1ng_f56b6b5c}

Write access to base64.py lets you inject code that runs as root when the sudo script imports the module.

Want more picoCTF 2023 writeups?

Useful tools for Binary Exploitation

Related reading

What to try next