Skip to content

OverTheWire: Bandit — Levels 7-15

Reference: https://overthewire.org/wargames/bandit/

See also: level_1-5.md.md for levels 0-6, SSH basics, find reference, hidden files, special filenames.


Level 7 → 8

Password: morbNTDkSW6jIlUc0ymOdMaLnOlFVAaj

Concept: Find the password next to the word "millionth" in data.txt.

grep "millionth" data.txt

grep = search for a pattern in a file. Returns the entire line containing the match.

data.txt has thousands of lines in word: password format. Rather than reading through it, you search for the specific word you know is next to the password.


Level 8 → 9

Password: dfwvzFQi4mU0wfNbFOe9RoWskMLg7eEc

Concept: The password is the only line that appears exactly once in data.txt.

sort data.txt | uniq -u

Full breakdown:

Part What it does
sort data.txt Sort all lines alphabetically. uniq only works on adjacent duplicate lines — sort puts duplicates next to each other
\| Pipe sorted output into uniq
uniq -u Print only lines that appear exactly once (-u = unique). Lines appearing 2+ times are suppressed

Why sort first? uniq compares adjacent lines only. Without sorting, duplicate lines scattered throughout the file wouldn't be detected. Sorting groups identical lines together so uniq can find them.

uniq flag reference:

Flag What it does
-u Only print unique lines (appear exactly once)
-d Only print duplicate lines (appear more than once)
-c Prefix each line with its count
(none) Remove consecutive duplicates, print one of each

The mistake in the raw notes was using uniq without -u and trying to count manually — -u does exactly that.


Level 9 → 10

Password: 4CKMh1JI91bUIZZPXDqGanal4xvAg0JM

Concept: Password is in data.txt (a binary file) as one of the few human-readable strings, preceded by = characters.

strings data.txt | grep '=='
Part What it does
strings data.txt Extract all sequences of printable characters (4+ chars by default) from any file — ignores binary bytes
grep '==' Filter for lines containing == (the = characters before the password)

file vs strings: - file = tells you the type of a whole file - strings = pulls readable text out of a file regardless of its type

Useful whenever a binary/compiled file might contain embedded plaintext (passwords, config, keys).


Level 10 → 11

Password: FGUW5ilLVJrxX9kMYMmlN4MgbpfMiqey

Concept: data.txt contains base64-encoded data.

base64 -d data.txt

base64 -d = decode base64. -d flag means decode (same as --decode).

What is base64? A way to encode binary data as printable ASCII characters. Uses characters A-Z, a-z, 0-9, +, /, and = as padding. You'll recognise it by the alphanumeric string often ending with = or ==.

It's encoding, not encryption — anyone can decode it instantly. Used for data transport (email attachments, JWTs, Kubernetes secrets) not for security.

echo "aGVsbG8=" | base64 -d    # → hello
echo -n "hello" | base64        # → aGVsbG8=

Level 11 → 12

Password: dtR173fZKb0RRsDFSGsg2RWnpNVj3qRr

Concept: data.txt has been ROT13 encoded.

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

What is ROT13?

Rotate by 13 — every letter shifts 13 positions forward in the alphabet:

A B C D E F G H I J K L M  →  N O P Q R S T U V W X Y Z
N O P Q R S T U V W X Y Z  →  A B C D E F G H I J K L M

A→N, B→O, M→Z, N→A. The alphabet has 26 letters, 13 is exactly half — so applying ROT13 twice gets you back to the original. Encrypt and decrypt are the same operation.

Zero security — just shifts letters. Used in CTFs as light obfuscation.

tr = translate characters:

tr 'set1' 'set2'

Maps each character from set1 to the character at the same position in set2, one-to-one.

echo "hello" | tr 'a-z' 'A-Z'          # HELLO — lowercase to uppercase
echo "hello" | tr -d 'aeiou'           # hll — delete vowels (-d = delete)
echo "a   b" | tr -s ' '               # a b — squeeze multiple spaces into one (-s = squeeze)
echo "hello" | tr 'a-z' 'n-za-m'       # uryyb — ROT13 lowercase only

ROT13 mapping breakdown: - A-Z (26 chars) maps to N-ZA-M = N through Z (13 chars) + A through M (13 chars) - a-z maps to n-za-m same logic for lowercase - Non-letter characters pass through unchanged

tr only reads from stdin — you can't give it a filename directly. Always pipe into it.


Level 12 → 13

Password: 7x16WNeHIi5YkIhWsfFIqoognUTyj9Q4

Concept: data.txt is a hexdump of a file that has been repeatedly compressed.

This level is a chain — you reverse the hexdump, then decompress multiple times, each time checking the file type to know which decompression tool to use.

# 1. Create a working directory (can't write to home)
mkdir /tmp/work && cd /tmp/work
cp ~/data.txt .

# 2. Reverse the hexdump back to binary
xxd -r data.txt > data.bin

# 3. Check what type it is
file data.bin

# 4. Rename and decompress — repeat until you get ASCII text
mv data.bin data.gz  && gzip -d data.gz        # if gzip
mv data.bin data.bz2 && bzip2 -d data.bz2      # if bzip2
mv data.bin data.tar && tar -xf data.tar        # if tar

# Keep running: file <result> → rename → decompress → repeat
# Until: file <result> shows "ASCII text"

Tools used:

Tool What it does Command
xxd Hexdump utility — xxd file = to hex, xxd -r = from hex back to binary xxd -r data.txt > data.bin
file Identify file type by magic bytes file data.bin
gzip GNU zip compression gzip -d file.gz (decompress)
bzip2 bzip2 compression (better ratio than gzip) bzip2 -d file.bz2
tar Tape archive — bundles multiple files, optionally compressed tar -xf file.tar

tar flags:

Flag What it does
-x Extract
-f Next argument is the filename
-z gzip compressed (.tar.gz / .tgz)
-j bzip2 compressed (.tar.bz2)
-v Verbose — print files as extracted
-c Create archive

Why can't you just decompress without renaming? Tools like gzip check the file extension. gzip -d file without .gz extension errors out. file tells you the actual type, then you rename to match.


Level 13 → 14

Password: FO5dwFsc0cbaIiH0h8J2eUks2vdTDwAn

Concept: No password for this level — you get an SSH private key file (sshkey.private) that logs you directly into bandit14.

ssh -i sshkey.private -p 2220 bandit14@bandit.labs.overthewire.org

-i = identity file (private key). Instead of a password, SSH uses the key pair for authentication.


Level 14 → 15

Password: 8xCjnmgoKbGLhHFAZlGE5Tmu4M2tKJQo

Concept: You logged in with a private key so you never typed the password. But you need it to submit to port 30000. It's stored at /etc/bandit_pass/bandit14 (readable only by bandit14, which you are).

# 1. Get your current level's password
cat /etc/bandit_pass/bandit14

# 2. Submit it to port 30000 on localhost
echo "MU4VWeTyX8kuzw8s7Xf9OHxq4Uqzsr1J" | nc localhost 30000

nc = netcat — the Swiss Army knife of networking.

Opens a raw TCP (or UDP) connection to a host:port. Whatever you pipe in gets sent. Whatever the remote end responds with gets printed.

nc <host> <port>           # interactive connection
echo "data" | nc host port # send data and print response
nc -l -p 1234              # listen on port 1234 (simple server)

Here: you're connecting to localhost:30000 where a service is running. It expects the current level's password — you send it, it replies with the next level's password.

/etc/bandit_pass/ — where all passwords live:

Every level's password is at /etc/bandit_pass/banditN. Each file is only readable by that user. As bandit14 you can read /etc/bandit_pass/bandit14 but not bandit15.

How to find this yourself if you didn't know:

find / -name "*pass*" 2>/dev/null
ls /etc/ | grep -i pass
find / -name "*bandit*" 2>/dev/null

Pattern recognition — /etc is always worth enumerating. Credentials, configs, and system-wide files live there by convention.

Check what's listening on a port:

ss -tlnp | grep 30000      # ss = socket statistics, modern replacement for netstat
nmap -p 30000 localhost    # nmap port scan

ss flag What it does
-t TCP only
-l Listening sockets only
-n Show numbers not names (port 80 not http)
-p Show process name/PID

Level 15 → 16

Concept: Same as level 14→15 but port 30001, using SSL/TLS.

openssl s_client -connect localhost:30001

Then type the password and press Enter. openssl s_client opens an SSL-encrypted connection — the raw TCP of nc won't work here because the service requires TLS.

Or pipe it:

echo "8xCjnmgoKbGLhHFAZlGE5Tmu4M2tKJQo" | openssl s_client -connect localhost:30001 -quiet

-quiet suppresses the verbose SSL handshake output.


Command Reference — New Tools This Set of Levels

# Text searching
grep "pattern" file              # lines matching pattern
grep -n "pattern" file           # with line numbers
grep -i "pattern" file           # case insensitive
grep -v "pattern" file           # lines NOT matching

# Sorting & deduplication
sort file                        # sort alphabetically
sort -n file                     # sort numerically
sort -r file                     # reverse sort
uniq file                        # remove consecutive duplicates
uniq -u file                     # unique lines only (appear once)
uniq -d file                     # duplicate lines only
uniq -c file                     # count occurrences
sort file | uniq -u              # find line appearing exactly once

# Binary file inspection
strings file                     # extract readable text from binary
xxd file                         # hexdump
xxd -r hexfile > binary          # reverse hexdump

# Encoding
base64 -d file                   # decode base64
echo -n "text" | base64          # encode to base64

# Character translation
tr 'a-z' 'A-Z'                   # lowercase to uppercase
tr -d 'chars'                    # delete characters
tr -s ' '                        # squeeze repeated spaces
cat file | tr 'A-Za-z' 'N-ZA-Mn-za-m'  # ROT13

# Compression
gzip -d file.gz                  # decompress gzip
bzip2 -d file.bz2                # decompress bzip2
tar -xf file.tar                 # extract tar
tar -xzf file.tar.gz             # extract tar+gzip
tar -xjf file.tar.bz2            # extract tar+bzip2

# Networking
nc host port                     # raw TCP connection
echo "data" | nc host port       # send data, print response
ss -tlnp                         # list listening ports
nmap -p PORT host                # scan specific port
openssl s_client -connect host:port    # SSL/TLS connection

# SSH
ssh -p 2220 user@host            # custom port
ssh -i keyfile -p 2220 user@host # private key auth
chmod 400 keyfile                # private keys must be owner-read-only or SSH refuses

Lessons from These Levels

man <command> is worth 60 seconds. uniq -u would've been found immediately. After finishing a level, skim the man page for the tool you used — flags like -u, -d, -c stick once you have context.

file before anything else when dealing with mystery binary files. Don't guess the compression format — check. file data → rename → decompress → repeat.

/etc is always worth enumerating on any Linux box. Credentials, configs, system-wide settings all live there by convention.

2>/dev/null whenever searching from / — otherwise permission denied errors from /proc, /sys, /root bury the actual results.