Failure Failure picoCTF 2026 Solution

Published: March 20, 2026

Description

Welcome to Failure Failure - a high-availability system challenge. It simulates a real-world failover scenario where one server is prioritized over the other. A load balancer stands between you and the flag - it won't hand over the flag until you force its hand.

Launch the challenge instance and note the URL.

Download the HAProxy configuration and application code provided with the challenge.

Visiting the URL returns 'No flag in this service' from the primary server.

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Understand the HAProxy setup
    Observation
    I noticed the challenge provides both a HAProxy configuration file and application code, which suggested that the flag's exposure depends on understanding how the two interact rather than finding a hidden route on the primary server.
    Read the HAProxy configuration and application code. The primary server rate-limits at 300 requests per minute and returns 503 when exceeded. When the proxy sees a non-200 response it fails over to the backup server which returns the flag.
    bash
    cat haproxy.cfg
    bash
    # Primary server: rate-limits to 300 req/min, returns 503 on excess
    bash
    # Backup server: returns the flag
    bash
    # HAProxy: switches to backup when primary returns non-200

    Expected output

    picoCTF{f41lur3_f41lur3_...}
    What didn't work first

    Tried: Trying to extract the flag directly by visiting the /flag endpoint or guessing hidden routes on the primary server

    The primary server never returns the flag regardless of the URL path - it only returns 'No flag in this service'. The flag lives exclusively on the backup server, which HAProxy only routes to after the primary signals failure. No amount of path enumeration on the primary will expose it.

    Tried: Reading only the app code and ignoring haproxy.cfg, assuming the flag is hidden in an environment variable or commented out in the source

    The app code confirms the primary returns no flag, but the failover logic that exposes the backup is entirely in haproxy.cfg. Skipping the config file means missing the 503-triggers-failover rule, which is the entire vulnerability. Both files together reveal the attack path.

    Learn more

    HAProxy is a high-performance TCP/HTTP load balancer. In this challenge it is configured in active-passive mode: all traffic goes to the primary backend. If the primary returns a non-200 response (such as a 503 Service Unavailable), HAProxy automatically routes subsequent requests to the backup server.

    The primary server enforces a rate limit of 300 requests per minute. Exceeding this causes the primary to return 503, which triggers HAProxy's failover to the backup. The backup server does not have this rate limit and serves the flag directly.

  2. Step 2
    Flood the primary server to trigger failover
    Observation
    I noticed from haproxy.cfg that HAProxy routes to the backup only when the primary returns a non-200 response, and the app code showed the primary enforces a 300 req/min rate limit with a 503 on excess, which suggested deliberately saturating that limit with parallel requests would force the failover to the backup holding the flag.
    Send more than 300 requests to the endpoint in under a minute to trigger the rate limit. Use xargs with parallel workers to send the requests fast enough.
    bash
    # Generate 500 requests in parallel using xargs (50 threads)
    bash
    seq 1 500 | xargs -n1 -P50 -I[] curl -s http://<HOST>:<PORT_FROM_INSTANCE>/ -o /dev/null
    bash
    # Sleep briefly to let HAProxy detect the failure
    bash
    sleep 2
    bash
    # Now make one more request - it should hit the backup server with the flag
    bash
    curl http://<HOST>:<PORT_FROM_INSTANCE>/
    What didn't work first

    Tried: Sending 500 requests sequentially with a loop (for i in $(seq 1 500); do curl ...; done) instead of using xargs parallel workers

    A sequential shell loop can only fire one curl at a time, so 500 requests may take several minutes - far too slow to exceed 300 requests per minute. The rate limit window resets and the primary never trips. The xargs -P50 flag runs 50 simultaneous curl processes, compressing 500 requests into a few seconds and reliably saturating the limit.

    Tried: Making exactly 300 or 301 requests and then immediately checking the response, expecting the flag on the 301st request

    The rate limit triggers a 503 from the primary, but HAProxy does not instantly failover on the first 503. It waits for its health-check interval (typically every few seconds) before marking the primary down and routing to the backup. Skipping the sleep 2 command means the final curl still hits the primary, which may have already recovered, returning 'No flag in this service' again.

    Learn more

    xargs -P50 runs 50 curl processes in parallel. With 500 requests spread across 50 threads, the primary receives well over 300 requests per minute and triggers its rate limiter, returning 503. HAProxy detects this failure and marks the primary as down.

    HAProxy polls backend health at an interval (typically every few seconds). After the primary starts returning 503 errors, HAProxy switches traffic to the backup on the next health check cycle. The sleep gives HAProxy time to detect the failure before you make the final request.

    In real-world attacks, this technique (deliberately overwhelming a primary to force failover to a less-hardened backup) is a form of availability attack. Proper HA configurations apply rate limiting at the load-balancer level (not just the application), use circuit breakers that degrade gracefully, and apply the same security controls to backup servers as to primary servers.

Interactive tools
  • URL Encoder / DecoderEncode and decode URL-encoded (percent-encoded) strings. Useful for web exploitation challenges involving query parameters, form data, and HTTP headers.
  • JWT DecoderDecode JSON Web Tokens and inspect the header, payload, and signature. Useful for web exploitation challenges.

Flag

Reveal flag

picoCTF{f41lur3_f41lur3_...}

Flood the primary server with over 300 requests/minute using parallel curl via xargs to trigger its rate limit (503 response). HAProxy fails over to the backup server which returns the flag.

Key takeaway

High-availability load balancers route traffic away from unhealthy backends automatically, but this failover logic becomes a security primitive when the backup is less hardened than the primary. Deliberately triggering a primary's failure condition to redirect traffic is a form of availability attack, and it appears in real penetration tests wherever rate limits, circuit breakers, or error thresholds live at the application layer rather than the load-balancer layer. The same principle applies to any multi-tier redundancy system, including CDN origin fallbacks, DNS failover, and database read-replica promotion.

Related reading

Want more picoCTF 2026 writeups?

Useful tools for General Skills

What to try next