Bandit Complete Walkthrough
- State “DONE” from “TODO”
The Bandit wargame is aimed at absolute beginners. It will teach the basics needed to be able to play other wargames. If you notice something essential is missing or have ideas for new levels, please let us know!
Note for beginners This game, like most other games, is organised in levels. You start at Level 0 and try to “beat” or “finish” it. Finishing a level results in information on how to start the next level. The pages on this website for “Level <X>” contain information on how to start level X from the previous level. E.g. The page for Level 1 has information on how to gain access from Level 0 to Level 1. All levels in this game have a page on this website, and they are all linked to from the sidemenu on the left of this page.
You will encounter many situations in which you have no idea what you are supposed to do. Don’t panic! Don’t give up! The purpose of this game is for you to learn the basics. Part of learning the basics, is reading a lot of new information. If you’ve never used the command line before, a good first read is this introduction to user commands.
There are several things you can try when you are unsure how to continue:
- First, if you know a command, but don’t know how to use it, try the manual (man page) by entering man <command>. For example, man ls to learn about the “ls” command. The “man” command also has a manual, try it! When using man, press q to quit (you can also use / and n and N to search).
- Second, if there is no man page, the command might be a shell built-in. In that case use the “help <X>” command. E.g. help cd
- Also, your favorite search-engine is your friend. Learn how to use it! I recommend Google.
- Lastly, if you are still stuck, you can join us via chat
- You’re ready to start! Begin with Level 0, linked at the left of this page. Good luck!
Note for VMs: You may fail to connect to overthewire.org via SSH with a “broken pipe error” when the network adapter for the VM is configured to use NAT mode. Adding the setting IPQoS throughput to /etc/ssh/ssh_config should resolve the issue. If this does not solve your issue, the only option then is to change the adapter to Bridged mode
- Level 0: ZjLjTmM6FvvyRnrb2rfNWOZOTa6ip5If
- Level 1: 263JGJPfgU6LtdEvgfWU1XP5yac29mFx
- Level 2: MNk8KNH3Usiio41PRUEoDFPqfxLPlSmx
- Level 3: 2WmrDFRmJIq3IPxneAaMGhap0pFhF3NJ
- Level 4:
- The
filecommand gives us the type of data of the file, e.g. ELF which is not human-readable. The most common data encodings that are human-readable areASCIIandUnicode - So we can just do
file ./*do see which file is human-readable and then cat the content giving us the password. - 4oQYVPkxZOOEOO5pTW81FB8j8lxXGUQw
- The
- Level 5 -> 6:
- We are looking for a file that is
human-readable,1033 bytesandnot executable - So we need to use some combination of
file,du,ls - A couple of helpful commands:
du -b -a-> gives us the byte size for all files, we can feed this intogrep 1033to get all files with the bytesize of 1033
find . -type f -size 1033c ! -executable -exec file '{}' \; | grep ASCII- find all files
- with size 1033
- which are non-executable
exec file '{}'executes the file command to get the file type for all results - we then filter usinggrep ASCII
- HWasnPhtq9AVKe0dmk45nxy20cvUa6EG
- We are looking for a file that is
- Level 6 -> 7
- find has flags for -user and -group
find / -type f -user bandit7 -group bandit6 -size 33c 2>/dev/null- morbNTDkSW6jIlUc0ymOdMaLnOlFVAaj
- Level 7 -> 8
- dfwvzFQi4mU0wfNbFOe9RoWskMLg7eEc
- Level 8 -> 9
sort data.txt | uniq -u- 4CKMh1JI91bUIZZPXDqGanal4xvAg0JM
- Level 9 -> 10
strings data.txt | grep =- FGUW5ilLVJrxX9kMYMmlN4MgbpfMiqey
- Level 10 -> 11
base64 -d data.txt- dtR173fZKb0RRsDFSGsg2RWnpNVj3qRr
- Level 11 -> 12
cat data.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m'- 7x16WNeHIi5YkIhWsfFIqoognUTyj9Q4
- Level 12 -> 13
- The password for the next level is stored in the file data.txt, which is a hexdump of a file that has been repeatedly compressed.
- First we need to reverse hexdump
xxd -r data.txt - Then look at the first hex values, e.g.
1f 8bwhich is a gzip compressed file. renamemv data.txt data.gz, unzip and proceed usinggzip -d,bzip -dandtar -xvfuntil human-readable file. - FO5dwFsc0cbaIiH0h8J2eUks2vdTDwAn
- Level 13 -> 14
- The password for the next level is stored in
/etc/bandit_pass/bandit14and can only be read by user bandit14. For this level, you don’t get the next password, but you get a private SSH key that can be used to log into the next level. Note: localhost is a hostname that refers to the machine you are working on - MU4VWeTyJk8ROof1qqmcBPaLh7lDCPvS
- The password for the next level is stored in
- Level 14 -> 15
- The password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost.
echo 'password' | nc localhost 30000- 8xCjnmgoKbGLhHFAZlGE5Tmu4M2tKJQo
- Level 15 -> 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/TLS encryption.
echo 'password' | ncat --ssl localhost 30001- kSkvUpMQ7lBYyCM4GBPvCvT1BfWRy0Dx
- Level 16 -> 17
- The credentials for the next level can be retrieved by submitting the password of the current level to a port on localhost in the range 31000 to 32000. First find out which of these ports have a server listening on them. Then find out which of those speak SSL/TLS and which don’t. There is only 1 server that will give the next credentials, the others will simply send back to you whatever you send to it.
- Scan open ports
nmap -p 31000-32000 localhost - Find out which ports run ssl:
nmap -p 31000-32000 -sV localhost - Try the ports via
echo 'password' | ncat --ssl localhost 31790 - Correct -> ssh creds
- Level 17 -> 18
- There are 2 files in the homedirectory: passwords.old and passwords.new. 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
- find the password via
diff password.old password.new - x2gLTTjFwMOhQ8oWNbMN362QKxfRqGlO
- Level 18 -> 19
- 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.
- so we get logged out immediately - let’s then use ssh to run a command before logging out:
sudo ssh -i bandit17 bandit17@bandit.labs.overtheiwre.org "cat readme" - cGWpMaKXVwDUNgPAVJbWYuGHVn9zl3j8
- Level 19 -> 20
- Read the bandit20 pass by using the setuid binary
- 0qXahG8ZjOVMN9Ghs7iOWsCfZyXOUbYO
- Level 20 -> 21
- 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).
- First, we need to serve the password on a specific port; we can do so via netcat:
echo 'password' | nc -l -p1234 &. The&sign puts the command in the puts the command in the background. (we can also use ‘CTRL + Z’ and bg) - Then we can connect to the port using the binary given
- EeoULMCra2q0dSkYj561DX7s1CpBuOBt
- Level 21 -> 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.
- Check cronjob under
/etc/cron.d/cronjob_bandit22 - Then check the contents under
/usr/bin/cronjob_bandit22.sh - tRae0UfB9v0UzbCdn9cY0gQnds9GF58Q
- Level 22 -> 23
- Check
/usr/bin/cronjob_bandit23.sh - It runs a bash script copying the pass to an unknown temp folder. But (!) the tmp folder gets created by md5sum’ming the user name. We can copy the bash script and hardcode bandit23 instead of ‘whoami’.
- 0Zf11ioIjMVN551jX3CmStKLYqjk54Ga
- Check
- Level 23 -> 24
- 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. NOTE: this will require you to write your own shell script. - check the cronjob under
/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 - The script will execute all scripts in the folder
/var/spool/bandit24/foo/. So what we should do is place a file in the folder above that copies the password to a folder of our choosing. - First, create a hard-to-guess temporary folder via
mktemp -d, then cd into itcd /tmp/tmp.QA8mBfFz1D. - Create a bash script that copies the password from bandit24 into a file that we created in the tmp folder.
!#/bin/bash cat /etc/bandit_pass/bandit24 >> /tmp/tmp.QA8mBfFz1D/bandit24_pw - This should read the password from the file and print it to the file specified in our script.
- gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8
- A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in
- Level 24 -> 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 combinations, called brute-forcing.
- Let’s see what is happening on port 30002:
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. gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8 0000 Wrong! Please enter the correct current password and pincode. Try again. gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8 0001 Wrong! Please enter the correct current password and pincode. Try again. gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8 0002 Wrong! Please enter the correct current password and pincode. Try again. - Okay, so netcat shows us that there is a daemon asking for the current password and a numerical pin and gives back a reply. We can repeat this process numerous times without closing the connection. So the following steps should be done to find the pin via bruteforce:
- Create a temporary folder
mktemp -d. Cd into the folder created - Create a script file and make it executable
bandit24@bandit:/tmp/tmp.5XoBXIIkjm$ touch brute_force bandit24@bandit:/tmp/tmp.5XoBXIIkjm$ chmod +x brute_force - Create a list of all 9999 combinations of password and pin
#!/bin/bash password=gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8 for i in ${seq -w 0 9999}; do echo "$password $i" >> combinations done - Feed this list to netcat
cat ./combinations | nc localhost 30002 .. .. Wrong! Please enter the correct current password and pincode. Try again. Correct! The password of user bandit25 is /redacted/
- Create a temporary folder
- iCi86ttT4KSNe1armKiwbQNmB3YJP3q4
- Level 25 -> 26
- 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.
- The user shell can be found in
/etc/passwd; so we can find out the user shell viacat /etc/passwd | grep bandit26. It shows that it is something called/usr/bin/showtext. - The content of this file is as follows:So the file executes
bandit25@bandit:~$ cat /usr/bin/showtext #!/bin/sh export TERM=linux exec more ~/text.txt exit 0morewith text file. A quick look at the manual formoregives us this:MORE(1) User Commands MORE(1) NAME more - display the contents of a file in a terminal SYNOPSIS more [options] file ... DESCRIPTION more is a filter for paging through text one screenful at a time. This version is especially primitive. Users should realize that less(1) provides more(1) emulation plus extensive enhancements. - Next check the
homefolder of user bandit25: it handily contains a ssh key for bandit26. However, when we use this key to ssh into the server as user bandit26, the shell gets dropped immediately. It seems the text.txt file is too short to get us intomoreinteractively - what can be done? Simple: just make the terminal window that you use for ssh smaller so thatmoreenters interactive mode! We can then hitvto move intovimand gain a shell or read the password:- Read the password:
:e /etc/bandit_pass/bandit26 - Gain a shell: We can set a different shell for vim
:set shell=/bin/bashand then use:shellfor executing a bandit26 shell.
- Read the password:
- s0773xxkk0MXfdqOfPRVr9L3jJBUOgCZ
- Level 26 -> 27
- Good job getting a shell! Now hurry and grab the password for bandit27!
- When in the home folder of user bandit26, we see a file called
/bandit27-do. We already know this type of file, it serves to run a command as another user, so a simple./bandit27-do cat /etc/bandit_pass/bandit27will give us the next password. - upsNCc7vzaRDx6oZC6GiR6ERwe1MowGB
- Level 27 -> 28
- There is a git repository at ssh://bandit27-git@localhost/home/bandit27-git/repo via the port 2220. The password for the user bandit27-git is the same as for the user bandit27.
- Okay, this is about cloning a git repo locally. First, create a temporary folder via
mktemp -dandcdinto it. Then usegit clone ssh://bandit27-git@localhost:2220/home/bandit27.git/repoand cd into the downloaded repo. There is a file calledREADMEwhich contains the password. - Yz9IpL0sBcCeuG7m9uQFt8ZNpS4HZRcN
- Level 28 -> 29
- There is a git repository at ssh://bandit28-git@localhost/home/bandit28-git/repo via the port 2220. The password for the user bandit28-git is the same as for the user bandit28.
- Okay, this seems like the same exercise as the previous level. However, when we clone the repo as before, we see that the
README.mdfile only contains the user and the password is redactedHowever, this is a git repo, remember?# Bandit Notes Some notes for level29 of bandit. ## credentials - username: bandit29 - password: xxxxxxxxxx - So let’s snoop around a bit:
git log --oneline --graph --decorate --allAh, that is interesting, we see that there was an info leak which has been fixed in the latest release. So let’s checkout a prior release:* 817e303 (HEAD -> master, origin/master, origin/HEAD) fix info leak * 3621de8 add missing data * * 0622b73 initial commit of README.mdgit checkout 3621de8. - Now if we check
README.md, we find the password. - 4pT1t5DENaYuqnqvadYs1oE4QLCdjmJ7
- Level 29 -> 30
- There is a git repository at ssh://bandit29-git@localhost/home/bandit29-git/repo via the port 2220. The password for the user bandit29-git is the same as for the user bandit29.
- Proceed as in the previous levels:So it says no passwords in production. Looking at the graph for
bandit29@bandit:/tmp/tmp.tVMV0827cM/repo$ cat README.md # Bandit Notes Some notes for bandit30 of bandit. ## credentials - username: bandit30 - password: <no passwords in production!>git log --oneline --graph --decorate --allwe see that there is a development branch:bandit29@bandit:/tmp/tmp.tVMV0827cM/repo$ git log --oneline --graph --decorate --all * 081ac38 (origin/dev) add data needed for development * 03aa12c add gif2ascii | * 7226732 (origin/sploits-dev) add some silly exploit, just for shit and giggles |/ * 6ac7796 (HEAD -> master, origin/master, origin/HEAD) fix username * e65a928 initial commit of README.md - Checkout one of the development branches:
git checkout 081ac38et voila, theREADME.mdfile contains a password. - qp30ex3VLz5MDG1n91YowTv4Q8l7CDZL
- Level 30 -> 31
- Start the same way as in the exercises before by making a tmp directory and cd’ing into it. Then clone the repo.
- Checking the file, we only see an empty file. The git history does not show any other commits, so no luck there. So we need to look somewhere else.
- In comes
git tag. This usually serves to tag important releases (v1.0/2.0) etc. When we rungit taghere, we seeAh! We see that there is a tag called ‘secret’ - could be interesting! So let’s look at it by usingbandit30@bandit:/tmp/tmp.oN0GdVHuQ6/repo$ git tag secret bandit30@bandit:/tmp/tmp.oN0GdVHuQ6/repo$ git show secretgit show secretand find our password! - fb5S2xb7bRyFmAvQYQGEqsbhVyJqhnDy
- Level 31 -> 32
- There is a git repository at ssh://bandit31-git@localhost/home/bandit31-git/repo via the port 2220. The password for the user bandit31-git is the same as for the user bandit31.
- Looking at the
README.md, we see that we need to push a file to the remote repo to find out the password.bandit31@bandit:/tmp/tmp.cLzwKk9FvU/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 - So, first we need to create the file
touch key.txt, then use a text editor orecho 'May I come in?' > key.txt. - When we try to add the file to git, we see that it is ignored via .gitignore:Luckily, git itself already gives us the necessary tools to add the file anyway using the
bandit31@bandit:/tmp/tmp.cLzwKk9FvU/repo$ git add key.txt The following paths are ignored by one of your .gitignore files: key.txt hint: Use -f if you really want to add them. hint: Turn this message off by running hint: "git config advice.addIgnoredFile false"-fflag. - We then
git commit -m 'Bandit Level 31'and push the repo to the remote:bandit31@bandit:/tmp/tmp.cLzwKk9FvU/repo$ git commit -m 'Bandit Level 31' [master 665c836] Bandit Level 31 1 file changed, 1 insertion(+) create mode 100644 key.txt bandit31@bandit:/tmp/tmp.cLzwKk9FvU/repo$ git push -u origin master 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/bandit31/.ssh' (Permission denied). Failed to add the host to the list of known hosts (/home/bandit31/.ssh/known_hosts). _ _ _ _ bandit31-git@localhost's password: Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 2 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 326 bytes | 326.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0), pack-reused 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: /redacted/ remote: remote: .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo. remote: To ssh://localhost:2220/home/bandit31-git/repo - 3O9RfhqyAlVBEZpVb6LYStshZoqoSx5K
- Level 32 -> 33
- After all this git stuff, it’s time for another escape. Good luck!
- We get dropped into a “UPPERCASE” shell. And true enough: once we drop to the shell, we see that everything we type in gets translated to uppercases and we have no permission to run those. So, we need to think about things that are already uppercase in linux. And these are VARIABLES like
$SHELL,$HOME,$0etc. - Trying some of these variables we do at least see that we get the results back for them.However, we still are not allowed to run any of these variables/results (and running them would make no sense in most cases anyhow), so we need to think of sth. else. In comes
Welcome TO THE UPPERCASE SHELL >> SHELL sh: 1: SHELL: Permission denied >> $SHELL WELCOME TO THE UPPERCASE SHELL >> $TERM sh: 1: xterm-256color: Permission denied >> $HOME sh: 1: /home/bandit32: Permission denied >> $PWD sh: 1: /home/bandit32: Permission denied$0which is the path of the current running program. And voila: if we run $0, we get dropped out of the shell.A quick>> $0 $ $0 $ ls -la total 36 drwxr-xr-x 2 root root 4096 Sep 19 07:08 . drwxr-xr-x 70 root root 4096 Sep 19 07:09 .. -rw-r--r-- 1 root root 220 Mar 31 2024 .bash_logout -rw-r--r-- 1 root root 3771 Mar 31 2024 .bashrc -rw-r--r-- 1 root root 807 Mar 31 2024 .profile -rwsr-x--- 1 bandit33 bandit32 15136 Sep 19 07:08 uppershellls -lashows us the files, which are not very promising right now. But wait: we see that theuppershellscript is actually run by the user bandit33. So maybe we are already bandit33?$ whoami bandit33 $ cat /etc/bandit_pass/bandit33 - tQdtbs5D5i2vJwkO8mEyYEyTL8izoeJ0
- Level 33
- And it seems we are done - for now:
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 it seems we are done - for now: