Skip to main content

Ready Gladiator 2 picoCTF 2023 Solution

Compete in a CoreWars-style battle and dominate every round by designing a superior warrior program.

Published: April 26, 2023Updated: August 25, 2026

Description

For the final duel you must win every single round against the Imp. A tuned bomber warrior is the classic 100% solution: it drops DAT instructions across memory on a stride that covers every cell the Imp will ever visit, killing the Imp before it completes a full sweep.

Craft or copy a warrior with a 100 percent win rate versus the Imp (Herem/Scimitar is a reliable bomber).

Test locally: pmars -r 100 herem.red imp.red and confirm 100/0 before connecting.

Pipe the warrior into nc saturn.picoctf.net <PORT_FROM_INSTANCE> and ensure it records 100 wins.

bash
cat <<'RED' > herem.red
;redcode-94
;name Herem/Scimitar
;author aCa
;strategy bomber tuned versus the Imp
bomb       dat #4, #4
start      add.ab #4, bomb
           mov.i   bomb, @bomb
           jmp     start
end start
RED
bash
printf ';redcode\nMOV 0, 1\nend\n' > imp.red
bash
pmars -r 100 herem.red imp.red
bash
nc saturn.picoctf.net <PORT_FROM_INSTANCE> < herem.red

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Use a bomber strategy
    Observation
    The challenge wants every round won, not a majority. That calls for a deterministic bomber whose stride covers every cell the Imp can ever occupy, rather than a probabilistic fighter.
    Herem/Scimitar walks memory dropping DAT bombs every 4 cells. The Imp marches at 1 cell per turn, so a 4-stride bomb pattern covers every cell the Imp will ever visit.
    Learn more

    Herem/Scimitar is a tuned bomber written in ICWS-94 Redcode. Two modifier choices matter. add.ab adds only into the B-field of the bomb pointer, leaving the A-field alone. Every instruction costs the same single cycle in the MARS, so this is not about speed: add.f would bump the A-field too, mutating the bomb the warrior plants instead of just advancing where it lands. mov.i copies the entire instruction (both fields plus opcode) so the destination receives a real dat bomb, not just one field.

    Concrete trace. Picture an 8000-cell circular memory. Bomb stride is 4, so on successive loop iterations the bomber drops dat instructions into cells 0, 4, 8, 12, .... The Imp starts somewhere random (call it cell 1) and steps cell-by-cell: 1, 2, 3, 4, .... When the Imp reaches cell 4 (or any multiple of 4 that the bomber has already covered), it executes dat and dies. Even if the Imp's starting offset is unfavourable, the bomber gets ahead of it: the loop is three instructions (add, mov, jmp), so it costs three cycles to advance the bomb pointer by 4, while the Imp advances only 3 cells in those same three cycles. That 4-to-3 ratio means the bomb line steadily pulls away and the Imp walks into a bombed cell well before it can complete a lap of the core.

    The 100/100 rule is what raises the bar from Gladiator 1 to Gladiator 2. The server samples random starting offsets across rounds; a 100 percent win rate means the warrior beats the Imp regardless of where they start relative to each other in memory. A warrior that wins 99 of 100 had one offset configuration where the strategy fails, and the server will not award the flag. If you only see 99/1 locally with pMARS, change the bomb stride or pick a stronger warrior; do not just retry hoping for variance.

  2. Step 2Verify 100 wins
    Observation
    The server evaluates exactly 100 rounds with randomized starting offsets. Reproduce that locally with pmars -r 100 and confirm zero losses before piping the warrior to the remote.
    Run pmars -r 100 herem.red imp.red locally to confirm 100/0 before submitting.
    bash
    pmars -r 100 herem.red imp.red
    bash
    nc saturn.picoctf.net <PORT_FROM_INSTANCE> < herem.red

    Expected output

    picoCTF{d3m0n_3xpu...24e}
    What didn't work first

    Tried: Skipping the local pmars test and piping a warrior that won 99/100 rounds directly to the server, hoping the unlucky offset does not appear.

    The server samples starting offsets across exactly 100 rounds and demands a clean sweep, so a warrior losing even one round fails every time; it will not happen to skip the bad offset. If a local run shows 99 wins and a loss, the stride is wrong. Tune it until no cell is missed, then connect.

    Tried: Running pmars without the -r 100 flag (just pmars herem.red imp.red) and concluding the warrior is good enough from a single round result.

    A single-round run uses one starting offset and almost always reports a win, hiding the one or two offsets where the strategy breaks. The -r 100 flag randomizes offsets across a hundred rounds to match the server. Omit it and you get false confidence, with the losing offset undiscovered until the submission is rejected.

    Learn more

    -r 100 runs 100 rounds with randomised starting offsets, matching the server setup. The standard cycle limit is 80000 per round; omitting -c uses the pMARS default, which is a faithful match for typical CTF server configurations. A warrior that wins 100-0 locally will succeed on the server.

    If you only manage 99/1 locally: tune the stride (the Imp moves 1 cell per cycle and the bomb loop costs 3 cycles, so the stride has to exceed 3 for the bomber to gain ground; 4 and 5 are the usual candidates, the key is that the bomber must seed enough cells to intercept the Imp before the Imp completes a full sweep, not that the stride must be coprime to the core size), or upgrade to a stronger warrior (a quick scan of the King of the Hill archives turns up dozens of 100/0 anti-Imp bombers).

    Beyond pure bomber tactics, this exact analysis (proving a strategy wins regardless of offset) is the spirit of formal verification: do not just observe a few good runs, prove the win condition holds across the entire input space.

Flag

Reveal flag

picoCTF{d3m0n_3xpu...24e}

Consistency is key: choose a warrior with deterministic wins rather than probabilistic ones.

Key takeaway

Winning every round under randomized starting conditions needs a strategy provably correct across all inputs, not one observed to work on a sample. What guarantees the win is a bomb stride fast enough to seed every region the Imp will walk before it completes a sweep, whether or not the stride is coprime with the core size. A three-cycle loop that advances the bomb pointer by 4 outpaces an Imp stepping 1 cell per cycle, so the bomb line pulls ahead and the Imp walks into a bombed cell before it can lap the core. Validating locally with the server's round count and randomization is the practical stand-in for formal verification: see zero failures before committing.

Related reading

Useful tools for Reverse Engineering

Where to go next