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
-type f— regular files only-size 1033c— exactly 1033 bytes (c= bytes)! -perm /111— not executable by owner/group/other
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
find /— search from root, the entire filesystem-type f— regular files only-user bandit7/-group bandit6— ownership filters-size 33c— exactly 33 bytes2>/dev/null— hides "Permission denied" noise
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.
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 :)