OverTheWire: Bandit

Level 0

The goal of this level is for you to log into the game using SSH. The host to which you need to connect is bandit.labs.overthewire.org. The username is bandit0 and the password is bandit0. Once logged in, go to the Level 1 page to find out how to beat Level 1.

About as easy as it gets, log in.

otw@iDi:~/bandit$ ssh bandit0@bandit.labs.overthewire.org
The authenticity of host 'bandit.labs.overthewire.org (178.79.134.250)' 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
Warning: Permanently added 'bandit.labs.overthewire.org,178.79.134.250' (ECDSA) to the list of known hosts.

This is the OverTheWire game server. More information on http://www.overthewire.org/wargames

[...]

bandit0@melinda:~$ id
uid=11000(bandit0) gid=11000(bandit0) groups=11000(bandit0)

Level 0 > Level 1

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 to log into that level and continue the game.

They speak the truth. cat it out.

bandit0@melinda:~$ ls
readme
bandit0@melinda:~$ cat readme 
boJ9jbbUNNfktd78OOpsqOltutMc3MY1

Level 1 > Level 2

The password for the next level is stored in a file called - located in the home directory

- has special meaning, you can’t just cat out the file or it will hang waiting for input.

bandit1@melinda:~$ cat -
^C

Throw in the current directory to overcome this.

bandit1@melinda:~$ cat ./-
CV1DtqXWVFXTvM2F0k09SHz0YwRINYA9

Level 2 > Level 3

The password for the next level is stored in a file called spaces in this filename located in the home directory

Use escape characters for the spaces.

bandit2@melinda:~$ ls
spaces in this filename
bandit2@melinda:~$ cat spaces\ in\ this\ filename 
UmHadQclWmgdLOKQ3YNgjWxGoRMb5luK

Level 3 > Level 4

The password for the next level is stored in a hidden file in the inhere directory.

ls -a shows hidden files (i.e those that begin with a dot). I’m in the habit of using ls -alh to do this, which adds the more detailed format and human-readable file sizes.

bandit3@melinda:~$ ls
inhere
bandit3@melinda:~$ cd inhere/
bandit3@melinda:~/inhere$ ls -alh
total 12K
drwxr-xr-x 2 root    root    4.0K Nov 14  2014 .
drwxr-xr-x 3 root    root    4.0K Nov 14  2014 ..
-rw-r----- 1 bandit4 bandit3   33 Nov 14  2014 .hidden
bandit3@melinda:~/inhere$ cat .hidden 
pIwrPrtPN36QITSp3EQaw936yaFoFgAB

Level 4 > Level 5

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.

The file command will do this.

bandit4@melinda:~$ ls
inhere
bandit4@melinda:~$ cd inhere/
bandit4@melinda:~/inhere$ ls
-file00  -file01  -file02  -file03  -file04  -file05  -file06  -file07  -file08  -file09
bandit4@melinda:~/inhere$ file *
file: Cannot open `ile00' (No such file or directory).
file: Cannot open `ile01' (No such file or directory).
file: Cannot open `ile02' (No such file or directory).
file: Cannot open `ile03' (No such file or directory).
file: Cannot open `ile04' (No such file or directory).
file: Cannot open `ile05' (No such file or directory).
file: Cannot open `ile06' (No such file or directory).
file: Cannot open `ile07' (No such file or directory).
file: Cannot open `ile08' (No such file or directory).
file: Cannot open `ile09' (No such file or directory).

The dash in front of each file name is messing us up again, use ./* instead.

bandit4@melinda:~/inhere$ file ./*
./-file00: data
./-file01: data
./-file02: data
./-file03: data
./-file04: data
./-file05: data
./-file06: data
./-file07: ASCII text
./-file08: data
./-file09: data
bandit4@melinda:~/inhere$ cat ./-file07
koReBOKuIDDepwhWk7jZC0RTdopnAYKh

Only -file07 is text, done.

Level 5 > Level 6

The password for the next level is stored in a file somewhere under the inhere directory and has all of the following properties: - human-readable - 1033 bytes in size - not executable

bandit5@melinda:~$ ls
inhere
bandit5@melinda:~$ cd inhere/
bandit5@melinda:~/inhere$ ls
maybehere00  maybehere03  maybehere06  maybehere09  maybehere12  maybehere15  maybehere18
maybehere01  maybehere04  maybehere07  maybehere10  maybehere13  maybehere16  maybehere19
maybehere02  maybehere05  maybehere08  maybehere11  maybehere14  maybehere17
bandit5@melinda:~/inhere$ ls maybehere00
-file1  -file2  -file3  spaces file1  spaces file2  spaces file3

There are many directories, each with many files. find will recurse into each directory and return files that match the properties we’re after.

As it turns out, we don’t need to be concerned with the ‘human-readable’ part because only one file matches the other criteria (with a ton of whitespace added at the end to make the password 1033 bytes).

bandit5@melinda:~$ find inhere/ -size 1033c ! -executable
inhere/maybehere07/.file2
bandit5@melinda:~$ cat inhere/maybehere07/.file2
DXjZPULLxYr17uwoI01bNLQbtFemEgo7
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        bandit5@melinda:~$

If that was a concern, we could have used -exec which will run a command over the results.

bandit5@melinda:~$ find inhere/ -size 1033c ! -executable -exec file {} \;
inhere/maybehere07/.file2: ASCII text, with very long lines

Level 6 > Level 7

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

find to the rescue again. Running find over the entire filesystem will inevitably throw a lot of permissions errors as there are plenty of places bandit6 is not allowed access.

bandit6@melinda:~$ find / -user bandit7 -group bandit6 -size 33c
find: `/root': Permission denied
find: `/proc/tty/driver': Permission denied
[...]

These are written to stderr and can be filtered out by dumping stderr to /dev/null.

bandit6@melinda:~$ find / -user bandit7 -group bandit6 -size 33c 2>/dev/null
/var/lib/dpkg/info/bandit7.password

Since we’re only expecting to find one file with this search, we could have been extra cute and cat‘d it out in the same command.

bandit6@melinda:~$ cat $(find / -user bandit7 -group bandit6 -size 33c 2>/dev/null)
HKBPTKQnIay4Fw76bEy8PVxKEDQRKTzs

Level 7 > Level 8

The password for the next level is stored in the file data.txt next to the word millionth

grep for the line containing ‘millionth.’

bandit7@melinda:~$ ls
data.txt
bandit7@melinda:~$ grep millionth data.txt 
millionth	cvX2JJa4CFALtqS87jk27qwqGhBM9plV

Level 8 > Level 9

The password for the next level is stored in the file data.txt and is the only line of text that occurs only once

bandit8@melinda:~$ ls
data.txt
bandit8@melinda:~$ cat data.txt | sort | uniq -u
UsvVyFSfZZWbi6wgC7dAFyFuR6jQQUhR

The trick here is to know what uniq is doing. It does not eliminate duplicates throughout the file, it eliminates duplicate consecutive lines. sort makes duplicate entries into neighbors and uniq -u takes them out.

UNIQ(1)                                           User Commands                                          UNIQ(1)

NAME
       uniq - report or omit repeated lines

SYNOPSIS
       uniq [OPTION]... [INPUT [OUTPUT]]

DESCRIPTION
       Filter adjacent matching lines from INPUT (or standard input), writing to OUTPUT (or standard output).

Level 9 > Level 10

The password for the next level is stored in the file data.txt in one of the few human-readable strings, beginning with several ‘=’ characters.

strings to the rescue.

bandit9@melinda:~$ ls
data.txt
bandit9@melinda:~$ strings data.txt | grep =
epr~F=K
7?YD=
?M=HqAH
/(Ne=
C=_"
I========== the6
z5Y=
`h(8=`
n\H=;
========== password
========== ism
N$=&
l/a=L)
f=C(
========== truKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLk
ie)=5e

The garbage lines that contain but do not start with ‘=’ can be filtered out with a regular expression matching only lines that begin with an equals sign.

bandit9@melinda:~$ strings data.txt | grep '^='  
========== password
========== ism
========== truKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLk

Level 10 > Level 11

The password for the next level is stored in the file data.txt, which contains base64 encoded data

Decode base64 with the… base64 command. Excellent work, tool-naming people!

bandit10@melinda:~$ ls
data.txt
bandit10@melinda:~$ base64 -d data.txt 
The password is IFukwKGsFW8MOq3IRFqrxE1hxTNEbUPR

Level 11 > Level 12

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

tr maps characters from one set into another. Give it the alphabet of lowercase and uppercase letters and map into the alphabets in the wrong order by half (i.e. rot13).

bandit11@melinda:~$ ls
data.txt
bandit11@melinda:~$ cat data.txt 
Gur cnffjbeq vf 5Gr8L4qetPEsPk8htqjhRK8XSP6x2RHh
bandit11@melinda:~$ cat data.txt | tr '[a-zA-Z]' '[n-za-mN-ZA-M]'
The password is 5Te8Y4drgCRfCx8ugdwuEX8KFC6k2EUu

This example is easier to understand but ridiculous to actually use.

bandit11@melinda:~$ cat data.txt | tr 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ' 'nNoOpPqQrRsStTuUvVwWxXyYzZaAbBcCdDeEfFgGhHiIjJkKlLmM'
The password is 5Te8Y4drgCRfCx8ugdwuEX8KFC6k2EUu

Level 12 > Level 13

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 manpages!)

Wow, those bastards… this one is pretty hilarious.

I’ll need a scratch space for this and since the home directory is wisely not writable, I’ll make an oddly-named directory in /tmp as advised. We might want to use this in the future with other banditXX users so I’ll open up the permissions.

bandit12@melinda:~$ mkdir -p /tmp/588e5fd1b
bandit12@melinda:~$ chmod 777 /tmp/588e5fd1b

The first file is a hexdump, as expected.

bandit12@melinda:/tmp/588e5fd1b$ cp ~/data.txt .
bandit12@melinda:/tmp/588e5fd1b$ file data.txt 
data.txt: ASCII text
bandit12@melinda:/tmp/588e5fd1b$ 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....

xxd -r will un-hexdump a dump. We’ll name the resulting binary data2.bin since we see that in the hexdump.

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

Well… here we go. Since data.txt gave us data2.bin we’ll stick with the pattern to avoid confusion (even though it ends up getting confusing anyway).

bandit12@melinda:/tmp/588e5fd1b$ gzip -d data2.bin -c > data3
bandit12@melinda:/tmp/588e5fd1b$ file data3
data3: bzip2 compressed data, block size = 900k
bandit12@melinda:/tmp/588e5fd1b$ bzip2 -d data3 -c > data4
bandit12@melinda:/tmp/588e5fd1b$ file data4
data4: gzip compressed data, was "data4.bin", from Unix, last modified: Fri Nov 14 10:32:20 2014, max compression
bandit12@melinda:/tmp/588e5fd1b$ gzip -d data4 -c > data5
bandit12@melinda:/tmp/588e5fd1b$ file data5
data5: POSIX tar archive (GNU)
bandit12@melinda:/tmp/588e5fd1b$ tar xf data5
bandit12@melinda:/tmp/588e5fd1b$ ls
data.txt  data2.bin  data3  data4  data5  data5.bin
bandit12@melinda:/tmp/588e5fd1b$ file data5.bin 
data5.bin: POSIX tar archive (GNU)
bandit12@melinda:/tmp/588e5fd1b$ tar xf data5.bin
bandit12@melinda:/tmp/588e5fd1b$ ls
data.txt  data2.bin  data3  data4  data5  data5.bin  data6.bin
bandit12@melinda:/tmp/588e5fd1b$ file data6.bin 
data6.bin: bzip2 compressed data, block size = 900k
bandit12@melinda:/tmp/588e5fd1b$ bzip2 -d data6.bin -c > data7
bandit12@melinda:/tmp/588e5fd1b$ file data7
data7: POSIX tar archive (GNU)
bandit12@melinda:/tmp/588e5fd1b$ tar xf data7
bandit12@melinda:/tmp/588e5fd1b$ ls
data.txt  data2.bin  data3  data4  data5  data5.bin  data6.bin  data7  data8.bin
bandit12@melinda:/tmp/588e5fd1b$ 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/588e5fd1b$ gzip -d data8.bin -c > data9 
bandit12@melinda:/tmp/588e5fd1b$ file data9
data9: ASCII text
bandit12@melinda:/tmp/588e5fd1b$ cat data9
The password is 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL

I’m rusty on bash scripts so this might not be stylistically very good, but it does the job. All of the above can be automated with a recursive script. The random file name generation is a cool trick I adapted from StackOverflow.

#~/bin/bash

R=$(cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 24)

if [ -f $1 ]
  then
    case $(file $1) in
    *gzip*)
      echo "gzip!"
      gzip -d $1 -c > $R
      ./$0 $R
      ;;
    *bzip2*)
      echo "bzip2!"
      bzip2 -d $1 -c > $R
      ./$0 $R
      ;;
    *POSIX\ tar*)
      echo "tar!"
      tar xOf $1 > $R
      ./$0 $R
      ;;
    *ASCII*)
      echo "ascii!"
      cat $1
      ;;
    esac
fi

And… go!

bandit12@melinda:/tmp/588e5fd1b$ ./go.sh data2.bin 
gzip!
bzip2!
gzip!
tar!
tar!
bzip2!
tar!
gzip!
ascii!
The password is 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL

Level 13 > Level 14

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

Indeed, there is an SSH private key waiting for us.

bandit13@melinda:~$ ls
sshkey.private
bandit13@melinda:~$ cat sshkey.private 
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAxkkOE83W2cOT7IWhFc9aPaaQmQDdgzuXCv+ppZHa++buSkN+
gg0tcr7Fw8NLGa5+Uzec2rEg0WmeevB13AIoYp0MZyETq46t+jk9puNwZwIt9XgB
ZufGtZEwWbFWw/vVLNwOXBe4UWStGRWzgPpEeSv5Tb1VjLZIBdGphTIK22Amz6Zb
ThMsiMnyJafEwJ/T8PQO3myS91vUHEuoOMAzoUID4kN0MEZ3+XahyK0HJVq68KsV
ObefXG1vvA3GAJ29kxJaqvRfgYnqZryWN7w3CHjNU4c/2Jkp+n8L0SnxaNA+WYA7
jiPyTF0is8uzMlYQ4l1Lzh/8/MpvhCQF8r22dwIDAQABAoIBAQC6dWBjhyEOzjeA
J3j/RWmap9M5zfJ/wb2bfidNpwbB8rsJ4sZIDZQ7XuIh4LfygoAQSS+bBw3RXvzE
pvJt3SmU8hIDuLsCjL1VnBY5pY7Bju8g8aR/3FyjyNAqx/TLfzlLYfOu7i9Jet67
xAh0tONG/u8FB5I3LAI2Vp6OviwvdWeC4nOxCthldpuPKNLA8rmMMVRTKQ+7T2VS
nXmwYckKUcUgzoVSpiNZaS0zUDypdpy2+tRH3MQa5kqN1YKjvF8RC47woOYCktsD
o3FFpGNFec9Taa3Msy+DfQQhHKZFKIL3bJDONtmrVvtYK40/yeU4aZ/HA2DQzwhe
ol1AfiEhAoGBAOnVjosBkm7sblK+n4IEwPxs8sOmhPnTDUy5WGrpSCrXOmsVIBUf
laL3ZGLx3xCIwtCnEucB9DvN2HZkupc/h6hTKUYLqXuyLD8njTrbRhLgbC9QrKrS
M1F2fSTxVqPtZDlDMwjNR04xHA/fKh8bXXyTMqOHNJTHHNhbh3McdURjAoGBANkU
1hqfnw7+aXncJ9bjysr1ZWbqOE5Nd8AFgfwaKuGTTVX2NsUQnCMWdOp+wFak40JH
PKWkJNdBG+ex0H9JNQsTK3X5PBMAS8AfX0GrKeuwKWA6erytVTqjOfLYcdp5+z9s
8DtVCxDuVsM+i4X8UqIGOlvGbtKEVokHPFXP1q/dAoGAcHg5YX7WEehCgCYTzpO+
xysX8ScM2qS6xuZ3MqUWAxUWkh7NGZvhe0sGy9iOdANzwKw7mUUFViaCMR/t54W1
GC83sOs3D7n5Mj8x3NdO8xFit7dT9a245TvaoYQ7KgmqpSg/ScKCw4c3eiLava+J
3btnJeSIU+8ZXq9XjPRpKwUCgYA7z6LiOQKxNeXH3qHXcnHok855maUj5fJNpPbY
iDkyZ8ySF8GlcFsky8Yw6fWCqfG3zDrohJ5l9JmEsBh7SadkwsZhvecQcS9t4vby
9/8X4jS0P8ibfcKS4nBP+dT81kkkg5Z5MohXBORA7VWx+ACohcDEkprsQ+w32xeD
qT1EvQKBgQDKm8ws2ByvSUVs9GjTilCajFqLJ0eVYzRPaY6f++Gv/UVfAPV4c+S0
kAWpXbv5tbkkzbS0eaLPTKgLzavXtQoTtKwrjpolHKIHUz6Wu+n4abfAIRFubOdN
/+aLoRQ0yBDRbdXMsZN/jvY44eM+xRLdRVyMmdPtP8belRi2E2aEzA==
-----END RSA PRIVATE KEY-----

These are usually short enough to copy/paste, but I’ll pull it down with scp (also WTF private keys in the clipboard) and rename it to something meaningful.

bandit13@melinda:~$ exit
logout
Connection to bandit.labs.overthewire.org closed.
otw@iDi:~/bandit$ scp bandit13@bandit.labs.overthewire.org:/home/bandit13/sshkey.private ./bandit14

[...]

bandit13@bandit.labs.overthewire.org's password: 
bandit14                                                                       100% 1679     1.6KB/s   00:00

SSH keys require restrictive permissions so we’ll set that and log in!

otw@iDi:~/bandit$ chmod 600 bandit14
otw@iDi:~/bandit$ ssh -i bandit14 bandit14@bandit.labs.overthewire.org

[...]

bandit14@melinda:~$ id
uid=11014(bandit14) gid=11014(bandit14) groups=11014(bandit14)

Level 14 > Level 15

The password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost.

We don’t know the password to the current level since we logged in with an SSH key, but the instructions on the opening page of the challenge told us where to find each (with permissions restricted to that user obviously, or this would be pretty easy).

bandit14@melinda:~$ cat /etc/bandit_pass/bandit14 
4wcYUJFw0k0XLShlDzztnTBHiqxU3b3e

The password can be sent to the local port using netcat. I prefer to use ncat over nc because it has many useful additional features bestowed by the Nmap people (the ability to use SSL/TLS being a major plus).

bandit14@melinda:~$ ncat -v 127.0.0.1 30000 < /etc/bandit_pass/bandit14
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:30000.
Correct!
BfMYroe26WYalil77FoDi9qh59eK5xNr

Ncat: 33 bytes sent, 43 bytes received in 0.03 seconds.

It’s nice to remember what features are in vanilla nc in case that’s all you have, though.

bandit14@melinda:~$ nc -v 127.0.0.1 30000 < /etc/bandit_pass/bandit14
Connection to 127.0.0.1 30000 port [tcp/*] succeeded!
Correct!
BfMYroe26WYalil77FoDi9qh59eK5xNr

Level 15 > Level 16

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.

ncat will handle this nicely, though for some reason our earlier technique does not work with the redirected input. Instead we’ll paste the password into the command line (a HORRIBLE act I was trying to avoid).

bandit15@melinda:~$ ncat --ssl -v 127.0.0.1 30001 < /etc/bandit_pass/bandit15
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: SSL connection to 127.0.0.1:30001.
Ncat: SHA-1 fingerprint: 6872 7805 D7EC 03BA 51E2 B301 2651 8989 0556 7D66
Ncat: 33 bytes sent, 0 bytes received in 0.04 seconds.
bandit15@melinda:~$ ncat --ssl -v 127.0.0.1 30001                            
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: SSL connection to 127.0.0.1:30001.
Ncat: SHA-1 fingerprint: 6872 7805 D7EC 03BA 51E2 B301 2651 8989 0556 7D66
BfMYroe26WYalil77FoDi9qh59eK5xNr
Correct!
cluFn7wTiGryunymYOu4RcffSxQluehd
^C

This can also be done with the openssl tools (strange things are amiss if you don’t use -quiet).

bandit15@melinda:~$ cat /etc/bandit_pass/bandit15 | openssl s_client -connect 127.0.0.1:30001 -quiet
depth=0 CN = li190-250.members.linode.com
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = li190-250.members.linode.com
verify return:1
Correct!
cluFn7wTiGryunymYOu4RcffSxQluehd

read:errno=0

Level 16 > Level 17

The password 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.

nmap can tell us what ports are open in the range (default SYN scan) and test for SSL\TLS (ssl-enum-ciphers script) in one swoop.

bandit16@melinda:~$ nmap --script=ssl-enum-ciphers -p 31000-32000 --reason localhost

Starting Nmap 6.40 ( http://nmap.org ) at 2015-08-15 21:41 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up, received syn-ack (0.00080s latency).
Not shown: 996 closed ports
Reason: 996 conn-refused
PORT      STATE SERVICE REASON
31046/tcp open  unknown syn-ack
31518/tcp open  unknown syn-ack
31691/tcp open  unknown syn-ack
31790/tcp open  unknown syn-ack
31960/tcp open  unknown syn-ack

Nmap done: 1 IP address (1 host up) scanned in 0.12 seconds

As it turns out, the script doesn’t like to execute on ports which are not commonly used with SSL\TLS. There is a fairly recent topic on this on their github here.

Version detection might have some insight.

bandit16@melinda:~$ nmap -sV -p 31000-32000 --reason localhost

Starting Nmap 6.40 ( http://nmap.org ) at 2015-08-28 04:59 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up, received syn-ack (0.00087s latency).
Not shown: 996 closed ports
Reason: 996 conn-refused
PORT      STATE SERVICE REASON  VERSION
31046/tcp open  echo    syn-ack
31518/tcp open  msdtc   syn-ack Microsoft Distributed Transaction Coordinator (error)
31691/tcp open  echo    syn-ack
31790/tcp open  msdtc   syn-ack Microsoft Distributed Transaction Coordinator (error)
31960/tcp open  echo    syn-ack
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 41.39 seconds

Out of curiosity let’s connect to echo and see if it’s what we’d expect.

bandit16@melinda:~$ ncat -v 127.0.0.1 31046   
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:31046.
balls
balls
^C

Indeed! That leaves only two ports that can be checked manually. I’ll guess the second one since I did this already and know the answer. ;)

bandit16@melinda:~$ ncat -v --ssl 127.0.0.1 31790                            
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: SSL connection to 127.0.0.1:31790.
Ncat: SHA-1 fingerprint: 6872 7805 D7EC 03BA 51E2 B301 2651 8989 0556 7D66
cluFn7wTiGryunymYOu4RcffSxQluehd
Correct!
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAvmOkuifmMg6HL2YPIOjon6iWfbp7c3jx34YkYWqUH57SUdyJ
imZzeyGC0gtZPGujUSxiJSWI/oTqexh+cAMTSMlOJf7+BrJObArnxd9Y7YT2bRPQ
Ja6Lzb558YW3FZl87ORiO+rW4LCDCNd2lUvLE/GL2GWyuKN0K5iCd5TbtJzEkQTu
DSt2mcNn4rhAL+JFr56o4T6z8WWAW18BR6yGrMq7Q/kALHYW3OekePQAzL0VUYbW
JGTi65CxbCnzc/w4+mqQyvmzpWtMAzJTzAzQxNbkR2MBGySxDLrjg0LWN6sK7wNX
x0YVztz/zbIkPjfkU1jHS+9EbVNj+D1XFOJuaQIDAQABAoIBABagpxpM1aoLWfvD
KHcj10nqcoBc4oE11aFYQwik7xfW+24pRNuDE6SFthOar69jp5RlLwD1NhPx3iBl
J9nOM8OJ0VToum43UOS8YxF8WwhXriYGnc1sskbwpXOUDc9uX4+UESzH22P29ovd
d8WErY0gPxun8pbJLmxkAtWNhpMvfe0050vk9TL5wqbu9AlbssgTcCXkMQnPw9nC
YNN6DDP2lbcBrvgT9YCNL6C+ZKufD52yOQ9qOkwFTEQpjtF4uNtJom+asvlpmS8A
vLY9r60wYSvmZhNqBUrj7lyCtXMIu1kkd4w7F77k+DjHoAXyxcUp1DGL51sOmama
+TOWWgECgYEA8JtPxP0GRJ+IQkX262jM3dEIkza8ky5moIwUqYdsx0NxHgRRhORT
8c8hAuRBb2G82so8vUHk/fur85OEfc9TncnCY2crpoqsghifKLxrLgtT+qDpfZnx
SatLdt8GfQ85yA7hnWWJ2MxF3NaeSDm75Lsm+tBbAiyc9P2jGRNtMSkCgYEAypHd
HCctNi/FwjulhttFx/rHYKhLidZDFYeiE/v45bN4yFm8x7R/b0iE7KaszX+Exdvt
SghaTdcG0Knyw1bpJVyusavPzpaJMjdJ6tcFhVAbAjm7enCIvGCSx+X3l5SiWg0A
R57hJglezIiVjv3aGwHwvlZvtszK6zV6oXFAu0ECgYAbjo46T4hyP5tJi93V5HDi
Ttiek7xRVxUl+iU7rWkGAXFpMLFteQEsRr7PJ/lemmEY5eTDAFMLy9FL2m9oQWCg
R8VdwSk8r9FGLS+9aKcV5PI/WEKlwgXinB3OhYimtiG2Cg5JCqIZFHxD6MjEGOiu
L8ktHMPvodBwNsSBULpG0QKBgBAplTfC1HOnWiMGOU3KPwYWt0O6CdTkmJOmL8Ni
blh9elyZ9FsGxsgtRBXRsqXuz7wtsQAgLHxbdLq/ZJQ7YfzOKU4ZxEnabvXnvWkU
YOdjHdSOoKvDQNWu6ucyLRAWFuISeXw9a/9p7ftpxm0TSgyvmfLF2MIAEwyzRqaM
77pBAoGAMmjmIJdjp+Ez8duyn3ieo36yrttF5NSsJLAbxFpdlc1gvtGCWW+9Cq0b
dxviW8+TFVEBl1O4f7HVm6EpTscdDxU+bCXWkfjuRb7Dy9GOtt9JPsX8MBTakzh3
vBgsyi/sN3RqRBcGU40fOoZyfAMT8s1m/uYv52O6IgeuZ/ujbjY=
-----END RSA PRIVATE KEY-----

Level 17 > Level 18

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

Save the key from the previous level on your local machine, fix its permissions for use, and log in.

otw@sake:~/bandit$ vim bandit17
[...]
otw@sake:~/bandit$ chmod 600 bandit17
otw@sake:~/bandit$ ssh -i bandit17 bandit17@bandit.labs.overthewire.org

There are two text files in the home directory as expected.

bandit17@melinda:~$ ls
passwords.new  passwords.old
bandit17@melinda:~$ file *
passwords.new: ASCII text
passwords.old: ASCII text

The diff command will report differences between them.

bandit17@melinda:~$ diff passwords.old passwords.new 
42c42
< BS8bqB1kqkinKJjuxL6k072Qq9NRwQpR
---
> kfBf3eYk5BPBRzwjqutbbfE887SVc5Yd

Level 18 > Level 19

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.

Try to log in.

otw@sake:~/bandit$ ssh bandit18@bandit.labs.overthewire.org
[...]
Byebye !
Connection to bandit.labs.overthewire.org closed.

The login is successful but the connection immediately closes as expected. A command supplied as an argument to the ssh command will execute on the remote system and output to our terminal. First confirm we can do this by checking that the file we’re looking for is present.

otw@sake:~/bandit$ ssh bandit18@bandit.labs.overthewire.org ls -lh
[...]
bandit18@bandit.labs.overthewire.org's password: 
total 4.0K
-rw-r----- 1 bandit19 bandit18 33 Nov 14  2014 readme

Experiment succesful - cat it out.

otw@sake:~/bandit$ ssh bandit18@bandit.labs.overthewire.org cat readme
[...]
bandit18@bandit.labs.overthewire.org's password: 
IueksS7Ubh8G3DCwVzrTd8rAVOwq3M5x

Level 19 > Level 20

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 to setuid binary.

First confirm the expected.

bandit19@melinda:~$ ls -lh
total 8.0K
-rwsr-x--- 1 bandit20 bandit19 7.2K Nov 14  2014 bandit20-do
bandit19@melinda:~$ file bandit20-do 
bandit20-do: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=08e74b8e092a91103efaab7916d75f08b887ab4d, not stripped

Obviously what you should do when given a mysterious executable is run it!

bandit19@melinda:~$ ./bandit20-do 
Run a command as another user.
  Example: ./bandit20-do id
bandit19@melinda:~$ ./bandit20-do id
uid=11019(bandit19) gid=11019(bandit19) euid=11020(bandit20) groups=11020(bandit20),11019(bandit19)

Using this command we should be able to cat out /etc/bandit_pass/bandit20 which belongs to bandit20.

bandit19@melinda:~$ ls -lh /etc/bandit_pass/bandit20
-r-------- 1 bandit20 bandit20 33 Nov 14  2014 /etc/bandit_pass/bandit20
bandit19@melinda:~$ ./bandit20-do cat !$ 
./bandit20-do cat /etc/bandit_pass/bandit20
GbKksEFF4yrVs6il55v6gwY5aVje5f0j

Fun trick, !$ is shorthand for the last argument of the previous command.

Level 20 > Level 21

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).

Recon.

bandit20@melinda:~$ ls -lh
total 8.0K
-rwsr-x--- 1 bandit21 bandit20 7.9K Nov 14  2014 suconnect
bandit20@melinda:~$ file suconnect 
suconnect: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=abcc6c52af9bbea6e735f10665c1095b89c25bd5, not stripped
bandit20@melinda:~$ ./suconnect 
Usage: ./suconnect <portnumber>
This program will connect to the given port on localhost using TCP. If it receives the correct password from the other side, the next password is transmitted back.

In one terminal we’ll set a netcat listener ready to pump out the current password. I’m in the habit of using -nlvp for this to not resolve DNS, listen, be verbose, and finally specify the port.

bandit20@melinda:~$ ncat -nlvp 6969 < /etc/bandit_pass/bandit20
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Listening on :::6969
Ncat: Listening on 0.0.0.0:6969

In the second terminal we’ll connect using the instructions provided by the usage message.

bandit20@melinda:~$ ./suconnect 6969
Read: GbKksEFF4yrVs6il55v6gwY5aVje5f0j
Password matches, sending next password

Looking back at the listener we see that the connection from suconnect sent over a password.

bandit20@melinda:~$ ncat -nlvp 6969 < /etc/bandit_pass/bandit20
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Listening on :::6969
Ncat: Listening on 0.0.0.0:6969
Ncat: Connection from 127.0.0.1.
Ncat: Connection from 127.0.0.1:40249.
gE269g2h3mw3pwgrj0Ha9Uoqen1c9DGr

Level 21 > 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.

Check out /etc/cron.d.

bandit21@melinda:~$ cd /etc/cron.d
bandit21@melinda:/etc/cron.d$ ls
behemoth4_cleanup  cronjob_bandit24       melinda-stats          natas25_cleanup~  semtex0-32   sysstat
cron-apt           cronjob_bandit24_root  natas-session-toucher  natas26_cleanup   semtex0-64   vortex0
cronjob_bandit22   leviathan5_cleanup     natas-stats            natas27_cleanup   semtex0-ppc  vortex20
cronjob_bandit23   manpage3_resetpw_job   natas25_cleanup        php5              semtex5

Presumably we’re interested in cronjob_bandit22.

bandit21@melinda:/etc/cron.d$ cat cronjob_bandit22
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
bandit21@melinda:/etc/cron.d$ cat /usr/bin/cronjob_bandit22.sh 
#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv

Each time this script executes, a world-readable file is created in /tmp by bandit22 which contains bandit22’s password. How handy!

For fun confirm and then cat it out.

bandit21@melinda:/etc/cron.d$ ls -lh /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
-rw-r--r-- 1 bandit22 bandit22 33 Aug 28 05:42 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
bandit21@melinda:/etc/cron.d$ cat !$
cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
Yk7owGAcWjwMVRwrTesJEwB7WVOiILLI

Level 22 > 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.

As usual, first thing is to check it out.

bandit22@melinda:~$ cat /etc/cron.d/cronjob_bandit23
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh  &> /dev/null
bandit22@melinda:~$ 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

$myname will contain bandit23 because that is who invokes the script. $mytarget is calculated at runtime. We’ll repeat this step making sure to fill in the correct value for $myname.

bandit22@melinda:~$ echo I am user bandit23 | md5sum | cut -d ' ' -f 1 
8ca319486bfbbc3663ea0fbe81326349

It’s important to understand how the cut command works. In this case it cuts (d’oh) the string by spaces and returns the first substring. We can see this by removing it from the command.

bandit22@melinda:~$ echo I am user bandit23 | md5sum 
8ca319486bfbbc3663ea0fbe81326349  -

This reveals the secret location in /tmp of bandit23’s password. Under normal circumstances we could just look in /tmp but this machine is configured with specific restrictions.

bandit22@melinda:~$ ls -lh /tmp/8ca319486bfbbc3663ea0fbe81326349
-rw-rw-r-- 1 bandit23 bandit23 33 Aug 28 05:49 /tmp/8ca319486bfbbc3663ea0fbe81326349
bandit22@melinda:~$ cat !$
cat /tmp/8ca319486bfbbc3663ea0fbe81326349
jc1udXuA1tiHqjIsL8yaapX5XIAI6i0n

Level 23 > Level 24

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.

Derp.

bandit23@melinda:~$ cat /etc/cron.d/cronjob_bandit24
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
bandit23@melinda:~$ cat /usr/bin/cronjob_bandit24.sh
#!/bin/bash

myname=$(whoami)

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

The script does exactly as the echo‘d description claims - running and then deleting all scripts in /var/spool/bandit24. Bonus points for their not allowing infinite loops and the like to run indefinitely using the timeout command.

Checking that this directory exists, we see it is writable by us (bandit23) and bandit24.

bandit23@melinda:~$ ls -alh /var/spool/bandit24/
total 54K
drwxrwxrwx 2 bandit24 bandit23  49K Aug 28 05:51 .
drwxr-xr-x 6 root     root     4.0K May  3 12:32 ..

Since these are executed by bandit24, the most obvious tactic is to drop a script that will output bandit24’s password. In order to retrieve it, we’ll output to a file in our previously created, world-readable /tmp directory.

The script:

cat /etc/bandit_pass/bandit24 > /tmp/588e5fd1b/bandit24

Create the script, set its permissions as executable, and wait for it to disappear. A good way to do this is using the watch command but that’s hard to depict here.

bandit23@melinda:/var/spool/bandit24$ vim mmc.sh
[...]
bandit23@melinda:/var/spool/bandit24$ chmod +x mmc.sh 
bandit23@melinda:/var/spool/bandit24$ ls
mmc.sh
bandit23@melinda:/var/spool/bandit24$ ls
mmc.sh
bandit23@melinda:/var/spool/bandit24$ ls
bandit23@melinda:/var/spool/bandit24$

Check for output and poof!

bandit23@melinda:/var/spool/bandit24$ cat /tmp/588e5fd1b/bandit24
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ

Level 24 > Level 25

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 combinaties, called brute-forcing.

For this we’ll use the following script.

#!/bin/bash

for i in {0000..9999}
do
    echo "$i *************"
    echo "UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ $i" | ncat 127.0.0.1 30002
done

I did not know if bash would accept the quadruple 0’s, but a quick test on the side shows it works.

The first echo is to mark our place in the bruteforce, in case that isn’t clear from any output returned by the service. Run the script and use the tee command to output to stdout while saving a copy to disk.

bandit24@melinda:/tmp/588e5fd1b$ ./bandit25.sh | tee bandit25.out
0000 *************
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.
Wrong! Please enter the correct current password. Try again.
Exiting.
0001 *************
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.
Wrong! Please enter the correct current password. Try again.
Exiting.
0002 *************
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.
Wrong! Please enter the correct current password. Try again.
Exiting.
0003 ***********
[...]

I chose this technique because we’re bruteforcing over a relatively small space and having all the results for later analysis is powerful. Typically this is not feasible and we’d have to check for the desired output at each iteration in some way.

Previous levels use “Correct” so we’ll search for that. grep -C will display lines adjacent to the match which we’ll need since the password isn’t on that line.

bandit24@melinda:/tmp/588e5fd1b$ grep -C 2 Correct bandit25.out 
5669 *************
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 uNG9O58gUE7snukf3bvZ0rxhtnjzSGzG

Level 25 > Level 26

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.

The shell assigned to a user is stored in /etc/passwd.

bandit25@melinda:~$ cat /etc/passwd | grep bandit26
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
bandit25@melinda:~$ cat /usr/bin/showtext 
#!/bin/sh

more ~/text.txt
exit 0

Apparently when bandit26 logs in, instead of getting a a shell a file in bandit26’s home directory is more‘d out. The ‘fairly easy’ bit in the level description is a reference to the fact that we are given an ssh key. Let’s try the login.

bandit25@melinda:~$ ls
bandit26.sshkey
bandit25@melinda:~$ ssh -i bandit26.sshkey bandit26@localhost
[...]
 | |                   | (_) | |__ \ / /  
 | |__   __ _ _ __   __| |_| |_   ) / /_  
 | '_ \ / _` | '_ \ / _` | | __| / / '_ \ 
 | |_) | (_| | | | | (_| | | |_ / /| (_) |
 |_.__/ \__,_|_| |_|\__,_|_|\__|____\___/ 
Connection to localhost closed.

The fact that the script uses more is critial here. Let’s examine the behavior of more.

When a file is shorter than the terminal, it is displayed and more exits.

short.txt

When a file is longer than the terminal, the portion which fits is displayed and more waits for user input to move through the file.

long.txt

During this time if we press the v key, more will open the file in a text editor. From the manpage:

     v           Start up an editor at current line.  The editor is taken from
                 the environment variable VISUAL if defined, or EDITOR if VIS‐
                 UAL is not defined, or defaults to "vi" if neither VISUAL nor
                 EDITOR is defined.

Once in the editor, we can open another file - namely the one which contains bandit26’s password! The trick here is to make our window so small that the login banner exceeds the height of the terminal and more waits for input.

waiting

Open the password file from within vim.

open file

Boom!

password

5czgV9L3Xx8JPOyRbXh6lQbmIOWvPT6Z

Very creative challenge, really enjoyed getting that one.

Level 26 > Level 27

At this moment, level 27 does not exist yet.

Boo.