OverTheWire - Bandit

AI Generated picture of a hacker's computer setup

Sorry for the horrible AI generated art. I’ll probably replace it eventually.

Here is my writeup for solving the OverTheWire - Bandit wargame. This wargame is aimed at beginners, so I will attempt to give an explanation for what’s going on with each level.

I’m also publishing this page before everything is complete. I’ll be adding to it as I go, but the date of this post is the date it was originally published.

Also a quick note on navigating this page, the levels on OverTheWire use the following convention:
Level 0
Level 0 -> Level 1
Level 1 -> Level 2
Level 2 -> Level 3

The “Level 0 -> Level 1” page uses the username bandit0 to log in and gives the password for bandit1. My convention is slightly different - just click the page that you’re currently logged in as (or start at Level 0 if you’re not logged in yet). So, for example, if you’re logged in as “bandit7” looking for the password for “bandit8”, click the “bandit7” page below. (The header font when using ”->” was hideous, so in part that’s why I didn’t use that convention.)

If you have any questions or comments, feel free to reach out.


OverTheWire - Bandit


Getting Logged In

Note: If you didn’t read above, this covers the info on the Level 0 page from OverTheWire. Since this page doesn’t actually result in getting a new password for a user, I’m using a different navigation convention that will hopefully make it a bit easier to find what you’re looking for on this post.

  • Description: 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, on port 2220. 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.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

bash / PowerShell / Windows Command Prompt:

ssh bandit0@bandit.labs.overthewire.org -p 2220

More Info:

The first time you SSH to bandit, you will probably get a warning about trusting the connection. ‘Yes’ to continue, then you should see some ASCII text that says “bandit” and a request for bandit0’s password. As you type, character’s won’t appear, this is common for passwords on Linux systems. After you type the password (“bandit0”) and press enter, you’ll first get some info, tips, and tools. Then you should see the Command Line Interface (CLI) change from your local computer (this will be different depending on what CLI you’re using and what system you’re on) to:

bandit0@bandit:~$

Once you see this, you’ve completed level 0. In case you’re unfamiliar with SSH, what you’re essentially doing is creating a secure connection between your computer and the computer “bandit.labs.overthewire.org” on port 2220. The “bandit0” part before the ”@” means you are attempting to log in to the remote computer with the username “bandit0”. Generally to advance from level n (user bandit<n>) to level n+1 (user bandit<n+1>), you’ll need to find the password for user bandit<n+1> and connect as that next user.


Level 0:

  • Description: 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 (on port 2220) to login into the next level.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

cat readme

More Info:

The cat command concatenates files and prints them to standard output. In simpler terms, it displays the contents of a file.

My Steps

Just to make sure I was on the right track, I used the ls command to list the contents of the current directory, which did indeed contain a readme file. When logging in, you generally will be in the home directory, which is where the instructions specified the readme file would be, but I like to double check. Then I used the cat command to display the contents of the readme file, which contained the password for the next level.

bandit0@bandit:~$ ls
bandit0@bandit:~$ cat readme

This displayed some text and provide the password for bandit1. Per the rules, I’m not going to publish the password here. :)
I think there should be a couple of options now to advance to the next level. Probably the simplest and preferred is to run the exit command as bandit0. From here you will get a logout and be back in your regular environment. Now you can SSH to bandit1@bandit.labs.overthewire.org with the new password. I recommend copying and pasting (likely this will mean highlighting and then right clicking rather than ctrl+c, then right clicking again when you need to paste instead of ctrl+v) to avoid typos. You can even save that password somewhere with the level login info to pick back up where you left off.

I attempted using SSH from bandit0 to bandit1@localhost, but was denied saying it was blocked to conserve resources and that I should log out and log back in.

I also attempted switching users:

bandit0@bandit:~$ su - bandit1

and it does ask for a password, but I wasn’t able to get this to work. I tried typing the password and copying and pasting it in, but just got authentication errors. I’m not sure if bandit0 doesn’t have permission to change users or if something else is going on. If you are able to get this to work, let me know!


Level 1:

  • Description: The password for the next level is stored in a file called - located in the home directory
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

cat ./-

More Info:

From here, if you just try cat -, it won’t work. When you do that, cat uses - to mean standard input. So you need some workaround. You can get this by redirecting input using <, using a command that can interpret - as a file, or specifying the filename more completely.

bandit1@bandit:~$ cat < -

In this case, we take the file - and redirect it as input to cat.

bandit1@bandit:~$ more -

This uses a different command altogether. Instead of concatenanting a file’s contents to standard output, more displays the contents of a file in the terminal. This is useful if your file is long since cat will just dump everything all at once and more will let you page through it. More importantly for our use case here, more doesn’t interpret - as standard input.

bandit1@bandit:~$ cat ./-

This is my preferred method for this one, just specifying the filename more completely. The ./ represents your current working directory, and then the file - is appended.

My Steps

Again, I started with ls to make sure the file I was intending to read is there, and it was. Admittedly, just to make sure, I tried cat -, but when it didn’t do anything, I used ctrl+c to cancel and knew I needed to find a way to escape that character.


Level 2:

  • Description: The password for the next level is stored in a file called spaces in this filename located in the home directory
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

cat 'spaces in this filename'

More Info:

With this one we can use quotes around a file name with cat to read a file that includes spaces in the name. It works with single or double quotes.

bandit2@bandit:~$ cat "spaces in this filename"

Another option, which you can find using tab complete, is to escape the space characters with \. If you type “cat sp” then press “tab”, it should autocomplete with the file name and the spaces escaped.

bandit2@bandit:~$ cat spaces\ in\ this\ filename

My Steps

With this one, I started by guessing that the single quote method would work, and it did.


Level 3:

  • Description: The password for the next level is stored in a file called inhere located in the home directory
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

cat inhere/...Hiding-From-You

More Info:

The file this time isn’t in the same directory that we are in when we log in (the home directory, which shows up as ~). So now we either have to change to the inhere directory and look there:

bandit3@bandit:~$ cd inhere
bandit3@bandit:~/inhere$ ls

But when we do that, nothing shows up. Files that have names begining with a . will appear hidden. So there are a few options here. You can list all of the contents with the -a flag for ls:

bandit3@bandit:~/inhere$ ls -a

That should now list “all” the files and directories, including hidden ones. We still need to read the file, but there isn’t anything special about cat with hidden files. Just be sure to include the dot (or dots) at the beginning of the filename.

bandit3@bandit:~/inhere$ cat ...Hiding-From-You

Alternatively to using ls -a, you can use tab completion by typing cat then pressing tab from inside the inhere directory. Or even from the home directory, you can use tab completion as I showed in the tl;dr.

My Steps

The very first thing I did, again (and you can assume fairly safely that it will be most of the others too), I used ls to list the contents of the home directory. I navigated to the inhere directory, and knowing that the file was supposed to be hidden, used ls -a to see all the contents. Then used cat ...Hiding-From-You.


Level 4:

  • Description: 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.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

for i in {0..9}; do file ./inhere/-file0$i; done
cat ./inhere/-file07

More Info:

We get to do something a little more fun with this one. The file command tells what type of file something is. Useful when there aren’t file extensions (or if those extensions are deceiving). The more fun part is making a loop to test them all at once. This is a for loop, going from 0 to 9, substituting the number at the end of the filename. It will output all of the filetypes. All of them are data except for one, -file07, which is ASCII text (i.e. should be human readable). We can then use cat as we’ve been doing to read the contents.

My Steps

I didn’t remember the syntax off the top of my head for the for loop in the tl;dr, but a Google search pointed me in the right direction. With only 10 files, you absolutely could do this manually, but I think even with 10, it’s faster to write the loop.

I did try using du first, seeing that it was one of the “commands you may need to solve this level” listed on the OverTheWire page, but all of the files appear to be the same size, so it wasn’t helpful.

Also, I did goof at first. I put the path inside quotes for i in {0..9}; do file "./inhere/-file0$i"; done and that was fine. But when I tried to change it to use ~ it failed. It was interpreting that as a literal character because it was in quotes, so don’t do that.


Level 5:

  • Description: 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

  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

find . -size 1033c -exec cat {} +

More Info:

Turns out there is only one file in the directory that is exactly that size, so “human-readable”and “not executable” weren’t that important to solving it.

My Steps

I started by going to the inhere directory and poking around. There were a lot of directories with a lot of files, so I had thoughts for two different approaches. One was to use find and the other was to do a recursive use of file similar to the last level. I suspected find would be more efficient and successful, so I started there. I checked the man page for find to see how to use the flags correctly. I started by just checking for files that were the right size and not executable, since I didn’t find anything to check for human readability with find. This narrowed it down to 11 files.

bandit5@bandit:~/inhere$ find . -not -executable -size -1033c 

So I thought at this point that I should probably run file against the output of that find. I tried piping it, and it didn’t work. After some quick searching, I found the way to pass the output of find to file.

bandit5@bandit:~/inhere$ find . -not -executable -size -1033c -exec file {} +

The {} acts as a placeholder for the results of find and the + passes all the values at once instead of one at a time.
Unfortunately, this didn’t narrow it down as much as I had hoped. I decided we could likely ignore the “ASCII text, with very long lines” files, but that still left six that were ASCII text, not executable, and 1033 bytes. I started looking at them with cat and none of this seemed right. I also suspected they weren’t all 1033 bytes, since they were very different size chunks of text. So I double checked with ls -la on some of the directories containing the files that were returned from find, and sure enough, they were not the right size. I think the -not flag was negating both the size and executable flags. I likely needed to and them together, but first I tried just using the size, and there’s only one file that fit.


Level 6:

  • Description: 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

  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

find / -size 33c -group bandit6 -user bandit7 2>&1 | grep -v 'Permission denied' | grep -v 'No such file'
cat /var/lib/dpkg/info/bandit7.password

More Info:

In this one, we do have to use more of the properties as well as expanding our find search.

My Steps

In this case, there isn’t anything in bandit6’s home directory, so the file has to be somewhere else. I tried running find from the root and just checking size

bandit6@bandit:~$ find / -size 33c

but there were a lot of files that were returned, so I had to narrow it down with the other attributes that were given.

bandit6@bandit:~$ find / -size 33c -group bandit6 -user bandit7

This returned a lot of things that had “Permission denied”, which means that I can’t execute find on those files. I tried to filter out those with grep.

bandit6@bandit:~$ find / -size 33c -group bandit6 -user bandit7 | grep -v 'Permission denied'

This didn’t seem to do anything. I did a quick search, and the “Permission denied” error is sent to stderr not stdout. So, I found a way to send it to stdout so that I could filter with grep.

bandit6@bandit:~$ find / -size 33c -group bandit6 -user bandit7 2>&1 | grep -v 'Permission denied'

You can read more about 2>&1 here.
There were still a handful of files that produced a “No such file or directory” error, but the list was small enough that I could see only one file that made sense: /var/lib/dpkg/info/bandit7.password. I checked it with cat and it was correct. I included an additional filter in the tl;dr to get rid of the other errors as well.


Level 7:

  • Description: The password for the next level is stored in the file data.txt next to the word millionth
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

grep "millionth" data.txt

More Info:

This one is pretty straightforward. Use grep to search for the word “millionth” in data.txt, which is in bandit7’s home directory and the password is on that line.


Level 8:

  • Description: The password for the next level is stored in the file data.txt and is the only line of text that occurs only once
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

sort data.txt | uniq -u

More Info:

This one uses sort to sort the lines of data.txt and then uniq -u to filter out the unique lines. uniq by itself only filters out adjacent duplicate lines, so sort is used first to put all of the duplicate lines next to each other.

My Steps

This one seemed slightly less straightforward than the previous one, but I suspected it probably followed a similar pattern. grep is pretty powerful, so I suspected it had a way to search for unique lines. I looked at the man page for grep and found the -c flag, but I wasn’t able to get it to count unique lines.

I took another look at the OverTheWire page for a hint, and it suggested sort and uniq. Looking at the man pages for those, I was pretty sure I could sort and then use uniq to get unique lines, which did end up working.


Level 9:

  • Description: The password for the next level is stored in the file data.txt in one of the few human-readable strings, preceded by several ‘=’ characters.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

grep -ao '==.*' data.txt

More Info:

This level requires searching through data.txt for human-readable strings preceded by several ‘=’ characters. Relatively straightforward, but requires using some different grep flags than we have so far. -a is used to display the text, -o is used to only show the matching text, and we change the pattern to ==.* to match the equals signs followed by any characters, which will show us the matched text and any text after it.

My Steps

Once again, we have a single file, data.txt. I started by using cat to look at the contents, and as the description suggests, most of it isn’t human readable. I tried using grep to search for the equals signs that preceed the password.

bandit9@bandit:~$ grep '==' data.txt

When I tried that I only got “binary file matches”. A quick search told me to use the -a flag to display the text anyway.

bandit9@bandit:~$ grep -a '==' data.txt

This did give me the answer, but it required looking somewhat carefully (there are words to the right of several of the equals signs and some human readable text next to the last set). I wanted to see the answer more obviously, so I searched for a way to get grep to only show the human readable text and found the -o flag.

bandit9@bandit:~$ grep -ao '==.*' data.txt

This returned the answer in a much more obvious manner.


Level 10:

  • Description: The password for the next level is stored in the file data.txt, which contains base64 encoded data
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

base64 -d data.txt

More Info:

This one involves decoding some base64 encoded text. You can read more about base64 here. Something particular to note for those of you new to cybersecurity is that base64 encoding is not encryption. It is a way to encode data so that it can be transmitted as ASCII text, which might obfuscate the data, but it doesn’t require anything more than a base64 decoder to get the original data back.

My Steps

Since we started again with just data.txt, I used cat to look at the contents. Aside from being told on the OverTheWire page that the contents were base64 encoded, the ASCII text also ended with ”==”, which is a common ending for base64 encoded text. From here, I just had to decode the text.

bandit10@bandit:~$ base64 --decode data.txt

You could also plug the text into an online base64 decoder to get the same result. A fun one that I will mention here is CyberChef, which can do a lot more than just base64 decoding.


Level 11:

  • Description: 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
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

cat data.txt | tr 'a-zA-Z' 'n-za-mN-ZA-M'

More Info:

This is a fairly common cipher, in the category of substitution ciphers, the same as the famous Caesar cipher. There are a few ways to decode it. One is to use an online tool like CyberChef. Another is by shifting the letters yourself. This can be done with the tr command. The tr command is used to translate or delete characters. In this case, we are translating a-z and A-Z to n-za-mN-ZA-M, which is the same as rotating them by 13 places in the alphabet.

My Steps

I recognized this as “rot13”, which is a simple encoding scheme that shifts letters by 13 places. This was reinforced by the hint to look at the Wikipedia page for rot13. So I started by using cat to look at the contents of data.txt. The pattern of the words looked like the previous level, but with a different password. I copied the text to cyberchef and decoded it with rot13.


Level 12:

  • Description: 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. Use mkdir with a hard to guess directory name. Or better, use the command “mktemp -d”. Then copy the datafile using cp, and rename it using mv (read the manpages!)
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

mkdir /tmp/tmp.YSFLL0Jky7
cp data.txt /tmp/tmp.YSFLL0Jky7
cd /tmp/tmp.YSFLL0Jky7
xxd -r data.txt data
mv data data.gz
gunzip data.gz
bunzip2 data
mv data.out data.gz
gunzip data.gz
tar -xvf data
cat data8
tar -xvf data5.bin
mv data6.bin data6.bz2
bunzip2 data6.bz2
tar -xvf data6
mv data8.bin data8.gz
gunzip data8.gz
cat data8
rm -rf /tmp/tmp.YSFLL0Jky7

More Info:

This level might be somewhat tedious, but it should familiarize you with decompressing and using file to check the type of a file.

My Steps

Per the instructions, I created a temporary directory. In my case, I used mktemp -d which gave it the name tmp.YSFLL0Jky7. In the tl;dr, I hardcoded this same name. If you follow along with my steps, you’ll need to substitute the name of your temporary directory. I then copied data.txt to that directory. I navigated to the directory and listed the contents to make sure data.txt was there.

bandit12@bandit:~$ mktemp -d
bandit12@bandit:~$ cp data.txt /tmp/tmp.YSFLL0Jky7
bandit12@bandit:~$ cd /tmp/tmp.YSFLL0Jky7
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ ls

Then I did a couple of quick checks on the file with file and cat. It didn’t turn up anything that I wasn’t expecting, so I knew from the instructions that I needed to reverse the hexdump first. I did that with xxd.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ xxd -r data.txt data

I double checked that it worked the way I expected with ls, then decided to see what sort of compressed file it was. I did this with file. I also was curious, so I used cat to look at the contents, expecting it to be garbage, but it actually crashed the graphics driver for my PowerShell window, so I had to reconnect and pick back up. But with file I found it was gzip compressed. I attempted to unzip it with gunzip, but got an error: “gzip: data: unkown suffix — ignored.” I did a quick search and found gunzip and gzip -d expect the file to have a .gz suffix, so I added that and tried again.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ file data
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ gunzip data
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ mv data data.gz
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ gunzip data.gz

Now when I checked the file type with file, it was bzip2 compressed data, so I went throug the same process again, this time using bunzip2, without first adding the .bz2 suffix. When I did this, it assumed the file was called data.out and renamed it to match. I checked with ls and file, and found the file (now renamed to data.out) was “gzip compressed data”.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ bunzip2 data
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ ls
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ file data.out

So, then I did the same song and dance with gzip.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ mv data.out data.gz
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ gunzip data.gz
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ file data

This time I got a “POSIX tar archive”. I knew from the instructions that I needed to decompress it, so I used tar and checked again.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ tar -xf data
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ ls

Then I had a new file called data5.bin. I double checked that it was a binary file with file, but it turned out to be another POSIX tar archive. So I extracted that one and checked again.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ tar -xvf data5.bin
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ file data6.bin

data6.bin was “bzip2 compressed data”, so I went through the same process again, this time using bunzip2.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ mv data6.bin data6.bz2
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ bunzip2 data6.bz2
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ file data6

This gave another POSIX tar archive, so I extracted it and checked again.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ tar -xvf data6
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ file data8

data8 was “gzip compressed data”, so I went through this again, but with gunzip.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ mv data8.bin data8.gz
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ gunzip data8.gz
bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ file data8

Finally, I got to an ASCII file, which I checked with cat.

bandit12@bandit:/tmp/tmp.YSFLL0Jky7$ cat data8

And that gave me the password for the next level. I also cleaned up the temporary directory with rm -rf /tmp/tmp.YSFLL0Jky7.


Level 13:

  • Description: 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
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

ssh -i sshkey.private bandit14@localhost -p 2220
cat /etc/bandit_pass/bandit14

More Info:

This one is a bit different from the previous ones. We know where the password is, but it’s owned by bandit14, so we can’t see it from bandit13. We need to use a given private SSH key to log in to bandit14, then we’ll be able to see the password.

My Steps

I started by logging in as usual and just checking to see if anything was in the home directory. There was a file called “sshkey.private”, and double checking with file confirmed that it was a private SSH key. I knew I would need to SSH from bandit13 to bandit14, but I wasn’t sure how to do that with the private key. A quick search turned up this page, which I tried:

bandit13@bandit:~$ ssh -i sshkey.private bandit14@localhost

This didn’t work. I got the following error:

Could not create directory '/home/bandit13/.ssh' (Permission denied).
Failed to add the host to the list of known hosts (/home/bandit13/.ssh/known_hosts).

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

!!! You are trying to log into this SSH server on port 22, which is not intended.

bandit14@localhost: Permission denied (publickey).

Given that error, I thought of a couple of different approaches to try. I could try to change the permissions on the key file, but my gut said that would be unlikely to work, since if that was the solution it might allow people to mess with some other parts of the game. It also says port 22 is not intended, so I thought I could try to SSH to a different port.

I took a look at the commands and helpful reading materials from the OverTheWire page for this level, it didn’t mention anything about changing the permissions on the file, so I decided to try the different SSH port route first. I checked the man page and used nc to see what ports were open on the server:

bandit13@bandit:~$ nc -z localhost 1-65535

This returned a list of ports that were open, only port 22 showed up as [tcp/ssh]. The others all showed [tcp/*]. I wanted some more information about what was running on the other ports before proceeding. I tried adding the -v flag to nc, but all it did was return the failures in addition to the successes. So then I spent a little too long looking for an elegant way to pass the port numbers to nmap, but sometimes a known working less elegant solution is better. So I just hand-jammed it.

bandit13@bandit:~$ nmap -sV -p 22,1111,1840,2220,2221,2230,2231,2232,4091,4321,8000,30000,30001,30002,31046,31518,31691,31790,31960,50001,51790,59150,60917 localhost

Even with the reduced port numbers, I knew this would take a little while to run. I got this list back with some unrecognized services as well:

PORT      STATE  SERVICE             VERSION
22/tcp    open   ssh                 OpenSSH 9.6p1 (protocol 2.0)
1111/tcp  open   time                (32 bits)
1840/tcp  open   ssl/netopia-vo2?
2220/tcp  open   ssh                 OpenSSH 9.6p1 (protocol 2.0)
2221/tcp  open   ssh                 OpenSSH 9.6p1 (protocol 2.0)
2230/tcp  open   ssh                 OpenSSH 9.6p1 (protocol 2.0)
2231/tcp  open   ssh                 OpenSSH 9.6p1 (protocol 2.0)
2232/tcp  open   ssh                 OpenSSH 9.6p1 (protocol 2.0)
4091/tcp  open   ewinstaller?
4321/tcp  open   rwhois?
8000/tcp  open   http-alt?
30000/tcp open   ndmps?
30001/tcp open   ssl/pago-services1?
30002/tcp open   pago-services2?
31046/tcp open   echo
31518/tcp open   ssl/echo
31691/tcp open   echo
31790/tcp open   ssl/unknown
31960/tcp open   echo
50001/tcp open   unknown
51790/tcp open   unknown
59150/tcp closed unknown
60917/tcp open   unknown

So it appeared that there were some more SSH ports open, so I tried connecting like I did before, but to the other ports, starting with 2220.

bandit13@bandit:~$ ssh -i sshkey.private bandit14@localhost -p 2220

Bingo! No need to try the other ports. Then I just had to use cat to display the contents of the password file, per the instructions.

bandit13@bandit:~$ cat /etc/bandit_pass/bandit14

Level 14:

  • Description: The password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

cat /etc/bandit_pass/bandit14 | nc localhost 30000

More Info:

For this one, we use netcat to pass the password to localhost on port 30000. Pretty straightforward.

My Steps

For this one, I knew I needed to send the bandit14 password to localhost. That sounded like probably telnet or nc, so I stared with nc. I first tried hand-jamming it, which worked:

bandit14@bandit:~$ <BANDIT14_PASSWORD REDACTED PER THE RULES> | nc localhost 30000

Then I wanted to make sure I could give a good tl;dr without having to put a spot for the redacted password, so I double checked that I could pipe the contents of the password file from the previous level to nc, which worked and is the solution in the tl;dr.


Level 15:

  • Description: The password for the next level can be retrieved by submitting the password of the current level to port 30001 on localhost using SSL/TLS encryption.
  • Helpful note: Getting “DONE”, “RENEGOTIATING” or “KEYUPDATE”? Read the “CONNECTED COMMANDS” section in the manpage.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

openssl s_client -connect localhost:30001
<PASTE BANDIT15 PASSWORD>

More Info:

This level uses openssl to connect to a port securely, then we submit the current password to that port.

My Steps

I wasn’t as sure reading this one, so I did a quick search and found that I likely won’t be able to use nc with SSL/TLS encryption. I took a look at the OverTheWire page and found several potentially helpful commands. I started by Googling ones that looked promising to be able to securely submit the password: socat, openssl, s_client, and ss.

socat - I was thinking the ‘s’ at the beginning might have been “secure”, but it’s short for “SOcket CAT”, so likely not that one. openssl - This implements SSL/TLS, so I thought that might be the one. I did a little more reading on the man page and it mentioned s_client, which was next on my list anyway, so I switched to reading about that. It looked like that was what I was looking for, so I tried it:

bandit14@bandit:~$ cat /etc/bandit_pass/bandit14 | openssl s_client -connect localhost:30001

This did connect, but it only gave me a bunch of information about the TLS tickets. I still thought this was on the right track, so I tried just connecting without the pipe.

bandit14@bandit:~$ openssl s_client -connect localhost:30001

This gave me a “read R BLOCK” prompt, and appeared to be waiting for input, so I submitted the password from bandit14, and it returned the next password.

I realized I was still using bandit14, and the instructions specified to submit the password for the current level, which should be the password for bandit15. So I tried that too, and it gave me the same result.

bandit15@bandit:~$ openssl s_client -connect localhost:30001
<BANDIT15_PASSWORD REDACTED PER THE RULES>

Level 16:

  • Description: 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/TLS 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.
  • Helpful note: Getting “DONE”, “RENEGOTIATING” or “KEYUPDATE”? Read the “CONNECTED COMMANDS” section in the manpage.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

mkdir /tmp/soidvaw0
cat /etc/bandit_pass/bandit16 | openssl s_client -connect localhost:31790 -ign_eof > /tmp/soidvaw0/s_client-output.txt
awk '
  {if ($0 ~ /Correct!/) found =1;
  if (found && $0 ~ /-----BEGIN RSA PRIVATE KEY-----/) printing =1;
  if (printing) print;
  if (printing && $0 ~ /-----END RSA PRIVATE KEY-----/) {printing=0; exit}
  }' /tmp/soidvaw0/s_client-output.txt > /tmp/soidvaw0/sshkey.private
chmod 600 /tmp/soidvaw0/sshkey.private
ssh -i /tmp/soidvaw0/sshkey.private bandit17@localhost -p 2220
cat /etc/bandit_pass/bandit17
exit
rm -r /tmp/soidvaw0

Note: You don’t have to name your directory soidvaw0, I just hit some random keys on the keyboard. If you’re wanting to follow along exactly, you can use that one, or make your own and replace soidvaw0 with whatever your directory is.

More Info:

This level is sort of a combination of the solutions for level 13 and level 15. Like in level 13, we need to port scan (or since it’s on the same machine, use the actual results of the scan on level 13), then like in level 15, we need to use openssl s_client to securely connect to the port and submit the password. Then like level 13 again, we need to use the private key returned by the server to log in to the next level.

The main part of this that is unique is that we need to extract the private key from the output of openssl s_client, which I did using awk, but could likely be done with sed and grep or other tools.

My Steps

Conveniently, we ran nmap earlier (in level 13), and found that the open ports between 31000 and 32000 were the following:
31046/tcp open     echo
31518/tcp open     ssl/echo
31691/tcp open     echo
31790/tcp open     ssl/unknown
31960/tcp open     echo

With those, I didn’t need to retry scanning the ports.The instructions say that most of the open ports will just send back whatever you send to them, so I started with the one that didn’t have “echo” in the service name - port 31790. Trying to avoid copying and pasting the password, I looked up a way to pass text to openssl s_client and found the -ign_eof flag, so I gave that a shot.

bandit16@bandit:~$ cat /etc/bandit_pass/bandit16 | openssl s_client -connect localhost:31790 -ign_eof

All this told me was “Correct!”, so I tried just connecting via openssl s_client without the pipe. (Edit from later in the post: turns out it did give me an RSA private key, and I wasn’t paying enough attention, so just keep reading.)

bandit16@bandit:~$ openssl s_client -connect localhost:31790
<PASTE BANDIT16 PASSWORD>

This gave me a “read R BLOCK” prompt, so I submitted the password and it returned “KEYUPDATE”. There was a warning about this on the OverTheWire page, so I did a little more reading in the openssl man page. Didn’t find what I was looking for there, so I did a Google search. I found this page, which mentioned that if you use “k” it tries to do a key update, which I didn’t want to do. This is likely because of the beginning of the password, so I tried submitting it with quotation marks around it.

bandit16@bandit:~$ openssl s_client -connect localhost:31790
"<PASTE BANDIT16 PASSWORD>"

This said it was incorrect, so I decided to try to revisit the man pages. Turns out I needed to read more closely, because I was on the wrong man page. Instead of man openssl, or man s_client, I had to look at man openssl-s_client. The s_client man page said as much. Unfortunately, the man page didn’t help me figure out how to submit the password without it being sent as a key update. I was still pretty sure this was the correct port, so I went back to Google. I didn’t find anything that helped, so I just kept trying things and went back to the openssl-s_client man page, which made me try -ign_eof again. Seeing it, I think it may have actually worked last time, but instead of a password after “Correct!”, it gave me an RSA private key. This could be the key for the next level.

Seeing this, I knew I needed to try to get the key into a file so I could use it like we did in level 13.

bandit16@bandit:~$ mkdir /tmp/soidvaw0
bandit16@bandit:~$ cat /etc/bandit_pass/bandit16 | openssl s_client -connect localhost:31790 -ign_eof > /tmp/soidvaw0/sshkey.private

But checking this with file and cat, this didn’t seem to be exactly what I was expecting. If it’s similar to level 13, the output of file should be “sshkey.private: PEM RSA private key”, but instead is “ASCII text”. And the only contents of the file from cat should start with “-----BEGIN RSA PRIVATE KEY-----” and end with “-----END RSA PRIVATE KEY-----” with the key itself between. Instead of that, I have the whole output from s_client.

If I wanted to do something other than copying and pasting, I needed to edit what was going in that file. I had to do a bit of digging, and found a way to do it with awk.

bandit16@bandit:~$ mv /tmp/soidvaw0/sshkey.private /tmp/soidvaw0/s_client-output.txt
bandit16@bandit:~$ awk '
  {if ($0 ~ /Correct!/) found =1;
  if (found && $0 ~ /-----BEGIN RSA PRIVATE KEY-----/) printing =1;
  if (printing) print;
  if (printing && $0 ~ /-----END RSA PRIVATE KEY-----/) {printing=0; exit}
  }' /tmp/soidvaw0/s_client-output.txt > /tmp/soidvaw0/sshkey.private
bandit16@bandit:~$ file /tmp/soidvaw0/sshkey.private
bandit16@bandit:~$ cat /tmp/soidvaw0/sshkey.private

This looked right with file and cat, so I gave it a shot.

bandit16@bandit:~$ ssh -i /tmp/soidvaw0/sshkey.private bandit17@localhost -p 2220

I got a permissions error saying that the private key was too open. I set the permissions with chmod 600 and tried again.

bandit16@bandit:~$ chmod 600 /tmp/soidvaw0/sshkey.private
bandit16@bandit:~$ ssh -i /tmp/soidvaw0/sshkey.private bandit17@localhost -p 2220
bandit17@bandit:~$ cat /etc/bandit_pass/bandit17

And that did it! I went back to clean up after myself.

bandit17@bandit:~$ exit
bandit16@bandit:~$ rm -r /tmp/soidvaw0

Level 17:

  • Description: 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
  • NOTE: if you have solved this level and see ‘Byebye!’ when trying to log into bandit18, this is related to the next level, bandit19
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

diff passwords.old passwords.new | grep "^>" | awk '{print $2}'

More Info:

This one is pretty straightforward.diff compares two files and shows the differences between them. In this case, the only line that has been changed between passwords.old and passwords.new is the password for the next level.

My Steps

I knew I needed to diff the two files and get the new password.

bandit17@bandit:~$ diff passwords.old passwords.new

I double checked that the password on the right side was the one I was looking for, and it was. I did a little searching and experimenting to make the tl;dr only return the password.


Level 18:

  • Description: 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.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

ssh bandit18@bandit.labs.overthewire.org -p 2220 "cat readme"

More Info:

We aren’t able to log in to bandit18 and read the file normally, so we have to find a way to read it before being kicked off by the .bashrc file.

My Steps

When I first logged in, I was immediately kicked off. This was expected based on the instructions from the last two levels. I logged back in as bandit17 to try to check out the .bashrc file. I tried

bandit17@bandit:~$ cat /home/bandit18/.bashrc

and got a permission denied error. I can’t say I’m surprised, but I was hoping it would be something simple like that. My next thought was to see if I could find a way to ssh into bandit18 without triggering the .bashrc file. I tried

ssh bandit18@bandit.labs.overthewire.org -p 2220 --noprofile

and got an error that it didn’t recognize ”— -“. I tried

ssh bandit18@bandit.labs.overthewire.org -p 2220 BASH_ENV=/dev/null

and got no output. I suspect I was logged in and was kicked off because of .bashrc without getting feedback.

I decided it was time to try a new approach. So I looked for a way to send a command with the login.

ssh bandit18@bandit.labs.overthewire.org -p 2220 "ls"

and that did return “readme” after entering the prompted password, so I knew I was on the right track.

ssh bandit18@bandit.labs.overthewire.org -p 2220 "cat readme"

Worked, and gave me the password.


Level 19:

  • Description: 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 the setuid binary.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

./bandit20-do cat /etc/bandit_pass/bandit17

More Info:

This level is pretty straightforward. The setuid binary allows you to run arbitrary commands as another user, so we just need to run cat on the password file for bandit20.

My Steps

I started, per the instructions, by executing the setuid binary without arguments.

bandit19@bandit:~$ ./bandit20-do

It returned “Run a command as another user.
    Example: ./bandit20-do id”

So it sounded like I should be able to run arbitrary commands as another user. Given that, I wanted to run cat on the password file for bandit20.

bandit19@bandit:~$ ./bandit20-do cat /etc/bandit_pass/bandit17

And that did it!


Level 20:

  • Description: 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).
    NOTE: Try connecting to your own network daemon to see if it works as you think
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

tmux
C-b %
cat /etc/bandit_pass/bandit20 | nc -l 42000
C-b <-
./suconnect 42000
C-b d

More Info:

This level involves setting up a server and listening for a connection, then sending the password for the next level when the connection is made. I did this with tmux to split the terminal, but it could be done with other tools.

My Steps

Similar to the previous level, I started with the instructions and executing the binary without arguments. This gave me the impression that the binary sets up a listening server on a port on localhost, then when something else connects to it and sends a line of text, it will compare that to the password for bandit20, and if correct it will return the password for bandit21.

I wanted to use a port that wasn’t being used by anything else, so I started with a port that wasn’t in the list from level 13: 42000. I was expecting it to probably just sit and wait, so I got another terminal instance ready to connect to it.

bandit20@bandit:~$ ./suconnect 42000 &
bandit20@bandit:~$ cat /etc/bandit_pass/bandit20 | nc localhost 42000

This did not work as I expected. I tried a variety of commands, but couldn’t seem to get anywhere. I tried using tmux to split the terminal, leave the binary running in one and connect with nc on the other but that didn’t work. I checked with nmap on the other, and the port 42000 was closed, so something wasn’t working as I expected.

After each time I ran the binary, it would say “could not connect” and then give me what appeared to be a different CLI interface for a single command before terminating the job, but when I checked things like pwd and whoami, it appeared that it was likely the same bash instance, maybe just something weird about backgrounding the job. I started thinking I was on the wrong path. Maybe I was approaching this backwards?

I decided to try setting up a nc server on port 42000.

bandit20@bandit:~$ tmux
bandit20@bandit:~$ C-b %
bandit20@bandit:~$ nc -l 42000

I left this running in tmux and went back to the other terminal to run the binary.

bandit20@bandit:~$ cat /etc/bandit_pass/bandit20 | ./suconnect 42000

This didn’t work exactly, but I thought I was close. I tried a few variations, and was able to eventually figure it out.

tmux-left:

bandit20@bandit:~$ nc -l 42000

tmux-right:

bandit20@bandit:~$ ./suconnect 42000

tmux-left:

<paste bandit20 password>

I also found a way to do this without pasting the password - you can pipe the password from cat to the server:

bandit20@bandit:~$ cat /etc/bandit_pass/bandit20 | nc -l 42000

Level 21:

  • Description: 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.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv

More Info:

The tl;dr for this level kind of bypasses the the actual steps required to solve the level. For this one, we need to look at the cronjobs that are running on the system:

bandit21@bandit:~$ ls /etc/cron.d/
bandit21@bandit:~$ cat /etc/cron.d/cronjob_bandit22

This shows us a crontab or cron table entry for bandit22. It tells us that every minute (the * symbol in each position), it will run a script from the /usr/bin/cronjob_bandit22.sh file. So then we need to look at that script.

bandit21@bandit:~$ cat /usr/bin/cronjob_bandit22.sh

This script is storing the password for bandit22 in a file in the /tmp directory. So then all we need to do is read that file, which is what the tl;dr shows.

bandit21@bandit:~$ cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv

My Steps

I started by just following the instructions. I checked in the directory /etc/cron.d/. I used ls -la and found the following:

total 44
drwxr-xr-x   2 root root  4096 Sep 19 07:10 .
drwxr-xr-x 121 root root 12288 Sep 20 18:37 ..
-rw-r--r--   1 root root   120 Sep 19 07:08 cronjob_bandit22
-rw-r--r--   1 root root   122 Sep 19 07:08 cronjob_bandit23
-rw-r--r--   1 root root   120 Sep 19 07:08 cronjob_bandit24
-rw-r--r--   1 root root   201 Apr  8  2024 e2scrub_all
-rwx------   1 root root    52 Sep 19 07:10 otw-tmp-dir
-rw-r--r--   1 root root   102 Mar 31  2024 .placeholder
-rw-r--r--   1 root root   396 Jan  9  2024 sysstat

I was expecting to see a file for cronjob_bandit21, but it wasn’t there. I took a look at the files in there anyway. The cronjobs for bandit22, bandit23, and bandit24 all had the same format; they look like every minute they run a shell script from the respective user’s bin directory. The file otw-tmp-dir looked interesting, and the permissions seemed to indicate that it was a regular executable file, rather than a directory as the name might suggest. I did not have permission to read or execute it, so I decided to leave it alone for the moment.

I decided to take a look at what was executing for bandit22: /usr/bin/cronjob_bandit22.sh, and found that it was a script that stored the password in a file in the /tmp directory:

#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv

So I took a look at that file with cat and found the next password.


Level 22:

  • Description: 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.
    NOTE: Looking at shell scripts written by other people is a very useful skill. The script for this level is intentionally made easy to read. If you are having problems understanding what it does, try executing it to see the debug information it prints.
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

target=$(echo "I am user bandit23" | md5sum | cut -d ' ' -f 1)
cat /tmp/$target

More Info:

This level is very similar to the previous one. The script is going to store the password for bandit23 in the /tmp directory. All we need to do is read the script and figure out how it’s generating the filename.

My Steps

Picking up from the previous level, I looked at the next cronjob: /etc/cron.d/cronjob_bandit23 and the associated script /usr/bin/cronjob_bandit23.sh. I did initially try to read the script from bandit21, but got a permission denied error. I switched to bandit22 and was able to read the script:

#!/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

This script looked like it was going to store the password for bandit23 in the /tmp directory, with a filename based on the md5sum of the string “I am user bandit23”. I wasn’t very familiar with cut. I knew I could reproduce the “mytarget” value by just running it with “myname” set to “bandit23”, but I wanted to figure out what cut was doing first.

A little reading the cut man page said that it was using the single space as a delimiter instead of tab, and then only taking the first field. So I ran the following:

bandit22@bandit:~$ echo "I am user bandit23" | md5sum

and it looked like cut was removing the space and hyphen at the end of the md5sum value. So then I was comfortable enough to just run the script and check for the password in the /tmp directory.

bandit22@bandit:~$ target=$(echo "I am user bandit23" | md5sum | cut -d ' ' -f 1)
bandit22@bandit:~$ echo $target
bandit22@bandit:~$ cat /tmp/$target

And that was successful!


Level 23:

  • Description: 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.
  • NOTE: This level requires you to create your own first shell-script. This is a very big step and you should be proud of yourself when you beat this level!
  • NOTE 2: Keep in mind that your shell script is removed once executed, so you may want to keep a copy around…
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

printf "#!/bin/bash\ncat /etc/bandit_pass/bandit24 | nc localhost 42042" > /var/spool/bandit24/foo/password-sender.sh
chmod 755 /var/spool/bandit24/foo/password-sender.sh
nc -l 42042
<wait for 60 seconds for password to come back>
ctrl+c

More Info:

Depending on how quickly you enter those and when the cron job is running, the tl;dr might not work the first time.

My Steps

I started off the same was I did in the previous two level: I looked at the cronjob: /etc/cron.d/cronjob_bandit24 and the associated script /usr/bin/cronjob_bandit24.sh.

#!/bin/bash

myname=$(whoami)

cd /var/spool/$myname/foo
echo "Executing and deleting all scripts in /var/spool/$myname/foo:"
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

This script appeared to execute any files that are owned by bandit23 (if [ "${owner}" = "bandit23" ]; then) in the /var/spool/bandit24/foo directory as long as they aren’t named ”.” or ”..” (if [ "$i" != "." -a "$i" != ".." ]; then). This gives them 60 seconds to run before being killed (timeout -s 9 60 ./$i). I had to look up the “9” to see what it meant, and that is the signal number for SIGKILL, which is the signal that will kill the process. The “60” is the number of seconds before the signal is sent. Then it deletes the file (rm -f ./$i).

This sounded (along with the instructions) like I needed to create a script. Since it would be removed (also per the instructions), I wrote it and stored it elsewhere first:

bandit23@bandit:~$ mkdir /tmp/asdlfojwainvasvawn
bandit23@bandit:~$ vim /tmp/asdlfojwainvasvawn/password-sender.sh
bandit23@bandit:~$ chmod 755 /tmp/asdlfojwainvasvawn/password-sender.sh

password-sender.sh:

#!/bin/bash

cat /etc/bandit_pass/bandit24 | nc localhost 42042

I was intending for this to work similar to level 20. The script should, when run by the cron job, use netcat to send the password to port 42042. So before I copied this script into /var/spool/bandit24/foo/, I used tmux and set up a listener on that port as well.

bandit23@bandit:~$ tmux
bandit23@bandit:~$ C-b %

tmux-right:

bandit23@bandit:~$ nc -l 42042
bandit23@bandit:~$ C-b <-

tmux-left:

bandit23@bandit:~$ cp /tmp/asdlfojwainvasvawn/password-sender.sh /var/spool/bandit24/foo/

After a few moments of bated breath, the right side of the screen popped up with the password.

I cleaned up after myself and went on my merry way.

tmux-left:

bandit23@bandit:~$ C-b ->
bandit23@bandit:~$ C-c
bandit23@bandit:~$ C-b d
bandit23@bandit:~$ rm -rf /tmp/asdlfojwainvasvawn

Level 24:

  • Description: 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.
    You do not need to create new connections each time
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

bandit24pass=$(cat /etc/bandit_pass/bandit24)
for i in {0000..9999}; do echo "$bandit24pass $i" >> /tmp/asdvaweansdvoanlnionoinlk.txt; done
cat /tmp/asdvaweansdvoanlnionoinlk.txt | nc localhost 30002

More Info:

This level is fairly straightforward. It involves brute forcing a 4-digit pincode by sending a list of password + pincode combinations to the port and seeing which one works.

My Steps

This looked like it was going to be another level left somewhat open ended. I first started by trying to send the password for bandit24 to the port 30002 to check if it gave me an error for the format of how it wanted the password and pincode.

bandit24@bandit:~$ cat /etc/bandit_pass/bandit24 | nc localhost 30002

Thankfully, I did get an error, and even better, it gave me the format it wanted.

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 and pincode. Try again.

Given the instructions, I knew I would need to brute force the pincode. The question at this point was whether that brute force needed to happen during the connection, or if I could pass in a list of password + pincode combinations to try. I decided the latter would be easier to start with, so I wrote a script to generate a list of all possible 4 digit combinations and then write them to a file:

bandit24@bandit:~$ mkdir /tmp/asdvaweansdvoanlnionoinlk
bandit24@bandit:~$ vim /tmp/asdvaweansdvoanlnionoinlk/pincodegenerator.sh

pincodegenerator.sh:

bandit24pass=$(cat /etc/bandit_pass/bandit24)
for i in {0000..9999}; do echo "$bandit24pass $i" >> /tmp/asdvaweansdvoanlnionoinlk/pincodes.txt; done
bandit24@bandit:~$ chmod 755 /tmp/asdvaweansdvoanlnionoinlk/pincodegenerator.sh
bandit24@bandit:~$ /tmp/asdvaweansdvoanlnionoinlk/pincodegenerator.sh
bandit24@bandit:~$ less /tmp/asdvaweansdvoanlnionoinlk/pincodes.txt

I checked the pincodes file with less and it looked like it was what I expected, so I passed that file to nc to send to the port.

bandit24@bandit:~$ cat /tmp/asdvaweansdvoanlnionoinlk/pincodes.txt | nc localhost 30002

And that gave me the password for bandit25. So I cleaned up and moved on.

bandit24@bandit:~$ rm -r /tmp/asdvaweansdvoanlnionoinlk

I did this one a little late, and realized in my sleepy state that I didn’t need to write a script and execute it - those are pretty short commands, so I could have just run those instead of scripting it.


Level 25:

  • Description: 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.
  • NOTE: if you’re a Windows user and typically use Powershell to ssh into bandit: Powershell is known to cause issues with the intended solution to this level. You should use command prompt instead.
  • Category: Shell escape
  • Difficulty: beginner

TL;DR:

<Log in as bandit25 and save the private key to your machine; set permissions to 600 if applicable>
<Resize CLI window to make it fairly short/small>
ssh -i bandit26.sshkey bandit26@bandit.labs.overthewire.org -p 2220
v
<Resize window to make it readable again>
q:
:set sh=/bin/bash
:!/bin/bash
cat /etc/bandit_pass/bandit26

More Info:

When logging in with SSH to bandit26, the shell is not /bin/bash, but a script that essentially runs the more command on the text.txt file in the home directory of bandit26. From there, you have to figure out how to break out of the shell and get to the password. I struggled a little with this one and had to get a hint. This solution opens the file being read by more with vi, from where you can then send a command to execute the bash shell and get to the password.

My Steps

I wasn’t sure exactly where to start with this one, so I just logged in and started looking around. In the home directory for bandit25 was an RSA private key called “bandit26.sshkey”, so I decided to try logging in with that just like in levels 13 and 18.

bandit25@bandit:~$ ssh -i bandit26.sshkey bandit26@localhost -p 2220

This looked like even though I got an error, it was briefly successful. I decided to see if I could get some more information by running commands like in level 18.

bandit25@bandit:~$ ssh -i bandit26.sshkey bandit26@localhost -p 2220 "pwd"

Unfortuantely, this didn’t work. It just sat and waited after giving me an error about trying to log into an SSH server with a password on port 2220 from localhost. Since my issue seemed to be related to SSH with localhost, I decided to try SSHing from my machine to bandit26 instead of from bandit25 to bandit26 by copying out the private key.

I was using Windows Command Prompt at the time, but if you are using bash, as I later went back and did, you will need to set the permissions of the key file to 600.

chmod 600 bandit26.sshkey

I did successfully SSH into bandit26 from my machine without getting any errors, but it still closed the connection immediately. I was nonethless hopeful that I could try again getting information from bandit26 this way.

ssh -i bandit26.sshkey bandit26@bandit.labs.overthewire.org -p 2220 "pwd"
C-c
ssh -i bandit26.sshkey bandit26@bandit.labs.overthewire.org -p 2220 "ls"

I got the same blinking cursor just sitting there waiting like before. So I decided to log back in as “bandit25” to see if I could find anything else interesting that might point me in the right direction.

bandit25@bandit:~$ ssh bandit25@bandit.labs.overthewire.org -p 2220

I checked the home directory of bandit26 and it had some files that looked interesting. I looked through the ones I could, but didn’t see anything I wasn’t expecting. Looking at the instructions again, I googled how to figure out what shell bandit26 was using. I found that it was listed in the password file, so I checked there:

bandit25@bandit:~$ cat /etc/passwd | grep bandit26

This showed me that bandit26 was using /usr/bin/showtext as its shell. I took a look at the showtext script:

bandit25@bandit:~$ cat /usr/bin/showtext

showtext:

#!/bin/sh

export TERM=linux

more ~/text.txt
exit 0

This looked like it was just printing the contents of the text.txt file in the home directory of bandit26 with the more command. I decided to try to cat the file:

bandit25@bandit:~$ cat /home/bandit26/text.txt

But I got a permission denied error. I kind of beat my head against a wall for a while and decided to look for a hint online. I found this post that confirmed I was on the right track, but I wasn’t approaching the last part of the solution correctly. I should have paid more attention (pun intended) to the commands listed on the instructions page, specifically more and vi.

Prior to this, I was unaware that if more could display the entire contents of a file, then it wouldn’t prompt for the next page and that when prompting for the next page, you could pass a command to view the file with vi.

So, following the other writeup, I exited, and SSH’d in again from my machine with a resized window to force more to only display part of the file, and then used v to view the file with vi.

ssh -i bandit26.sshkey bandit26@bandit.labs.overthewire.org -p 2220
v
<Resize window to make it readable>

From here, I tried not to read much more from the other writeup, but I did see that I needed to use vi to send a command, so I used that as a jumping off point to do some googling. I found that I could use :! to send a command to the shell. However, that didn’t work directly; I had to enter command mode first (ex mode), so I had to use q: to get to ex mode and then :!/bin/bash to attempt to execute the bash shell. However, this still just ran the more command on the file. I had to change the shell used by ex mode to /bin/bash to get a real shell. From there I could just cat the password file.

q:
:set sh=/bin/bash
:!/bin/bash
bandit26@bandit:~$ cat /etc/bandit_pass/bandit26

Level 26:

  • Description: Good job getting a shell! Now hurry and grab the password for bandit27!
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

<Resize CLI window to make it fairly short/small>
<log in as bandit26>
v
<Resize window to make it readable again>
q:
:set sh=/bin/bash
:!/bin/bash
./bandit27-do cat /etc/bandit_pass/bandit27

More Info:

This level combines the previous level with level 19.

My Steps

Now with the password for bandit26, I could log in without using the private key. I used the password, but had to use the same method from the previous level actually get a shell before starting to look for the password for bandit27.

Once logged in, I knew from the last level that there was an executable file in the home directory called bandit27-do. I ran it, and it without any extra arguments, and it gave me the usage for the program. This was similar to level 19, where I had to run a command as another user. Based on that, I just ran cat on the password file via the executable.

bandit26@bandit:~$ ./bandit27-do
Run a command as another user.
  Example: ./bandit27-do id
bandit26@bandit:~$ ./bandit27-do cat /etc/bandit_pass/bandit27

And that gave me the password for bandit27.


Level 27:

  • Description: There is a git repository at ssh://bandit27-git@localhost/home/bandit27-git/repo via the port 2220. The password for the user bandit27-git is the same as for the user bandit27.
    Clone the repository and find the password for the next level.
  • Category: Git
  • Difficulty: beginner

TL;DR:

mkdir /tmp/ionviwlsmzzmffunfslk
cd /tmp/ionviwlsmzzmffunfslk
git clone ssh://bandit27-git@localhost:2220/home/bandit27-git/repo
<BANDIT 27 PASSWORD>
cat README
rm -rf /tmp/ionviwlsmzzmffunfslk

More Info:

This one is pretty straightforward. Just clone a repository and look in it.

My Steps

I was going to attempt to clone the repository into a temporary directory:

bandit27@bandit:~$ mkdir /tmp/ionviwlsmzzmffunfslk
bandit27@bandit:~$ cd /tmp/ionviwlsmzzmffunfslk
bandit27@bandit:/tmp/ionviwlsmzzmffunfslk$ git clone ssh://bandit27-git@localhost:2220/home/bandit27-git/repo

but this got a couple of errors. This defaulted to port 22, which wasn’t allowed, and it also said that it couldn’t create /home/bandit27/.ssh (permission denied). So I started by tackling the port issue, and it ended up solving both.

bandit27@bandit:/tmp/ionviwlsmzzmffunfslk$ git clone ssh://bandit27-git@localhost:2220/home/bandit27-git/repo
<BANDIT 27 PASSWORD>

There was a README file in the repository that contained the password.

bandit27@bandit:/tmp/ionviwlsmzzmffunfslk$ cat README

Cleaned up and left.

bandit27@bandit:/tmp/ionviwlsmzzmffunfslk$ rm -rf /tmp/ionviwlsmzzmffunfslk

Level 28:

  • Description: There is a git repository at ssh://bandit28-git@localhost/home/bandit28-git/repo via the port 2220. The password for the user bandit28-git is the same as for the user bandit28.
    Clone the repository and find the password for the next level.
  • Category: Git
  • Difficulty: beginner

TL;DR:

mkdir /tmp/ionviwlsmzzmffunfslk
cd /tmp/ionviwlsmzzmffunfslk
git clone ssh://bandit28-git@localhost:2220/home/bandit28-git/repo
<BANDIT 28 PASSWORD>
git show 3621 -- README.md
rm -rf /tmp/ionviwlsmzzmffunfslk

More Info:

This level requires looking for the password in a previous version of the README file using git.

My Steps

I followed the same steps as for level 27 to begin this one.

bandit28@bandit:~$ mkdir /tmp/ionviwlsmzzmffunfslk
bandit28@bandit:~$ cd /tmp/ionviwlsmzzmffunfslk
bandit28@bandit:/tmp/ionviwlsmzzmffunfslk$ git clone ssh://bandit28-git@localhost:2220/home/bandit28-git/repo
<BANDIT 28 PASSWORD>
bandit28@bandit:/tmp/ionviwlsmzzmffunfslk$ ls
bandit28@bandit:/tmp/ionviwlsmzzmffunfslk$ cat README

All this showed was

# Bandit Notes
Some notes for level29 of bandit.

## credentials

- username: bandit29
- password: xxxxxxxxxx

I suspected that the password might have been in a previous version of the README file, which should be visible via git.

bandit28@bandit:/tmp/ionviwlsmzzmffunfslk$ git log

This showed the commit history, which had a message on the last revision that said “fix info leak”. So I checked out the diff on the version before that.

bandit28@bandit:/tmp/ionviwlsmzzmffunfslk$ git show 3621 -- README.md

And this showed the password in plaintext.

As always, I cleaned up after myself.

bandit28@bandit:/tmp/ionviwlsmzzmffunfslk$ rm -rf /tmp/ionviwlsmzzmffunfslk

Level 29:

  • Description: There is a git repository at ssh://bandit29-git@localhost/home/bandit29-git/repo via the port 2220. The password for the user bandit29-git is the same as for the user bandit29.
    Clone the repository and find the password for the next level.
  • Category: Git
  • Difficulty: beginner

TL;DR:

More Info:


Level 30:

  • Description: There is a git repository at ssh://bandit30-git@localhost/home/bandit30-git/repo via the port 2220. The password for the user bandit30-git is the same as for the user bandit30.
    Clone the repository and find the password for the next level.
  • Category: Git
  • Difficulty: beginner

TL;DR:

More Info:


Level 31:

  • Description: There is a git repository at ssh://bandit31-git@localhost/home/bandit31-git/repo via the port 2220. The password for the user bandit31-git is the same as for the user bandit31.
    Clone the repository and find the password for the next level.
  • Category: Git
  • Difficulty: beginner

TL;DR:

More Info:


Level 32:

  • Description: After all this git stuff, it’s time for another escape. Good luck!
  • Category: Basic commands
  • Difficulty: beginner

TL;DR:

More Info:

At the time of writing, that is the end of this wargame. If new levels come out and I don’t update this post, please reach out and let me know. I’ll be glad to update when I can.