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.

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.

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

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.

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.

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.

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.

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

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.

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.

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

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

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.

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.

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.

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

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.

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

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

See the full history below.

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.

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

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

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

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

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,

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.

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

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.

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

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

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

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.

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

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,

The cronjob_bandit22 could be interesting.

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.

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.

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.

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

Lets try the following,

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.

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

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

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

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.

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.

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

Then I created the following bashscript, namely bruteforce.sh

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

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:

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

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.

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:

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

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

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

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

If we look into git log, we get the following

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

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

The README.md within repo contains the following

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

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

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.

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

.gitignore contains the following

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.

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.

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

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

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

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