KimbakiS Portfolio

This is a collection of some of the projects I've worked on during my ventures into the Cybersecurity world.

View on GitHub

OverTheWire’s Bandit Challenge

Informal writeup with a collection of screenshots and some notes as I made my way through the Bandit challenge from OverTheWire, which I revisited after investing some more time in learning scripting.

Level 1: the password is stored in a file called “readme”

SSH into the game as bandit 0 on port 2220

image

Cat the readme file

image

Level 2: the password is stored in a file called -

SSH as bandit1 and cat the - file

image

Level 3: the password is in a file called “spaces in this filename”

SSH as bandit2 and cat the filename with the spaces:

image

Level 4: the password is in a hiddne file called “inhere”

SSH as bandit3, CD into directory, and cat the hidden file

image

Level 5: the password is stored in the only human-readable file in the “inhere” directory

SSH as bandit4 and retrieve the only human-readable text from the list of files:

image

Since the files were each very small, I simply catted all of them out to save time **(not pretty, but it works).

Level 6: the password is stored in “inhere” directory, is human-readable, is 1033 bytes, and is not executable

image

Managed to find the right file matching only two of the conditions:

Level 7: the password is stored somewhere on the server, is owned by user bandit7 and group bandit6, and is 33 bytes

image

Level 8: the password is stored in the file “data.txt” next to the word “millionth”

image

Level 9: the password is stored in the file “data.txt” and is the only line that occurs just once

image

We naturally have to sort the file first for it to check for duplicates, and then, only return the unique lines via uniq -u)

Level 10: the password is stored “file.txt”, is human-readable, and is preceded by several “=” signs

image

Level 11: the passwords is in “data.txt”, which is base64-encoded

Simply decode the base64-encoded data:

image

Level 12: the passwords is in “data.txt”, where all letters are rotated by 13 positions

Classic case of Rot13, so we just need to rotate the characters back:

image

tr can be used to ‘translate’ (or ‘rotate’) the letters by 13 characters.

Logic:

Level 13: the password is stored in “data.txt”, which is a hexdump of a file that’s bene repeatedly compressed

Make a temporary directory to work with the file

image

Revert the hexdump to its original form:

image

Before it was converted to a hexdump, the file was a Gzip called “data2.bin”

It took many, many iterations to decompress the file, and it involved the following process:

  1. Display what type of file it is with file
  2. If in Gzip format: mv data1 data2.gzgzip -d data2.gz
  3. If in Bzip format: bzip2 -d data2
  4. If in Tar format: tar -xf data2

image

At data9, we FINALLY have ASCII text, which contains the password.

image

Level 14: use the SSH key to log in as bandit14

This is a classic RSA key:

image

Copied the key into a file bandit14.rsa, modified the permissions to be able to use it, then SSHed as bandit14 with the key:

image

Level 15: submit bandit14’s password to port 30000 to retrieve the next password

The previous level mentioned where the password was, so we just connect to the port via Netcat and send over the contents of the password file through a pipe (|) and get its reply:

image

Level 16: submit bandit15’s password to port 30001 using SSL/TLS encryption

We have to use openssl to connect securely (with an encrypted session) to that port:

image

Simply submitted bandit15’s password and it returned the next one:

image

Level 17: find a listening port that speaks SSL/TLS and submit bandit16’s password to it.

Easy method would be to run Nmap locally to find open ports in the range given:

image

The more challenging method is to write out your own script, which is useful for when you don’t have port scanning tools such as Nmap available on the local system.

So, I made a temp directory to write out the script:

image

portscanner.py

import socket

# Variables: IP to range of ports to scan
ip = "127.0.0.1"
port_range = range(31000, 32001)

openPorts = [] # empty list to add matches to

# Iterate over each port
for port in port_range:

        # Create a socket and attempt to connect to the port
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        result = sock.connect_ex((ip, port))

        # If the connection is successful, append to the list:
        if result == 0:
                openPorts.append(f"Port {port} is open")

        # Close the socket (connection)
        sock.close()

# Print out the open ports
print("\n".join(openPorts))

Then, changed the permissions on the script and ran it:

image

Open Ports: 31046, 31518, 31691, 31790, 31960

Since there are only 5 ports open, I just tested each of them manually to see if they successfully connected with openssl:

image

Both 31518 and 31790 accept input, but there’s a KEYUPDATE generated, so I had to do some research into this error and ended up finding a parameter that can bypass it -> -ign_eof:

image

Port 31790 accepted the password and returned a private key

image

Level 18: the password is the only line that’s different between the two given files

Simply ran a diff against the two password files to find the change:

image

Level 19: find a way to retrieve the password in “readme” while being immediately logged out of SSH upon loggin in”

We should still be able to pass commands to the system through SSH even if we can’t use an interactive terminal, so since we know the name of the file we want, can just cat that:

image

Level 20: use the binary file to get the next password

strings returns a few interesting things: 1. Line of text: “Run a command as another user.” 2. bandit20.c → I’m wondering if the binary references this file. 3. There’s also a location given /usr/bin/env, so maybe this is where the C file is?

image

Since the file’s name references the bandit20 user, maybe all we need to do is run a cat command through the binary:

image

Yep…it was that simple. Note to self to always run the program BEFORE trying to reverse engineer it.

Level 21: use the binary file to retrieve the password

According to the level notes, the binary suconnect does the following: connects to ‘localhost’ on a specified port → reads a line of text from the connection → compares the line to bandit20’s password → if it’s a match, it transmits bandit21’s password.

Since the binary needs to retrieve the text for the comparison from a port connection, we probably need a way to store text in a port in the first place. I was not familiar with how to do this, so I had to do some research and discovered that we can actually do just that with Netcat:

image

Essentially, we create a listening port 4444 and pass bandit20’s password to it, background the listener, and then have the binary access that listening port to retrieve the text.

And because the lines match, we do indeed get bandit21’s password.

Level 22: use the program being run via cron to retrieve the password

Found a script being run at reboot: /usr/bin/cronjob_bandit22.sh, which is a bash script that changes permissions on a temp file, then cats out bandit22’s password to that file.

image

Simply read the file referenced in that script and got the password.

Level 23: another cronjob challenge

Similar process to before, located a binary that copies the password files for a username provided by the whoami prompt over to a temp directory.

image

The script isn’t writeable, but it can be run by bandit22 and I believe the key is to trick it into thinking we’re bandit23, as it runs the whoami command to get the username.

I tried making variables for both whoami and myname, but this didn’t work.

Through trial and error, I discovered that I could possibly make my own copy of the script with the same title as the existing one, change the PATH to start with the location of my own script, and then when the job runs next, it will run my script first (with root privileges of course).

So, I created a temp directory and prepended the PATH variable with that directory.

image

I copied over the original script code to my own file with the same name as the original, changing the line that specifies the myname variable to the value “bandit23” instead of performing whoami:

And now, the temp directory is the first place that will be checked for the script instead of “/usr/bin”.

Finally, the script details that the name of the file that will contain bandit23’s password is an MD5 hash, so I ran that line of code separately to get the exact value, then catted out the file:

image

I’m extremely proud of myself right now 😊

Level 24: there’s a time-based job that’s running a command at regular intervals

  1. The script shows that everything within the directory /var/spool/bandit24/foo gets run periodically.
  2. Made a simple reading script:

image

  1. Added executable privileges on my script.
  2. Made a file called “bandit25” in the temp directory and changed its permissions, too.
  3. Copied over the script to /var/spool/bandit24/foo and waited for it to run……and it didn’t
  4. After a lot of digging, I found out it was because I needed to set the permissions of my temp directory, too
  5. Ran it again and it worked:

image

Level 25: bruteforce the 4-digit passcode for the port to get the password

Wrote a simple bash script to send a range of 4-digit numbers and bandit24’s password to the Netcat port and send the output from the server to a text file:

#!/bin/bash

for num in {1000..9999}
do
    echo <password> $num
done | nc [localhost](http://localhost) 30002 > results.txt

Add executable permissions to the script and run it.

image

Grep out the wrong answers to highlight the correct one

image

Level 26: log in as bandit26 with the given key and break out of the shell

  1. Tried to SSH in with the key, but the shell immediately crashes.
  2. Checked from bandit25’s session to see what shell bandit26 is using, which is showtext.
  3. Looking at the binary for this interesting shell, it looks like it displays a text file with the more command, then immediately exits.

image

I did realize that the more command would play a role here, but it took a lot of digging to realize that it’s basically the entry point to gain a regular shell. And to prompt it to display, the terminal needs to be shrunk to a very small size:

image

Once this is triggered, V can be pressed to actually open up Vim and return to normal windows size, after which we can change the shell being used by bandit26 to a simple Bash via :set shell=/bin/bash, switch to it, and finally cat out bandit26’s password:

image

Level 27: grab the password

There is a simple binary in the current directory where you can run a command as bandit27, so I used that to grab the password (most of the work was done in the previous level):

image

Level 28: clone the Git repository and find the next password

Created a temp directory and cloned the specified repository there, then just catted the README file:

image

Level 29: clone the Git repository and find the next password

  1. Same first step as previous level, but for bandit28’s repo.
  2. The “README” file contains notes for the next level, including a placeholder for the password.
  3. My first thought is that the password was written here before the current version of the file (because of the placeholder), so I’ll check the history:

image

And the previous version did indeed have the password.

Level 30: clone the Git repository and find the next password

  1. Same first step as previous 2 levels, but for bandit29’s repo.
  2. The README.md file says no passwords are in production, but I’ll double-check the history. Yes, it returns nothing.
  3. git log --all → checked history of commits for all of the branches.
  4. Found a commit with the note “add data needed for development”.
  5. git show <commit> returned the original data for the password line, which is the actual password.

image

Level 31: clone the Git repository and find the next password

  1. Same first step as previous 3 levels, but for bandit30’s repo.
  2. There is nothing in the logs this time, and there’s only one branch.
  3. After trying various commands (referencing a categorized list I found online), git tag returned a tag called “secret”.
  4. git show secret returned what looks to be the password.

image

Level 32: clone the Git repository and find the next password

  1. Same first step as previous 4 levels, but for bandit31’s repo.
  2. The README file this time says that the task is to push a file called “key.txt” with the content “May I come in?” to the remote repository’s master branch.

image

  1. Pushed the file to the remote repository, and the message displayed as confirmation of the commit’s receipt was the password for the next level.

image

image

Level 33: the only thing it says is this is an “escape” challenge

  1. It says we are using a n “UPPERCASE SHELL”
  2. Many commands are restricted, and it’s converting the commands to uppercase form.
  3. I tried to see if environment variables could be assigned, but this didn’t work.
  4. The hint given is the command sh which seems to be related to a Bash interpreter.
  5. After reading the man page, I’m sure the key is in variables.
  6. It ended up being as simple as switching to a regular shell via $0.