- Published on
OverTheWire - Bandit All levels (Solved)
- Authors
- Name
- Muhammad Haris
- @ArcusTen
Table of Contents
- Level 0
- Level 1
- Level 2
- Level 3
- Level 4
- Level 5
- Level 6
- Level 7
- Level 8
- Level 9
- Level 10
- Level 11
- Level 12
- Level 13
- Level 14
- Level 15
- Level 16
- Level 17
- Level 18
- Level 19
- Level 20
- Level 21
- Level 22
- Level 23
- Level 24
- Level 25
- Level 26
- Level 27
- Level 28
- Level 29
- Level 30
- Level 31
- Level 32
- Level 33
Level 0:
The password for the next level is stored in a file called readme located in the home directory. Use this password to log into bandit1 using SSH. Whenever you find a password for a level, use SSH (on port 2220) to log into that level and continue the game.
NH2SXQwcBdpmTEzi3bvBHMM9H66vVXjL
Explanation
Use this command to login to the server:
ssh bandit0@bandit.labs.overthewire.org -p 2220
bandit0

Use ls
to see a list of all files and directories. You will see the readme file there. Use cat
to display its contents.

Level 01:
The password for the next level is stored in a file called -
located in the home directory
rRGizSaX8Mk1RTb1CNQoXTcYZWU6lgzi
Explanation:
Use any of these commands:
cat ←
OR
cat ./-

Level 02:
The password for the next level is stored in a file called spaces in this filename located in the home directory.
aBZ0W5EmUfAf7kHTQeOwd8bauFJ2lAiG
Explanation:
Type cat spaces
then press tab button to get actual name: spaces\ in\ this\ filename.
cat spaces\ in\ this\ filename
The backslashes (\
) in this command are used as escape operators to escape spaces and instruct cat
to treat them as part of the filename rather than as terminators.

Level 03:
The password for the next level is stored in a hidden file in the inhere directory.
2EW7BBsr6aMMoJ2HjW067dm8EgX26xNe
Explanation:
cd inhere
We use ls
with -a
flag to also list hidden files and directories:
ls -a
Here, is the hidden file .hidden
. Use cat
to print its content on the terminal:
cat .hidden

Level 04:
The password for the next level is stored in the only human-readable file in the inhere directory.
(Tip: If your terminal is messed up, try the “reset” command.)
lrIWWI6bB37kxfiCQZqUdOIYfr6eEeqR
Explanation:
To access the content of all 10 files in this directory, simply use cat
command along with the wildcard *
. The wildcard instructs the system to include all files within the specified directory:
cat ./-file0*
./
: This represents the current directory.
-file0*
: This part refers to a file or files whose names start with -file0 in the current directory, with the *
acting as a wildcard character, matching any characters that follow "file0".
So, this command will display the contents of all files in the current directory whose names begin with -file0.

Level 05:
The password for the next level is stored in a file somewhere under cd inthe inhere directory and has all of the following properties:
human-readable
1033 bytes in size
not executable
P4L4vucdmLnm8I7Vl7jG1ApGSfjYKqJU
Explanation:
Command that I used:
find ~/inhere -type f -readable -size 1033c ! -executable
~/inhere
: This specifies the directory where the search will take place.
-type f
: This option instructs find to only consider files (not directories).
-readable
: This flag ensures that only files that are readable by the user executing the command are considered.
-size 1033c
: This specifies the size of the files to search for. Here, it looks for files with a size of exactly 1033 bytes (c
).
! -executable
: This part of the command uses the !
operator to negate the -executable condition. So, it excludes files that are executable.

And now cat that file out:

Level 06:
The password for the next level is stored somewhere on the server and has all of the following properties:
owned by user bandit7
owned by group bandit6
33 bytes in size
z7WtoNQU2XfjmMtWA8u5rN4vzqu4v99S
Explanation:
Command that I used:
find / -type f -user bandit7 -group bandit6 -size 33c 2>/dev/null
/
: This specifies the starting directory for the search. In this case, it starts from the root directory, searching the entire filesystem.
-type f
: This option specifies that only files should be considered (not directories).
-user bandit7
: This option specifies that the files must be owned by the user bandit7.
-group bandit6
: This option specifies that the files must belong to the group bandit6.
-size 33c
: This option specifies that the files must have a size of 33 bytes.
2>/dev/null
: This redirects any error messages generated during the search to /dev/null
, effectively suppressing them.
So, altogether the command is searching the entire filesystem for regular files owned by user bandit7, belonging to group bandit6 and having a size of 33 bytes. Any errors encountered during the search are discarded.

And now cat that file out:

Level 07:
The password for the next level is stored in the file data.txt next to the word millionth.
TESKZC0XvTetK0S9xNwm25STk5iWrBvP
Explanation:
I used grep
to filter out line that contains word "millionth". Command that I used:
cat data.txt | grep "millionth"
|
: This is known as a pipe operator. It takes the output of the command on its left (cat data.txt
in this case) and sends it as input to the command on its right (grep "millionth"
).
Output:

Level 08:
The password for the next level is stored in the file data.txt and is the only line of text that occurs only once.
EN632PlfYiZbn3PhVK3XOGSlNInNE00t
Explanation:
For this challenge I was read manual of uniq
command and saw this:

So the final command that I used:
sort data.txt | uniq -u

Level 09:
The password for the next level is stored in the file data.txt in one of the few human-readable strings, preceded by several ‘=’ characters.
G7w8LIi6J3kTb8A7j9LgrywtEUlyyp6s
Explanation:
I used strings
command to find for strings (human-readable) in data.txt:
strings data.txt | grep "=="

Level 10:
The password for the next level is stored in the file data.txt, which contains base64 encoded data.
6zPeziLdR2RKNdNYFNb6nVCKzphlXHBM
Explanation:
This is how you can decode a base64 encoded string, in linux:
base64 -d data.txt
-d
: This option is used to decode a base64 encoded data.

Level 11
The password for the next level is stored in the file data.txt, where all lowercase (a-z) and uppercase (A-Z) letters have been rotated by 13 positions.
JVNBBFSmZwKKOP0XbFXOoW8chDz5yVRv
Explanation:
This is how you can decode a rot13 encoded string, in linux:
cat data.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m'
tr 'A-Za-z' 'N-ZA-Mn-za-m'
: This command, tr (short for "translate" or "transliterate"), is used to replace characters in a stream of text.
The first argument,
'A-Za-z'
, specifies the range of characters to be translated. Here, it covers all uppercase and lowercase letters in the English alphabet.The second argument,
'N-ZA-Mn-za-m'
, specifies the replacement characters for each character in the range defined in the first argument. This particular sequence is a Caesar cipher with a shift of 13 characters, commonly known as ROT13. It shifts each letter 13 positions forward in the alphabet, wrapping around if necessary. For example, 'A' becomes 'N', 'B' becomes 'O', 'C' becomes 'P', and so on.

Level 12:
The password for the next level is stored in the file data.txt, which is a hexdump of a file that has been repeatedly compressed. For this level it may be useful to create a directory under /tmp in which you can work using mkdir. For example: mkdir /tmp/myname123. Then copy the datafile using cp, and rename it using mv (read the man pages!)
wbWdlBxEir4CaE8LaPhauuOo6pwRmrDw
Explanation:
Creating a directory under tmp and copying data.txt file into it because we don’t have permission to write into home directory 🙃
mkdir /tmp/arcus && cp data.txt /tmp/arcus && cd /tmp/arcus
Now lets convert data.txt
back to its binary form:
xxd -r data.txt > data
xxd
: is typically used for creating a hex dump of a given file or for converting a hex dump back into its original binary form.
-r
: This option tells xxd
to reverse the operation of creating a hex dump and instead convert a hex dump back into binary form.
> data
: This part of the command is redirecting the output of the xxd command to a file named data. So, the binary data resulting from the conversion will be stored in a file named data.
Now run file
command on data
to see its actual file type and change its extension to its actual file type and then decompress it. We have to repeat this process over and over again:

mv data data.gz
Now, decompress it using this command:
gzip -d data.gz
Check the file type of data
:

mv data data.bz2
Now, decompress it using this command:
bzip2 -d data.bz2
Check the file type of data
:

mv data data.gz
Now, decompress it using this command:
gzip -d data.gz
Check the file type of data
:

mv data data.tar
Now, decompress it using this command:
tar -xf data.tar
We how have a file named data5.bin
:

mv data5.bin data5.tar
Now, decompress it using this command:
tar -xf data5.tar
We how have a file named data6.bin
:

mv data6.bin data6.bz2
Now, decompress it using this command:
bzip2 -d data6.bz2
Check the file type of data6
:

mv data6 data6.tar
Now, decompress it using this command:
tar -xf data6.tar
We how have a file named data6.bin
:

mv data8.bin data8.gz
Now, decompress it using this command:
gzip -d data8.gz
Finally, we got an ASCII file, cat that out:

Level 13:
The password for the next level is stored in /etc/bandit_pass/bandit14 and can only be read by user bandit14. For this level, you don’t get the next password, but you get a private SSH key that can be used to log into the next level. Note: localhost is a hostname that refers to the machine you are working on.
fGrHPx402xGC7U7rXKDaxiWFTOiF0ENq
Note: This is actual password for bandit level 14
Explanation:
To use the private key for SSH
authentication, simply use the ssh
command with the -i
flag to specify the path to your private key. i.e., ssh -i ~/.ssh/id_rsa username@remote_server
ssh -i sshkey.private bandit14@localhost -p 2220
Now after logging in:
cat /etc/bandit_pass/bandit14

Level 14:
The password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost.
jN2kgmIXJ6fShzhT2avhotn4Zcka6tnt
Explanation:
I used netcat for establishing network connection:
nc localhost 30000
Submit password fGrHPx402xGC7U7rXKDaxiWFTOiF0ENq
(Remember to stay logged into the server)

Level 15:
The password for the next level can be retrieved by submitting the password of the current level to port 30001 on localhost using SSL encryption.
JQttfApK4SeyHwDlI9SXGR50qclOAil1
Explanation:
As netcat doesn't have an option for SSL, I used netcat instead to establish a network connection for this task
ncat --ssl localhost 30001
Submit password of current level (jN2kgmIXJ6fShzhT2avhotn4Zcka6tnt
)

Level 16:
The credentials for the next level can be retrieved by submitting the password of the current level to a port on localhost in the range 31000 to 32000. First find out which of these ports have a server listening on them. Then find out which of those speak SSL and which don’t. There is only 1 server that will give the next credentials, the others will simply send back to you whatever you send to it.
ssh -i key bandit17@bandit.labs.overthewire.org -p 2220
Explanation
I used nmap
to scan for open ports. Command that I used:
nmap localhost -p 31000-32000

It will show a list of services. Submit the password of this level (JQttfApK4SeyHwDlI9SXGR50qclOAil1
) to all of them using:
ncat --ssl localhost <port-no>
One of them (port: 31790
) will give a RSA key.

Copy it to your local machine and set its permission to 400 (chmod 400 key
) and now connect to level 17 using this RSA key:
ssh -i key bandit17@bandit.labs.overthewire.org -p 2220

Level 17:
There are 2 files in the homedirectory: passwords.old and passwords.new. The password for the next level is in passwords.new and is the only line that has been changed between passwords.old and passwords.new.
NOTE: if you have solved this level and see ‘Byebye!’ when trying to log into bandit18, this is related to the next level, bandit19.
hga5tuuCLF6fFzUpnagiMN8ssu9LFrdg
Explanation:
Man page of grep
:

I used this command:
grep -f passwords.old --invert-match passwords.new

Level 18:
The password for the next level is stored in a file readme in the homedirectory. Unfortunately, someone has modified .bashrc to log you out when you log in with SSH.
awhqfNnAbc1naukrpqDYcF95h7HoMTrC
Explanation:
No problem, if bashrc is corrupted then we can call simple sh (pseudo-shell)

I used this command to get a shell:
ssh -t bandit18@bandit.labs.overthewire.org -p 2220 /bin/sh

Rest of challenge is simple.

Level 19:
To gain access to the next level, you should use the setuid binary in the homedirectory. Execute it without arguments to find out how to use it. The password for this level can be found in the usual place (/etc/bandit_pass), after you have used the setuid binary.
VxCazJaVykI6W36BkBU0mJTCM8rR95XT
Explanation:
Here, you can see an ELF
named bandit20-do
with bandit20
’s user SUID set on it:


To learn about what is SUID and how they can be exploited. Click here. Anyways, upon running it it tells us how to use it:

So let’s use use it to get bandit20
’s pasword:
./bandit20-do cat /etc/bandit_pass/bandit20

Level 20:
There is a setuid binary in the homedirectory that does the following: it makes a connection to localhost on the port you specify as a commandline argument. It then reads a line of text from the connection and compares it to the password in the previous level (bandit20). If the password is correct, it will transmit the password for the next level (bandit21).
NOTE: Try connecting to your own network daemon to see if it works as you think.
NvEJF7oVjkddltPSrdKEFOllh9V1IBcq
Explanation:
Set up a netcat listener on your local machine, on any port:

Now set password of current level VxCazJaVykI6W36BkBU0mJTCM8rR95XT
:

Level 21:
A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
WdDozAdTM2z9DiFEQ2mGlwngMfj4EZff
Explanation:
In /etc/cron.d
directory, you can find a cronjob for bandit22
which runs cronjob_bandit22.sh
script, very minute of every hour of every day. This script is just basically storing password for bandit22
into another file that is readable by other users.

Level 22:
A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
NOTE: Looking at shell scripts written by other people is a very useful skill. The script for this level is intentionally made easy to read. If you are having problems understanding what it does, try executing it to see the debug information it prints.
QYw0Y2aiA672PsMmh9puTQuhoz8SyR2G
Explanation:
In /etc/cron.d
directory, you can find a cronjob for bandit23
which runs cronjob_bandit23.sh
script, very minute of every hour of every day. This script is just basically storing password for bandit23
into another file named after string "bandit23" MD5 hash value and that file is present in /tmp
directory. How do I know? Because the script is being run as the user bandit23, who is the owner of this file and the cronjob, the result of the whoami command will be bandit23:

So, to find out the name of the file that has the password for bandit23
stored in it, I used this command:
echo "I am user bandit23" | md5sum | cut -d ' ' -f 1

Level 23:
A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
NOTE: This level requires you to create your own first shell-script. This is a very big step and you should be proud of yourself when you beat this level!
NOTE 2: Keep in mind that your shell script is removed once executed, so you may want to keep a copy around…
VAfGXJ1PBSsPSnvsjI8p759leLZ9GGar
Explanation:
In /etc/cron.d
directory, you can find a cronjob for bandit24
which runs cronjob_bandit24.sh
script, very minute of every hour of every day. This script is

Contents of /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
This script starts by figuring out the current user's name, then heads over to a specific directory named /var/spool/$myname/foo
. It goes through all the files in there, even the hidden ones like .
and ..
, and for each file, it looks at who owns it. If the owner is labeled as bandit23
, it runs the script but sets a limit of 60 seconds, then promptly removes the script file from the directory.
So, what I will do is first create a directory where everyone can read, write, and execute and I will also create a file in /var/spool/bandit24/foo
to copy the password of bandit24
from /etc/bandit_pass/bandit24
into a file that I can read. Since (according to the cronjob) scripts owned by me will be executed as bandit24
, I will have no problem executing my script.
Commands will be:

Contents of /tmp/ineedcontrol/main.sh
:

Save it, copy it to /var/spool/bandit24/foo
make it executable and wait for 1-2 mints:

And then cat /tmp/ineedcontrol/pass.txt
:

Level 24:
A daemon is listening on port 30002 and will give you the password for bandit25 if given the password for bandit24 and a secret numeric 4-digit pincode. There is no way to retrieve the pincode except by going through all of the 10000 combinations, called brute-forcing.
You do not need to create new connections each time.
p7TaowMYrmu23Ol8hiZh9UvD0O9hpx8d
Explanation:
I wrote a bash script to bruteforce all the possible 10,000 password combinations:
#!/bin/bash
for i in {0000..9999}
do
#echo "$i"
echo "VAfGXJ1PBSsPSnvsjI8p759leLZ9GGar $i"
done | nc localhost 30002
Make it executable and run it:

(Remember to do this in a writeable directory, you can create one in /tmp
.)
Level 25:
Logging in to bandit26 from bandit25 should be fairly easy… The shell for user bandit26 is not /bin/bash, but something else. Find out what it is, how it works and how to break out of it.
c7GvcKlw9mC7aUQaPx7nwFstuAIBw1o1
Explanation:
We have a private ssh key for bandit26
:

Let's try to login using this key:
ssh -i bandit26.sshkey bandit26@bandit.labs.overthewire.org -p 2220
It automatically logs me out when I try to connect to it:

In the challenge description, they said the shell of bandit26 is not a regular bash shell, it's different, so let’s have a look at it first:
cat /etc/passwd | grep "bandit26"

showtext
?? Never heard of that type of shell.
So, I searched a bit and yes there is no such such type of shell. Let’s have a look at its executable:

So, its basically just using more
command to read a file named text.txt
and then exit out with exit code of 0. So that’s why it automatically disconnects when tried to run.
What we need to do is trigger more
to enter its command mode (Refer to the man page of more
if you're unfamiliar with command mode), ensuring that the SSH request doesn't simply exit.
Let’s make our terminal as small as possible then ssh in:

So yeah we have successfully launched more
in its command mode.
That’s the way to break out. Very out of the box to get out of the box.
Now, If we look at the man-page of more
we can see that by pressing the “v” key (while in interactive mode) it will open the current line in an editor that is defined by the VISUAL and EDITOR environment variables. If both the variables are not set then Vim will be used. Lets see on pressing “v” which editor we get.
And we got vim:

Now, we can open another file using :e
command.
We want the password for bandit26
so the command will be:
:e /etc/bandit_pass/bandit26
Run it and we got the password:

but we haven’t got a shell still and when we will ssh into this level it will still kick us out.
Thank God we can call a shell from Vim; otherwise, it would be a hell of a difficulty level.
To get a shell, we will use :shell
command that vim offers. This command, uses the default shell of user (which in our case is /usr/bin/showtext
). What we need to do is to set the default shell of the user in vim to actual shell (/bin/bash
). The command to do that will be :set shell=/bin/bash
and then now simply call it:
:shell
And we are in:

Tricky challenge I Know. 🙃
Level 26:
Good job getting a shell! Now hurry and grab the password for bandit27!
YnQpBuifNMas1hcUFk70ZmqkhUU2EuaS
Explanation:
Easy, same as level 19.

I Used this command to get bandit27’s pasword:
./bandit27-do cat /etc/bandit_pass/bandit27

Level 27:
There is a git repository at ssh://bandit27-git@localhost/home/bandit27-git/repo
via the port 2220
. The password for the user bandit27-git
is the same as for the user bandit27
.
Clone the repository and find the password for the next level.
AVanL161y9rsbcJIsFHuw35rjaOM19nR
Explanation:
First move into a directory where we have write permissions. Now clone the provided repository via port 2220
by running this command:
git clone ssh://bandit27-git@localhost:2220/home/bandit27-git/repo
It will ask you for the password. Type the password of curent level:

We got a README
file in cloned repo. Cat that out:

Level 28:
There is a git repository at ssh://bandit28-git@localhost/home/bandit28-git/repo
via the port 2220
. The password for the user bandit28-git
is the same as for the user bandit28
.
Clone the repository and find the password for the next level.
tQKvmcwNYcFS6vmPHIUSI3ShmsrQZK8S
Explanation:
First move into a directory where we have write permissions. Now clone the provided repository via port 2220
by running this command:
git clone ssh://bandit28-git@localhost:2220/home/bandit28-git/repo
It will ask you for the password. Type the password of curent level:

We got a README
file in cloned repo. Cat that out:

UMMM.
Let’s have a look at logs:

Let’s check the commit add missing data
:

Now, cat that again:

Level 29:
There is a git repository at ssh://bandit29-git@localhost/home/bandit29-git/repo
via the port 2220
. The password for the user bandit29-git
is the same as for the user bandit29
.
Clone the repository and find the password for the next level.
xbhV3HpNGlTIdnjUrdAlPzc2L6y9EOnS
Explanation:
By now you should know how to clone a repository. In the cloned repo, we have README.md
file. Cat that out:

Hmmmm. Let’s have a look at logs:

Let’s check the “initial commit”:

Now, cat that again. Nope same output:

Let’s see what other branches we have:
git branch -r
We are currently on master
.

Let's switch to the dev
branch and see what they have for us there:
git checkout dev

Let’s cat this README.md
file:

Level 30:
There is a git repository at ssh://bandit30-git@localhost/home/bandit30-git/repo
via the port 2220
. The password for the user bandit30-git
is the same as for the user bandit30
.
Clone the repository and find the password for the next level.
OoffzGDlzhAlerFJ2cAiz1D41JW1Mhmt
Explanation:
In the cloned repo, we have README.md
file. Cat that out:

Hmmmm. Let’s have a look at logs:

We are already on the “initial commit”. Let’s see what other branches we have:
git branch -r
We are currently on master
and we have no other branches:

Let's check tags
. In git, tags are used to mark specific points in history such as release versions for easy reference.

We have one tag named secret
. Let's see what it is and here is the password:

Level 31:
There is a git repository at ssh://bandit31-git@localhost/home/bandit31-git/repo
via the port 2220
. The password for the user bandit31-git
is the same as for the user bandit31
.
Clone the repository and find the password for the next level.
rmCBvG56y58BXzv98yZGdO7ATVL5dW8y
Explanation:
Contents of README.md
file:

Let’s have a look at logs:

We are already on the “initial commit”. Let’s see what other branches we have:

We are currently on master
and we have no other branches plus the README
file says that the key.txt
is in master branch:

Look what I found:

.gitignore
files are used to specify intentionally untracked files and directories that Git should ignore, preventing them from being staged or committed. They help maintain clean repositories by filtering out files like build artifacts, temporary files etc. In our case, it includes *.txt
, which means it will ignore all text files. That's why we can't find the key.txt
file.

To retrieve password, remove the .gitignore
file and create a key.txt
file with content specified in the README.md
file:

Stage it, commit and push to the repo:

Here is the password:

Level 32:
After all this git
stuff its time for another escape. Good luck!
odHo63fHiFqcWWJG9rLiLDtPm45KzUKy
Explanation:
For this level, we got a weird shell "THE UPPERCASE SHELL". That just capitalize whatever command is passed to it:

So basically, what's going on is that this shell we are looking at is just a binary file. It takes whatever we type in, switches it to uppercase and then tells shell to run it as a command. Remember how we check what shell we have by running echo "$0"
:

This is because variable $0
stores the name of the file orscript that is currently being executed. If we run echo "$0"
in the terminal, we will see that we are getting the name of the currently used shell. But if we just run $0
, it spawns a new shell(zsh
):

Let's try out this theory in level 32:

We got a stable shell. Plus, here is the password:

EASY...
Level 33:
At this moment, level 34 does not exist yet.