Some time ago I decided that it is time to brush up my computer security skills. I went to, which is a site with hacking challenges and did some of those. I did their simplest game, called Bandit. Some of the puzzles were too basic for me, some of them included researching obscure functions in manpages. So I did not finish the challenges, since my motivation left. I had some writeups of the levels and thought that I should not publish them, since they are not complete. They lay around in my drafts-folder for a year and since I do not think I will ever finish them, I will now publish them. Have fun reading.

Level 0

So I went to this site and it said that I should ssh to with password bandit0 and username bandit0

h@ophit:~$ ssh
The authenticity of host ' (' can't be established.
ECDSA key fingerprint is 05:3a:1c:25:35:0a:ed:2f:cd:87:1c:f6:fe:69:e4:f6.
+--[ECDSA  256]---+
|    ..oo=        |
|     o.= o       |
|     .=   .      |
|      ..o.       |
|       *S+       |
|      . * o .    |
|       . o o     |
|          . +.   |
|           +o.E  |
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ',' (ECDSA) to the list of known hosts.

This is the OverTheWire game server. More information on

Please note that wargame usernames are no longer level<X>, but wargamename<X>
e.g. vortex4, semtex2, ...

Note: at this moment, blacksun is not available.'s password: 
      ,----..            ,----,          .---. 
     /   /   \         ,/   .`|         /. ./|
    /   .     :      ,`   .'  :     .--'.  ' ;
   .   /   ;.  \   ;    ;     /    /__./ \ : |
  .   ;   /  ` ; .'___,/    ,' .--'.  '   \' .
  ;   |  ; \ ; | |    :     | /___/ \ |    ' ' 
  |   :  | ; | ' ;    |.';  ; ;   \  \;      : 
  .   |  ' ' ' : `----'  |  |  \   ;  `      |
  '   ;  \; /  |     '   :  ;   .   \    .\  ; 
   \   \  ',  /      |   |  '    \   \   ' \ |
    ;   :    /       '   :  |     :   '  |--"  
     \   \ .'        ;   |.'       \   \ ;     
  www. `---` ver     '---' he       '---"     
Welcome to the OverTheWire games machine!

If you find any problems, please report them to Steven on

--[ Playing the games ]--

  This machine holds several wargames. 
  If you are playing "somegame", then:

    * USERNAMES are somegame0, somegame1, ...
    * Most LEVELS are stored in /somegame/.
    * PASSWORDS for each level are stored in /etc/somegame_pass/.

  Write-access to homedirectories is disabled. It is advised to create a
  working directory with a hard-to-guess name in /tmp/.  You can use the
  command "mktemp -d" in order to generate a random and hard to guess
  directory in /tmp/.  Read-access to both /tmp/ and /proc/ is disabled
  so that users can not snoop on eachother.

  Please play nice:
    * don't leave orphan processes running
    * don't leave exploit-files laying around
    * don't annoy other players
    * don't post passwords or spoilers
    * again, DONT POST SPOILERS! 
      This includes writeups of your solution on your blog or website!

--[ Tips ]--

  This machine has a 64bit processor and many security-features enabled
  by default, although ASLR has been switched off.  The following
  compiler flags might be interesting:

    -m32                    compile for 32bit
    -fno-stack-protector    disable ProPolice
    -Wl,-z,norelro          disable relro 

  In addition, the execstack tool can be used to flag the stack as
  executable on ELF binaries.

  Finally, network-access is limited for most levels by a local

--[ Tools ]--

 For your convenience we have installed a few usefull tools which you can find
 in the following locations:

    * peda ( in /usr/local/peda/
    * gdbinit ( in /usr/local/gdbinit/
    * pwntools ( in /usr/src/pwntools/
    * radare2 ( should be in $PATH

--[ More information ]--

  For more information regarding individual wargames, visit

  For questions or comments, contact us through IRC on


Don’t post spoilers? Well, how can an individual interested in security learn about all this stuff if there are no instructions anywhere? But in order to honor the creators of the challenge, I am going to redact the passwords.

bandit0@melinda:~$ l
bandit0@melinda:~$ cat readme
<secret password>

Look what we have here: A nice password for the next level.

Level 1

With the password we can access the next level.

hjgk@ophit:~$ ssh's password: 
bandit1@melinda:~$ l

What is this? A file with a funny name? Indeed.

bandit1@melinda:~$ ls -la
total 24
-rw-r-----   1 bandit2 bandit1   33 Nov 14  2014 -
drwxr-xr-x   2 root    root    4096 Nov 14  2014 .
drwxr-xr-x 167 root    root    4096 Jul  9 16:27 ..
-rw-r--r--   1 root    root     220 Apr  9  2014 .bash_logout
-rw-r--r--   1 root    root    3637 Apr  9  2014 .bashrc
-rw-r--r--   1 root    root     675 Apr  9  2014 .profile
bandit1@melinda:~$ cat ./-   
<secret password>

And up to the next level.

Level 2

Again logging in with ssh.

bandit2@melinda:~$ l
spaces in this filename
bandit2@melinda:~$ cat spaces\ in\ this\ filename
<secret password>

At this time I wondered if it is a mistake that bash-completion is enabled. Well… Let’s check the next one.

Level 3

bandit3@melinda:~$ l
bandit3@melinda:~$ less inhere/.hidden 
bandit3@melinda:~$ cat inhere/.hidden

Piece of cake.

Level 4

bandit4@melinda:~$ l                 
bandit4@melinda:~$ cd inhere/
bandit4@melinda:~/inhere$ l
-file00  -file01  -file02  -file03  -file04  -file05  -file06  -file07  -file08  -file09
bandit4@melinda:~/inhere$ cat *
cat: invalid option -- 'f'
Try 'cat --help' for more information.
bandit4@melinda:~/inhere$ cat -file0
cat: invalid option -- 'f'
Try 'cat --help' for more information.
bandit4@melinda:~/inhere$ cat ./*
<many funny signs><something that looks like a password>
bandit4@melinda:~/inhere$ grep <piece of the password> ./*
./-file07:<secret password>

That was more fun, but I am starting to wonder if I am the right target group. Come on, I am not a shell-noob. Where are the code injections?

Level 5

This level is more fun. We have many files scattered around many folders. Too much to look at all of them. We assume that the flag resides in a file with only one line and contains only ascii-characters, like in the previous levels. So we list all files and their corresponding line numbers

bandit5@melinda:~$ find . * -exec wc -l {} \;

Some of them contain only one line, so it seems we are on the right track. We are only interested in the one-liners, so we search with grep if the output contains “1 “. The space is important to exclude files with 13 or 17 lines. Then, we strip the “1 “ away, such that only the filenames remain.

bandit5@melinda:~$ find . * -exec wc -l {} \;|grep "^1 "|sed 's/1 //'

Now I want to know which of those are ASCII. Unfortunately some of the files contain spaces. So later mangling is difficult. We have to think of another way. We could first look which are ASCII and then pick the small ones.

Let us start by addressing the many errors that occur when find yields a file and wc -l is invoke on a file. The find command has the switch -t which allows to determine the type of the match. We want files, so we add ‘-t f’ to find.
Also we want the delimiters to be different. File has the flag –print0 to use zero-characters as delimiters. These are not ASCII-zeros but binary zeros, like those used in delimiting strings in C. xargs has a corresponding option -0 to also use zero-characters as delimiters.

bandit5@melinda:~$ find . -type f -print0 |xargs -0 file

Now we can pick the ASCII-files. The command ‘file’ sometimes says that a file is “ASCII text, with very long lines”. We probably do not want to have them.

bandit5@melinda:~$ find . -type f -print0 |xargs -0 file|grep ASCII|grep -v "very long"

Seven files remain which we can check by hand. But, surprise, all the strings are horribly long and do not look like passwords. That’s when I came to the hints on the website of the bandit-wargame. There it says that the file is human-readable, has 1033 bytes and is not executable. Damn. We threw the password away when throwing everything away which had long lines.

So. Back again. We are now searching for a file with exactly 1033 bytes.

bandit5@melinda:~$ find . -type f -print0 |xargs -0 ls -la|grep 1033

Bam! Got the password. Next level!

Level 6

When connecting to as bandit6 we see that the home directory is empty. The hint on the website says that the password is stored somewhere on the server, is owned by user bandit7, owned by group bandit6, and is 33 bytes in size.

bandit6@melinda:~$ cd /
bandit6@melinda:/$ find . -type f -print0|xargs -0 ls -la|grep bandit6|grep bandit7|grep 33

Probably not how they thought I should solve this, but effective. After pressing enter I see a file which contains the password. Nice challenge.

Level 7

So, on to level 7.

In the home-directory we have a file called data.txt with too many lines to read them all. Each lines contains a pair of a name and something that looks like a password. The hint is that the password is stored next to the word “millionth”.

bandit7@melinda:~$ grep millionth data.txt 
millionth <secret password>


Level 8

Level 8 is really similar to level 7. We have a file called data.txt and the password is the only line that occurs only once.

bandit8@melinda:~$ uniq -c data.txt |sort -n

uniq -c counts the occurences of the lines. sort -n sorts the lines as if they were numbers, so not lexicographically. And well, it does not work. uniq only deletes adjacent duplicate lines. So, first we have to sort the lines, then delete the ajacent duplicate lines an prepend them with their number of occurences. Lastly, we sort again, but reverse, so that the smallest number of occurences is at the bottom.

sort data.txt |uniq -c|sort -nr


Level 9

Level 9 is again a data.txt. We are searching the only human-readable string which starts with a number of equal signs. The command strings dumps the human readable strings and then we have to grep for the equal sign.

bandit9@melinda:~$ strings data.txt |grep ==
I========== the6
========== password
========== ism
========== <secret password>

Hmpf! That was easy.

Level 10

I log in and again i have this data.txt. This time it is base64-encoded. So i have to decode it. There is a tool for this surprisingly called base64. There is the flag -d for decoding. So all i have to do is the following.

bandit10@melinda:~$ base64 -d data.txt 
The password is <secret password>

Done! Up to the next one.

Level 11

Oh no. Not again a data.txt. I increase the volume of my earphones slightly. What is it this time? Looks like a string which is somehow encrypted. The hint at the overthewire-site says that all characters are rotated by 13 positions. Well, sounds an awful lot like rot13.

Fortunately there is a tool called tr which can substitute characters by other characters.

bandit11@melinda:~$ cat data.txt | tr '[A-Za-z]' '[N-ZA-Mn-za-m]'
The password is <secret string>

Does this constitute a useless use of cat?

bandit11@melinda:~$ tr '[A-Za-z]' '[N-ZA-Mn-za-m]' data.txt 
tr: extra operand 'data.txt'
Try 'tr --help' for more information.

…..Probably not.

Level 12

Again we have a data.txt. This time it looks a lot like hex.

bandit12@melinda:~$ head data.txt 
0000000: 1f8b 0808 34da 6554 0203 6461 7461 322e  ....4.eT..data2.
0000010: 6269 6e00 013f 02c0 fd42 5a68 3931 4159  bin..?...BZh91AY
0000020: 2653 5982 c194 8a00 0019 ffff dbfb adfb  &SY.............
0000030: bbab b7d7 ffea ffcd fff7 bfbf 1feb eff9  ................
0000040: faab 9fbf fef2 fefb bebf ffff b001 3b18  ..............;.
0000050: 6400 001e a000 1a00 6468 0d01 a064 d000  d.......dh...d..
0000060: 0d00 0034 00c9 a320 001a 0000 0d06 80d1  ...4... ........
0000070: a340 01b4 98d2 3d13 ca20 6803 40d1 a340  .@....=.. h.@..@
0000080: 1a00 0340 0d0d 0000 000d 0c80 6803 4d01  ...@........h.M.
0000090: a3d4 d034 07a8 0683 4d0c 4034 069e 91ea  ...4....M.@4....

A direct xxd -r which casts it back to binary does not work this time. So i read the hint at the website. It is a file that has been compressed repeatedly. Well. Nothing easier than that. First we try to create a separate directory somewhere in /tmp

bandit12@melinda:~$ mkdir /tmp/a
mkdir: cannot create directory '/tmp/a': File exists
bandit12@melinda:~$ mkdir /tmp/mydir
mkdir: cannot create directory '/tmp/mydir': File exists
bandit12@melinda:~$ mkdir /tmp/s    
mkdir: cannot create directory '/tmp/s': File exists

Damn. I have to think of a more difficult name.

bandit12@melinda:~$ mkdir /tmp/decompressdir
bandit12@melinda:~$ cp data.txt /tmp/decompressdir
bandit12@melinda:~$ cd /tmp/decompressdir

Let us hope i can remember this one.

bandit12@melinda:/tmp/decompressdir$ xxd -r data.txt > a
bandit12@melinda:/tmp/decompressdir$ file a
a: gzip compressed data, was "data2.bin", from Unix, last modified: Fri Nov 14 10:32:20 2014, max compression

So the first layer is a gzip-file containing some data.bin.

bandit12@melinda:/tmp/decompressdir$ gunzip a 
gzip: a: unknown suffix -- ignored

Stupid gunzip. It looks at the file-ending and is not convinced that the file a is indeed gzipped. We can change that.

bandit12@melinda:/tmp/decompressdir$ cp a a.gz
bandit12@melinda:/tmp/decompressdir$ gunzip a.gz 
gzip: a already exists; do you wish to overwrite (y or n)? y
bandit12@melinda:/tmp/decompressdir$ l
a  data.txt

Seemed to work.

bandit12@melinda:/tmp/decompressdir$ file a 
a: bzip2 compressed data, block size = 900k

Yep. Worked. The file is now a different one.

bandit12@melinda:/tmp/decompressdir$ bunzip2 a
bunzip2: Can't guess original name for a -- using a.out

Yeah. Whatever. As long as you tell me how you name it.

bandit12@melinda:/tmp/decompressdir$ file a.out 
a.out: gzip compressed data, was "data4.bin", from Unix, last modified: Fri Nov 14 10:32:20 2014, max compression
bandit12@melinda:/tmp/decompressdir$ cp a.out a.gz
bandit12@melinda:/tmp/decompressdir$ gunzip a.gz 
bandit12@melinda:/tmp/decompressdir$ l
a  a.out  data.txt

Peeling away another layer.

bandit12@melinda:/tmp/decompressdir$ file a
a: POSIX tar archive (GNU)
bandit12@melinda:/tmp/decompressdir$ tar xvf a

Nice challenge. I guess now we have gone through all compression tools except cpio.

bandit12@melinda:/tmp/decompressdir$ file data5.bin 
data5.bin: POSIX tar archive (GNU)
bandit12@melinda:/tmp/decompressdir$ tar xvf data5.bin
bandit12@melinda:/tmp/decompressdir$ file data6.bin 
data6.bin: bzip2 compressed data, block size = 900k

At this point perhaps I thought that I should perhaps write a tool to automate the decompression process. But I persisted.

bandit12@melinda:/tmp/decompressdir$ bunzip2 data6.bin
bunzip2: Can't guess original name for data6.bin -- using
bandit12@melinda:/tmp/decompressdir$ file data6.bin.out 
data6.bin.out: POSIX tar archive (GNU)
bandit12@melinda:/tmp/decompressdir$ tar xvf data6.bin.out
bandit12@melinda:/tmp/decompressdir$ file data8.bin 
data8.bin: gzip compressed data, was "data9.bin", from Unix, last modified: Fri Nov 14 10:32:20 2014, max compression
bandit12@melinda:/tmp/decompressdir$ cp data8.bin data8.bin.gz
bandit12@melinda:/tmp/decompressdir$ gunzip data8.bin.gz 
gzip: data8.bin already exists; do you wish to overwrite (y or n)? y
bandit12@melinda:/tmp/decompressdir$ file data8.bin 
data8.bin: ASCII text

Sigh! Finally! And yes. The file contained the password for the next level.

Level 13

I log into the box and this time there is no data.txt. What a relief. Instead there is a sshkey.private. Well….. Level solved, right?

SSH-keys are keys for asymmetric encryption which i use daily. To simplify. This is like a password. The hint on the website says that the password is stored in /etc/bandit_pass/bandit14 and can only be read by user bandit14. So. Let’s log in as bandit14 with the private key and get the password.

bandit13@melinda:~$ ssh -i sshkey.private bandit14@localhost
Could not create directory '/home/bandit13/.ssh'.
The authenticity of host 'localhost (' can't be established.
ECDSA key fingerprint is 05:3a:1c:25:35:0a:ed:2f:cd:87:1c:f6:fe:69:e4:f6.
Are you sure you want to continue connecting (yes/no)? yes

Obviously it does not know the fingerprint of the machine I am connecting to. Normally it should copy it to .ssh/known_hosts so that it knows the other machine the next time. In this case, the permissions are set such that the copying does not take place and the next player will also have his fun.

bandit14@melinda:~$ cat /etc/bandit_pass/bandit14
<secret key>


Level 14

This time the hint is that I should submit the current passwort on port 30000 on localhost. So I log in on the machine. The next step is establishing a connection to itself, i. e., localhost. You can think of port 30000 as an identifier so that the computer does not mix up different connections to the same machine.

bandit14@melinda:~$ telnet localhost 30000
Connected to localhost.
Escape character is '^]'.
<current password>
<new secret password>

Connection closed by foreign host.


Level 15

The hint says that we first have to find out the correct port on localhost which is somewhere between 31000 and 32000. At first I tried netstat -tulpen, but there were many listening ports and the info which process was listening was missing, so I tried nmap.

bandit15@melinda:~$ nmap -A -p 31000-32000

Starting Nmap 6.40 ( ) at 2016-01-17 14:23 UTC
Nmap scan report for localhost (
Host is up (0.00080s latency).
Not shown: 995 closed ports
31000/tcp open  ssh     (protocol 2.0)
| ssh-hostkey: 1024 23:51:06:ec:31:58:1e:64:10:51:58:9c:92:6f:08:55
| 2048 85:e5:7b:e2:87:74:18:c5:f4:d0:50:9f:13:56:9c:a7 (RSA)
|_256 05:3a:1c:25:35:0a:ed:2f:cd:87:1c:f6:fe:69:e4:f6 (ECDSA)
31046/tcp open  echo
31518/tcp open  msdtc   Microsoft Distributed Transaction Coordinator
31691/tcp open  echo
31790/tcp open  msdtc   Microsoft Distributed Transaction Coordinator
31960/tcp open  echo
1 service unrecognized despite returning data. If you know the
service/version, please submit the following fingerprint at :
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 41.47 seconds

So…. nothing new since the netstat. Well, what happens if we just connect to some of the ports and talk to them? Most of them just respond with the same stuff we have given to then. But 30001 speaks SSL. So we can try to connect with a different client. I feel we are on to something.

bandit15@melinda:/tmp/graar$  openssl s_client -connect localhost:30001       
depth=0 CN =
verify error:num=18:self signed certificate
verify return:1
depth=0 CN =
verify return:1
Certificate chain
 0 s:/
Server certificate
No client certificate CA names sent
SSL handshake has read 1714 bytes and written 637 bytes
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
    Protocol  : SSLv3
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: F5DE5629DD4FEEAF08302227F2CD97FAF0C435B9603C056C1E33E978E9BBD912
    Master-Key: 2B6BBA6209CE1655D8F0BC3A123C7FE35217AE91E6C48CE7701169179BAF18ED4EF895BAE179F5A96FD0D20AC184F8F0
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1453043227
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)

That is the SSL-handshake which we use to connect.

<current password>
read R BLOCK

Why doesn’t it give us the password? In fact, i have no idea. What works is if we give it the argument -quiet which is neither documented in s_client nor in openssl. Damn! I hate openssl. I have only found this solution through googling.

bandit15@melinda:/tmp/graar$ cat /etc/bandit_pass/bandit15 | openssl s_client -connect localhost:30001 -quiet
depth=0 CN =
verify error:num=18:self signed certificate
verify return:1
depth=0 CN =
verify return:1
<next password>


Got it! Thanks.


Well, hacking is fun. Overthewire is a great site. Cya next time.


26 November 2016