#!/usr/bin/env python3
"""SSRF target server.

Stands in for an internal/loopback service (e.g. http://127.0.0.1:9222,
http://169.254.169.254/latest/meta-data/, http://192.168.1.1/admin) that an
attacker would target. If the Chrome BROWSER PROCESS issues a GET to this
server because of a Cast MEDIA_STATUS image URL, the SSRF is proven.

Listens on 127.0.0.1:18080.
"""

import http.server
import socketserver
import sys
import datetime

HOST, PORT = "127.0.0.1", 47713
HITS = []


class Handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):  # noqa: N802
        ts = datetime.datetime.now().isoformat(timespec="milliseconds")
        line = (
            f"\n"
            f"========================================================\n"
            f"[SSRF-TARGET] {ts}  *** REQUEST RECEIVED ***\n"
            f"  Method : {self.command}\n"
            f"  Path   : {self.path}\n"
            f"  Client : {self.client_address[0]}:{self.client_address[1]}\n"
            f"  UA     : {self.headers.get('User-Agent', '-')}\n"
            f"  Origin : {self.headers.get('Origin', '<none>')}\n"
            f"  SecFetch-Site: {self.headers.get('Sec-Fetch-Site', '<none>')}\n"
            f"========================================================\n"
        )
        sys.stderr.write(line)
        sys.stderr.flush()
        HITS.append(self.path)
        if self.path.startswith("/SSRF-PROBE"):
            sys.stderr.write(
                "[SSRF-TARGET] >>> CONFIRMED: Chrome browser process fetched "
                "an attacker-controlled loopback URL delivered via a Cast "
                "MEDIA_STATUS image field. Local Network Access did NOT "
                "block it. <<<\n\n"
            )
            sys.stderr.flush()
        # Respond with a tiny PNG so BitmapFetcher's decoder doesn't error
        # (not required for the SSRF — the GET already happened — but keeps
        # logs clean).
        png = bytes.fromhex(
            "89504E470D0A1A0A0000000D49484452000000010000000108060000001F15C489"
            "0000000A49444154789C6300010000000500010D0A2DB40000000049454E44AE426082"
        )
        self.send_response(200)
        self.send_header("Content-Type", "image/png")
        self.send_header("Content-Length", str(len(png)))
        self.end_headers()
        self.wfile.write(png)

    def log_message(self, fmt, *args):
        pass  # silence default access log


class ReuseAddrTCPServer(socketserver.TCPServer):
    allow_reuse_address = True


if __name__ == "__main__":
    sys.stderr.write(
        f"[SSRF-TARGET] listening on http://{HOST}:{PORT}/ — this stands in "
        f"for an internal service the attacker wants Chrome to hit.\n"
    )
    sys.stderr.flush()
    with ReuseAddrTCPServer((HOST, PORT), Handler) as httpd:
        httpd.serve_forever()
