OverTheWire Bandit
These are my solution to the Bandit game on overthewire.org. They are quite easy and serves as a good introduction to using Linux and its tools. (I did them because im bored and wanted a memory refresh).
Level 0
ssh into the server with the given credentials.
ssh bandit0@bandit.labs.overthewire.org -p 2220
Level 0 → Level 1
Use cat
to read file content.
cat readme
Level 1 → Level 2
The file name is -
, which need to be escape (using backslash \
) so that cat can read it without being confuse as flag.
cat ./\-
Level 2 → Level 3
Since the file name have space, those space will also need to be escape.
cat spaces\ in\ this\ filename
Level 3 → Level 4
ls -a
to list all files, including hidden ones.
Level 4 → Level 5
The file
command can be use to see what file type a given file is, and file that are human-readable would return ASCII text
.
To run file
on all files, combine it with find
.
find inhere/ -exec file {} +
The command above will run find
on the inhere/
dir and execute file
on all of files it found.
Level 5 → Level 6
The find
command also have support to find files by size and executability.
find inhere/ -size 1033c ! -executable -exec file {} + | grep ASCII
We use the same trick last level to search for human-readable file, and grep
it since there might be lots of file.
Level 6 → Level 7
find
to the rescue again, it can also search by user and group.
Since they say that the file is somewhere in the server, just search it in the root dir.
find / -size 33c -group bandit6 -user bandit7 -exec grep -v denied {} +
We need to use grep
to find files that we can actually read, the -v
flags is to search for any lines that does not contains the word denied.
There might be a more correct way to filter out the denied files, since my grep
weirdly does not filter out, and also return the content inside the correct file as well! Maybe someone knowledgeable about this could help me understand this interaction.
Level 7 → Level 8
grep millionth data.txt
Level 8 → Level 9
Linux have a wonderfull command call uniq
, which find any lines that does not repeat.
We sort the data.txt
files, so that any same lines will be next to each other (repeated), then remove them.
sort data.txt | uniq -u
Level 9 → Level 10
grep "==" data.txt --text
Level 10 → Level 11
cat data.txt | base64 --decode
Level 11 → Level 12
Rotated by 13 positions is just ROT13, a special Caesar cipher is it own inverse (the encoder is also the decoder).
import codecs
print(codecs.decode("cipher here", "rot13"))
Level 12 → Level 13
There are much better ways to complete this level (automate it for example), but I was sleepy at that time and just recursively decompressed it by hand and checked the file type using file
to figured out which decompressor to use.
Level 13 → Level 14
This level is trivial since it a prep step for the next level. Just cat the file in ~
for the private ssh key and log in directly using the key.
chmod 600 sshkey.private
ssh -i sshkey.private bandit14@bandit.labs.overthewire.org -p 2220
Then cat /etc/bandit_pass/bandit14
since we log in as bandit14.
Level 14 → Level 15
Use nc
to send data to the port.
nc localhost 30000
Level 15 → Level 16
Same as the last level, but instead we use openssl
.
openssl s_client -connect localhost:30001
Level 16 → Level 17
Use netstat to search for open port that is listening.
netstat -plnt
Luckily, only 2 ports open in the range 31000-32000. Just simply check for each of them with openssl
.
Level 17 → Level 18
diff passwords.old passwords.new
Level 18 → Level 19
Use scp
to direcly copy files through ssh.
scp -P 2220 bandit18@bandit.labs.overthewire.org:~/readme .
Level 19 → Level 20
The given binary file ./bandit20-do
can be use to execute command as another user (similar to setuid
).
./bandit20-do cat /etc/bandit_pass/bandit20
Level 20 → Level 21
The way this level is work is that, the given binary ./suconnect
will listen to a specific port, and return the next level password if received the bandit20’s password.
We use nc
to open a port, send the password in with echo
. The &
is use to keep this command running in the background, so that we can use the terminal.
echo "password" | nc -l 4444 &
./suconnect 4444
./suconnect
will read the password we sent into port 4444 from nc, and return the new password.
Level 21 → Level 22
Look inside the bandit22’s cronjob cat /etc/cron.d/cronjob_bandit22
return:
@reboot bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
It appears that this cronjob will execute the /usr/bin/cronjob_bandit22.sh
shell script. Inspect the shell script yield:
#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
This shell script would cat
the password of bandit22 into a temp file. We cannot access the bandit22
file since we are not bandit22, but we can access the temp file.
cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
Level 22 → Level 23
The first few step is similar to the last level.
$ cat /etc/cron.d/cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
The shell script content:
$ cat /usr/bin/cronjob_bandit23.sh
#!/bin/bash
myname=$(whoami)
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
echo "Copying passwordfile /etc/bandit_pass/$myname to /tmp/$mytarget"
cat /etc/bandit_pass/$myname > /tmp/$mytarget
What is shellscript does is that it will get the username, do md5 hash on the string I am user $myname
, and cat
the password of that current user to the temp file. The output if run is:
Copying passwordfile /etc/bandit_pass/bandit22 to /tmp/8169b67bd894ddbb4412f91573b38db3
The cut
is for cleaning up the leftover characters after the hash. IDK why md5sum
does this, my machine only have md5
and it does not produce the leftover characters
We cannot edit the shell script, so we have to construct the hash ourself.
$ echo I am user bandit23 | md5sum | cut -d ' ' -f 1
8ca319486bfbbc3663ea0fbe81326349
$ cat /tmp/8ca319486bfbbc3663ea0fbe81326349
Level 23 → Level 24
Same as above, look at /etc/cron.d/cronjob_bandit24
cronjob.
@reboot bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
Check the /usr/bin/cronjob_bandit24.sh
script.
#!/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 look a bit more complicated than the last one. But basically, it will execute any file inside /var/spool/bandit24/foo
if the owner of that file is bandit23 (us), and delete all files. Which means that any files inside /var/spool/bandit24/foo
will be executed with bandit24 permission.
Let’s check if bandit23 have any permission to that directory.
$ ls -ld /var/spool/bandit24/foo
drwxrwx-wx 8 root bandit24 4096 Feb 19 12:15 /var/spool/bandit24/foo
Notice the last 2 char “wx”. It means that we have write and execute permission in it. Let’s create a script that will fetch the password like the last level.
#!/bin/bash
cat /etc/bandit_pass/bandit24 > /tmp/password24
After waiting for 1 minutes (that’s the cronjob schedule), we can cat /tmp/password24
to get bandit24 password.
Level 24 → Level 25
Generate all of the possible combinations of 4-digit code with bandit24 password in form {password} {secret code} into /tmp/passwords.txt
.
pw = "..."
f = open("/tmp/passwords.txt", "w")
for i in range(0, 10000):
sc = f"{i:{0}{4}}"
sent = f"{pw} {sc}\n"
f.write(sent)
f.close()
Then just feed /tmp/passwords.txt
into the port 30002.
cat /tmp/passwords.txt | nc localhost 30002
At first, I did not know that you can pass the whole 10000 inputs at the same time, so I created a Python script that talk to the port and receive data for every input. While it was probably correct and could work, I never got to see the answer since the port just kept shutting down (erno 32 broken pipe). So thank you to this blog.
Also their generator in bash look much nicer than mine.
Level 25 → Level 26
Ok so this level is quite interesting and is definitely require much more “outside the box” thinking. This entry would be different from previous entries, as I am trying to log my thought process.
After login to bandit25, we immediately saw bandit26.sshkey
(bandit26’s private ssh key) in the home dir. Trying to login normally using this ssh key results in a connect and immediate connection close. The level guide said that bandit26 does not use /bin/bash
but something else, so we should check what shell its using.
$ cat /etc/passwd | grep bandit26
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
Check for /usr/bin/showtext
yield:
#!/bin/sh
export TERM=linux
exec more ~/text.txt
exit 0
So, this script call more
on ~/text.txt
and immediately exit, that explain why we got immediately kick out of the connection. Going back to the connection output to see if there are any extra text printing out from more, and found this.
_ _ _ _ ___ __
| | | (_) | |__ \ / /
| |__ __ _ _ __ __| |_| |_ ) / /_
| '_ \ / _` | '_ \ / _` | | __| / / '_ \
| |_) | (_| | | | | (_| | | |_ / /| (_) |
|_.__/ \__,_|_| |_|\__,_|_|\__|____\___/
Cute logo, but that does not offer any more clue. At this point, I was quite stuck, I kinda guess that the attack vector would lies in the more
program here, but not really sure how.
But then I had an epiphany, you can edit the current file more
is by pressing v
, and editing file means that you have access to vim
, or particularly, its ability to run shell command with :!
. You can even choose the shell you want to run with :set shell=/bin/bash
, thereby bypassing the user default bogus shell.
The real kicker of this level is how to stay in more
pager. Turn out, the solution is to resize your own terminal smaller height wise so that more
cannot display the whole output. After that, its smooth sailing.
Press v
to enter Vim, do :set shell=/bin/bash
, then :shell
. You now gain bash
shell.
Level 26 → Level 27
This continue directly from the last level after gaining bash
shell inside Vim.
There is a binary bandit27-do
, which is the same as level 19 → level 20. Use it to retrived bandit27’s password.
./bandit27-do cat /etc/bandit_pass/bandit27
Level 27 → Level 28
git clone ssh://bandit27-git@bandit.labs.overthewire.org:2220/home/bandit27-git/repo
The password is in README.md
Level 28 → Level 29
git clone ssh://bandit28-git@bandit.labs.overthewire.org:2220/home/bandit28-git/repo
The password is in README.md, but in the previous commit. View changes with git diff HEAD~1
.
Level 29 → Level 30
The password is also in README.md, but in branch dev
. Do git checkout dev
.
Level 30 → Level 31
git tag
git show secret
Level 31 → Level 32
Follow README.md instruction
Level 32 → Level 33
Bandit31’s shell is called UPPERCASE
shell, where every input is uppercase.
WELCOME TO THE UPPERCASE SHELL
>> ls
sh: 1: LS: not found
>> CD .
sh: 1: CD: not found
This lead to problem as it prevent the ability to use all of the commands that have alphabetical in it. To solve this, we have to find any command that are not aphabetical.
Usually, the interactive shell hold what type of shell it is using in $0
. This is perfect as that particular command does not change when uppercased, and it will open up a new interactive shell.
>> $0
$ ls
uppershell
$ cd ../bandit33
$ cat README.txt
Congratulations on solving the last level of this game!
At this moment, there are no more levels to play in this game. However, we are constantly working
on new levels and will most likely expand this game with more levels soon.
Keep an eye out for an announcement on our usual communication channels!
In the meantime, you could play some of our other wargames.
If you have an idea for an awesome new level, please let us know!