Code in public

OverTheWire - Bandit

Computer security is something I have always been interested in, but I have never really invested much time into it. So after some poking around online, OverTheWire came up in my searches as a good capture the flag style site to learn and practice some security concepts.

The Bandit CTF is the easiest option, so I started there. Each of the 33 levels covered a different topic:

  • level 0 covered basic ssh access.
  • level 1 → 4 required some basic handling of files with different names and properties. This included using the file command.
  • level 5 → 6 cover the use of the find command to locate specific files
  • level 7 → 9 required some grep, sort and uniq commands to manipulate the contexts of some text data.
  • level 10 → 12 covered base64 and rot13 encoding and decrypting these.
  • level 13 deals with different kinds of compression and decompressing the provided data.
  • level 14 → 17 start to feel like real hacking, with data needing to be sent to services running on different ports. This needed netcat, openssl and nmap.
  • level 18 → 19 involve some file handling locally and remote
  • level 20 → 33 have less of a set theme and often require a couple of different tricks, with some being pretty challenging.

Things really start to feel like 'real hacking' at around level 23!

Overall this was a lot of fun to play with and I definitely plan to play around with more of the OverTheWire games.

Details on each of the levels and write up on how I went about tackling it is provided below. NOTE: THIS CONTAINS SPOILERS!

For each level, the login username is bandit<level number> and the host stays the same.

Level 0

Level Goal

We are given the following information

  • host: bandit.labs.overthewire.org
  • port: 2220
  • username: bandit0
  • password: bandit0

The instruction say to log into the host using SSH and the information provided

Solution

This simply involved logging into the host bandit.labs.overthewire.org on port 2220 with user and password bandit0, using this command:

ssh bandit0@bandit.labs.overthewire.org -p 2220

entering the provide password bandit0 when prompted.

This got me into the host and produced a very rewarding motd with some useful information. It also had some advise around using the mktemp command to generate a random directory under tmp, which I hadn't used before but I wish I had known about.

Level 0 → 1

Level Goal

We are told that the password is stored in readme file located in the home directory

Solution

Getting the flag involved finding the readme file and outputting its contents:

bandit0@bandit:~$ ls
readme
bandit0@bandit:~$ cat readme
NH2SXQwcBdpmTEzi3bvBHMM9H66vVXjL

Level 1 → 2

Level Goal

This is similar to the previous level, but the filename containing the flag is -

Solution

This took some researching to figure out how to handle dashed filenames:

bandit0@bandit:~$ ls
-
bandit0@bandit:~$ cat ./-
rRGizSaX8Mk1RTb1CNQoXTcYZWU6lgzi

Running cat - directly seems to have the same effect as just running cat, which it accepts input and then just echos it. Apparently using a - as filename is typically used to mean stdin/stdout.

Level 2 → 3

Level Goal

Like the two prior levels, the flag is contained in a file, this time the filename contains spaces.

Solution

This one was easier than the prior level in that using tab completion provided correct command, which uses \ characters before each space

bandit2@bandit:~$ cat spaces\ in\ this\ filename
aBZ0W5EmUfAf7kHTQeOwd8bauFJ2lAiG

Level 3 → 4

Level Goal

We are told that the flag is stored in the inhere directory.

Solution

At first the file appears to be missing, but it is prefixed with a ., making it a hidden file.

bandit3@bandit:~$ ls
inhere
bandit3@bandit:~$ cd inhere/
bandit3@bandit:~/inhere$ ls
bandit3@bandit:~/inhere$ ls -a
.  ..  .hidden
bandit3@bandit:~/inhere$ cat .hidden
2EW7BBsr6aMMoJ2HjW067dm8EgX26xNe

Level 4 → 5

Level Goal

The clue is more cryptic than previous levels, we are told that the flag is stored in the only human-readable file in the inhere directory.

Solution

Using the trick learned from level 1 to handle dashed files, you are able to run the file command with a wildcard to give you hint about which file contains the human-readable content:

bandit4@bandit:~/inhere$ file ./-file0*
./-file00: data
./-file01: data
./-file02: data
./-file03: data
./-file04: data
./-file05: data
./-file06: data
./-file07: ASCII text
./-file08: data
./-file09: Non-ISO extended-ASCII text, with no line terminators
bandit4@bandit:~/inhere$ cat ./-file07
lrIWWI6bB37kxfiCQZqUdOIYfr6eEeqR

Level 5 → 6

Level Goal

We are told the flag file is somewhere in the inhere directory, and it has the follow properties:

  • human-readable
  • 1033 bytes in size
  • not executable

Solution

For this, I used find with a test on the file size:

bandit5@bandit:~/inhere$ find ./ -size 1033c -printf '%p %s\n'
./maybehere07/.file2 1033
bandit5@bandit:~/inhere$ cat ./maybehere07/.file2
P4L4vucdmLnm8I7Vl7jG1ApGSfjYKqJU

Level 6 → 7

Level Goal

Similar to the previous level, but with a lot more files to consider. We are told that the file is somewhere on the server and has the following attributes:

  • owned by user bandit7
  • owned by group bandit6
  • 33 bytes in size

Solution

We use the find command to search / with the specified size and group tests. This results in two possible flag files, but checking the file details shows only one is owned by bandit7:

bandit6@bandit:~$ find / -size 33c -group bandit6 2>/dev/null
/var/lib/dpkg/info/bandit7.password
/etc/bandit_pass/bandit6
bandit6@bandit:~$ ls -l /var/lib/dpkg/info/bandit7.password
-rw-r----- 1 bandit7 bandit6 33 Apr 23 18:04 /var/lib/dpkg/info/bandit7.password
bandit6@bandit:~$ ls -l /etc/bandit_pass/bandit6
-r-------- 1 bandit6 bandit6 33 Apr 23 18:04 /etc/bandit_pass/bandit6
bandit6@bandit:~$ cat /var/lib/dpkg/info/bandit7.password
z7WtoNQU2XfjmMtWA8u5rN4vzqu4v99S

Level 7 → 8

Level Goal

For this we are given a data.txt file and told the flag is next to the word millionth

Solution

For this we use grep to search for the line we are looking for:

bandit7@bandit:~$ grep millionth data.txt
millionth	TESKZC0XvTetK0S9xNwm25STk5iWrBvP

Level 8 → 9

Level Goal

Given data.txt, we have to find the one unique line in the file.

Solution

We can use uniq command to find the unique lines. Something to note, which is mentioned in the man page, is that file needs be sorted first in order to detect repeated lines.

bandit8@bandit:~$ cat data.txt | sort | uniq -u
EN632PlfYiZbn3PhVK3XOGSlNInNE00t

Level 9 → 10

Level Goal

The flag is somewhere in the data.txt file, which contains mostly non human-readable strings, and is preceded by several '=' characters.

Solution

Using grep and some regex worked here:

grep -a -o "===\s\w*" data.txt

Level 10 → 11

Level Goal

The data.txt file is base64 encoded and contains the flag

Solution

bandit10@bandit:~$ base64 -d data.txt
The password is 6zPeziLdR2RKNdNYFNb6nVCKzphlXHBM

Level 11 → 12

Level Goal

The data.txt file is rot13 encrypted and contains the flag

Solution

Using the tr command, you undo the rotation:

bandit11@bandit:~$ cat data.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m'
The password is JVNBBFSmZwKKOP0XbFXOoW8chDz5yVRv

Level 12 → 13

Level Goal

We are provided the data.txt file which contains a hexdump that has been repeatedly compressed.

Solution

I started by having a look what the file contains using the file command and then outputting the contents:

bandit12@bandit:~$ ls
data.txt
bandit12@bandit:~$ file data.txt
data.txt: ASCII text
bandit12@bandit:~$ cat data.txt
00000000: 1f8b 0808 2773 4564 0203 6461 7461 322e  ....'sEd..data2.
00000010: 6269 6e00 0145 02ba fd42 5a68 3931 4159  bin..E...BZh91AY
00000020: 2653 597b 4f96 5f00 0018 ffff fd6f e7ed  &SY{O._......o..
00000030: bff7 bef7 9fdb d7ca ffbf edff 8ded dfd7  ................
00000040: bfe7 bbff bfdb fbff ffbf ff9f b001 3b56  ..............;V
00000050: 0400 0068 0064 3400 d341 a000 0680 0699  ...h.d4..A......
00000060: 0000 69a0 0000 1a00 1a0d 0034 0034 d3d4  ..i........4.4..
00000070: d1a3 d464 6834 6403 d469 b422 0d00 3400  ...dh4d..i."..4.
00000080: 1a68 068d 3403 4d06 8d00 0c80 00f5 0003  .h..4.M.........
00000090: 4031 3119 00d0 1a68 1a34 c86d 4640 00d0  @11....h.4.mF@..
000000a0: 0007 a80d 000d 00e9 a340 d034 0341 a000  .........@.4.A..
000000b0: 0699 07a9 881e a0d0 da80 6834 0c43 4068  ..........h4.C@h
000000c0: 6432 0340 0c80 6800 0346 8006 8000 d034  d2.@..h..F.....4
000000d0: 0001 f0e1 810e 1958 b7a4 92c7 640e 421a  .......X....d.B.
000000e0: a147 6142 a67e 3603 a756 3ba9 1b08 e034  .GaB.~6..V;....4
000000f0: 41fd 1247 661d b380 00b7 cd8c b23e b6b2  A..Gf........>..
00000100: 1947 e803 0be5 6077 a542 e9ea 7810 29f0  .G....`w.B..x.).
00000110: 429d e1d7 ad8b 0b78 056b e37c 06df 4917  B......x.k.|..I.
00000120: 9b46 f69d 4473 80b4 edc2 ee10 04e3 3e52  .F..Ds........>R
00000130: dd34 2244 08cb 5e64 9314 9521 505e e767  .4"D..^d...!P^.g
00000140: 9021 d029 85e7 9ce2 d1ce d44f 5ec5 f6d6  .!.).......O^...
00000150: d918 de31 f1f5 d149 4695 0937 d06b f046  ...1...IF..7.k.F
00000160: 789d 1bd0 ca69 11eb 2c9a 3290 3d9e 0511  x....i..,.2.=...
00000170: 6cad 205b edc8 c4b5 4691 379a 5978 58c3  l. [....F.7.YxX.
00000180: 4846 a4a0 3ba5 a89a a794 1f93 c588 8160  HF..;..........`
00000190: 016e 2504 2c74 643b 5046 4154 751c 33b1  .n%.,td;PFATu.3.
000001a0: c3e5 53d8 a959 5fdc 6c12 f2bd 02f3 2d83  ..S..Y_.l.....-.
000001b0: b965 3188 0d3c b097 4156 e950 9d49 64f6  .e1..<..AV.P.Id.
000001c0: da4a 2db5 a4ea 5365 27c0 1e79 8109 5f31  .J-...Se'..y.._1
000001d0: c184 46c9 74a5 f923 5ea1 6861 f058 226c  ..F.t..#^.ha.X"l
000001e0: 3df6 5d10 d11f d966 77c9 e488 448c 5a6f  =.]....fw...D.Zo
000001f0: 2c10 410b 4280 140a 0818 8afa 0cfa 8bf7  ,.A.B...........
00000200: ad34 3308 4077 6552 9849 378e 7d85 1fd8  .43.@weR.I7.}...
00000210: f287 1238 7639 11e2 f1e6 483b 7548 25e2  ...8v9....H;uH%.
00000220: 7de4 24ff 1a69 0b85 4b4c ebd0 1231 a512  }.$..i..KL...1..
00000230: f9fb 109c e7ea d932 98fd eb76 f4f8 fa29  .......2...v...)
00000240: 967c e152 9c69 c607 6207 eaef 2095 9441  .|.R.i..b... ..A
00000250: a64e 9ffc 5dc9 14e1 4241 ed3e 597c 9f2e  .N..]...BA.>Y|..
00000260: f0c8 4502 0000                           ..E...
bandit12@bandit:~$

In order to restore the file from the hexdump, we use the xxd command. This produced a gzip file.

bandit12@bandit:/tmp/tmp.8Ys1Tohzei$ xxd -r data.txt data_file
bandit12@bandit:/tmp/tmp.8Ys1Tohzei$ file data_file
data_file: gzip compressed data, was "data2.bin", last modified: Sun Apr 23 18:04:23 2023, max compression, from Unix, original size modulo 2^32 581

Unzipping this file resulted in another compressed file. At each iteration, I inspected the file using the file command, then renamed the file to include the correct suffix. When running the decompress commands, I used the keep flag so the original archive wasn't removed. This pattern of decompressing repeated for a number of different types of compression:

bandit12@bandit:/tmp/tmp.8Ys1Tohzei$ ls -l
total 72
-rw-rw-r-- 1 bandit12 bandit12   614 May 28 06:11 data1.gz
-rw-rw-r-- 1 bandit12 bandit12   581 May 28 06:11 data2.bzip
-rw-rw-r-- 1 bandit12 bandit12   438 May 28 06:11 data3.gz
-rw-rw-r-- 1 bandit12 bandit12 20480 May 28 06:11 data4.tar
-rw-r--r-- 1 bandit12 bandit12 10240 Apr 23 18:04 data5.tar
-rw-r--r-- 1 bandit12 bandit12   220 Apr 23 18:04 data6.bzip
-rw-r--r-- 1 bandit12 bandit12 10240 Apr 23 18:04 data7.tar
-rw-r--r-- 1 bandit12 bandit12    79 Apr 23 18:04 data8.gz
-rw-r--r-- 1 bandit12 bandit12    49 Apr 23 18:04 data9.txt
-rw-r----- 1 bandit12 bandit12  2642 May 28 05:56 data.txt
bandit12@bandit:/tmp/tmp.8Ys1Tohzei$ cat data9.txt
The password is wbWdlBxEir4CaE8LaPhauuOo6pwRmrDw
bandit12@bandit:/tmp/tmp.8Ys1Tohzei$

Level 13 → 14

Level Goal

For this level you are provided with an ssh private key for the bandit14 user. We are also told that the level 14 flag is stored in /etc/bandit_pass/bandit14 and can only be read by user bandit14.

Solution

The ssh key file can provided to the ssh command with the -i flag:

bandit13@bandit:~$ ls
sshkey.private
bandit13@bandit:~$ ssh -i sshkey.private bandit14@localhost -p 2220

Once logged in as bandit14 we are able to access the flag:

bandit14@bandit:~$ cat /etc/bandit_pass/bandit14
fGrHPx402xGC7U7rXKDaxiWFTOiF0ENq

Level 14 → 15

Level Goal

This level requires the flag from the previous level to be passed to a service running on port 30000.

Solution

By running netcat against localhost and port 30000, you can open a connection and paste the flag from the previous level:

bandit14@bandit:~$ nc localhost 30000
fGrHPx402xGC7U7rXKDaxiWFTOiF0ENq
Correct!
jN2kgmIXJ6fShzhT2avhotn4Zcka6tnt

Level 15 → 16

Level Goal

This level requires the flag from the previous level to be passed to a service running on port 30001 using SSL

Solution

An SSL connection can be established using the openssl command, which you can then paste in the flag to get the next flag:

bandit15@bandit:~$ openssl s_client -connect localhost:30001
....
....
jN2kgmIXJ6fShzhT2avhotn4Zcka6tnt
Correct!
JQttfApK4SeyHwDlI9SXGR50qclOAil1

closed

Level 16 → 17

Level Goal

The goal is identify an SSL service which is listening in the range of 31000 and 32000, that accepts the previous flag and return the next one.

Solution

Firstly finding the possible services in the given port range was done using nmap with a port range.

bandit16@bandit:~$ nmap -v -p 31000-32000 localhost
Starting Nmap 7.80 ( https://nmap.org ) at 2023-05-28 07:25 UTC
Initiating Ping Scan at 07:25
Scanning localhost (127.0.0.1) [2 ports]
Completed Ping Scan at 07:25, 0.00s elapsed (1 total hosts)
Initiating Connect Scan at 07:25
Scanning localhost (127.0.0.1) [1001 ports]
Discovered open port 31960/tcp on 127.0.0.1
Discovered open port 31518/tcp on 127.0.0.1
Discovered open port 31691/tcp on 127.0.0.1
Discovered open port 31790/tcp on 127.0.0.1
Discovered open port 31046/tcp on 127.0.0.1
Completed Connect Scan at 07:25, 0.04s elapsed (1001 total ports)
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00013s latency).
Not shown: 996 closed ports
PORT      STATE SERVICE
31046/tcp open  unknown
31518/tcp open  unknown
31691/tcp open  unknown
31790/tcp open  unknown
31960/tcp open  unknown

Unfortunately this didn't provide much information about the services which were detected. Running this again with the version detection provided more useful information:

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.08 seconds
bandit16@bandit:~$ nmap -sV -v -p 31000-32000 localhost
Starting Nmap 7.80 ( https://nmap.org ) at 2023-05-28 07:27 UTC
NSE: Loaded 45 scripts for scanning.
Initiating Ping Scan at 07:27
Scanning localhost (127.0.0.1) [2 ports]
Completed Ping Scan at 07:27, 0.00s elapsed (1 total hosts)
Initiating Connect Scan at 07:27
Scanning localhost (127.0.0.1) [1001 ports]
Discovered open port 31046/tcp on 127.0.0.1
Discovered open port 31691/tcp on 127.0.0.1
Discovered open port 31518/tcp on 127.0.0.1
Discovered open port 31960/tcp on 127.0.0.1
Discovered open port 31790/tcp on 127.0.0.1
Completed Connect Scan at 07:27, 0.02s elapsed (1001 total ports)
Initiating Service scan at 07:27
Scanning 5 services on localhost (127.0.0.1)
Service scan Timing: About 20.00% done; ETC: 07:30 (0:02:44 remaining)
Completed Service scan at 07:29, 97.74s elapsed (5 services on 1 host)
NSE: Script scanning 127.0.0.1.
Initiating NSE at 07:29
Completed NSE at 07:29, 0.01s elapsed
Initiating NSE at 07:29
Completed NSE at 07:29, 0.01s elapsed
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00010s latency).
Not shown: 996 closed ports
PORT      STATE SERVICE     VERSION
31046/tcp open  echo
31518/tcp open  ssl/echo
31691/tcp open  echo
31790/tcp open  ssl/unknown
31960/tcp open  echo
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port31790-TCP:V=7.80%T=SSL%I=7%D=5/28%Time=6473026D%P=x86_64-pc-linux-g
SF:nu%r(GenericLines,31,"Wrong!\x20Please\x20enter\x20the\x20correct\x20cu
SF:rrent\x20password\n")%r(GetRequest,31,"Wrong!\x20Please\x20enter\x20the
SF:\x20correct\x20current\x20password\n")%r(HTTPOptions,31,"Wrong!\x20Plea
SF:se\x20enter\x20the\x20correct\x20current\x20password\n")%r(RTSPRequest,
SF:31,"Wrong!\x20Please\x20enter\x20the\x20correct\x20current\x20password\
SF:n")%r(Help,31,"Wrong!\x20Please\x20enter\x20the\x20correct\x20current\x
SF:20password\n")%r(SSLSessionReq,31,"Wrong!\x20Please\x20enter\x20the\x20
SF:correct\x20current\x20password\n")%r(TerminalServerCookie,31,"Wrong!\x2
SF:0Please\x20enter\x20the\x20correct\x20current\x20password\n")%r(TLSSess
SF:ionReq,31,"Wrong!\x20Please\x20enter\x20the\x20correct\x20current\x20pa
SF:ssword\n")%r(Kerberos,31,"Wrong!\x20Please\x20enter\x20the\x20correct\x
SF:20current\x20password\n")%r(FourOhFourRequest,31,"Wrong!\x20Please\x20e
SF:nter\x20the\x20correct\x20current\x20password\n")%r(LPDString,31,"Wrong
SF:!\x20Please\x20enter\x20the\x20correct\x20current\x20password\n")%r(LDA
SF:PSearchReq,31,"Wrong!\x20Please\x20enter\x20the\x20correct\x20current\x
SF:20password\n")%r(SIPOptions,31,"Wrong!\x20Please\x20enter\x20the\x20cor
SF:rect\x20current\x20password\n");

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 98.16 seconds
bandit16@bandit:~$

This output shows 2 ssl services, with an unknown service on port 31790. We can connect to the this service using the following command:

$ openssl s_client -connect localhost:31790
    │       │        │        │       │
    │       │        │        │       └ Target port number to connect to.
    │       │        │        └ Target host to connect to.
    │       │        └ Specifies that we are connecting to another host.
    │       └ Use the SSL client. See https://linux.die.net/man/1/s_client.
    └─ openssl command line tool. See https://linux.die.net/man/1/openssl.

After connecting using openssl, we could provide the previous flag and get the next flag:

bandit16@bandit:~$ openssl s_client -connect localhost:31790
CONNECTED(00000003)
Can't use SSL_get_servername
depth=0 CN = localhost
verify error:num=18:self-signed certificate
verify return:1
depth=0 CN = localhost
verify error:num=10:certificate has expired
notAfter=May 25 14:09:04 2023 GMT
verify return:1
depth=0 CN = localhost
notAfter=May 25 14:09:04 2023 GMT
verify return:1
---
Certificate chain
 0 s:CN = localhost
   i:CN = localhost
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA1
   v:NotBefore: May 25 14:08:04 2023 GMT; NotAfter: May 25 14:09:04 2023 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDCzCCAfOgAwIBAgIEYAl7PTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls
b2NhbGhvc3QwHhcNMjMwNTI1MTQwODA0WhcNMjMwNTI1MTQwOTA0WjAUMRIwEAYD
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDg
IGUha7KV/lFMUBBJCEtUxxDGXrpOi30oN8DoRGhyyzhy9z8idZTdKqQjfUeVg1ou
kVkUTMeMdAAEiW6ulI46JqDybZkBXEN39LXTHwi6iMWkrgxM/eErfHgb6T5juKlA
CXDNuM1E3L1gmEKhu3estoCHVU811JgwVbX4GR3wZkm17TERALNEoLIRxONZqyVd
+KGENHCXDtZCYCp03ygl14Z24Qd7CfiwLTuaGj962Zx68/XiwVgfX4sDbPLu5/Yf
rqymsh29cKSKqDvdv/ZqBukNzDLnpkmSiv9xJJLT2Yy6wZk/ZN5k526MJ76FUAy3
bTi/ve4wVtWlxIYTGR0BAgMBAAGjZTBjMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDBL
BglghkgBhvhCAQ0EPhY8QXV0b21hdGljYWxseSBnZW5lcmF0ZWQgYnkgTmNhdC4g
U2VlIGh0dHBzOi8vbm1hcC5vcmcvbmNhdC8uMA0GCSqGSIb3DQEBBQUAA4IBAQAV
4ayu1YssdPlnSE/kBSxH1XJSM+30PxPUamo9AkmJ23v/c/rlXeAbM1rPHe2gXtro
jxOtkBY/cYK4okPtxVpfpIAmXxE18UGvv7UtmE1J4wLrAliFDAHWRB5rUYRHtbPL
v7bk7gb+/7r2R6hhr4laq3013vVpfTN/VBzL3gSIHTm4IuoukrKg0i320v8pqJdA
AmH3BWouNr0Wxd70Y2fo1Wezq6pzBfXnBDkhLbIn14DFMkibu87nKCEsYkRdsVkH
fxLimiO+gNOXeUVDKZ6mQN3AMgADiM37AXijqDXq+C3bDP80iBkNq3viYCVFwSeA
kAEXLmJFhK6G4vlqwWmu
-----END CERTIFICATE-----
subject=CN = localhost
issuer=CN = localhost
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1339 bytes and written 373 bytes
Verification error: certificate has expired
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 10 (certificate has expired)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: BCA1BB621BECC6981FE04CF24AA1D9D9648A7104108DEB850E683D47250619F8
    Session-ID-ctx:
    Resumption PSK: CE509805D592031706729D7A35655AC6A3AB86F346FB0871E511013B3E3428C6BD18772DA0495312FCEB3B690E6308DE
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:
    0000 - 2c 0e fb 39 16 33 06 8c-99 5a 89 da df d9 95 0c   ,..9.3...Z......
    0010 - 8a 5e a3 fe 25 89 8e 07-0d 84 32 48 0e ff 40 b0   .^..%.....2H..@.
    0020 - 31 b0 9e f6 44 1b 55 61-a0 e8 be 06 fe c4 23 d0   1...D.Ua......#.
    0030 - 4a f1 96 f7 34 69 ed eb-dd 2f 1d 5e c6 98 72 8d   J...4i.../.^..r.
    0040 - e9 a1 33 be 82 06 e9 0f-a5 e6 bb 8a 9c f1 03 14   ..3.............
    0050 - b5 d5 6b 8c 23 fc fb dd-15 6b 45 54 09 44 d8 94   ..k.#....kET.D..
    0060 - 58 48 23 a1 f7 21 44 dc-09 5d 4b d2 91 a0 f6 8d   XH#..!D..]K.....
    0070 - ff f8 5c 93 67 b9 7e b7-aa 4d 0a 76 60 31 1d 3a   ..\.g.~..M.v`1.:
    0080 - fc fd 8d 5c 5f fa ce 66-52 80 3c 59 ba 3c 57 dd   ...\_..fR.<Y.<W.
    0090 - 15 40 4c 64 1a 29 19 3a-cd 6b 51 a7 69 73 79 0c   .@Ld.).:.kQ.isy.
    00a0 - e9 95 01 fd 14 1f b4 fe-a5 eb 1a b9 3c b0 6b 1e   ............<.k.
    00b0 - e5 63 e8 26 e2 ee b6 2d-aa f5 01 35 b8 cc 6a 9f   .c.&...-...5..j.
    00c0 - 67 5f 5d 96 cc ce 04 40-24 7a f5 26 1b df d6 60   g_]....@$z.&...`

    Start Time: 1685259676
    Timeout   : 7200 (sec)
    Verify return code: 10 (certificate has expired)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: 621BA60A1CC362E5DD097E3E5826392894228D6A7502C557EEADCDAA31ABE237
    Session-ID-ctx:
    Resumption PSK: D8710361E5ED097D6EEB5B60E41D2C38F1C0F35A5381ECDD5E7A90F8D7C0DDA5BE8FF97819C9A617967DF719028C5DDD
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:
    0000 - 2c 0e fb 39 16 33 06 8c-99 5a 89 da df d9 95 0c   ,..9.3...Z......
    0010 - be 66 ed a2 b6 62 2b 1a-24 d1 cc c3 68 b4 b8 f5   .f...b+.$...h...
    0020 - 23 bb 5c 59 dc 5a 9e 5e-28 0b f1 6c fe 69 88 a1   #.\Y.Z.^(..l.i..
    0030 - fc 52 2d 38 9f 5f f3 5b-f2 b8 aa 45 ce 31 77 00   .R-8._.[...E.1w.
    0040 - 23 54 02 ec 95 e5 11 06-8a 62 ce 6f 87 85 ba 4b   #T.......b.o...K
    0050 - 9f b8 a0 fc 7f d3 6a 9b-9c 3f 95 15 b0 e2 db d9   ......j..?......
    0060 - 89 19 d2 9d a8 c9 fa 31-cd 87 72 33 a9 4b 1a 32   .......1..r3.K.2
    0070 - 7a 9d b7 e0 65 e3 7b 11-7c 25 44 4f e1 fd 24 ef   z...e.{.|%DO..$.
    0080 - fd 73 a1 c4 2f d8 94 c9-68 d3 c8 17 51 3d 42 ce   .s../...h...Q=B.
    0090 - d0 0a 09 3d f8 48 76 6a-4d 4c 2d 27 fb b4 19 5a   ...=.HvjML-'...Z
    00a0 - 66 49 23 ae c6 0c 59 4a-50 64 aa 01 a9 21 0a c9   fI#...YJPd...!..
    00b0 - 36 85 eb 35 1e 3d 67 0d-77 05 be 80 63 a7 05 bd   6..5.=g.w...c...
    00c0 - a0 a1 64 c3 4e 6d 37 48-6e c5 96 3b 9c f0 13 ca   ..d.Nm7Hn..;....

    Start Time: 1685259676
    Timeout   : 7200 (sec)
    Verify return code: 10 (certificate has expired)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK
JQttfApK4SeyHwDlI9SXGR50qclOAil1
Correct!
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAvmOkuifmMg6HL2YPIOjon6iWfbp7c3jx34YkYWqUH57SUdyJ
imZzeyGC0gtZPGujUSxiJSWI/oTqexh+cAMTSMlOJf7+BrJObArnxd9Y7YT2bRPQ
Ja6Lzb558YW3FZl87ORiO+rW4LCDCNd2lUvLE/GL2GWyuKN0K5iCd5TbtJzEkQTu
DSt2mcNn4rhAL+JFr56o4T6z8WWAW18BR6yGrMq7Q/kALHYW3OekePQAzL0VUYbW
JGTi65CxbCnzc/w4+mqQyvmzpWtMAzJTzAzQxNbkR2MBGySxDLrjg0LWN6sK7wNX
x0YVztz/zbIkPjfkU1jHS+9EbVNj+D1XFOJuaQIDAQABAoIBABagpxpM1aoLWfvD
KHcj10nqcoBc4oE11aFYQwik7xfW+24pRNuDE6SFthOar69jp5RlLwD1NhPx3iBl
J9nOM8OJ0VToum43UOS8YxF8WwhXriYGnc1sskbwpXOUDc9uX4+UESzH22P29ovd
d8WErY0gPxun8pbJLmxkAtWNhpMvfe0050vk9TL5wqbu9AlbssgTcCXkMQnPw9nC
YNN6DDP2lbcBrvgT9YCNL6C+ZKufD52yOQ9qOkwFTEQpjtF4uNtJom+asvlpmS8A
vLY9r60wYSvmZhNqBUrj7lyCtXMIu1kkd4w7F77k+DjHoAXyxcUp1DGL51sOmama
+TOWWgECgYEA8JtPxP0GRJ+IQkX262jM3dEIkza8ky5moIwUqYdsx0NxHgRRhORT
8c8hAuRBb2G82so8vUHk/fur85OEfc9TncnCY2crpoqsghifKLxrLgtT+qDpfZnx
SatLdt8GfQ85yA7hnWWJ2MxF3NaeSDm75Lsm+tBbAiyc9P2jGRNtMSkCgYEAypHd
HCctNi/FwjulhttFx/rHYKhLidZDFYeiE/v45bN4yFm8x7R/b0iE7KaszX+Exdvt
SghaTdcG0Knyw1bpJVyusavPzpaJMjdJ6tcFhVAbAjm7enCIvGCSx+X3l5SiWg0A
R57hJglezIiVjv3aGwHwvlZvtszK6zV6oXFAu0ECgYAbjo46T4hyP5tJi93V5HDi
Ttiek7xRVxUl+iU7rWkGAXFpMLFteQEsRr7PJ/lemmEY5eTDAFMLy9FL2m9oQWCg
R8VdwSk8r9FGLS+9aKcV5PI/WEKlwgXinB3OhYimtiG2Cg5JCqIZFHxD6MjEGOiu
L8ktHMPvodBwNsSBULpG0QKBgBAplTfC1HOnWiMGOU3KPwYWt0O6CdTkmJOmL8Ni
blh9elyZ9FsGxsgtRBXRsqXuz7wtsQAgLHxbdLq/ZJQ7YfzOKU4ZxEnabvXnvWkU
YOdjHdSOoKvDQNWu6ucyLRAWFuISeXw9a/9p7ftpxm0TSgyvmfLF2MIAEwyzRqaM
77pBAoGAMmjmIJdjp+Ez8duyn3ieo36yrttF5NSsJLAbxFpdlc1gvtGCWW+9Cq0b
dxviW8+TFVEBl1O4f7HVm6EpTscdDxU+bCXWkfjuRb7Dy9GOtt9JPsX8MBTakzh3
vBgsyi/sN3RqRBcGU40fOoZyfAMT8s1m/uYv52O6IgeuZ/ujbjY=
-----END RSA PRIVATE KEY-----

closed

Level 17 → 18

Level Goal

The flag from the previos level was provided in the form of the private sshkey, which needed to be used to login for the bandit17 user.

We first needed to change the permissions on the keyfile using chmod with a permission of 600.

The goal for this level was to find the single changed entry between password.new and password.old files.

Solution

Using the diff command, you can see which entries have changed:

bandit17@bandit:~$ diff passwords.new passwords.old
42c42
< hga5tuuCLF6fFzUpnagiMN8ssu9LFrdg
---
> glZreTEH1V3cGKL6g4conYqZqaEj0mte
bandit17@bandit:~$ grep hga5tuuCLF6fFzUpnagiMN8ssu9LFrdg passwords.new
hga5tuuCLF6fFzUpnagiMN8ssu9LFrdg
bandit17@bandit:~$

Level 18 → 19

Level Goal

When logging in with bandit18, the ssh session is closed. The hint provided is that someone has modified the .bashrc to cause this to happen.

We are also told that the flag is stored in the readme file.

Solution

We can retrieve the contents of the file by adding the remote command to the ssh command:

user@system76-pc:~/workspace/overTheWire/bandit/level16$ ssh bandit18@bandit.labs.overthewire.org -p 2220 'cat readme'
                         _                     _ _ _
                        | |__   __ _ _ __   __| (_) |_
                        | '_ \ / _` | '_ \ / _` | | __|
                        | |_) | (_| | | | | (_| | | |_
                        |_.__/ \__,_|_| |_|\__,_|_|\__|


                      This is an OverTheWire game server.
            More information on http://www.overthewire.org/wargames

bandit18@bandit.labs.overthewire.org's password:
awhqfNnAbc1naukrpqDYcF95h7HoMTrC

Level 19 → 20

Level Goal

We are provided with a binary, bandit20-do, which is apparently a setuid binary. This needs to be used to access the flag in /etc/bandit_pass.

Solution

Running the bandit20-do command provides a usage message and seems to execute the given command as the bandit20 user:

bandit19@bandit:~$ ./bandit20-do
Run a command as another user.
  Example: ./bandit20-do id
bandit19@bandit:~$ ./bandit20-do id
uid=11019(bandit19) gid=11019(bandit19) euid=11020(bandit20) groups=11019(bandit19)
bandit19@bandit:~$ whoami
bandit19
bandit19@bandit:~$ ./bandit20-do whoami
bandit20

Using this binary, we can cat the contents of the bandit20 password file:

bandit19@bandit:~$ ./bandit20-do cat /etc/bandit_pass/bandit20
VxCazJaVykI6W36BkBU0mJTCM8rR95XT

Level 20 → 21

Level Goal

There is a setuid binary in the home directory 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).

There is a hint to try connecting to our own network daemon to see if it works as we expect.

Solution

Because we needed 2 processes running for this, I created two screen sessions.

Based on the hint provided, I then setup a netcat process to listen on port 36969, using nc with -k to keep the connection alive and -l to listen for incoming connections:

bandit20@bandit:/tmp/tmp.p4g7AJfF4E$ nc -k -l 36969

In the other screen session, I then connected to the listening netcat process on port 36969. To test that it was behaving as expected, I sent the message "sent from client" from the client netcat process I had just started and then replied with "sent from the server" from the listing netcat process spawned from the step above.

bandit20@bandit:/tmp/tmp.p4g7AJfF4E$ nc -k -l 36969
sent from client
sent from server
^C

After seeing this work as expected, we can replace the connecting netcat with the provided binary.

With the netcat process listening on 36969, we execute the suconnect to call the same port. Then on the listening side, we paste in the flag from prior level. This sent the old flag to the suconnect, which then replied with the next flag:

The first flag was pasted in by hand, the second was the reply received:

bandit20@bandit:~$ nc -k -l 36969
VxCazJaVykI6W36BkBU0mJTCM8rR95XT
NvEJF7oVjkddltPSrdKEFOllh9V1IBcq
^C

The output from the suconnect process shows old password was received and next one was sent:

bandit20@bandit:~$ ./suconnect 36969
Read: VxCazJaVykI6W36BkBU0mJTCM8rR95XT
Password matches, sending next password

Level 21 → 22

Level Goal

We are told that a cron job is running periodically and we need to see which command is being executed. The configuration is found in etc/cron.d.

Solution

We can check which jobs exist, then what script they are calling and finally output the script. In this case the scrip is periodically writing the contents of the password to a temp file, which we then output:

bandit21@bandit:~$ ls -alt /etc/cron.d
total 56
drwxr-xr-x   2 root root  4096 Apr 23 18:05 .
-rwx------   1 root root    52 Apr 23 18:05 otw-tmp-dir
drwxr-xr-x 108 root root 12288 Apr 23 18:05 ..
-rw-r--r--   1 root root    62 Apr 23 18:04 cronjob_bandit25_root
-rw-r--r--   1 root root   120 Apr 23 18:04 cronjob_bandit24
-rw-r--r--   1 root root   122 Apr 23 18:04 cronjob_bandit23
-rw-r--r--   1 root root   120 Apr 23 18:04 cronjob_bandit22
-rw-r--r--   1 root root    62 Apr 23 18:04 cronjob_bandit17_root
-rw-r--r--   1 root root    62 Apr 23 18:04 cronjob_bandit15_root
-rw-r--r--   1 root root   102 Mar 23  2022 .placeholder
-rw-r--r--   1 root root   201 Jan  8  2022 e2scrub_all
-rw-r--r--   1 root root   396 Feb  2  2021 sysstat
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:~$ ls -alt /usr/bin/cronjob_bandit22.sh
-rwxr-x--- 1 bandit22 bandit21 130 Apr 23 18:04 /usr/bin/cronjob_bandit22.sh
bandit21@bandit:~$ cat /usr/bin/cronjob_bandit22.sh
#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
bandit21@bandit:~$ cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
WdDozAdTM2z9DiFEQ2mGlwngMfj4EZff
bandit21@bandit:~$

Level 22 → 23

Level Goal

We are again told that a cron job is running periodically and we need to see which command is being executed. The configuration is found in etc/cron.d.

This time we are given a hint that a custom script is run.

Solution

This time we check the cron configuration and find that custom script is being run:

bandit22@bandit:~$ ls /etc/cron.d/
cronjob_bandit15_root  cronjob_bandit22  cronjob_bandit24       e2scrub_all  sysstat
cronjob_bandit17_root  cronjob_bandit23  cronjob_bandit25_root  otw-tmp-dir
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

The contents of this script are:

#!/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

From this, we can determine what mytarget would be for the bandit23 user:

bandit22@bandit:~$ echo I am user bandit23 | md5sum | cut -d ' ' -f 1
8ca319486bfbbc3663ea0fbe81326349
bandit22@bandit:~$ cat /tmp/8ca319486bfbbc3663ea0fbe81326349
QYw0Y2aiA672PsMmh9puTQuhoz8SyR2G

Level 23 → 24

Level Goal

Similar to the previous 2 levels, were are told that 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.

We are provided a hint that we are going to need to write our own script for this one

Solution

Based on the solution from the previous levels, we can see that the script being run by the cron is /usr/bin/cronjob_bandit24.sh

#!/bin/bash

myname=$(whoami)

cd /var/spool/$myname/foo || exit 1
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 -rf ./$i
    fi
done

This script seems to run all of the script contained in the //var/spool/bandit24/foo directory. Each script needs to be owned by bandit23 and will timeout after 60 seconds. They are then all deleted.

We also know that the flag we are looking for is stored at etc/bandit_pass/bandit24, so our script could follow the same pattern as the previous level and cat the password to a tmp file.

As a proof of concept, I created a simple script to output to a tmp file:

#!/bin/bash

echo "It ran" > /tmp/tmp.8mlHq5Huee.out

which worked as expected:

bandit23@bandit:/tmp/tmp.8mlHq5Huee$ cat /tmp/tmp.8mlHq5Huee.out
It ran

Knowing that the cron and script worked as expected, it was updated to the follow:

#!/bin/bash

echo "Running.." > /tmp/tmp.8mlHq5Huee.out
cat /etc/bandit_pass/bandit24 >> /tmp/tmp.8mlHq5Huee.out
echo "Done" >> /tmp/tmp.8mlHq5Huee.out

This resulted in the flag being captured in our output file:

bandit23@bandit:/tmp/tmp.8mlHq5Huee$ cat /tmp/tmp.8mlHq5Huee.out
Running..
VAfGXJ1PBSsPSnvsjI8p759leLZ9GGar
Done

Level 24 → 25

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. You do not need to create new connections each time

Solution

Poking around a bit, I found that you can cat a list of password and pin number combinations to the port using netcat.

bandit24@bandit:/tmp/tmp.aQwi1Ti4zL$ cat list.txt | nc localhost 30002 | tee output.txt
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.
^C

This gives us a starting point, but we now need to populate the list with all 10000 pin code combinations. This was a bit tricky an required the seq command in order to left pad the pins with 0's.

The following script generated the full password list:

#!/bin/bash

for i in $(seq -f "%04g" 0 10000)
do
  echo VAfGXJ1PBSsPSnvsjI8p759leLZ9GGar $i >> list.txt
done

When attempting to cat all of the 9999 pin codes, it seemed to repeatedly hit an issue at around 6300, where the we didn't get anymore output. Because of this I tried doing it in two batches of 5000:

bandit24@bandit:/tmp/tmp.tgFt3ekfvA$ cat list.txt |head -n 5000| nc localhost 30002 > output.txt
bandit24@bandit:/tmp/tmp.tgFt3ekfvA$ cat list.txt |tail -n 5000| nc localhost 30002 > tail_output.txt

This produced the flag for bandit25:

bandit24@bandit:/tmp/tmp.tgFt3ekfvA$ grep -v Wrong *output.txt
output.txt: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.
output.txt:Timeout. Exiting.
tail_output.txt: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.
tail_output.txt:Correct!
tail_output.txt:The password of user bandit25 is p7TaowMYrmu23Ol8hiZh9UvD0O9hpx8d
tail_output.txt:
tail_output.txt:Exiting.

Level 25 → 26

Level Goal

We are given what looks like a private sshkey for bandit26, but told that the shell for bandit26 is not bin/bash.

Solution

When trying to login my the bandit25 session failed, so trying from outside.

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEApis2AuoooEqeYWamtwX2k5z9uU1Afl2F8VyXQqbv/LTrIwdW
pTfaeRHXzr0Y0a5Oe3GB/+W2+PReif+bPZlzTY1XFwpk+DiHk1kmL0moEW8HJuT9
/5XbnpjSzn0eEAfFax2OcopjrzVqdBJQerkj0puv3UXY07AskgkyD5XepwGAlJOG
xZsMq1oZqQ0W29aBtfykuGie2bxroRjuAPrYM4o3MMmtlNE5fC4G9Ihq0eq73MDi
1ze6d2jIGce873qxn308BA2qhRPJNEbnPev5gI+5tU+UxebW8KLbk0EhoXB953Ix
3lgOIrT9Y6skRjsMSFmC6WN/O7ovu8QzGqxdywIDAQABAoIBAAaXoETtVT9GtpHW
qLaKHgYtLEO1tOFOhInWyolyZgL4inuRRva3CIvVEWK6TcnDyIlNL4MfcerehwGi
il4fQFvLR7E6UFcopvhJiSJHIcvPQ9FfNFR3dYcNOQ/IFvE73bEqMwSISPwiel6w
e1DjF3C7jHaS1s9PJfWFN982aublL/yLbJP+ou3ifdljS7QzjWZA8NRiMwmBGPIh
Yq8weR3jIVQl3ndEYxO7Cr/wXXebZwlP6CPZb67rBy0jg+366mxQbDZIwZYEaUME
zY5izFclr/kKj4s7NTRkC76Yx+rTNP5+BX+JT+rgz5aoQq8ghMw43NYwxjXym/MX
c8X8g0ECgYEA1crBUAR1gSkM+5mGjjoFLJKrFP+IhUHFh25qGI4Dcxxh1f3M53le
wF1rkp5SJnHRFm9IW3gM1JoF0PQxI5aXHRGHphwPeKnsQ/xQBRWCeYpqTme9amJV
tD3aDHkpIhYxkNxqol5gDCAt6tdFSxqPaNfdfsfaAOXiKGrQESUjIBcCgYEAxvmI
2ROJsBXaiM4Iyg9hUpjZIn8TW2UlH76pojFG6/KBd1NcnW3fu0ZUU790wAu7QbbU
i7pieeqCqSYcZsmkhnOvbdx54A6NNCR2btc+si6pDOe1jdsGdXISDRHFb9QxjZCj
6xzWMNvb5n1yUb9w9nfN1PZzATfUsOV+Fy8CbG0CgYEAifkTLwfhqZyLk2huTSWm
pzB0ltWfDpj22MNqVzR3h3d+sHLeJVjPzIe9396rF8KGdNsWsGlWpnJMZKDjgZsz
JQBmMc6UMYRARVP1dIKANN4eY0FSHfEebHcqXLho0mXOUTXe37DWfZza5V9Oify3
JquBd8uUptW1Ue41H4t/ErsCgYEArc5FYtF1QXIlfcDz3oUGz16itUZpgzlb71nd
1cbTm8EupCwWR5I1j+IEQU+JTUQyI1nwWcnKwZI+5kBbKNJUu/mLsRyY/UXYxEZh
ibrNklm94373kV1US/0DlZUDcQba7jz9Yp/C3dT/RlwoIw5mP3UxQCizFspNKOSe
euPeaxUCgYEAntklXwBbokgdDup/u/3ms5Lb/bm22zDOCg2HrlWQCqKEkWkAO6R5
/Wwyqhp/wTl8VXjxWo+W+DmewGdPHGQQ5fFdqgpuQpGUq24YZS8m66v5ANBwd76t
IZdtF5HXs2S5CADTwniUS5mX1HO9l5gUkk+h0cH5JnPtsMCnAUM+BRY=
-----END RSA PRIVATE KEY-----

Trying to execute commands directly with the ssh command also failed.

Pocking around the password file, etc/passwd, we can see the shell is set to a strange binary:

bandit25@bandit:~$ grep bandit26 /etc/passwd
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext

Running this showtext executable seems to try and read a text.txt file from the local directory. We can see that there is a text.txt in the bandit26 home as well:

bandit25@bandit:~$ /usr/bin/showtext bandit26.sshkey
more: cannot open /home/bandit25/text.txt: No such file or directory
bandit25@bandit:~$ ls /home/bandit26/
bandit27-do  text.txt
bandit25@bandit:~$ ls -al /home/bandit26/text.txt
-rw-r----- 1 bandit26 bandit26 258 Apr 23 18:04 /home/bandit26/text.txt
bandit25@bandit:~$

Investigating more, the showtext shell is as custom script:

bandit25@bandit:~$ which /usr/bin/showtext
/usr/bin/showtext
bandit25@bandit:~$ file /usr/bin/showtext
/usr/bin/showtext: POSIX shell script, ASCII text executable
bandit25@bandit:~$ cat /usr/bin/showtext
#!/bin/sh

export TERM=linux

exec more ~/text.txt
exit 0

I reproduced this by creating my own copy of showtext and executing it via an ssh command, which behaved in a similar way. It was strange that more was being used, rather than cat, but I thought it had something to do with where the output was being sent.

Eventually I ended up looking around for hints… I was onto something here: more functions differently when the window is too small for the contents, so you have to force that to happen. Once you have more running interactively, you can get to an editor using the v command.

Once in the editor, which defaults to vim, you can open etc/bandit_pass-bandit26 to get the password c7GvcKlw9mC7aUQaPx7nwFstuAIBw1o1 for bandit26.

Level 26 → 27

Level Goal

The hint here was simply 'Good job getting a shell! Now hurry and grab the password for bandit27!'

Solution

After having to look for hints online for the last challenge, I realized that I had to think outside of the box and it would take multiple steps:

  1. Get log into with bandit25 user and ssh key, making sure the window is small enough to force more to enter interactive mode: /more.png
  2. Hitting v opened up vim, which we could then use to trigger a shell by running :term bash.
  3. Running ls in the terminal shows that we have a bandit27-do binary which runs with the bandit27 permissions. We can use this to get the flag for bandit27: /shell.png

    bandit26@bandit:~$ ./bandit27-do cat /etc/bandit_pass/bandit27
    YnQpBuifNMas1hcUFk70ZmqkhUU2EuaS

Level 27 → 28

Level Goal

For this we are given the details of a git repository:

  • Hosted at ssh://bandit27-git@localhost/home/bandit27-git/repo
  • port 2220
  • The password for the user bandit27-git is the same as for the user bandit27.

Solution

Pulling down the repo with git clone:

$ git clone ssh://bandit27-git@bandit.labs.overthewire.org:2220/home/bandit27-git/repo

Within the repo is a single README file which contains the flag:

$ cat README
The password to the next level is: AVanL161y9rsbcJIsFHuw35rjaOM19nR

Level 28 → 29

Level Goal

Like the previous level, we are given the details of a git repository:

  • Hosted at ssh://bandit28-git@localhost/home/bandit28-git/repo
  • port 2220
  • The password for the user bandit28-git is the same as for the user bandit28.

Solution

Pulling down the repo with git clone, we see a single file again, but it doesn't contain the password.

$ cat README.md
# Bandit Notes
Some notes for level29 of bandit.

## credentials

- username: bandit29
- password: xxxxxxxxxx

Looking into the git log, we see that a change was made with the commit message of 'fix info leak':

user@system76-pc:~/workspace/overTheWire/bandit/level29/repo$ git log
commit 899ba88df296331cc01f30d022c006775d467f28 (HEAD -> master, origin/master, origin/HEAD)
Author: Morla Porla <morla@overthewire.org>
Date:   Sun Apr 23 18:04:39 2023 +0000

    fix info leak

commit abcff758fa6343a0d002a1c0add1ad8c71b88534
Author: Morla Porla <morla@overthewire.org>
Date:   Sun Apr 23 18:04:39 2023 +0000

    add missing data

commit c0a8c3cf093fba65f4ee0e1fe2a530b799508c78
Author: Ben Dover <noone@overthewire.org>
Date:   Sun Apr 23 18:04:39 2023 +0000

    initial commit of README.md
user@system76-pc:~/workspace/overTheWire/bandit/level29/repo$ git show 899ba88df296331cc01f30d022c006775d467f28
commit 899ba88df296331cc01f30d022c006775d467f28 (HEAD -> master, origin/master, origin/HEAD)
Author: Morla Porla <morla@overthewire.org>
Date:   Sun Apr 23 18:04:39 2023 +0000

    fix info leak

diff --git a/README.md b/README.md
index b302105..5c6457b 100644
--- a/README.md
+++ b/README.md
@@ -4,5 +4,5 @@ Some notes for level29 of bandit.
 ## credentials

 - username: bandit29
-- password: tQKvmcwNYcFS6vmPHIUSI3ShmsrQZK8S
+- password: xxxxxxxxxx

user@system76-pc:~/workspace/overTheWire/bandit/level29/repo$

From this we can see the flag was removed in that commit.

Level 29 → 30

Level Goal

Like the previous level, we are given the details of a git repository:

  • Hosted at ssh://bandit29-git@localhost/home/bandit29-git/repo
  • port 2220
  • The password for the user bandit29-git is the same as for the user bandit29.

Solution

Pulling down the repo with git clone, we see a single file again, but it doesn't contain the password.

After checking for remote branches, we find a dev branch which contains the flag we are looking for:

user@system76-pc:~/workspace/overTheWire/bandit/level30/repo$ ls
README.md
user@system76-pc:~/workspace/overTheWire/bandit/level30/repo$ git branch -r
  origin/HEAD -> origin/master
  origin/dev
  origin/master
  origin/sploits-dev
user@system76-pc:~/workspace/overTheWire/bandit/level30/repo$ git checkout origin/dev
Note: switching to 'origin/dev'.

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 13e7356 add data needed for development
user@system76-pc:~/workspace/overTheWire/bandit/level30/repo$ ls
code  README.md
user@system76-pc:~/workspace/overTheWire/bandit/level30/repo$ cat README.md
# Bandit Notes
Some notes for bandit30 of bandit.

## credentials

- username: bandit30
- password: xbhV3HpNGlTIdnjUrdAlPzc2L6y9EOnS

Level 30 → 31

Level Goal

Like the previous level, we are given the details of a git repository:

  • Hosted at ssh://bandit30-git@localhost/home/bandit30-git/repo
  • port 2220
  • The password for the user bandit30-git is the same as for the user bandit30.

Solution

Pulling down the repo with git clone, we see a single file again, but it doesn't contain the password.

The repo seems to have only a single remote branch, but running the git ls-remote command returns a reference to a secret tag:

user@system76-pc:~/workspace/overTheWire/bandit/level31/repo$ git branch -r
  origin/HEAD -> origin/master
  origin/master
user@system76-pc:~/workspace/overTheWire/bandit/level31/repo$ git ls-remote
                         _                     _ _ _
                        | |__   __ _ _ __   __| (_) |_
                        | '_ \ / _` | '_ \ / _` | | __|
                        | |_) | (_| | | | | (_| | | |_
                        |_.__/ \__,_|_| |_|\__,_|_|\__|


                      This is an OverTheWire game server.
            More information on http://www.overthewire.org/wargames

bandit30-git@bandit.labs.overthewire.org's password:
From ssh://bandit30-git@bandit.labs.overthewire.org:2220/home/bandit30-git/repo
59530d30d299ff2e3e9719c096ebf46a65cc1424	HEAD
59530d30d299ff2e3e9719c096ebf46a65cc1424	refs/heads/master
831aac2e2341f009e40e46392a4f5dd318483019	refs/tags/secret
user@system76-pc:~/workspace/overTheWire/bandit/level31/repo$

I am sure there is a better way of doing this, but when trying to checkout the tag, an error was returned suggesting the commit wasn't part of the same branch.

After poking around, found some information on the git unpack-objects command, thanks to stack overflow. I then looked at how to decompress the unpacked objects, with the help of this tutorial.

user@system76-pc:~/workspace/overTheWire/bandit/level31/repo$ cat pack-ce041ba8ee175c320e2f90422d56c0a25e6d6b86.pack | git unpack-objects

which produced a number of object files where the pack file used to be:

user@system76-pc:~/workspace/overTheWire/bandit/level31/repo/.git/objects$ tree
.
├── 02
│   └── 9ba421ef4c34205d52133f8da3d69bc1853777
├── 59
│   └── 530d30d299ff2e3e9719c096ebf46a65cc1424
├── 83
│   └── 1aac2e2341f009e40e46392a4f5dd318483019
├── bd
│   └── 85592e905590f084b8df33363a46f9ac4aa708
├── info
└── pack
    └── pack-ce041ba8ee175c320e2f90422d56c0a25e6d6b86.idx

Then using a python shell to inspect the objects:

user@system76-pc:~/workspace/overTheWire/bandit/level31/repo/.git/objects/83$ python3
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import zlib
>>> filename = '1aac2e2341f009e40e46392a4f5dd318483019'
>>> compressed_contents = open(filename, 'rb').read()
>>> decompressed_contents = zlib.decompress(compressed_contents)
>>> decompressed_contents
b'blob 33\x00OoffzGDlzhAlerFJ2cAiz1D41JW1Mhmt\n'
>>> exit()

Our flag is in the decompressed contents variable with the value of OoffzGDlzhAlerFJ2cAiz1D41JW1Mhmt.

Level 31 → 32

Level Goal

Like the previous level, we are given the details of a git repository:

  • Hosted at ssh://bandit31-git@localhost/home/bandit31-git/repo
  • port 2220
  • The password for the user bandit31-git is the same as for the user bandit30.

Solution

This one was relatively simple, with the instructions being to commit a key file:

user@system76-pc:~/workspace/overTheWire/bandit/level32/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

After adding the file and attempting to push the change, a message is returned with the next flag:

user@system76-pc:~/workspace/overTheWire/bandit/level32/repo$ git push
                         _                     _ _ _
                        | |__   __ _ _ __   __| (_) |_
                        | '_ \ / _` | '_ \ / _` | | __|
                        | |_) | (_| | | | | (_| | | |_
                        |_.__/ \__,_|_| |_|\__,_|_|\__|


                      This is an OverTheWire game server.
            More information on http://www.overthewire.org/wargames

bandit31-git@bandit.labs.overthewire.org's password:
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 343 bytes | 343.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: rmCBvG56y58BXzv98yZGdO7ATVL5dW8y
remote:
remote: .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
remote:
To ssh://bandit.labs.overthewire.org:2220/home/bandit31-git/repo
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'ssh://bandit.labs.overthewire.org:2220/home/bandit31-git/repo'

The flag returned is rmCBvG56y58BXzv98yZGdO7ATVL5dW8y.

Level 32 → 33

Level Goal

We are given very little to go on, besides needing to escape.

Solution

  • When logging in we are presented with the MOTD and a welcome message

    WELCOME TO THE UPPERCASE SHELL
    >> ls
    sh: 1: LS: not found
    >> help
    sh: 1: HELP: not found
    >> l
    sh: 1: L: not found
  • Used bandit30 to have a look at what the shell is for bandit32

    bandit30@bandit:~$ grep bandit32 /etc/passwd
    bandit32:x:11032:11032:bandit level 32:/home/bandit32:/home/bandit32/uppershell
    bandit30@bandit:~$ ls -alt /home/bandit32/
    total 36
    drwxr-xr-x 70 root     root      4096 Apr 23 18:05 ..
    drwxr-xr-x  2 root     root      4096 Apr 23 18:04 .
    -rwsr-x---  1 bandit33 bandit32 15128 Apr 23 18:04 uppershell
    -rw-r--r--  1 root     root       220 Jan  6  2022 .bash_logout
    -rw-r--r--  1 root     root      3771 Jan  6  2022 .bashrc
    -rw-r--r--  1 root     root       807 Jan  6  2022 .profile
    bandit30@bandit:~$

    We do see that owner seems to be bandit33, which provides a good hint about this being something we need to break out of or possible cause to crash.

  • I got something to at least run by trying calling the $PATH environment variable:

    >> $PATH
    sh: 1: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin: not found
    >>

Using print, we can check the list of possible environment variable, when called, causing value of the variable to be called.

  • After digging around, this seems to be a dash shell, which has some features to let you play with environment variables by removing matching prefixes and suffixes. See Erick's Cheat Sheet
  • Could get a shell to be run, such as /bin/bash or even sh, or for the password to be provided to us, which is in cat /etc/bandit_pass/bandit33
  • Either approach is going to require some manipulation of env variables. This guide also provided a lot of insight into what we could do here.
  • Using the ? wildcard, we can remove characters from the left and right side of terminal variables, and get these to be run as commands:

    >> ${PWD}
    sh: 1: /home/bandit32: Permission denied
    >> ${PWD%???}
    sh: 1: /home/bandi: not found
    >> ${PWD#???}
    sh: 1: me/bandit32: not found
    >>
    • Just as I was about to hit my head into the desk, I went on the hunt for more variables to play with when this happened!

      >> $0
      $ ls
      uppershell
      $ ls -alt
      total 36
      drwxr-xr-x 70 root     root      4096 Apr 23 18:05 ..
      drwxr-xr-x  2 root     root      4096 Apr 23 18:04 .
      -rwsr-x---  1 bandit33 bandit32 15128 Apr 23 18:04 uppershell
      -rw-r--r--  1 root     root       220 Jan  6  2022 .bash_logout
      -rw-r--r--  1 root     root      3771 Jan  6  2022 .bashrc
      -rw-r--r--  1 root     root       807 Jan  6  2022 .profile
      $

      And that let us get the final flag!

      $ cat /etc/bandit_pass/bandit33
      odHo63fHiFqcWWJG9rLiLDtPm45KzUKy

Level 33

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!