Having never really taken the time to try out the Internet’s offerings of public CTFs until recently (in preparation for creating BeeTF), I knocked out OverTheWire’s ‘Bandit’ wargame in a couple of hours. Indeed, pepare for the umpteenth blogpost on the Internet about Bandit.

OverTheWire's fantastic site logo

In keeping with the spirit of OverTheWire, I will try refraining from spoilers in this post. Please excuse any tip-toeing around the wargame’s content. Most people reading this page can likely solve it in a few hours, so I would recommend taking time to try it out if you haven’t, then come back to this post.

Sink or Swim, in the Shallow End

For a beginner-level CTF, Bandit is rather gnomic with its instructions; however it gets away with it in two great ways:

  • The instructions it provides are concise and straightforward

Last year, I took part in the Advent of Code for the first time. While I enjoyed its content (though could not finish it due to assignment work and the holidays getting in the way), I was not a fan of how it instructed players. A large amount of time and text is put into conceptualising the challenges through stories and exposition – in 2021’s case, a story about elves exploring the ocean in a submarine – but those stories still ended up feeling like they were simply contrived for the puzzles, instead of the puzzles being themed around the story (a squid that clearly just wants to play Bingo comes to mind), and thus it just got in the way for me.

Bandit gives you extremely simple and concise instructions. It tells you your trailhead, in less than a paragraph, then sets you loose. A newbie can’t get lost in the weeds of the instruction set because it is to-the-point.

  • “Commands you may need to solve this level”

Bandit puts a great emphasis on just trying things out. Of course, with an entire coreutil set to work from a complete beginner can’t just guess at what command(s) they need. Bandit hints at the commands you need, suggests to check out its man pages or Stack Overflow, and that’s your lot. This manages to be both terse and entirely what you need to solve every challenge in Bandit. It places emphasis on research, experimentation and – eventually – coming up with your own solution. Even an extremely suboptimal solution to a level is satisfying because it is one you came up with yourself.

By having a shortlist of every command that you need to solve each section (and often multiple choices of tools to get the job done – further owing to its focus on freedom), you can’t ever get “lost” in Bandit. You can certainly be stuck on how to use the tools at your disposal to complete its puzzles, but that is just the puzzles doing their job. While playing, I never had a moment where I was unsure what I could be using to proceed – just that I hadn’t utilised them to their fullest potentials yet.

My favourite levels

Three levels in Bandit stand out to me in particular:

Level 12

Level 12, as described in the problem statement, is about “a hexdump of a file that has been repeatedly compressed”. This is the first point at which making a temporary directory on the server is recommended for most. It is indeed “repeatedly compressed”, needing several decompressions across a variety of formats. This challenge is intentionally very slow and there’s no easy way to speed this process up. It takes advantage of the rather archaic differences of interfaces with compression tools in the Linux ecosystem to frustrate players.

You could create a script to automate this decompression process, but that process is even slower and would only be practical if this challenge required dozens or hundreds of decompressions; something you can’t reasonably know until you are that far in (it does not). This level is a bitter example of the fact that sometimes, you are best off just doing a job manually, even if it is so tempting to come up with something clever. It is a painful level in all the right ways.

The comic keeping mechanical turks afloat

Level 24

Level 24 involves interfacing with a daemon who wants a known password string, as well as an unknown 4-digit pincode. The only way to obtain this pincode is to bruteforce it. Interestingly, this level does not provide any helpful commands or reading material – though at this point, one should already be familiar with the best tool for this job: netcat.

There are two approaches to this level that are subtly different, but are drastic in their implications:

  • The naive way

I will admit that this was the first method I tried before realising how unhelpful it was. I created a monolithic bash script which iterated from 0000 to 9999, concatenating the password and pin together in an echo and piping that into an iterative netcat. The critical issue with this approach is that you create and destroy an entire netcat session each time you do this, up to 10,000 times. This is abominably slow (but will eventually get results)

  • The correct way

Realising my error, I simply dumped these echos into a flat file separated by newlines (done through a >> redirection), then fed that entire file into netcat in one go, and redirected netcat’s output into another flat file. This returns a result in mere seconds, compared to the extremely slow previous method.

This challenge is fantastic for teaching its players that even if a solution technically works, being proactive about performance when you write code will get even better results. If I kept running my old code, I likely would have got an answer faster than it took me to re-write the code. Due to code smells from my first attempt, I took a greater loss than if I simply thought harder about my first solution. This all-in-all helps people learn from their mistakes without directly punishing them; it feels good to learn, in an environment where you are all by yourself, that you did something in a terrible way.

Level 25

Straight after level 24 comes level 25. In this challenge, we have been set up with a user who does not have a particularly helpful shell program set. Solving this puzzle requires not only figuring out the program that the shell has been replaced with, but a specific quirk with that program where you can short-circuit its ‘run-then-kick’ routine with something you can do client-side. This is, in my opinion, the first instance of performing something akin to an exploit in OverTheWire. You have found a program, a way this program is being used to secure a target, and an oversight that allows you to turn the tides against it. It is also a pretty hilarious exploit that I initially thought was cheating.

After looking around; no, this is indeed the way you are supposed to solve this level. And it’s glorious.

How does it compare to BSc education?

Something I lament with my own coursework is how hand-holdy it tends to be. When learning something new, the contemporary education system generally seems to opt for showing you an exact process then asks you questions about what information you obtain from this process. I find that while this gets the answers students need, it doesn’t teach them how to actually use the tools they have been given. Of course, such is the eternal balance between wanting to drive students to innovate, while needing to meet the obligations of passing students that might fail if not given this sort of help.

Perhaps I’m being too harsh. Perhaps school hours need to be longer to give teachers more time to liaise with struggling students. Perhaps teachers should get paid more. What I do not think falls under a “perhaps”, however, is that the K-I-S-S approach Bandit takes works well and is something that lesson-to-lesson coursework could learn from. Students should be reading man pages of suggested programs and tools to carry out their tasks, instead of simply being told a magic pile of flags to run so that Input A becomes Output B.