This article contains a walkthrough for all 34 levels of the Bandit wargame on OverTheWire.
- Link to Bandit wargame: https://overthewire.org/wargames/bandit/
The OverTheWire wargames have been on the web for a long time. You don’t have to pay anything to play them. The OverTheWire maintainers are volunteering a lot of time to teach everyone about Linux security. Please consider donating to OverTheWire.
I’ve solved most of the levels in Bandit around 2017. I thought it would be useful to write up the shell commands I’ve used to solve each level without giving away the solution password themselves. Use this guide if you feel stuck and try your best coming up with your own original shell invocations.
I’ve marked all passwords in the command outputs with XXX...
or YYY...
.
And most importantly, have fun :)
Bandit level 0
Link to this level: https://overthewire.org/wargames/bandit/bandit0.html
To solve level 0, you need to log in to bandit0
with password bandit0
using SSH on bandit.labels.overthewrite.org
and port 2220.
Connect with ssh
by using the following command:
ssh bandit0@bandit.labs.overthewire.org -p 2220
When you connect successfully, you should see a message like this:
_ _ _ _
| |__ __ _ _ __ __| (_) |_
| '_ \ / _` | '_ \ / _` | | __|
| |_) | (_| | | | | (_| | | |_
|_.__/ \__,_|_| |_|\__,_|_|\__|
This is an OverTheWire game server.
More information on http://www.overthewire.org/wargames
...
Enjoy your stay!
bandit0@bandit:~$
Bandit level 1
Link to this level: https://overthewire.org/wargames/bandit/bandit1.html
Connect to this level’s account using the following command:
# The password is the same as level 0
ssh bandit0@bandit.labs.overthewire.org -p 2220
Read out the file called readme
using the cat
command and learn the password for the next level:
cat readme
This prints out the following:
Congratulations on your first steps into the bandit game!!
Please make sure you have read the rules at https://overthewire.org/rules/
If you are following a course, workshop, walkthrough or other educational activity,
please inform the instructor about the rules as well and encourage them to
contribute to the OverTheWire community so we can keep these games free!
The password you are looking for is: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Note the password contained within the readme
file and proceed to the next
level’s account on Bandit.
Bandit level 2
Link to this level: https://overthewire.org/wargames/bandit/bandit2.html
Use ssh
to connect to the bandit1
account on Bandit:
# Use the password from the previous level here:
ssh bandit1@bandit.labs.overthewire.org -p 2220
This level stores its password in a file called -
. Trying to just read
out the file using the command cat -
doesn’t work. The program cat
assumes
that you are passing it something over standard input.
Refer to the manual of cat
, retrieved on Bandit using man cat
. Here you
can see that cat
interprets the file called -
in a specific way:
NAME cat - concatenate files and print on the standard output
SYNOPSIS cat [OPTION]… [FILE]…
DESCRIPTION Concatenate FILE(s) to standard output.
With no FILE, or when FILE is -, read standard input.
The solution is to prepend the filename -
with a ./
. The following
command reveals the password for the next level:
cat ./-
Bandit level 3
Link to this level: https://overthewire.org/wargames/bandit/bandit3.html
Connect to bandit
using the following command:
# Enter password from level 1
ssh bandit2@bandit.labs.overthewire.org -p 2220
Solve the next level by escaping all spaces in the target filename. In bash,
put a backward slash \
before any spaces in a filename.
Here’s how to escape spaces in the filename spaces in this filename
and
print out its contents:
cat spaces\ in\ this\ filename
# You can also type this:
cat "spaces in this filename"
# or this
cat 'spaces in this filename'
Note the password and use it in the next level.
Bandit level 4
Link to this level: https://overthewire.org/wargames/bandit/bandit4.html
This level has a hidden filename. In many UNIX operating systems, filenames are “hidden” if they start with a period .
character.
Connect to the bandit3
account using the following command:
# Enter password from level 3
ssh bandit3@bandit.labs.overthewire.org -p 2220
Then run the following command to show the password for the next level:
cat inhere/.hidden
Note the password and use it in the next level.
Bandit level 5
Link to this level: https://overthewire.org/wargames/bandit/bandit5.html
This level has a bunch of files in the inhere
directory. Only one of them
is human-readable and contains the password. Your task is to find this file.
Connect to the level using ssh
:
# Use password from level 3 to log in
ssh bandit4@bandit.labs.overthewire.org -p 2220
Find out what files are in the inhere
directory:
bandit4@bandit:~$ ls inhere
-file00 -file01 -file02 -file03 -file04 -file05 -file06 -file07 -file08 -file09
Using the head
command, you can print the beginning of each file and the
name of that file. Try running head inhere/*
and find the file that has
the password for the next level:
bandit4@bandit:~$ head inhere/*
==> inhere/-file00 <==
QRrtZi H
|ȧ^
==> inhere/-file01 <==
7L3Yͯ ŴEY V&hF
==> inhere/-file02 <==
O̫`\-⃐Hx2K
==> inhere/-file03 <==
ix#e>VOp{ MUb4
==> inhere/-file04 <==
gQeE}:gj8<.e
==> inhere/-file05 <==
S 0]7b<~
==> inhere/-file06 <==
G=1B׃"
W9ؽ5
==> inhere/-file07 <==
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
==> inhere/-file08 <==
K~+9"T*Z$"r
==> inhere/-file09 <==
In my case, inhere/-file07
was the winner. Note the password and use it in
the next level.
Bandit level 6
Link to this level: https://overthewire.org/wargames/bandit/bandit6.html
This level has you look for a specific file within the inhere
directory.
The file isn’t executable, 1033 bytes long, and human-readable. The find
command is useful for finding a file using specific criteria like these.
First, connect to this level using ssh
:
# Use the password from level 5
ssh bandit5@bandit.labs.overthewire.org -p 2220
This is the find
invocation that found the file for me.
find inhere -type f -size 1033c -exec cat {} \;
The flags used here do the following:
-type f
looks for regular files.-size 1033c
looks for a file exactly 1033 bytes long.-exec cat {} \;
prints the contents of the file usingcat
if found.
Find may print out a bunch of gibberish files as well. Note the password and use it in the next level.
Bandit level 7
Link to this level: https://overthewire.org/wargames/bandit/bandit7.html
This level is a continuation of the previous level. Use find
again to solve
it. This time, the winning file belongs to the user bandit7
, is owned by
the group bandit6
, and is 33 bytes long. The file could be anywhere
on the system and not only in the bandit6
user’s home directory.
First, connect to the level using ssh
:
ssh bandit6@bandit.labs.overthewire.org -p 2220
Use the following find
invocation to find the file:
find / -size 33c \
-user bandit7 \
-group bandit6 -exec head {} \; 2> /dev/null
The arguments used for the find
command used this time do the following:
- The
/
argument makesfind
search starting from the filesystem root. -size 33c
only looks for 33 byte long files.-user bandit7
looks for files belonging to the userbandit7
.-group bandit6
looks for files belonging to the groupbandit6
.-exec head {}\;
prints the contents of any file matching these criteria.2> /dev/null
tells Bash to discard any errors
Discarding errors is important here because the find
command produces a lot
of errors when scanning through the complete filesystem. In the machines
filesystems there are a lot of files that the bandit6
user isn’t allowed to
access. The find
command informs you of every error that it encounters when
reading files. This can cause it to produce a lot of output and makes finding
the file you are looking for difficult.
Bandit level 8
Link to this level: https://overthewire.org/wargames/bandit/bandit8.html
In this level, you need to search the file data.txt
for the next level’s
password. The password is written right next to the string millionth
.
Use the grep
command to solve this level.
Connect to the level using ssh
:
ssh bandit7@bandit.labs.overthewire.org -p 2220
The following regular expression used with grep
finds the word millionth
and anything written after it:
millionth.*
Here’s how to use it with the grep
command:
grep -e 'millionth.*' data.txt
You should see something like the following:
millionth XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Note the password written after millionth
and use it for the next level.
Bandit level 9
Link to this level: https://overthewire.org/wargames/bandit/bandit9.html
In this level, you need to find a line that occurs only once in a file called
data.txt
. Every other line in this file appears at least twice.
Connect using ssh
:
ssh bandit8@bandit.labs.overthewire.org -p 2220
Use sort
piped into uniq --unique
to first sort the lines, exclude duplicate
lines, and then only output the lines that appear exactly once.
sort < data.txt | uniq --unique
This prints the password for the next level.
Bandit level 10
Link to this level: https://overthewire.org/wargames/bandit/bandit10.html
This level wants you to use grep
to search for the password for the next
level. The password is one of the only human-readable strings and is preceded
by at least one =
character.
Connect using ssh
:
ssh bandit9@bandit.labs.overthewire.org -p 2220
Use the strings
command to extract human-readable strings from a file. Pipe
the result into grep
and only output lines that start with at least two
=
characters. These two commands put together look like this:
strings data.txt | grep -e '^=='
The output for this invocation looks like this:
========== passwordk^
========== is
========== XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Note down the password and use it in Bandit level 11.
Bandit level 11
Link to this level: https://overthewire.org/wargames/bandit/bandit11.html
This level gives you the password in a file called data.txt
. This file contains
Base64 encoded data that you have to decode to get the password.
Connect using ssh
:
ssh bandit10@bandit.labs.overthewire.org -p 2220
Run the following command and observe the output:
base64 -d data.txt
You should see something like the following:
The password is XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Bandit level 12
Link to this level: https://overthewire.org/wargames/bandit/bandit12.html
In this level, the file data.txt
contains a ROT13 encoded password. To continue to the next level, you have to find
a way to decode this password.
Connect using ssh
:
ssh bandit11@bandit.labs.overthewire.org -p 2220
If you scroll down the Wikipedia article linked here, you can find the solution
for decoding ROT13 with tr
here.
Run the following tr
invocation to find the next level’s password:
tr 'A-Za-z' 'N-ZA-Mn-za-m' < data.txt
You should see the following output after running this command:
The password is JVNBBFSmZwKKOP0XbFXOoW8chDz5yVRv
Bandit level 13
Link to this level: https://overthewire.org/wargames/bandit/bandit13.html
This level has you unpack, decode, or decompress a file 8 times to find the password. The order of operation from start to finish is:
- Compress with
gzip
- Archive with
tar
- Archive with
tar
a second time - Archive with
tar
a third time - Compress with
gzip
- Compress with
bzip2
- Compress with
gzip
- Convert to hex dump with
xxd
When unpacking this file, you need to run these operations in reverse.
Connect using ssh
:
ssh bandit12@bandit.labs.overthewire.org -p 2220
To convert the hex dump back into binary data, use xxd -r
:
xxd -r < data.txt
This outputs binary data to your terminal and won’t immediately be useful.
To see what format this binary output is, pipe the output of xxd -r
into
file -
like so:
xxd -r < data.txt | \
file -
This should print that it’s gzip
compressed data:
/dev/stdin: gzip compressed data, was "data2.bin"
last modified: Thu Oct 5 06:19:20 2023, max compression, from Unix
Decompress this data using zcat
and check the output format like so:
xxd -r < data.txt | \
zcat | \
file -
This time file
tells you that the data is bzip2
compressed:
/dev/stdin: bzip2 compressed data, block size = 900k
Decompress this data using bzip2 --decompress --force
and output it to
standard out with the --stdout
flag. This way, you can pipe the output
into the next program. Inspect the contents again using file -
:
xxd -r < data.txt | zcat | \
bzip2 --decompress --force --stdout | file -
file
tells you that the output is a tar
archive:
/dev/stdin: POSIX tar archive (GNU)
Now, to unpack the contents, decompress the contents into a new temporary directory:
# change into temporary directory
cd $(mktemp -d)
# Will CD into something like this:
# /var/folders/k8/jnlz0xdn5jd48zttf3ktv7200000gn/T/tmp.0eOTs8AHV5
xxd -r < $HOME/data.txt | \
zcat | \
bzip2 --decompress --force --stdout | \
zcat | \
tar -xf -
Now check the contents of each unpacked file using file
:
# Still in the same temporary directory as above
file *
file
reports that there is one file data5.bin
containing another tar
archive:
data5.bin: POSIX tar archive (GNU)
Unpack the archive using the following command:
# Unpack data5.bin into the current directory
tar xvf data5.bin
This unpacks a file called data6.bin
. This file is another tar
archive.
Here’s how you can unpack data6.bin
:
# Unpack data6.bin into the same directory
tar xvf data6.bin
The file data6.bin
contains a gzip
compressed file called data8.bin
.
In total, you should now have three uncompressed files:
# Contents of current temporary directory
data5.bin data6.bin data8.bin
Here’s what file
reports when you run it on data8.bin
:
data8.bin: gzip compressed data, was "data9.bin", last modified: Thu Oct 5 06:19:20 2023, max compression, from Unix, original size modulo 2^32 49
Print the contents of data8.bin
by using zcat
:
zcat data8.bin
Note the password contained in the file and use it in the next level:
The password is XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Bandit level 14
Link to this level: https://overthewire.org/wargames/bandit/bandit14.html
This level gives you an SSH key that you can use to log into Bandit level 14. Connect to level 13 using SSH:
ssh bandit13@bandit.labs.overthewire.org -p 2220
After you connect, print out the SSH private key contained in sshkey.private
and store it on your own machine:
cat sshkey.private
The SSH private key looks like this:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAxkkOE83W2cOT7IWhFc9aPaaQmQDdgzuXCv+ppZHa++buSkN+
... rest left out
/+aLoRQ0yBDRbdXMsZN/jvY44eM+xRLdRVyMmdPtP8belRi2E2aEzA==
-----END RSA PRIVATE KEY-----
Store the whole private key in a file called level_14.key
and use it in the
next level.
Bandit level 15
Link to this level: https://overthewire.org/wargames/bandit/bandit15.html
In this level, you need to send the current level’s password to a TCP server
listening on port 30000 on the same machine. Where’s the current level’s password
if the only thing you have is the SSH key? Passwords for each level are
stored in /etc/bandit_pass
. Each password file for a level is only
accessible by that levels’ account. For example, the user bandit14
can access
the file /etc/bandit_pass/bandit14
.
Connect to the level using ssh
and give it the private key file level_14.key
from the last level.
ssh bandit14@bandit.labs.overthewire.org -p 2220 -i level_14.key
If SSH complains about the key at level_14.key
being world readable, run
the following command to fix its permissions:
chmod 400 level_14.key
After you’ve connected, read out the password for bandit14
stored in
/etc/bandit_pass/bandit14
.
# Read out the password and note it
cat /etc/bandit_pass/bandit14
Use nc
to pass the password to port 30000 on the same machine:
# Contents of `/etc/bandit_pass/bandit14`
# v
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" | nc localhost 30000
When you run this command, the server on port 30000 gives you the password for the next level. Write it down and use it for the next level.
Bandit level 16
Link to this level: https://overthewire.org/wargames/bandit/bandit16.html
To solve level 16, you need to forward the current level’s password to a server listening on the same machine. The difference to level 15 is that this time you need to connect to it using TLS encryption.
Connect to the level using ssh
:
ssh bandit15@bandit.labs.overthewire.org -p 2220 -i /dev/null
The command that you can use to connect to a server using TLS encryption is
called openssl s_client
. OpenSSL is full of useful tools for certificate
related operations and features a TLS client called s_client
as well.
Here’s the command that solves this level:
# Password from level 15
# v
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" | \
openssl s_client -quiet -connect localhost:30001
When you pass the -quiet
flag to openssl s_client
, it won’t print connection
status or certificate information. This information is useful for debugging,
but can be noisy when you just want to see the flag.
After you run the preceding command, you should receive the password for the next level.
Bandit level 17
Link to this level: https://overthewire.org/wargames/bandit/bandit17.html
To solve this level, you need to do 3 things:
- Find which port on the current machine between 31000 and 32000 is open.
- Find out which of these open ports lets you connect with TLS.
- Connect to the right port and send the current level’s password and get the next level’s password.
Connect to the current level using ssh
:
ssh bandit16@bandit.labs.overthewire.org -p 2220 -i /dev/null
I admit that I’ve brute-forced this level. I tried all 1000 ports and directly
connected with openssl s_client
. This script discards all error messages
to /dev/null
. The output is long and verbose. If you scroll through the output,
you should eventually see the private key for the next level. Here’s
the script that you can just paste and run in the SSH session:
for i in $(seq 31000 32000); do
echo "Trying port $i"
# Current level's password
# v
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" | \
openssl s_client -quiet -connect "localhost:$i" 2>/dev/null
done
The OpenSSL invocation is the same as in the previous level and uses -quiet
again.
This script pipes any error messages when OpenSSL fails to connect to
/dev/null
and thus discards them. The script runs for a while and at some point
you should see the following output:
[...]
Correct!
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAvmOkuifmMg6HL2YPIOjon6iWfbp7c3jx34YkYWqUH57SUdyJ
...
vBgsyi/sN3RqRBcGU40fOoZyfAMT8s1m/uYv52O6IgeuZ/ujbjY=
-----END RSA PRIVATE KEY-----
[...]
Save this private key in a file called level_17.key
and move on to the
next level.
Bandit level 18
Link to this level: https://overthewire.org/wargames/bandit/bandit18.html
In this level, you need to spot the difference between two files passwords.old
and passwords.new
. Only one line has changed, and the changed line in
passwords.new
is the password for the next level.
Connect to bandit17
using ssh
with the private key level_17.key
from the last level.
# Fix key permissions if necessary
chmod 400 level_17.key
ssh bandit17@bandit.labs.overthewire.org -p 2220 -i level_17.key
Use the diff
command to print out the differences between passwords.old
and passwords.new
like so:
diff -u passwords.old passwords.new
You should see the following output. The line marked with a +
character
in the beginning tells you what the new line in passwords.new
is. The line
with the -
character is the line in passwords.old
that someone has deleted.
--- passwords.old 2024-07-17 15:57:13.545795226 +0000
+++ passwords.new 2024-07-17 15:57:13.549795225 +0000
@@ -XX,7 +XX,7 @@
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
-OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
+NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
The password is obfuscated in this output.
The line marked with the +
character is the password for the next level.
Bandit level 19
Link to this level: https://overthewire.org/wargames/bandit/bandit19.html
Messing with SSH to escape user shell configurations is a real method that penetration testers use.
A recent vulnerability report, CVE-2024-47516 in Fedora Pagure shows this. Read the full report here
The authors identify weaknesses that when combined allow
users to run arbitrary code when connecting to git@gitinstance.com
with an
SSH client.
This is a no-privilege, low-complexity, and network exploitable vulnerability with
high CIA impact.
In this level, you need to leverage a similar vulnerability and read out the
readme
file in user bandit18
’s home directory. Directly connecting
with ssh
doesn’t work. The .bashrc
is set to automatically kick you out.
To read out the readme
file, pass the command that you want to run
directly to SSH. This is how to do it:
ssh bandit18@bandit.labs.overthewire.org -p 2220 \
cat readme
This is what you should see when it runs successfully, where XXX...
is the
password for the next level:
_ _ _ _
| |__ __ _ _ __ __| (_) |_
| '_ \ / _` | '_ \ / _` | | __|
| |_) | (_| | | | | (_| | | |_
|_.__/ \__,_|_| |_|\__,_|_|\__|
This is an OverTheWire game server.
More information on http://www.overthewire.org/wargames
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Bandit level 20
Link to this level: https://overthewire.org/wargames/bandit/bandit20.html
In this level you need to use a setuid command to gain another user’s privileges.
The challenge server stores Bandit level password in the /etc/bandit_pass/
directory.
Each Bandit level user can only access their own password in there.
For this level, you connect as bandit19
and you can only read the password in /etc/bandit_pass/bandit19
. To read out the password for bandit20
, you need
to be able to become bandit20
, at least temporarily.
The bandit19
user’s home directory
contains a setuid binary that can run commands as the user bandit20
.
The goal is to use this binary and read out the user bandit20
’s password
in the /etc/bandit_pass/
directory.
Connect to bandit19
using ssh
:
ssh bandit19@bandit.labs.overthewire.org -p 2220
Here’s the setuid binary that lets you become bandit20
:
./bandit20-do
Run without any arguments, bandit-20
prints the following:
Run a command as another user.
Example: ./bandit20-do id
This is how you can read out the user bandit20
’s password file:
./bandit20-do cat /etc/bandit_pass/bandit20
Note the password that it prints out and use it in the next level.
Bandit level 21
Link to this level: https://overthewire.org/wargames/bandit/bandit21.html
In this level, you need to send your password to a specific port using a setuid binary.
Connect to this level:
ssh bandit20@bandit.labs.overthewire.org -p 2220
nc -l 20000 # ctrl-z
./suconnect 20000 # ctrl-z
fg %1
# type password from the last level
Here’s how it should look like, with comments denoted with a #
symbol:
# Start nc and listen on port 20000
bandit20@bandit:~$ nc -l 20000
# Put nc -l in the background by pressing ctrl-z
^Z
[1]+ Stopped nc -l 20000
# Start ./suconnect and connect to port 20000
bandit20@bandit:~$ ./suconnect 20000
# Put ./suconnect 20000 in the background by pressing ctrl-z
^Z
[2]+ Stopped ./suconnect 20000
# Put nc -l 20000 back in the foreground
bandit20@bandit:~$ fg %1
nc -l 20000
# Type the password from the last level
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Put nc -l 20000 in the background
^Z
[1]+ Stopped nc -l 20000
# Put ./suconnect 20000 in the foreground
bandit20@bandit:~$ fg %2
./suconnect 20000
# It shows you that it read the password correctly
Read: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# The ./suconnect 20000 sends the password to nc -l 20000 and quits
Password matches, sending next password
# Put nc -l 20000 in the foreground
bandit20@bandit:~$ fg %1
nc -l 20000
# This is the password for the next level
YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
Note the password that the nc -l
receives and use it in the next level.
Bandit level 22
Link to this level: https://overthewire.org/wargames/bandit/bandit22.html
In this level, you need to understand what a specific cron
job is doing to read
out the password. Connect with SSH:
ssh bandit21@bandit.labs.overthewire.org -p 2220
Find the cron
job description in /etc/cron.d
and understand where it
writes the password for the next level:
# List all cron job configurations
bandit21@bandit:~$ ls /etc/cron.d/
cronjob_bandit22 cronjob_bandit23 cronjob_bandit24 e2scrub_all otw-tmp-dir sysstat
# Read out the configuration for bandit22
bandit21@bandit:~$ cat /etc/cron.d/cronjob_bandit22
@reboot bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
# List the bandit22 user's cron job info at /usr/bin/cronjob_bandit22.sh
bandit21@bandit:~$ ls -l /usr/bin/cronjob_bandit22.sh
-rwxr-x--- 1 bandit22 bandit21 130 Jul 17 15:57 /usr/bin/cronjob_bandit22.sh
# Read out the cronjob file at /usr/bin/cronjob_bandit22.sh
bandit21@bandit:~$ cat /usr/bin/cronjob_bandit22.sh
#!/bin/bash
chmod 644 /tmp/YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
cat /etc/bandit_pass/bandit22 > /tmp/YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
# Read out the password written to the temporary file:
bandit21@bandit:~$ cat /tmp/YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Bandit level 23
Link to this level: https://overthewire.org/wargames/bandit/bandit23.html
This level is almost like the last level. The shell script that the cron
job invokes is a bit more involved. Once you figure out how it determines
the filenames, you can read out the password.
Connect to this level with SSH:
ssh bandit22@bandit.labs.overthewire.org -p 2220
Here are the steps I took to find the password:
# List all cron configurations
bandit22@bandit:~$ ls /etc/cron.d
cronjob_bandit22 cronjob_bandit23 cronjob_bandit24 e2scrub_all otw-tmp-dir sysstat
# Read out the cron configuration for bandit23
bandit22@bandit:~$ cat /etc/cron.d/cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
# Read out the cron job's script:
bandit22@bandit:~$ cat /usr/bin/cronjob_bandit23.sh
#!/bin/bash
myname=$(whoami)
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
echo "Copying passwordfile /etc/bandit_pass/$myname to /tmp/$mytarget"
cat /etc/bandit_pass/$myname > /tmp/$mytarget
# Find the hash $mytarget used for the filename
bandit22@bandit:~$ echo I am user bandit23 | md5sum | cut -d ' ' -f 1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Read out the file contents
bandit22@bandit:~$ cat /tmp/$(echo I am user bandit23 | md5sum | cut -d ' ' -f 1)
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
Bandit level 24
Link to this level: https://overthewire.org/wargames/bandit/bandit24.html
In this level, you have to trick a cron
job into executing your script instead.
Connect to the level using SSH:
ssh bandit23@bandit.labs.overthewire.org -p 2220
There’s a cron
job in /usr/bin/cronjob_bandit24.sh
. You can
trick it into running your script by putting an executable file in the right place:
bandit23@bandit:~$ cat /etc/cron.d/
cronjob_bandit22 cronjob_bandit24 otw-tmp-dir sysstat
cronjob_bandit23 e2scrub_all .placeholder
bandit23@bandit:~$ cat /etc/cron.d/cronjob_bandit24
@reboot bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
bandit23@bandit:~$ cat /usr/bin/cronjob_bandit24.sh
#!/bin/bash
myname=$(whoami)
cd /var/spool/$myname/foo
echo "Executing and deleting all scripts in /var/spool/$myname/foo:"
for i in * .*;
do
if [ "$i" != "." -a "$i" != ".." ];
then
echo "Handling $i"
owner="$(stat --format "%U" ./$i)"
if [ "${owner}" = "bandit23" ]; then
timeout -s 9 60 ./$i
fi
rm -f ./$i
fi
done
bandit23@bandit:~$ ls /var/spool/bandit24
Here’s the command I used to write an executable shell script into /var/spool/bandit24
.
The shell script uses the install
command to copy over the password file:
cat > /var/spool/bandit24/foo/cat_passwd <<EOF
#!/bin/bash
install --mode=444 /etc/bandit_pass/bandit24 /tmp/bandit_pass_bandit24
EOF
chmod +x /var/spool/bandit24/foo/cat_passwd
sleep 60
cat /tmp/bandit_pass_bandit24
Finally, this is how you can then print out the password:
cat /tmp/bandit_pass_bandit24
Note the password and use it in the next level.
Bandit level 25
Link to this level: https://overthewire.org/wargames/bandit/bandit25.html
Solve this level by connecting to port 30002 on localhost
and giving it
the right password. The password is a combination of the last level’s password and
a random 4 digit pin. The seq
command is useful for brute-forcing passwords.
Connect to the level with ssh
:
ssh bandit24@bandit.labs.overthewire.org -p 2220
Here’s the command that finds you the password. This filters out any lines
that contain the string Wrong!
. That way, you won’t get overwhelmed with
wrong password messages.
seq -f "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX %4g" 0 9999 |
socat STDIO TCP4:localhost:30002 |
grep -v Wrong!
After a while, this is what you should see once you send it the right code:
I am the pincode checker for user bandit25. Please enter the password for user bandit24 and the secret pincode on a single line, separated by a space.
Correct!
The password of user bandit25 is YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
Note the password and use it in the next level.
Bandit level 26
Link to this level: https://overthewire.org/wargames/bandit/bandit26.html
To solve this level, you need to find a way to escape the bandit26
user’s
default shell. First, connect to the bandit25
user and see what shell
bandit26
is using:
ssh bandit25@bandit.labs.overthewire.org -p 2220
This command filters out the bandit25
and bandit26
users from the
password file located at /etc/passwd
:
cat /etc/passwd | grep -e bandit25 -e bandit26
The bandit25
user’s shell is /bin/bash
, which is a regular shell.
The bandit26
user uses an uncommon shell located at /usr/bin/showtext
.
See the two user’s entries in the /etc/passwd
file here:
bandit25:x:11025:11025:bandit level 25:/home/bandit25:/bin/bash
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
To confirm what content the shell at /usr/bin/showtext
has, examine
the file using ls
and cat
like so:
ls -la /usr/bin/showtext
Here you can see that /usr/bin/showtext
is a 58 byte large executable file:
-rwxr-xr-x 1 root root 58 Jul 17 15:57 /usr/bin/showtext
Show the contents of /usr/bin/showtext
using cat /usr/bin/showtext
:
#!/bin/sh
export TERM=linux
exec more ~/text.txt
exit 0
All that the /usr/bin/showtext
command does is read out the contents of a file
called text.txt
in the current user’s directory. Note that you can change
what the tilde ~
character expands to by passing a different $HOME
variable.
Try running the /usr/bin/showtext
program while logged in as bandit25
:
bandit25@bandit:~$ /usr/bin/showtext
more: cannot open /home/bandit25/text.txt: No such file or directory
bandit25@bandit:~$ HOME=/home/bandit26 /usr/bin/showtext
more: cannot open /home/bandit26/text.txt: Permission denied
/usr/bin/showtext
doesn’t work since you don’t have a text.txt
file
in your own home directory. Changing the home directory to be the bandit26
user’s home directory doesn’t solve it either, since you don’t have access
to the bandit26
user’s data in their home directory.
Inspect your home directory with ls $HOME
and find the SSH key for the
bandit26
user:
bandit25@bandit:~$ ls $HOME
bandit26.sshkey
Print the contents of this file using cat $HOME/bandit26.sshkey
:
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEApis2AuoooEqeYWamtwX2k5z9uU1Afl2F8VyXQqbv/LTrIwdW
...
IZdtF5HXs2S5CADTwniUS5mX1HO9l5gUkk+h0cH5JnPtsMCnAUM+BRY=
-----END RSA PRIVATE KEY-----
Copy the contents of this file to your computer into a file called bandit26.sshkey
.
Change this file’s permissions so that only you can read it:
# Assuming you use the wayland clipboard
wl-paste > bandit26.sshkey
chmod 400 bandit26.sshkey
Connect to the bandit26
user with the SSH key at bandit26.sshkey
ssh -i bandit26.sshkey bandit26@bandit.labs.overthewire.org -p 2220
All that the /usr/bin/showtext
command does is show the contents of a
short text file using the more
command. The connection then terminates immediately because
more
quits after printing all text.
[...]
_ _ _ _ ___ __
| | | (_) | |__ \ / /
| |__ __ _ _ __ __| |_| |_ ) / /_
| '_ \ / _` | '_ \ / _` | | __| / / '_ \
| |_) | (_| | | | | (_| | | |_ / /| (_) |
|_.__/ \__,_|_| |_|\__,_|_|\__|____\___/
Connection to bandit.labs.overthewire.org closed.
There’s a way to trick the more
command into not quitting immediately.
While more
is running, you can make it read other files, open an editor or
execute commands.
Make your terminal small and connect to the bandit26
user again. If you are
using a tiling window manager, making the terminal float can help as well.
ssh -i bandit26.key bandit26@bandit.labs.overthewire.org -p 2220
While more
is running, press vv
to enter the vim
editor. Inside vim
type :e /etc/bandit_pass/bandit26<ENTER>
.
You can now see the password:
YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
You can even enter a full shell inside the vim
editor using the following:
set shell=/bin/sh
:shell
Note the password and use it in the next level.
Bandit level 27
Link to this level: https://overthewire.org/wargames/bandit/bandit27.html
Solve this level by using the same trick as in the previous level. Connect using SSH:
ssh bandit26@bandit.labs.overthewire.org -p 2220
Make your terminal small so that the more
command doesn’t quit immediately.
When you’re inside more
, press vv
to open vim
. Inside vim enter the
following command:
:set shell=/bin/sh<CR>:shell
This launches a shell. Run the following inside the shell to print the next level’s password:
./bandit27-do cat /etc/bandit_pass/bandit27
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Note the password and use it to connect to the next level.
Bandit level 28
Link to this level: https://overthewire.org/wargames/bandit/bandit28.html
This level was a lot of fun to solve. It’s good to keep in mind how much information can leak through git repositories.
Connect to the level using ssh
:
ssh bandit27@bandit.labs.overthewire.org -p 2220
Go into a temporary directory that you create using the mktemp -d
command.
Inside the temporary directory, clone the git repository at the following
address:
ssh://bandit27-git@localhost:2220/home/bandit27-git/repo
Here are the commands you can run to achieve this.
cd $(mktemp -d)
git clone ssh://bandit27-git@localhost:2220/home/bandit27-git/repo
List all files in the repository that you have checked out using the find
command:
find repo
You should see a README
file listed among the files:
[...]
repo/README
Read out the contents of the README
file using the cat
command:
cat repo/README
Note the password contained in the README
file and use it in the next level.
The password to the next level is: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Bandit level 29
Link to this level: https://overthewire.org/wargames/bandit/bandit29.html
Like in the last level, you have to find credentials in a git repository
that someone forgot to take out. Connect to the level using ssh
:
ssh bandit28@bandit.labs.overthewire.org -p 2220
Once you are connected, check out the repository and list its contents using the following commands:
# Create a temporary directory and change into it
cd $(mktemp -d)
# Clone the repository
git clone ssh://bandit28-git@localhost:2220/home/bandit28-git/repo
# List the contents
ls -la repo
total 16
drwxrwxr-x 3 bandit28 bandit28 4096 Aug 31 01:26 .
drwx------ 3 bandit28 bandit28 4096 Aug 31 01:26 ..
drwxrwxr-x 8 bandit28 bandit28 4096 Aug 31 01:26 .git
-rw-rw-r-- 1 bandit28 bandit28 111 Aug 31 01:26 README.md
This level has a README.md
file just like in level 28. Run cat
on it to check
if it contains any credentials:
cat repo/README.md
Someone removed the credentials in the README.md
file and replaced them
with x
characters.
# Bandit Notes
Some notes for level29 of bandit.
## credentials
- username: bandit29
- password: xxxxxxxxxx
If someone removed the password, perhaps the password was in the repository before?
Use git log -p
on the README.md
file to list all changes to it.
git log -p README.md
If you scroll down a bit, you should see the previous password like here:
[...]
commit 73f5d0435070c8922da12177dc93f40b2285e22a
Author: Morla Porla <morla@overthewire.org>
Date: Wed Jul 17 15:57:30 2024 +0000
add missing data
diff --git a/README.md b/README.md
index 7ba2d2f..d4e3b74 100644
--- a/README.md
+++ b/README.md
@@ -4,5 +4,5 @@ Some notes for level29 of bandit.
## credentials
- username: bandit29
-- password: <TBD>
+- password: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[...]
Note the password and use it in the next level.
Bandit level 30
Link to this level: https://overthewire.org/wargames/bandit/bandit30.html
Again, this level is a git repository forensics challenge. Connect to it
using ssh
:
ssh bandit29@bandit.labs.overthewire.org -p 2220
Clone the repository into a temporary directory:
cd $(mktemp -d)
git clone ssh://bandit29-git@localhost:2220/home/bandit29-git/repo
Inside the repository, search for the password in the README.md
file. This
time, it’s somewhere else:
bandit29@bandit:/tmp/tmp.T3dxdml6c7$ cd repo
bandit29@bandit:/tmp/tmp.T3dxdml6c7/repo$ ls -a
. .. .git README.md
bandit29@bandit:/tmp/tmp.T3dxdml6c7/repo$ cat README.md
# Bandit Notes
Some notes for bandit30 of bandit.
## credentials
- username: bandit30
- password: <no passwords in production!>
Even checking the git log
for the README.md
file doesn’t reveal
any credentials. Try it yourself:
git log -p
Here’s the transcript:
...
commit 5a53eb83a43bac1f0b4e223e469b40ef68a4b6e6
Author: Ben Dover <noone@overthewire.org>
Date: Wed Jul 17 15:57:31 2024 +0000
initial commit of README.md
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2da2f39
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+# Bandit Notes
+Some notes for bandit30 of bandit.
+
+## credentials
+
+- username: bandit29
+- password: <no passwords in production!>
+
It looks like the password was never committed in the first place. Maybe the password is in another branch. List the names of all git branches using the following command:
git branch -a
The git repository contains the following branches:
* master
origin
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/master
remotes/origin/sploits-dev
Going through each branch, you should finally find the password in the
origin/dev
branch:
git log -p origin/dev
Here’s the password in the first commit in the origin/dev
branch:
commit eef534022d1ecc3b41d6de068501c4db4154b2c7 (origin/dev)
Author: Morla Porla <morla@overthewire.org>
Date: Wed Jul 17 15:57:31 2024 +0000
add data needed for development
diff --git a/README.md b/README.md
index 1af21d3..bc6ad3d 100644
--- a/README.md
+++ b/README.md
@@ -4,5 +4,5 @@ Some notes for bandit30 of bandit.
## credentials
- username: bandit30
-- password: <no passwords in production!>
+- password: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Rest of git log -p origin/dev abbreviated
Note the password and use it to connect to level 31.
Bandit level 31
Link to this level: https://overthewire.org/wargames/bandit/bandit31.html
This is another git repository forensics challenge. Connect to the level
using ssh
:
ssh bandit30@bandit.labs.overthewire.org -p 2220
Clone the repository using the following commands:
cd $(mktemp -d)
git clone ssh://bandit30-git@localhost:2220/home/bandit30-git/repo
cd repo
This time, the password is neither in the git log for the main branch
or any other branch. Instead, take a look at the git tags using git tag -l
:
git tag -l
# This lists one tag called `secret`
This lists one git tag called secret
. Show the git commit that belongs to this
tag by running the following command:
git show secret
#> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Note the password and use it in the next level.
Bandit level 32
Link to this level: https://overthewire.org/wargames/bandit/bandit32.html
To solve this level, you need to create a specific commit and send it to
a git remote. When the git remote receives the correct file, it gives you
the password for the next level. Connect to this level using ssh
.
ssh bandit31@bandit.labs.overthewire.org -p 2220
Clone the repository into a temporary directory:
cd $(mktemp -d)
git clone ssh://bandit31-git@localhost:2220/home/bandit31-git/repo
cd repo
Create a file called key.txt
and commit it to your local repository:
cat > key.txt <<EOF
May I come in?
EOF
git add -f key.txt
git commit -m yo
Push your changes to origin with the following git push
invocation:
git push origin master
The git commit hook in origin
takes over and gives you the password for the
next level.
_ _ _ _
| |__ __ _ _ __ __| (_) |_
| '_ \ / _` | '_ \ / _` | | __|
| |_) | (_| | | | | (_| | | |_
|_.__/ \__,_|_| |_|\__,_|_|\__|
This is an OverTheWire game server.
More information on http://www.overthewire.org/wargames
bandit31-git@localhost's password:
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 317 bytes | 317.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: ### Attempting to validate files... ####
remote:
remote: .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
remote:
remote: Well done! Here is the password for the next level:
remote: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
remote:
remote: .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
remote:
To ssh://localhost:2220/home/bandit31-git/repo
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'ssh://localhost:2220/home/bandit31-git/repo'
Note the password that the pre-receive
hooks prints out and use it in the
next level. This might be a good opportunity to double-check your usage of
git hooks.
Bandit level 33
Link to this level: https://overthewire.org/wargames/bandit/bandit33.html
In this level, you need to escape a custom shell that turns all commands into
uppercase. For example, when you run cat
, the shell turns it into a
CAT
.
Connect to this level using ssh
:
ssh bandit32@bandit.labs.overthewire.org -p 2220
Here’s what you’re prompted with when connecting:
[...]
For more information regarding individual wargames, visit
http://www.overthewire.org/wargames/
For support, questions or comments, contact us on discord or IRC.
Enjoy your stay!
WELCOME TO THE UPPERCASE SHELL
To see what exactly this uppercase shell is, I connected to the previous
level and inspect the /etc/passwd
password file. Here’s how you can print out
the record for the bandit32
user from this level:
grep /etc/passwd -e bandit32
The bandit32
user’s shell is in /home/bandit32/uppershell
:
bandit32:x:11032:11032:bandit level 32:/home/bandit32:/home/bandit32/uppershell
It’s not possible to view the contents of uppershell
as bandit31
. The
file belongs to bandit32
.
After trying a lot, this is the command that eventually solved the challenge for me:
# Run the name of the current shell as a command
$0
And this is it. I have no idea why this works. Normally, one would suppose that
this just runs /home/bandit32/uppershell
again.
Print out the password:
cat /etc/bandit_pass/bandit33
Epic laser boom. You’ve solved all levels in the Bandit wargame. Use the password and connect to the next level for an epic win epic message.
Bandit level 34
Link to this level: https://overthewire.org/wargames/bandit/bandit34.html
Connect to this level using ssh
:
ssh bandit33@bandit.labs.overthewire.org -p 2220
Print the README.txt
file in this level’s home directory using cat README.txt
and celebrate:
Congratulations on solving the last level of this game!
At this moment, there are no more levels to play in this game. However, we are constantly working on new levels and will most likely expand this game with more levels soon. Keep an eye out for an announcement on our usual communication channels! In the meantime, you could play some of our other wargames.
If you have an idea for an awesome new level, please let us know!
The Bandit wargame is a great shell command teacher. Give it a try if you are interested in learning how to get weird with the shell. Impress people at parties with obscure knowledge about Bash.
Here are two useful resources that helped me solve the challenges:
GTFOBins
to learn how to escape certain programs likemore
.- Linux man pages on die.net to read manuals for many programs in your browser