← back to blog

OverTheWire (Bandit) lvl 0–12: Walkthrough

This is a gamified way of learning Linux/Unix. So, let's get into it!

Level 0

The goal is simply to connect to the game using SSH, on host bandit.labs.overthewire.org, port 2220, with the given password bandit0.

ssh username@hostname -p portnumber
ssh bandit0@bandit.labs.overthewire.org -p 2220

Level 1

The password is stored in a readme file in the home directory. Check the working directory, list its contents, and read the file:

pwd
ls
cat readme

Tip: keep a local note + password file for Bandit. Exit the SSH connection (Bandit won't let you create files/directories on the box) and run nano banditnotes locally to keep track as you go.

Level 2

Same idea as Level 1, but the file is named -. That's a special symbol in Linux — the standard "option" character — so files starting with it can't be referenced like normal files. cat - won't work, but prefixing the path fixes it:

ls
cat ./-

Level 3

The file is called --spaces in this filename--, in the home directory. Anything starting with - looks like an option to commands, even quoted. Either tell the command to stop parsing options with --, or prefix with ./:

cat -- "--spaces in this filename--"

Level 4

The password is in a hidden file (a dotfile) inside a directory called inhere, named ...Hiding-From_You. The leading dots confuse the shell into reading it as a parent-directory reference, so point straight at it:

cat ./...Hiding-From_You

Level 5

The password is in the only human-readable file inside inhere. List everything, then filter by type:

file * 2>/dev/null | grep -i -E 'text|ascii'

That prints a short type for each file, and grep filters for text/ASCII ones. The match was -file07, so:

cat -- -file07

Level 6

This password is somewhere in inhere, in a file that's human-readable, exactly 1033 bytes, and not executable:

find -type f -size 1033c ! -perm /111 -print -quit

Then confirm and read it: file "$file_path" and cat "$file_path".

Level 7

Now the password lives somewhere on the whole server: owned by user bandit7, group bandit6, exactly 33 bytes.

find / -type f -user bandit7 -group bandit6 -size 33c 2>/dev/null -print

Then cat whatever path gets printed.

Level 8

The password sits in a huge text file, data.txt, right next to the word "millionth." A tiny awk script handles this cleanly:

awk '{
  for(i=1;i<NF;i++){
    if($i=="millionth") print $(i+1)
  }
}' data.txt

NF is the number of fields (words) on the line; the loop scans each word, and whenever it matches "millionth," it prints the next one. One token per line, for every occurrence.

Level 9

The password is one of the few human-readable strings in data.txt, preceded by several = characters. Skimming the file works, but the pipeline way is cleaner:

strings -n 1 data.txt | grep -oP '=+\K\S+'

Level 10

The password is base64-encoded data. Base64 is an encoding — a way of representing binary data as ASCII text (== pads groups of four). Decoding it is one command:

base64 -d data.txt

Level 11

All the letters in data.txt have been rotated 13 positions (ROT13):

cat data.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m'

tr translates every letter 13 positions forward or back, which reverses ROT13 in one pass.

Level 12

data.txt isn't plain text here — it's a hex dump of a file that was compressed in multiple layers. The job: turn the hex dump back into binary, detect the file type, then repeatedly decompress/extract until plain text falls out.

1. Set up a safe workspace

workdir=$(mktemp -d /tmp/bandit.XXXXXX)
cd "$workdir"
cp /home/bandit12/data.txt ./hexdump.txt

Working in /tmp keeps the home directory clean and everything disposable.

2. The wrong hex → binary conversion

xxd -r -p hexdump.txt > data.bin
file data.bin

file came back unknown, and xxd -l 32 data.bin showed leading zero bytes — a corrupted binary. gunzip failed with "not in gzip format." The cause: xxd -r -p expects a plain hex stream, but this hex dump had offsets and an ASCII column, which -p can't parse correctly.

3. The correct conversion

xxd -r hexdump.txt > data_fixed.bin
file data_fixed.bin

This time file reported gzip compressed data, with the proper 1f 8b gzip magic bytes at the start.

4. Peel every layer

From here it was: decompress or extract → check file on the result → repeat, following whatever type came back.

gunzip -c data_fixed.bin > layer1.bin   # → bzip2
bunzip2 -c layer1.bin > layer2.bin      # → gzip
gunzip -c layer2.bin > layer3.bin       # → POSIX tar (GNU)

tar -xf layer3.bin                       # → data5.bin (tar)
tar -xf data5.bin                        # → data6.bin (bzip2)
bunzip2 -c data6.bin > data7.bin         # → POSIX tar (GNU)
tar -xf data7.bin                        # → data8.bin (gzip)
gunzip -c data8.bin > data9.bin          # → ASCII text

cat on a tar archive just prints garbage, since tar files are binary — extracting with tar -xf is the move there instead. After nine layers, data9.bin was plain ASCII text: the password.

Two lessons from this level: use xxd -r (not -r -p) on a standard hexdump with offsets and ASCII columns, and always run file after every step — let the reported type decide whether the next tool is gunzip, bunzip2, or tar.

Hope you had a fun gaming sesh — keep hacking :)

Late-night Bandit session — laptop screen mid-terminal next to an iced honey latte
fuel for levels 0–12 🧃