Skip to content
HTTPServer

HTTPServer

HTTP server on a daemon thread

HTTPServer listens for HTTP connections, while SimpleHTTPRequestHandler maps request paths to files beneath the current working directory. Running serve_forever() in a separate thread allows later exploit stages to continue while the server remains available.

import threading
from http.server import HTTPServer, SimpleHTTPRequestHandler

def start_http_server(port):
    try:
        server = HTTPServer(("0.0.0.0", port), SimpleHTTPRequestHandler)
    except OSError:
        print("[-] HTTP server port already in use")
        return
    print(f"[+] HTTP server on {port}")
    server.serve_forever()

server_thread = threading.Thread(target=start_http_server, args=(8000,), daemon=True)
server_thread.start()

daemon=True allows the Python interpreter to exit after the main thread finishes. During normal execution, the server continues until the script exits or shutdown() is called through a retained server object.

Find by: http server, serve files, daemon thread, simplehttprequesthandler, host payload, curl bash, stager, background, threading, port · Source: PG/XposedAPI, Hetemit

OOB capture server (log callbacks & exfil)

An out-of-band callback is a separate request sent from the target to a controlled listener. It can confirm blind SSRF, XXE, or command execution and can carry exfiltrated data in the path, headers, or body. BaseHTTPRequestHandler creates one handler object per inbound HTTP request and provides the parsed method, path, headers, client address, input stream, and output stream.

import threading
from http.server import HTTPServer, BaseHTTPRequestHandler

class CaptureHandler(BaseHTTPRequestHandler):
    def capture_request(self):
        content_length_header = self.headers.get("Content-Length", 0)
        content_length = int(content_length_header or 0)
        body = self.rfile.read(content_length)
        print(f"\n[OOB] {self.command} {self.path} from {self.client_address[0]}")
        print(self.headers, end="")
        if body:
            print("body:", body.decode("latin1"))
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"ok")

    def do_GET(self):
        self.capture_request()

    def do_POST(self):
        self.capture_request()

    def do_PUT(self):
        self.capture_request()

    def log_message(self, *a):
        pass

def serve(port=8000):
    server = HTTPServer(("0.0.0.0", port), CaptureHandler)
    server.serve_forever()

server_thread = threading.Thread(target=serve, args=(8000,), daemon=True)
server_thread.start()

do_GET(), do_POST(), and do_PUT() are method names the HTTP server calls for the corresponding request methods. Each delegates to the shared capture logic. rfile contains the inbound body bytes and wfile sends the response bytes. Overriding log_message() suppresses the handler’s default terminal log because the callback is already printed in the desired format.

Find by: oob, out of band, capture, callback, exfiltration, blind, ssrf, xxe, log requests, interaction, collaborator, listener, catch data