OverTheWire - Bandit Writeup

Posted by Nikolai Magnussen on January 11, 2017

Bandit Wargame

OverTheWire offer a multitude of wargames. Wargames are a series of security related challenges that vary in difficulty.

This blog post will cover the game that is recommended to play first, namely Bandit. I would highly recommend all that feel inclined to try this game. It is a very gentle introduction that try to expect no previous knowledge, meaning that people familiar with *NIX and using the terminal will not be challenged to the same degree in the early levels. But bear with me, because there sure will be some challenges at the later levels! Regardless of your current level of expertise, I would recommend you complete it, but it is by no means necessary.

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.

We can log into the ssh server by:

❯ ssh bandit0@bandit.labs.overthewire.org

and entering the password 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.

When logged in, we can find and read the file where the password is stored.

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

This mean that the password to the next level is boJ9jbbUNNfktd78OOpsqOltutMc3MY1, and we can connect to the next level by:

❯ ssh bandit1@bandit.labs.overthewire.org

and entering the password boJ9jbbUNNfktd78OOpsqOltutMc3MY1.

Level 1 ➡ Level 2

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

We can find and read the file where the next password is stored, but different from the previous level; we have to escape the file name by providing the path to it so the shell does not interpret it as the start of a switch, or to read from stdin.

bandit1@melinda:~$ ls
-
bandit1@melinda:~$ cat ./-
CV1DtqXWVFXTvM2F0k09SHz0YwRINYA9

Now, we can easily see that the password to the next level is CV1DtqXWVFXTvM2F0k09SHz0YwRINYA9 and we connect to it the same way as with the previous, but as the user bandit2.

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

Again, we want to find and read the file where the password is stored. In the same spirit as the previous level, we have to escape the spaces in the file name so the spaces are considered a part of the file name, and not a new file. Which can be achieved by prepending spaces with a \.

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

The password for level 3 is UmHadQclWmgdLOKQ3YNgjWxGoRMb5luK.

Level 3 ➡ Level 4

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

First, we find and enter the directory:

bandit3@melinda:~$ ls
inhere
bandit3@melinda:~$ cd inhere

And then we try to find the file, but ls does not display hidden files, but adding a few switches display them. Then we can read the file and the password:

bandit3@melinda:~/inhere$ ls
bandit3@melinda:~/inhere$ ls -lah
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

The password for level 4 is 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.

This mean that all files but the one with the password only contain data, and we can find out which by using the file utility:

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

Now, we can easily see that -file07 is the correct one, so let’s read it:

bandit4@melinda:~$ cat inhere/-file07
koReBOKuIDDepwhWk7jZC0RTdopnAYKh

Yielding the password for the next level: koReBOKuIDDepwhWk7jZC0RTdopnAYKh.

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

Most likely, there are few files that are 1033 bytes large, which is something find can search for:

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

And now we only have to read it:

bandit5@melinda:~$ cat inhere/maybehere07/.file2
DXjZPULLxYr17uwoI01bNLQbtFemEgo7

Giving the password for the next level: DXjZPULLxYr17uwoI01bNLQbtFemEgo7.

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

This can be done in the same manner as the previous level, because find can search for more than just size, and because we will get many errors because of permissions, we redirect the errors to /dev/null:

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

Again, what is left is for us to read it:

bandit6@melinda:~$ cat /var/lib/dpkg/info/bandit7.password
HKBPTKQnIay4Fw76bEy8PVxKEDQRKTzs

And the password for level 7 is HKBPTKQnIay4Fw76bEy8PVxKEDQRKTzs.

Level 7 ➡ Level 8

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

This mean that we should be searching for the word millionth, which is something grep handles effortlessly:

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

Meaning cvX2JJa4CFALtqS87jk27qwqGhBM9plV is the password for level 8.

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

First, we want to sort the lines, such that we can determine which lines are uniq and only print the unique ones:

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

Yielding the password UsvVyFSfZZWbi6wgC7dAFyFuR6jQQUhR for level 9.

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.

The password have to be human-readable, meaning that we can extract the strings, and only have the ones that start with =:

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

By assuming the same pattern as the previous passwords, the password for level 10 is truKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLk.

Level 10 ➡ Level 11

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

Because the file is base64 encoded, we simply have to decode it:

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

And the password for level 11 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

This can be decrypted by simply translating the letters from a-z to n-z and a-m both for upper and lower case, which can be accomplished using tr:

bandit11@melinda:~$ tr 'a-zA-Z' 'n-za-mN-ZA-M' < data.txt
The password is 5Te8Y4drgCRfCx8ugdwuEX8KFC6k2EUu

And we can easily see that the password for level 12 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!)

First, we need to convert the file from hexdump format back to the original file, which can be done by xxd. Then, we need to unpack the file by repeatedly unpacking and decompressing, and which method can be found by using the file utility. But here is the complete extraction sequence:

bandit12@melinda:~$ xxd -r data.txt | gunzip | bunzip2 | gunzip | tar xO | tar xO | bunzip2 | tar xO | gunzip
The password is 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL

Meaning that the password for level 13 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

Now, we simply need to connect to ourself as the bandit14 user authenticating using the private SSH key:

bandit13@melinda:~$ ls
sshkey.private
bandit13@melinda:~$ ssh -i sshkey.private bandit14@localhost
Could not create directory '/home/bandit13/.ssh'.
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is 05:3a:1c:25:35:0a:ed:2f:cd:87:1c:f6:fe:69:e4:f6.
--- LINES OMITTED ---
bandit14@melinda:~$ 

Now that we are logged in as bandit14, we need to read the password:

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

Yielding the password 4wcYUJFw0k0XLShlDzztnTBHiqxU3b3e for level 14.

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.

To submit the password to localhost:30000, we use netcat, or nc for short:

bandit14@melinda:~$ nc localhost 30000
4wcYUJFw0k0XLShlDzztnTBHiqxU3b3e
Correct!
BfMYroe26WYalil77FoDi9qh59eK5xNr

And the password for the next level is 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.

Because this is using encryption, netcat is not the correct tool for the job, but rather openssl and it’s s_client but make sure to ignore end of file:

bandit15@melinda:~$ openssl s_client -connect localhost:30001 -ign_eof
CONNECTED(00000003)
depth=0 CN = li190-250.members.linode.com
verify error:num=18:self signed certificate
--- LINES OMITTED ---
    Start Time: 1484143032
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---
BfMYroe26WYalil77FoDi9qh59eK5xNr
Correct!
cluFn7wTiGryunymYOu4RcffSxQluehd

read:errno=0

And we can easily determine that the next password is cluFn7wTiGryunymYOu4RcffSxQluehd.

Level 16 ➡ Level 17

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.

First, we have to scan the specified ports:

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

Starting Nmap 6.40 ( http://nmap.org ) at 2017-01-11 14:08 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00051s latency).
Not shown: 996 closed ports
PORT      STATE SERVICE
31046/tcp open  unknown
31518/tcp open  unknown
31691/tcp open  unknown
31790/tcp open  unknown
31960/tcp open  unknown

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

Then, we have to find out which port will provide the next credentials:

bandit16@melinda:~$ nc localhost 31046
test
test

bandit16@melinda:~$ nc localhost 31518
test
ERROR
140737354049184:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:s3_pkt.c:351:

bandit16@melinda:~$ nc localhost 31691
test
test

bandit16@melinda:~$ nc localhost 31790
test
ERROR
140737354049184:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:s3_pkt.c:351:

bandit16@melinda:~$ nc localhost 31960
test
test

Of all the servers, two are only accessible over SSL and the rest are echo servers, returning whatever they receive. So let’s try to access the two SSL-speaking servers:

bandit16@melinda:~$ openssl s_client -connect localhost:31518
CONNECTED(00000003)
depth=0 CN = li190-250.members.linode.com
verify error:num=18:self signed certificate
--- LINES OMITTED ---
    Start Time: 1484144012
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---
test
test

bandit16@melinda:~$ openssl s_client -connect localhost:31790
CONNECTED(00000003)
depth=0 CN = li190-250.members.linode.com
verify error:num=18:self signed certificate
--- LINES OMITTED ---
    Start Time: 1484144175
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---
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-----

It seems the server running at port 31790 is the correct one, but contrary to other levels, we are rewarded a private key, which we probably can use to SSH into the server as bandit17. So first, we have to copy and save the private key. Then we must change permissions such that only we, the owner can read it before using it to connect:

bandit16@melinda:~$ cat > /tmp/key_kake 
-----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-----
bandit16@melinda:~$ chmod 400 /tmp/key_kake
bandit16@melinda:~$ ssh -i /tmp/key_kake bandit17@localhost
Could not create directory '/home/bandit16/.ssh'.
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is 05:3a:1c:25:35:0a:ed:2f:cd:87:1c:f6:fe:69:e4:f6.
--- LINES OMITTED ---
bandit17@melinda:~$

Being authenticated as bandit17, we can read the password file:

bandit17@melinda:~$ cat /etc/bandit_pass/bandit17
xLYVMN9WE5zQ5vHacb0sZEVqbrp7nBTn

And the password for level 17 is xLYVMN9WE5zQ5vHacb0sZEVqbrp7nBTn.

Level 17 ➡ Level 18

There are 2 files in the home directory: 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

To find differences between two files, diff can be used, and it will output what was changed as well as what is was changed to:

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

Which mean that BS8bqB1kqkinKJjuxL6k072Qq9NRwQpR was the original in passwords.old, and kfBf3eYk5BPBRzwjqutbbfE887SVc5Yd is the new password from passwords.new. And thus, kfBf3eYk5BPBRzwjqutbbfE887SVc5Yd is the password for level 18.

Level 18 ➡ Level 19

The password for the next level is stored in a file readme in the home directory. Unfortunately, someone has modified .bashrc to log you out when you log in with SSH.

If we try to connect regularly, we automatically get logged off, meaning that we can’t get an interactive session, as we would normally get. But as part of the SSH logon, we can also supply a command that will be executed regardless:

❯ ssh bandit18@bandit.labs.overthewire.org cat readme

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

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.

bandit18@bandit.labs.overthewire.org's password: 
IueksS7Ubh8G3DCwVzrTd8rAVOwq3M5x

So upon writing the password, we get the password for level 19 back; namely IueksS7Ubh8G3DCwVzrTd8rAVOwq3M5x.

Level 19 ➡ Level 20

To gain access to the next level, you should use the setuid binary in the home directory. 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.

Let’s take a look at the setuid binary in our home directory:

bandit19@melinda:~$ ls -lah
total 28K
drwxr-xr-x   2 root     root     4.0K Nov 14  2014 .
drwxr-xr-x 172 root     root     4.0K Jul 10  2016 ..
-rw-r--r--   1 root     root      220 Apr  9  2014 .bash_logout
-rw-r--r--   1 root     root     3.6K Apr  9  2014 .bashrc
-rw-r--r--   1 root     root      675 Apr  9  2014 .profile
-rwsr-x---   1 bandit20 bandit19 7.2K Nov 14  2014 bandit20-do

The s in the permissions for bandit20-do mean that it will be executed as the owner, namely bandit20:

bandit19@melinda:~$ ./bandit20-do 
Run a command as another user.
  Example: ./bandit20-do id
bandit19@melinda:~$ ./bandit20-do whoami
bandit20

Which mean that we can use this to read the password from the regular location:

bandit19@melinda:~$ ./bandit20-do cat /etc/bandit_pass/bandit20 
GbKksEFF4yrVs6il55v6gwY5aVje5f0j

And the password for level 20 is GbKksEFF4yrVs6il55v6gwY5aVje5f0j.

Level 20 ➡ Level 21

There is a setuid binary in the home directory 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).

Here, we have a binary that will send the next password, given the current one. There is only one catch, we have to connect to it. This mean that must have two sessions; one that listens for the connection, and one that runs the binary.

First, we listen on a particular port using netcat:

bandit20@melinda:~$ nc -l localhost 13337

And in the second session, we run the binary and point it to the same port:

bandit20@melinda:~$ ./suconnect 13337

Then, from the nc connection, we can send the current password:

bandit20@melinda:~$ nc -l localhost 13337
GbKksEFF4yrVs6il55v6gwY5aVje5f0j
gE269g2h3mw3pwgrj0Ha9Uoqen1c9DGr

Meaning that gE269g2h3mw3pwgrj0Ha9Uoqen1c9DGr is the password for level 21.

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.

First, we look at the files in /etc/cron.d/:

bandit21@melinda:~$ ls -la /etc/cron.d
total 104
drwxr-xr-x   2 root root 4096 Oct  5 09:14 .
drwxr-xr-x 108 root root 4096 Jan 11 10:17 ..
-rw-r--r--   1 root root  102 Feb  9  2013 .placeholder
-r--r-----   1 root root   46 Nov 14  2014 behemoth4_cleanup
-rw-r--r--   1 root root  355 May 25  2013 cron-apt
-rw-r--r--   1 root root   61 Nov 14  2014 cronjob_bandit22
-rw-r--r--   1 root root   62 Nov 14  2014 cronjob_bandit23
-rw-r--r--   1 root root   61 May  3  2015 cronjob_bandit24
-rw-r--r--   1 root root   62 May  3  2015 cronjob_bandit24_root
-r--r-----   1 root root   47 Nov 14  2014 leviathan5_cleanup
-rw-------   1 root root  233 Nov 14  2014 manpage3_resetpw_job
-rw-r--r--   1 root root   51 Nov 14  2014 melinda-stats
-rw-r--r--   1 root root   54 Jun 25  2016 natas-session-toucher
-rw-r--r--   1 root root   49 Jun 25  2016 natas-stats
-r--r-----   1 root root   44 Jun 25  2016 natas25_cleanup
-r--r-----   1 root root   47 Aug  3  2015 natas25_cleanup~
-r--r-----   1 root root   47 Jun 25  2016 natas26_cleanup
-r--r-----   1 root root   43 Jun 25  2016 natas27_cleanup
-rw-r--r--   1 root root  510 Oct 29  2014 php5
-rw-r--r--   1 root root   63 Jul  8  2015 semtex0-32
-rw-r--r--   1 root root   63 Jul  8  2015 semtex0-64
-rw-r--r--   1 root root   64 Jul  8  2015 semtex0-ppc
-rw-r--r--   1 root root   35 Nov 14  2014 semtex5
-rw-r--r--   1 root root  396 Nov 10  2013 sysstat
-rw-r--r--   1 root root   29 Nov 14  2014 vortex0
-rw-r--r--   1 root root   30 Nov 14  2014 vortex20

Most likely, cronjob_bandit22 is the correct one and it is readable, so let’s see what it does:

bandit21@melinda:~$ cat /etc/cron.d/cronjob_bandit22
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null

Let’s follow the bread crumbs further:

bandit21@melinda:~$ cat /usr/bin/cronjob_bandit22.sh  
#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv

Meaning that every time it is run, the file /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv is made readable by all users and the password of bandit22 is written to the file. Which in turn can be read by us:

bandit21@melinda:~$  cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
Yk7owGAcWjwMVRwrTesJEwB7WVOiILLI

Meaning that the password for level 22 is 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.

First, let’s try to find the script being executed:

bandit22@melinda:~$ ls -la /etc/cron.d/
total 104
drwxr-xr-x   2 root root 4096 Oct  5 09:14 .
drwxr-xr-x 108 root root 4096 Jan 11 10:17 ..
-rw-r--r--   1 root root  102 Feb  9  2013 .placeholder
-r--r-----   1 root root   46 Nov 14  2014 behemoth4_cleanup
-rw-r--r--   1 root root  355 May 25  2013 cron-apt
-rw-r--r--   1 root root   61 Nov 14  2014 cronjob_bandit22
-rw-r--r--   1 root root   62 Nov 14  2014 cronjob_bandit23
-rw-r--r--   1 root root   61 May  3  2015 cronjob_bandit24
-rw-r--r--   1 root root   62 May  3  2015 cronjob_bandit24_root
-r--r-----   1 root root   47 Nov 14  2014 leviathan5_cleanup
-rw-------   1 root root  233 Nov 14  2014 manpage3_resetpw_job
-rw-r--r--   1 root root   51 Nov 14  2014 melinda-stats
-rw-r--r--   1 root root   54 Jun 25  2016 natas-session-toucher
-rw-r--r--   1 root root   49 Jun 25  2016 natas-stats
-r--r-----   1 root root   44 Jun 25  2016 natas25_cleanup
-r--r-----   1 root root   47 Aug  3  2015 natas25_cleanup~
-r--r-----   1 root root   47 Jun 25  2016 natas26_cleanup
-r--r-----   1 root root   43 Jun 25  2016 natas27_cleanup
-rw-r--r--   1 root root  510 Oct 29  2014 php5
-rw-r--r--   1 root root   63 Jul  8  2015 semtex0-32
-rw-r--r--   1 root root   63 Jul  8  2015 semtex0-64
-rw-r--r--   1 root root   64 Jul  8  2015 semtex0-ppc
-rw-r--r--   1 root root   35 Nov 14  2014 semtex5
-rw-r--r--   1 root root  396 Nov 10  2013 sysstat
-rw-r--r--   1 root root   29 Nov 14  2014 vortex0
-rw-r--r--   1 root root   30 Nov 14  2014 vortex20
bandit22@melinda:~$ cat /etc/cron.d/cronjob_bandit23 
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh  &> /dev/null

And the contents of that script:

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

The target file is generated based on the hashing of a string containing the user’s name. This mean that the file name can be recreated by manually replacing $myname with bandit23:

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

And we can read the contents of that file:

bandit22@melinda:~$ cat /tmp/8ca319486bfbbc3663ea0fbe81326349
jc1udXuA1tiHqjIsL8yaapX5XIAI6i0n

Which mean that jc1udXuA1tiHqjIsL8yaapX5XIAI6i0n is the password for the next level.

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.

Again, let’s see what we have and what the job does:

bandit23@melinda:~$ ls -la /etc/cron.d
total 104
drwxr-xr-x   2 root root 4096 Oct  5 09:14 .
drwxr-xr-x 108 root root 4096 Jan 11 10:17 ..
-rw-r--r--   1 root root  102 Feb  9  2013 .placeholder
-r--r-----   1 root root   46 Nov 14  2014 behemoth4_cleanup
-rw-r--r--   1 root root  355 May 25  2013 cron-apt
-rw-r--r--   1 root root   61 Nov 14  2014 cronjob_bandit22
-rw-r--r--   1 root root   62 Nov 14  2014 cronjob_bandit23
-rw-r--r--   1 root root   61 May  3  2015 cronjob_bandit24
-rw-r--r--   1 root root   62 May  3  2015 cronjob_bandit24_root
-r--r-----   1 root root   47 Nov 14  2014 leviathan5_cleanup
-rw-------   1 root root  233 Nov 14  2014 manpage3_resetpw_job
-rw-r--r--   1 root root   51 Nov 14  2014 melinda-stats
-rw-r--r--   1 root root   54 Jun 25  2016 natas-session-toucher
-rw-r--r--   1 root root   49 Jun 25  2016 natas-stats
-r--r-----   1 root root   44 Jun 25  2016 natas25_cleanup
-r--r-----   1 root root   47 Aug  3  2015 natas25_cleanup~
-r--r-----   1 root root   47 Jun 25  2016 natas26_cleanup
-r--r-----   1 root root   43 Jun 25  2016 natas27_cleanup
-rw-r--r--   1 root root  510 Oct 29  2014 php5
-rw-r--r--   1 root root   63 Jul  8  2015 semtex0-32
-rw-r--r--   1 root root   63 Jul  8  2015 semtex0-64
-rw-r--r--   1 root root   64 Jul  8  2015 semtex0-ppc
-rw-r--r--   1 root root   35 Nov 14  2014 semtex5
-rw-r--r--   1 root root  396 Nov 10  2013 sysstat
-rw-r--r--   1 root root   29 Nov 14  2014 vortex0
-rw-r--r--   1 root root   30 Nov 14  2014 vortex20
bandit23@melinda:~$ cat /etc/cron.d/cronjob_bandit24
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null

That script does the following:

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

Which mean that all script in the /var/spool/bandit24 will be executed. Now, we can create our own script that will get us the password, make it executable and copy it where the cronjob can see and execute it:

bandit23@melinda:~$ cat > /tmp/password.sh
#!/bin/bash

cat /etc/bandit_pass/bandit24 > /tmp/bandit24_password
bandit23@melinda:~$ chmod +x /tmp/password.sh
bandit23@melinda:~$ cp /tmp/password.sh /var/spool/bandit24/

Finally, let’s checkout the resulting file:

bandit23@melinda:~$ cat /tmp/bandit24_password
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ

Now we have access to bandit24 using the password 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 combinations, called brute-forcing.

Let’s first create a file containing all possible combinations by writing a python script:

bandit24@melinda:~$ python3
Python 3.4.3 (default, Sep 14 2016, 12:36:27) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> with open("/tmp/pins", "w") as f:
...     for pin in range(10000):
...         f.write("UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ {:04}\n".format(pin))

If we now inspect the file, we can see that the pattern is as we want it to be:

bandit24@melinda:~$ cat /tmp/pins
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 0000
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 0001
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 0002
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 0003
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 0004
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 0005
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 0006
--- LINES OMITTED ---
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 9994
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 9995
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 9996
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 9997
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 9998
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ 9999

This file can the be used as input to nc such that each line of that file is sent through netcat. But that will generate a very large amount of data to skim through, so we can use grep to search for Correct:

bandit24@melinda:~$ nc localhost 30002 < /tmp/pins | grep -C 5 Correct
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Correct!
The password of user bandit25 is uNG9O58gUE7snukf3bvZ0rxhtnjzSGzG

Exiting.

Now, we have the password for level 25; 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 hint here is that once we log into bandit26, we are not encountered by bash, but something else. Login shells are located in the /etc/passwd file, so the login shell for bandit26 is:

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

showtext is not a commonly known binary, so that file must be checked out:

bandit25@melinda:~$ file /usr/bin/showtext
/usr/bin/showtext: POSIX shell script, ASCII text executable
bandit25@melinda:~$ cat /usr/bin/showtext
#!/bin/sh

more ~/text.txt
exit 0

This mean that once bandit26 is logged into, more is run. But it is actually possible to run commands from both more and less if the text does not fit on one screen full:

 _                     _ _ _   ___   __  
| |                   | (_) | |__ \ / /  
| |__   __ _ _ __   __| |_| |_   ) / /_  
--More--(50%)

Trying to execute a simple ls:

 _                     _ _ _   ___   __  
| |                   | (_) | |__ \ / /  
| |__   __ _ _ __   __| |_| |_   ) / /_  
!ls
 _                     _ _ _   ___   __  
| |                   | (_) | |__ \ / /  
| |__   __ _ _ __   __| |_| |_   ) / /_  
--More--(50%)

Which is not how it is supposed to look… It turns out, all commands executed will be executed by the current shell, which in our case is /usr/bin/showtext. Because /usr/bin/showtext does not use any arguments; the command supplied is irrelevant, and we have hit a dead end.

Scouring the man more some more; we see that v will start an editor at the current line, which in our case is vim:

help.txt        For Vim version 7.4.  Last change: 2012 Dec 06

VIM - main help file
k
help.txt [Help][RO]                            1,1            Top
  _                     _ _ _   ___   __
 | |                   | (_) | |__ \ / /
 | |__   __ _ _ __   __| |_| |_   ) / /_
 | '_ \ / _` | '_ \ / _` | | __| / / '_ \
 | |_) | (_| | | | | (_| | | |_ / /| (_) |
 |_.__/ \__,_|_| |_|\__,_|_|\__|____\___/
~
~

And from vim, we are able to read the file containing the password using the command :e /etc/bandit_pass/bandit26:

5czgV9L3Xx8JPOyRbXh6lQbmIOWvPT6Z
~
~
~
~
~
~
~
"/etc/bandit_pass/bandit26" [readonly] 1L, 33C 

We can now use the password 5czgV9L3Xx8JPOyRbXh6lQbmIOWvPT6Z to access level 26.

This is currently the last level, and the challenge is completed. Congratulations if you followed and managed to solve it yourself!

Thanks to the team at OverTheWire for providing this great and exciting wargame!