Cameron Lonsdale

Automating security and making it more accessible
  • OverTheWire: Bandit Write-up

    This is a detailed write-up of my solutions to problems 0 - 25 for the Bandit wargame. This wargame is aimed at beginners, each level contains a password used to gain access to the next level. The game is linear, you start at Level 0 and move up towards Level 26. All passwords have been censored out of respect for the wargame and future players.

    Level 0

    Start by ssh’ing into Level 0 using the credentials provided.


    Level 0 → Level 1

    We are told that the file readme contains the password for Level 1. Using the ls command, we can see that the file exists.

    To display the file, we use cat.

    cat readme

    Level 1 → Level 2

    The password is stored in a file named ‘-‘.

    The character ‘-‘ however, is shell syntax for standard input (STDIN), so cat - waits for STDIN.

    To get around this you can specify the path of the file using ./

    cat ./- 

    Level 2 → Level 3

    The password is located in a file named ‘spaces in this filename’. cat can print out multiple files, and does so by separating files by spaces. Therefore, by doing cat spaces in this filename, cat will try to print out the file ‘spaces’ and then the file ‘in’ and then ‘this’ and then ‘filename’. Which, none of those files exist. Therefore, in order to pass the entire file name as one file, we can group the name in single quotes.

    cat 'spaces in this filename'

    Level 3 → Level 4

    The password is stored in a hidden file in the directory ‘inhere’. Navigate to this directory through cd inhere/. Once there, you need to use ls -a to display all files, included those which are hidden. The only hidden file is ‘.hidden’ so we cat that file.

    cat '.hidden'

    Level 4 → Level 5

    Inside the inhere directory, there are several files, each starting with a dash ‘-‘, thus when you try to cat them out, cat treats the filename as an argument instead of a file. The Level 1 trick comes in handy and we can use cat ./* to print out each file.

    We could write a small script to print out each on a  new line, but it’s easy to find the password in the mess.


    Alternatively, you can use the file ./* to print out which file is ASCII and then cat just that file, or use the strings filter to output only ASCII text from every file strings ./*

    Level 5 → Level 6

    The file is one out of many inside anyone of the possible sub-folders!

    find * lists all the files inside the sub-folder mess we have found. Luckily we are told some properties about the file, Most notably, it’s size. find allows us to perform a test on each file it finds, like test for file size. Thus,

    find * -size 1033c

    prints out the correct file. Cat that file and we get:


    Level 6 → Level 7

    Slightly more difficult. The file is stored somewhere on the server. Navigate to / directory and perform a find *. This time we need to use all properties otherwise we will get more results than what we need.

    find * -size 33c -group bandit6 -user bandit7

    However this output prints out lots of files which we do not have permission to read, obviously not going to be the password file. Piping this input into a grep command to filter out those message leaves us with the file that we were searching for.

    find * -size 33c -group bandit6 -user bandit7 2>&1 | egrep -v 'Permission denied$'
    cat var/lib/dpkg/info/bandit7.password

    Level 7 → Level 8

    Since the file is incredibly large, we need to use grep to find the word millionth.

    cat data.txt | grep 'millionth'

    Level 8 → Level 9

    The password only appears once in the whole file, so we can use uniq -u to get unique lines. However as uniq only works on adjacent lines, we need to sort the file first.

    cat data.txt | sort | uniq -u

    Level 9 → Level 10

    In order to get human readable characters we have to use the strings filter, and then grep for lines which start with ‘=’

    strings data.txt | grep '^='

    Level 10 → Level 11

    Base64 is used to translate all binary data into human readable ASCII. We need to decode it in order to get our password. A quick man base64 later and…

    base64 -d data.txt
    The password is IFuk****************************

    Level 11 → Level 12

    ROT 13 is easy to understand, a little annoying to decode using tr, but possible.

    cat data.txt | tr '[N-ZA-Mn-za-m]' '[A-Za-z]'
    The password is 5Te8****************************

    Level 12 → Level 13

    A hex dump which has been repeatedly compressed. Here we go…

    Using xxd we can reformat the hex dump into binary

    xxd -r data.txt > data

    Here’s where the file filter comes in handy. file data shows us that it was compressed with gzip. We need to first rename the file to data.gz and then use gunzip data.gz

    Still not plain text, file data shows us that it was now compressed with bzip2. bzcat unzips it to a gzip again, Now its a tar archive.

    tar -xvf data unpacks the archive and reveals data5.bin. again another tar archive. and we get data6.bin. bzip 2 again. Oh look now another tar archive. And another gzip.

    FINALLY we reach the plain text after what felt like 30 minutes.

    The password is 8Zjy****************************

    Level 13 → Level 14

    We are given the private key for bandit14, that’s good enough for me!

    Using sftp grab the private key and store it locally on my computer, the file needs to have its modifications changed in order to be recognized.

    chmod 600 sshkey.private

    Now you can use ssh.

    ssh -i sshkey.private

    Future Note: We don’t need to use sftp to get the key, we can use ssh as user bandit13 using the following:

    ssh -i sshkey.private bandit14@localhost

    Level 14 → Level 15

    For this task we need the password for Level 13, now that we are bandit14 we can read the file.

    cat /etc/bandit_pass/bandit14

    Then, we need to submit this password to the server listening on port 30000 of localhost. netcat is our friend here.

    nc localhost 30000

    Level 15 → Level 16

    We are required to submit the password to a server listening on port 30001 but this time communicate using SSL encryption. Communicating using SSL requires us to use openssl. A quick lookup of the syntax and we get

    openssl s_client -connect localhost:30001

    Except this prints out the HEARTBEATING message and not the password. The hint says to use -quiet to suppress that message, then the password will appear.

    openssl s_client -connect localhost:30001 -quiet

    Level 16 → Level 17

    A server is listening on a port somewhere between 30000 and 31000. We can use nmap to find out which ports are open and which aren’t.

    nmap localhost -p31000-32000
        31003/tcp open  unknown
        31046/tcp open  unknown
        31518/tcp open  unknown
        31691/tcp open  unknown
        31790/tcp open  unknown
        31960/tcp open  unknown

    Some of these use SSL and some don’t, quick trial and error solves this problem and we get our prize. A private key!

    -----END RSA PRIVATE KEY-----

    Level 17 → Level 18

    Two files, one line of difference. The diff command helps us here.

    diff passwords.old
    < kfBf****************************
    > BS8bqB1kqkinKJjuxL6k072Qq9NRwQpR

    And our password is,


    Level 18 → Level 19

    Level 18 is weird, I get logged off when I ssh in because apparently someone has modified .bashrc

    Easy way around, connect via sftp and get the file. No kicking :P


    An alternative method is to use the option for ssh which allows a command to be executed as soon as you are logged in. Something like this:

    ssh -t 'command; cat readme'

    will also give you the answer.

    Level 19 → Level 20

    We are given a setuid binary in order to give us permission to retrieve the password. The binary allows us to execute commands as another user (presumably bandit20) thus,

    ./bandit20-do cat /etc/bandit_pass/bandit20

    cats out the password for level 20.


    Level 20 → Level 21

    This is a bit tricky. our binary will connect to a port on localhost. The hint is that we need to run two consoles. The first is use nc to listen to a port and submit the current password for this level.

    We can do this through:

    echo 'GbKk****************************' | nc -l 1337

    in the other terminal we run ./suconnect 1337

    Because the passwords match, it sends the password back to the listener which prints out the new password for us.


    Level 21 → Level 22

    The configuration file tells us that a shell program is being run and then outputted to /dev/null

    If we navigate to and execute that script we see it echos the password into a temporary file, /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv

    lets cat out that file and we get our password.


    Level 22 → Level 23

    This task is similar to 21 except the shell script is more involved this time

    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

    What this is doing is printing the password for Level 22, which is what we already have. We want to print out the password for level 23. Since we can’t edit the file, or create a new script, we need to find out where it would place the password for bandit23

    echo I am user bandit23 | md5sum | cut -d ' ' -f 

    lucky for us, that file exists!

    cat /tmp/8ca319486bfbbc3663ea0fbe81326349
    the password is jc1u****************************

    Level 23 → Level 24

    Similar challenge, let’s find the script /usr/bin/ This time we get more complex

    cd /var/spool/$myname
    echo "Executing and deleting all scripts in /var/spool/$myname:"
    for i in * .*;
       if [ "$i" != "." -a "$i" != ".." ];   then
          echo "Handling $i"
          timeout -s 9 60 "./$i"
          rm -f "./$i"

    This doesn’t have anything to do with passwords… but, It says it is executing and then deleting scripts in /var/spool/$myname, so maybe we can write a script inside there to be run and get our password.

    The previous script for level 23 will be what we want, just need to make some modifications

    cp /usr/bin/ /var/spool/bandit24/

    Edit the file and modify whoami into bandit 24 and run it

    Our password has been copied into /tmp/ee4ee1703b083edac9f8183e4ae70293

    and we’ve got it.


    Level 24 → Level 25

    There’s a daemon waiting for the password and a 4 digit code in order to let us pass.

    Let’s create a shell script to brute force this pin

    for pin in {0..9}{0..9}{0..9}{0..9}; do
       echo UoMY**************************** $pin | nc localhost 30002 

    Letting this run for a while we find that 5669 is the pin and our password is:


    Level 25 → Level 26

    Once we login to 25 we see a private key for bandit26, save this for later.

    We need to find out which Shell bandit26 is using. From looking at /etc/passwd it seems that bandit26 uses /usr/bin/showtext as the default shell.

    All this shell does is more text.txt and then exits. We need to find a way around this..

    In order for more to activate we need to re-size the window to be quite small. only a few lines. More allows for interactivity, somehow we need to use this. More also allows for commands to be run with !, but this didn’t seem to work. We can also open vi on the file which is handy. From vi we can open another file, like say,


    and there we go, our password


    This next part is tricky, I had to look this up, but apparently we need to set the shell and then run it through vi. Whilst in vi do: 

    :set shell sh=/bin/bash

    Now we can look around! cat out README.txt and we have finished the wargame!

    cat README.txt
    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!