Hello again, and welcome to the penultimate post in my Overthewire Bandit wargame series. In the last post we expanded on our knowledge of setuid binaries and netcat
and finished with conducting our first brute-force attack. It’s a great time to reflect on how much we’ve progressed through the Bandit wargame. Looking back to Level 1, we began to learn simple commands to access information, and now we’re learning basic hacking techniques.
Through the next five levels, we’ll be moving on to using git
. git
is one of my favourite tools, and I look forward to solving these levels together! Let’s begin level 25.
Level 25 - Level 26
In this level, we are provided with an SSH private key as we have been on previous levels, but the shell for the user bandit26 is not /bin/bash. We need to find out what it is, how it works, and how to break out of it to retrieve the password for the next level.
First, let’s list the contents of the current directory:
$ ls -l
total 4
-r-------- 1 bandit25 bandit25 1679 Jun 20 04:07 bandit26.sshkey
Let’s use the provided SSH key to log into bandit26:
$ ssh -i bandit26.sshkey bandit26@localhost -p 2220
...
_ _ _ _ ___ __
| | | (_) | |__ \ / /
| |__ __ _ _ __ __| |_| |_ ) / /_
| '_ \ / _` | '_ \ / _` | | __| / / '_ \
| |_) | (_| | | | | (_| | | |_ / /| (_) |
|_.__/ \__,_|_| |_|\__,_|_|\__|____\___/
Connection to localhost closed.
You’ll notice that, after the usual welcome message, we get an additional ASCII art message and a message from ssh
indicating the connection has been closed.
The level description suggests checking the shell used by bandit26. We can do this with the getent
command, which retrieves entries from various databases supported by the system, such as the passwd database (stored at /etc/passwd if you’d like to view it manually):
$ getent passwd bandit26
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
If you decide to view the /etc/passwd file manually, you’ll notice that this output is directly from that file, which stores user account information. Each line in the file represents a single user and contains several fields separated by colons (:). From left to right, the fields are:
bandit26
: The user’s username.x
: Placeholder for the password (the actual passwords are stored encrypted in /etc/shadow).11026
: The user’s user ID (UID).11026
: The user’s group ID (GID).bandit level 26
: A comment field. It usually contains the full name of the user./home/bandit26
: The user’s home directory./usr/bin/showtext
: The user’s login shell.
In this case, the login shell for bandit26 is /usr/bin/showtext, instead of the typical /bin/bash. Let’s take a look at what this script does:
$ cat /usr/bin/showtext
#!/bin/sh
export TERM=linux
exec more ~/text.txt
As we can see, this is a straightforward script that sets the TERM
environment variable and executes the command more
on “~/text.txt” (the tilde character is shorthand for the user’s home directory, so for bandit26, it would resolve to “/home/bandit26/text.txt"). The more
command is a terminal pager program used to view the contents of a file one screen at a time. It’s useful when you need to view a file that is too large to fit on the terminal screen all at once. However, as you can see, it behaves like cat
when using it on a file with little content.
To bypass the showtext script, we can take advantage of the more
command’s behaviour when it cannot display the full file contents on the screen. We can shrink our terminal window to force more
to display only part of the text, giving us access to its interactive mode and, therefore, its commands. Specifically, we’ll have to shrink our terminal window to less than six rows, as that’s the number of lines in /home/bandit26/text.txt.
Once you’ve shrunk your terminal window, try logging in via SSH again. You should see something like this:
$ ssh -i bandit26.sshkey bandit26@localhost -p 2220
...
_ _ _ _ ___ __
| | | (_) | |__ \ / /
| |__ __ _ _ __ __| |_| |_ ) / /_
--More--(50%)
The terminal window was too small for the full message to be displayed, so more
printed the first few lines and stopped when it couldn’t print any more, ending with the prompt “–More–”. If we were to press Enter here, more
would continue paging until the entire message was displayed, after which the connection would be closed again. Instead, while we see this “–More–” prompt, we’ll press “v” to open the file in vim
(the default text editor for more
).
Now that we’re in vim
, we can use a command to change the file to /etc/bandit_pass/bandit26. Press “:” to enter command mode. You’ll notice that your cursor moves to the bottom of the window. Now, in command mode, type “e” (short for “edit") followed by a space, then type the path of the file you want to edit. Your full vim
command should look like this:
:e /etc/bandit_pass/bandit26
Press Enter to confirm the command. The password for bandit26 should now be displayed. You can exit vim
by issuing the command q!
(meaning “quit without saving"). It should look like this:
:q!
Level 26 - Level 27
In this level, we’ll encounter the same issue logging into bandit26 with a password as we did when using the SSH key in the last level. The difference is that we’ll need to get a shell this time, not just read a file.
First, like last time, resize the terminal window so that the more
command cannot display the full content of the file. This will allow us to access the more
command’s interactive mode. Once the window is resized, log into bandit26 with the password we obtained and, when you see the “–More–” prompt, press “v” to enter vim
again.
Instead of just reading a file like we did last time, we’ll set the shell to /bin/bash and then enter vim
’s shell mode. Setting the shell variable ensures that when we drop into shell mode, we get a bash
shell rather than the user’s default shell, which stops us from logging in.
In vim
, type :set shell=/bin/bash
and press Enter. Then, type :shell
and press Enter to enter vim
’s shell mode.
Now that we have a shell, list the contents of the home directory:
$ ls -l
total 20
-rwsr-x--- 1 bandit27 bandit26 14880 Jun 20 04:07 bandit27-do
-rw-r----- 1 bandit26 bandit26 258 Jun 20 04:07 text.txt
text.txt is the ASCII art message we’ve been seeing upon login. The interesting file here is another setuid binary called bandit27-do. We’ve seen files like this in levels 19 - 20 and 20 - 21. The bandit27-do binary is a setuid binary, meaning it runs with the privileges of its owner, bandit27. We can use this binary to read the password file for bandit27:
$ ./bandit27-do cat /etc/bandit_pass/bandit27
<password>
Level 27 - Level 28
In this level, there is a git
repository at ssh://bandit27-git@localhost/home/bandit27-git/repo via port 2220. The password for the user bandit27-git is the same as for the user bandit27. Our task is to clone the repository and find the password for the next level.
git
is a distributed version control system designed to track changes in source code during software development. It allows multiple developers to work on a project simultaneously without interfering with each other’s work. git
helps manage project versions and branches, making it easy to roll back changes, collaborate, and track the history of a project.
A repository (or “repo") in git
is a directory that contains all the project files and the entire revision history. Cloning a repository means making a local copy of the repository from a remote server, including all the project’s files and its history. This allows you to work on the project locally and later push changes back to the remote repository.
Now that we have an understanding of what git
is, let’s begin tackling this level. First, create a temporary directory using mktemp
and navigate to it:
$ mktemp -d
/tmp/tmp.bhUxSuR3ak
$ cd /tmp/tmp.bhUxSuR3ak
Now, clone the repository using git
, specifying the port 2220. You will be prompted for the password for the user “bandit27-git which, as the level description says, is the same as the password for bandit27.
$ git clone ssh://bandit27-git@localhost:2220/home/bandit27-git/repo
Cloning into 'repo'...
The authenticity of host '[localhost]:2220 ([127.0.0.1]:2220)' can't be established.
ED25519 key fingerprint is SHA256:C2ihUBV7ihnV1wUXRb4RrEcLfXC5CXlhmAAM/urerLY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Could not create directory '/home/bandit27/.ssh' (Permission denied).
Failed to add the host to the list of known hosts (/home/bandit27/.ssh/known_hosts).
_ _ _ _
| |__ __ _ _ __ __| (_) |_
| '_ \ / _` | '_ \ / _` | | __|
| |_) | (_| | | | | (_| | | |_
|_.__/ \__,_|_| |_|\__,_|_|\__|
This is an OverTheWire game server.
More information on http://www.overthewire.org/wargames
bandit27-git@localhost's password:
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
Now, you will have a directory named “repo”, the repository name you just cloned. Navigate into it:
$ cd repo
Let’s list the contents of the directory to see what’s inside the repo:
$ ls -l
total 4
-rw-rw-r-- 1 bandit27 bandit27 68 Jul 1 10:58 README
To find the password, simply read the README file:
$ cat README
<password>
Level 28 - Level 29
In this level, we have another git repository at ssh://bandit28-git@localhost/home/bandit28-git/repo via port 2220. Our task is to, again, clone the repository and find the password for the next level.
First, let’s create a temporary directory like last time. On an interesting side note, we can do that in a single command like this:
$ cd $(mktemp -d)
Now, clone the repository using git
:
$ git clone ssh://bandit28-git@localhost:2220/home/bandit28-git/repo
Cloning into 'repo'...
The authenticity of host '[localhost]:2220 ([127.0.0.1]:2220)' can't be established.
ED25519 key fingerprint is SHA256:C2ihUBV7ihnV1wUXRb4RrEcLfXC5CXlhmAAM/urerLY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Could not create directory '/home/bandit28/.ssh' (Permission denied).
Failed to add the host to the list of known hosts (/home/bandit28/.ssh/known_hosts).
_ _ _ _
| |__ __ _ _ __ __| (_) |_
| '_ \ / _` | '_ \ / _` | | __|
| |_) | (_| | | | | (_| | | |_
|_.__/ \__,_|_| |_|\__,_|_|\__|
This is an OverTheWire game server.
More information on http://www.overthewire.org/wargames
bandit28-git@localhost's password:
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 9 (delta 2), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (9/9), done.
Resolving deltas: 100% (2/2), done.
Now that we’ve cloned the repo, let’s navigate to it and see what’s inside:
$ cd repo
$ ls -l
total 4
-rw-rw-r-- 1 bandit28 bandit28 111 Jul 1 14:44 README.md
This time, we have a README.md file, which is a file written in the markdown format (hence the .md file extension) that is generally used in repositories to describe the project and how to use it. Let’s take a look at what it contains:
$ cat README.md
# Bandit Notes
Some notes for level29 of bandit.
## credentials
- username: bandit29
- password: xxxxxxxxxx
It looks like we have some credentials, but the password has been censored. As this is a git
repository, we will have the version history of every file, including this README.md. Let’s look at the version history, also known as the commit history in git
. We can use git log
to view this commit history. This will help us understand the changes made to the repository over time. A commit in git
represents a snapshot of the project’s files at a specific point in time, and each commit has a unique identifier known as a commit hash. Let’s use git log
and see the output:
$ git log
commit ad9a337071c5e3d4509559d36128b38a0e5571f1 (HEAD -> master, origin/master, origin/HEAD)
Author: Morla Porla [email protected]>
Date: Thu Jun 20 04:07:12 2024 +0000
fix info leak
commit 229f6001e1ff407bb935b82a94c6749e41a0693e
Author: Morla Porla [email protected]>
Date: Thu Jun 20 04:07:12 2024 +0000
add missing data
commit ea882192c25642e69627b13179f9fb98f409ed5d
Author: Ben Dover [email protected]>
Date: Thu Jun 20 04:07:12 2024 +0000
initial commit of README.md
Let’s break this down to understand this output. We have three different commits here, separated by blank lines. The commits are listed in chronological order, with the first commit listed (the one at the top) being made most recently. Each commit has the following fields:
- Commit hash: A unique identifier for the commit, for example, ad9a337071c5e3d4509559d36128b38a0e5571f1.
- Author: The person who made the commit, for example, Morla Porla.
- Date: The date and time when the commit was made, for example, Thu Jun 20 04:07:12 2024 +0000.
- Commit Message: A brief description of the changes made in the commit, such as “fix info leak”.
As we can see from this commit history, the most recent commit has the message “fix info leak”, suggesting that the previous commit might contain the leaked information. To view the state of the repository before the “fix info leak” commit, we can switch to the previous commit. The git switch
command allows us to switch between different commits or branches in the repository. We can give an abbreviated commit hash to git switch
, saving us from typing the full hash. We also have to specify the –detach option as we are switching to a commit hash rather than a branch:
$ git switch --detach 229f600
HEAD is now at 229f600 add missing data
Note that we could have also used the older git checkout
command to change to the previous commit:
$ git checkout 229f600
Note: switching to '229f600'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 229f600 add missing data
Now let’s reread the README.md file:
$ cat README.md
# Bandit Notes
Some notes for level29 of bandit.
## credentials
- username: bandit29
- password: <password>
Notice that the file contents are now different, revealing the password for bandit29. For this reason, it is important to be aware of the information you push to a public git
repository as changes and previous versions are always saved, potentially leaking sensitive information, such as credentials.
Level 29 - Level 30
In this level, we have another git
repository at ssh://bandit29-git@localhost/home/bandit29-git/repo via port 2220. Our task is to, again, clone the repository and find the password for the next level.
First, let’s create a temporary directory like last time.
$ cd $(mktemp -d)
Now, clone the repository using git
:
$ git clone ssh://bandit29-git@localhost:2220/home/bandit29-git/repo
Cloning into 'repo'...
The authenticity of host '[localhost]:2220 ([127.0.0.1]:2220)' can't be established.
ED25519 key fingerprint is SHA256:C2ihUBV7ihnV1wUXRb4RrEcLfXC5CXlhmAAM/urerLY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Could not create directory '/home/bandit29/.ssh' (Permission denied).
Failed to add the host to the list of known hosts (/home/bandit29/.ssh/known_hosts).
_ _ _ _
| |__ __ _ _ __ __| (_) |_
| '_ \ / _` | '_ \ / _` | | __|
| |_) | (_| | | | | (_| | | |_
|_.__/ \__,_|_| |_|\__,_|_|\__|
This is an OverTheWire game server.
More information on http://www.overthewire.org/wargames
bandit29-git@localhost's password:
remote: Enumerating objects: 16, done.
remote: Counting objects: 100% (16/16), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 16 (delta 2), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (16/16), done.
Resolving deltas: 100% (2/2), done.
Now that we’ve cloned the repo, let’s navigate to it and see what’s inside:
$ cd repo
$ ls -l
total 4
-rw-rw-r-- 1 bandit29 bandit29 131 Jul 1 15:56 README.md
Let’s see what README.md contains this time:
$ cat README.md
# Bandit Notes
Some notes for bandit30 of bandit.
## credentials
- username: bandit30
- password: <no passwords in production!>
Unsurprisingly, the current README.md file does not reveal the password. We can use git log
to view the commit history again, but it shows only two commits, and neither contains the password:
$ git log
commit a442ed81c95fac132590fdd218bd7b831db81fe4 (HEAD -> master, origin/master, origin/HEAD)
Author: Ben Dover [email protected]>
Date: Thu Jun 20 04:07:14 2024 +0000
fix username
commit 046a4d27b46af8f02879c890972d7f125f3ab824
Author: Ben Dover [email protected]>
Date: Thu Jun 20 04:07:14 2024 +0000
initial commit of README.md
The clue “no passwords in production!” in the README.md suggests that the password might be on a development branch. A branch in git
is a movable pointer to a commit. The master branch that we’re currently on is typically used for production code, while development branches are used for ongoing work.
When we clone a repository, we only clone the master branch. Let’s list the remote branches to see if they can help us. We use the -a option here, meaning “all” as otherwise git branch
would only show “master” due to it being the only local branch.
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/master
remotes/origin/sploits-dev
The asterisk (*) indicates the branch we’re currently on. The remote repository (origin) has three branches: dev, master, and sploits-dev. These are all prefixed with “remotes/origin” in this output, indicating they’re remote branches. Given the clue about “no passwords in production”, let’s look at the dev branch.
We’ll use the git switch
command again to change our branch. We’ll have to use the –detach option again because we haven’t got a copy of the branch locally, so git
will switch us to the commit that corresponds to the remote branch:
$ git switch --detach remotes/origin/dev
HEAD is now at 196330c add data needed for development
Now, let’s reread the README.md file:
$ cat README.md
# Bandit Notes
Some notes for bandit30 of bandit.
## credentials
- username: bandit30
- password: <password>
Congratulations on making it through levels 25 - 29 of the Bandit wargame. I hope this post has given you an insight into the power of git
. It’s a topic that we’ll be delving into in future blog posts, so if git
has piqued your interest, do bookmark my website so you can check back and learn more with me.
Thank you for following along with this series. I look forward to seeing you again in the next post where together, we’ll complete the Bandit wargame.