North-South picoCTF 2026 Solution

Published: March 20, 2026

Description

I've set up geo-based routing - can you outsmart it? Access to the real service is restricted based on your geographic location. Only requests from a specific region are routed to the server that holds the flag.

Launch the challenge instance and note the URL.

Install Tor and configure it to use Iceland exit nodes.

bash
sudo apt install tor
bash
# Or on macOS: brew install tor
  1. Step 1Geo-restriction: configure Tor for Iceland
    The 'Iceland' answer doesn't fall out of the air: probe the endpoint from a couple of regions (curl from a US/EU VPS and a non-EU VPS), or look up the server's IP in a GeoIP database and read the response patterns. Once the IS gate is confirmed, configure Tor with ExitNodes {is}.
    bash
    # Discovery first: probe from multiple regions or GeoIP-lookup the host
    bash
    curl -s ipinfo.io/<HOST>     # see what GeoIP says about the server
    bash
    curl -s --resolve <HOST>:80:<US_VPN_IP> http://<HOST>/   # response from US
    bash
    bash
    # Edit your Tor config - typically at /etc/tor/torrc
    bash
    echo 'ExitNodes {is}' | sudo tee -a /etc/tor/torrc
    bash
    echo 'StrictNodes 1' | sudo tee -a /etc/tor/torrc
    bash
    sudo systemctl restart tor
    bash
    # Watch the log on circuit-build failure (StrictNodes will refuse to fall back):
    bash
    sudo tail -f /var/log/tor/log    # look for 'No usable exit relays' errors
    bash
    # Or on macOS:
    bash
    echo 'ExitNodes {is}\nStrictNodes 1' >> /opt/homebrew/etc/tor/torrc
    bash
    brew services restart tor
    Learn more

    Geo-based routing (also called geolocation-based access control) uses the requester's IP address to determine their geographic location and serve different content or restrict access accordingly. Nginx and other reverse proxies implement this using GeoIP databases like MaxMind's GeoLite2, which map IP ranges to country codes. A simple Nginx config might use if ($geoip_country_code != IS) { return 403; } to block non-Icelandic traffic.

    Tor (The Onion Router) routes your traffic through a circuit of three relays: a guard node, a middle relay, and an exit node. The exit node is the final hop that connects to the destination server, so the server sees the exit node's IP address as the source. By specifying ExitNodes {is} in the Tor configuration, you instruct Tor to only build circuits that exit through nodes registered in Iceland. StrictNodes 1 enforces this strictly rather than falling back to other nodes when Icelandic exits are unavailable. The failure mode matters: if no Icelandic exits are reachable, Tor refuses to build any circuit and your requests hang. Watch /var/log/tor/log for messages like No usable exit relays found or Tried for 120 seconds to get a connection to [scrubbed]; that tells you to drop StrictNodes 1 temporarily, retry later, or pick a country with more exit nodes.

    In real-world security, geo-blocking is widely used as a coarse access control layer but is considered a weak defense because it is trivially bypassed by VPNs, proxies, and Tor. It has legitimate uses for regulatory compliance (e.g., GDPR geo-restrictions) but should never be relied upon for security-critical access control. This challenge demonstrates exactly why IP-based geolocation is an unreliable trust signal.

  2. Step 2Request the challenge URL through Tor
    With Tor routing through Iceland, your request appears to originate from an Icelandic IP. The geo-check passes and you're routed to the flag server.
    bash
    # Verify exit-node country first - response is JSON with a 'country' field:
    bash
    curl --proxy socks5h://localhost:9050 https://check.torproject.org/api/ip
    bash
    # Expected: {"IsTor":true,"IP":"...","country":"IS"}
    bash
    # If country != IS, restart Tor and retry until you get an IS exit.
    bash
    bash
    # Once country == IS, hit the challenge:
    bash
    curl --proxy socks5h://localhost:9050 http://<HOST>:<PORT_FROM_INSTANCE>/
    Learn more

    SOCKS5 proxies are a general-purpose network proxy protocol that operates at the transport layer. The socks5h:// scheme (note the "h") tells curl to resolve DNS through the proxy as well as route traffic through it. This is important for Tor because regular socks5://would resolve the hostname locally before proxying the connection, potentially leaking information about what you're connecting to.

    Tor's SOCKS listener runs on port 9050 by default. When you use --proxy socks5h://localhost:9050, curl hands the entire connection (including DNS lookup) to the Tor daemon, which builds an onion-routed circuit and makes the request appear to come from your chosen exit node's IP. Verifying your exit IP first using check.torproject.org is good practice to confirm the configuration is working before attempting the bypass.

    This same technique applies in penetration testing scenarios where testers need to simulate traffic from specific geographic regions. Many bug bounty programs require testing from specific regions or networks, and Tor exit node selection provides a lightweight way to accomplish this. Note that Tor circuits can be slow, especially with the added constraint of only using exit nodes from a small country like Iceland. See the networking tools guide for more on proxying and verification patterns.

Flag

picoCTF{g30_byp4ss_...}

The Nginx config routes Icelandic IPs to the flag server. Configure Tor with ExitNodes {is} and StrictNodes 1 to route requests through Iceland exit nodes.

Want more picoCTF 2026 writeups?

Useful tools for Web Exploitation

Related reading

What to try next