Post

OverTheWire Bandit: Level 22 to Level 23

OverTheWire Bandit: Level 22 to Level 23

The Goal

Another cron job running automatically. This time the script is more complex — it generates a filename using a hash and writes the password there. The challenge is figuring out what filename the script generates when it runs as bandit23.

What I Did

Checked /etc/cron.d/ and read the bandit23 cron job:

1
2
3
bandit22@bandit:/etc/cron.d$ cat cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh  &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh  &> /dev/null

Read the script:

1
2
3
4
5
6
bandit22@bandit:/etc/cron.d$ cat /usr/bin/cronjob_bandit23.sh
#!/bin/bash
myname=$(whoami)
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
echo "Copying passwordfile /etc/bandit_pass/$myname to /tmp/$mytarget"
cat /etc/bandit_pass/$myname > /tmp/$mytarget

The script runs as bandit23 via cron. That means $(whoami) returns bandit23. The filename is generated by hashing the string I am user bandit23 with md5sum and cutting the output to just the hash.

I needed to calculate that hash myself since the script runs as bandit23 but I’m logged in as bandit22:

1
2
3
bandit22@bandit:/tmp$ echo "I am user bandit23" | md5sum >> t1
bandit22@bandit:/tmp$ cat t1
8ca319486bfbbc3663ea0fbe81326349  -

The hash is 8ca319486bfbbc3663ea0fbe81326349. Read the file at that path:

1
2
bandit22@bandit:/tmp$ cat 8ca319486bfbbc3663ea0fbe81326349  -
gKXDTAXnIz3OBxiPjRZ2uqutUlPZrBsw

Understanding the Script

Breaking down the key line:

1
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)

Three commands chained with pipes:

echo I am user $myname — outputs the string I am user bandit23

md5sum — takes that string and produces a hash. MD5 is a cryptographic hash function — it takes any input and produces a fixed-length 32-character hex string. The same input always produces the same output, but you can’t reverse it to get the original. The raw output looks like:

1
8ca319486bfbbc3663ea0fbe81326349  -

The ` -` at the end means md5sum was reading from stdin.

cut -d ' ' -f 1 — splits the output by spaces and keeps only the first field. Without this, the filename would include the ` - suffix which would be messy. cut` strips it down to just the clean hash string.

The resulting hash becomes both the filename and an indirect reference to who the script ran as — you can only figure out the filename if you know it was generated from I am user bandit23.

What I Tried That Didn’t Work

Initially tried using $mytarget as a variable in my own shell — but that variable doesn’t exist in my session, only inside the script when it runs as bandit23. So cat /tmp/$mytarget expanded to cat /tmp/ which is a directory.

The fix was to manually calculate the hash value myself using the same commands the script uses, substituting bandit23 as the username.

What I Learned

$(command) is command substitution. Whatever is inside $() gets executed and its output becomes the value. So myname=$(whoami) stores the output of whoami into the variable myname.

cut extracts specific fields from text. -d sets the delimiter character to split on, -f specifies which field number to keep. It’s commonly used to parse structured output where fields are separated by a consistent character like spaces, colons, or commas.

MD5 is not secure for cryptography but is still widely used for non-security purposes like generating consistent filenames from input strings, checksums for file integrity, and similar tasks. For password hashing it’s completely broken — too fast to brute force and vulnerable to precomputed rainbow tables. Use bcrypt or Argon2 for passwords.

Reading a script carefully lets you predict its output without running it. The key insight here was realising the script runs as bandit23, substituting that username into the hash calculation, and computing the result manually.

Commands Used

CommandWhat it did
cat /usr/bin/cronjob_bandit23.shRead the script to understand what it does
echo "I am user bandit23" \| md5sumCalculated the hash the script generates when run as bandit23
cat /tmp/8ca319486bfbbc3663ea0fbe81326349Read the password from the file the script wrote
This post is licensed under CC BY 4.0 by the author.