← Back to Writeups
CUSTOMMediumWeb

РоБОТЫ 2

XESXOR9/2/20263 min read
#web#custom#medium#browser_impersonation#cloudflare_bot_bypass#ja3_impersonation#python_sandbox_enumeration#tls_fingerprint_bypass

РоБОТЫ 2

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: browser_impersonation, cloudflare_bot_bypass, ja3_impersonation, python_sandbox_enumeration, tls_fingerprint_bypass

Summary

Walkthrough of the CUSTOM Web РоБОТЫ 2. Task: Flask sandbox runs a user-supplied solve(url) function against a Cloudflare-protected target; requests.get returns 403 because Python's TLS/JA3 fingerprint is flagged as a bot. Solution: use cur

Description

Боты, боты и еще раз боты, они везде и повсюду! Уже все давным давно научились их вычислять, даже не по хедерам, а как-то по другому. А может ты тоже бот? Докажи обратное.

English summary: "Bots, bots, and more bots — they're everywhere! Everyone has long learned to detect them, not even by headers, but somehow differently. Maybe you're a bot too? Prove otherwise." The challenge is hosted at https://robots-2.t1.bug-makers.ru.

The key semantic hint is "not even by headers, but somehow differently" — this points to TLS / JA3 fingerprinting rather than HTTP header inspection. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Analysis

The homepage is served by Werkzeug/3.1.6 Python/3.9.25 (Flask) and presents a Python code editor. You must define a function:

python
def solve(url: str): ...

that returns a real HTTP response object with status 200, within a 30-second time limit. Code is submitted via POST /api/submit with a JSON body {"code": "..."}. The sandbox substitutes a placeholder <URL> with a Cloudflare-protected target and calls solve(target_url).

Observations during recon:

  • /robots.txt returns 404 — a red herring playing on the task name "robots".
  • Submitting the default code requests.get(url) returns HTTP 403 — "Cloudflare says you're still a bot" (Russian message). So the target is fronted by Cloudflare's bot-detection WAF.
  • A traceback leaked the sandbox path /app/sandbox.py line 276: result = solve_fn(target_url).
  • Rate limit is roughly 1 request/minute after a short burst. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Sandbox validation blacklist

Probing the validator revealed a blacklist of dangerous constructs:

  • open() — forbidden
  • getattr() — forbidden
  • substring __import__ — forbidden
  • attribute access __dict__ — forbidden
  • importing importlib — forbidden

Crucially, plain import statements are allowed (the default code itself imports requests). This means we can freely import alternative HTTP libraries.

Why requests fails

Cloudflare's bot detection here keys on the TLS/JA3 handshake fingerprint, not on HTTP headers. Python's requests (urllib3 over OpenSSL) produces a recognizable non-browser TLS ClientHello fingerprint and is blocked regardless of any User-Agent or header spoofing. This matches the challenge hint perfectly: detection is "not by headers, but somehow differently". ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Available libraries

Using plain try/except imports inside solve, the sandbox was probed for installed libraries. The following TLS-fingerprint-bypass-capable libraries were all available:

  • curl_cffi
  • cloudscraper
  • httpx
  • tls_client

The presence of curl_cffi is the strongest signal: it can impersonate a browser's exact TLS/JA3 fingerprint.

Solution

Use curl_cffi with browser impersonation. The impersonate="chrome120" option makes the underlying libcurl emit Chrome's exact TLS ClientHello (cipher suites, extensions, curves), so Cloudflare's JA3 fingerprinting sees a legitimate Chrome browser and returns HTTP 200. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

python
def solve(url):
    from curl_cffi import requests as creq
    r = creq.get(url, impersonate="chrome120")
    return r

Submit it via the API:

bash
curl -s https://robots-2.t1.bug-makers.ru/api/submit \
  -H 'Content-Type: application/json' \
  -d '{"code": "def solve(url):\n    from curl_cffi import requests as creq\n    r = creq.get(url, impersonate=\"chrome120\")\n    return r\n"}'

The response is HTTP 200 and contains the flag. Equivalent solutions exist with cloudscraper or tls_client, which also rewrite the TLS handshake to mimic a browser. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering browser_impersonation, cloudflare_bot_bypass, ja3_impersonation, python_sandbox_enumeration, tls_fingerprint_bypass was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-26 • CUSTOM • РоБОТЫ 2 • Difficulty: Medium