I appreciate the organizers for putting this CTF together because I enjoyed it a lot. It was at a very appropriate difficulty level for novices. Many thanks to my teammates for helping out. Even though it was only basically 2 active players 🙂, we managed to get 8th place, which I am pretty satisfied with considering our little experience.
🎵 For this CTF I was listening to Kygo - Gone Are The Days ft. James Gillespie!
Details | Links |
---|---|
CTFtime.org Event Page | https://ctftime.org/event/1288 |
Publicly-released challenges | https://github.com/UMD-CSEC/UMDCTF-2021-Public-Challenges |
Forensics
Phillip 1
Philip was working on a challenge when I took a snap of his vm. I found the flag, and I gonna be the only one to claim this flag since I scrubbed the flag from the raw image. MWAHAHA, more points for me >:)
Note: the dwarf and system map are the same for all Phillip challenges
hxxps://drive.google.com/drive/folders/1c6vdBabGu33edSLXQZY5s8JAeM8au8Uo?usp=sharing
author: drkmrin78
score: 3.5/10
Since we are given a VM snapshot, we will do memory forensics with volatility. I’ve never done this for Linux memory dumps before, so this will be cool. We first make a custom profile with the .dwarf and .map provided as outlined here https://github.com/volatilityfoundation/volatility/wiki/Linux#making-the-profile.
We then use the linux_psaux
plugin to list processes along with their full command line.
|
|
We see that an SSH connection is made to lubuntu@chals2.umdctf.io
with -i
meaning an identity file key
is used.
With the linux_bash
plugin, we also see that SCP was used to copy Phillip’s super-secret-flag
onto the remote server.
|
|
If we can obtain the SSH identity file key
, we can SSH onto the remote server and retrieve the flag.
Thus, we use linux_enumerate_files
and grep
for key
.
|
|
!! The file is found at /cow/upper/home/lubuntu/key
with an Inode value of 0xffff95f1c3139f60
. We can now dump it to disk with:
|
|
and use the identity file.
AttributeError: Struct xxx has no member xxx
like I did initially, be sure to get the latest volatility from github.If we were to use the identity file straight away, we will encounter a permissions error. Fix it with
chmod 600 private_key
and we are good to go.
And we are done!
Flag: UMDCTF-{G4ll4gh3r_4_1if3}
Phillip 2
Philip told me he found something to give him ctf flags for Dogecoin? I have to see for myself, but lets just take his!
Note: the dwarf and system map are the same for all Phillip challenges
hxxps://drive.google.com/drive/folders/1r6BGYZsTpfS0pWuIu2fWPjAqalsae6kx?usp=sharing
author: drkmrin78
score: 6/10
Utilizing the same custom profile we made in Phillip 1, we similarly look for processes and see the peculiar Mozilla Thunderbird email client running with process ID 2084
:
|
|
We can also check out network connections with linux_netstat
to see thunderbird
showing up again:
|
|
I was unfamiliar with what kind of files are related to Thunderbird, so let’s see the open file descriptors for its process with linux_lsof
.
|
|
This showed us various .sqlite
databases stored in ~/.thunderbird/<profile_name>/
, for which some have their purpose documented here: http://kb.mozillazine.org/Files_and_folders_in_the_profile_-_Thunderbird
At first, I tried dumping the global-messages-db.sqlite
and viewing its contents. While it does show us that there is an Invoice.zip
and a password of bigchungus4life
, my research apparently suggested that the actual attachment was not stored together in this SQLite database.
I found this Thunderbird Email Parser https://github.com/mdegrazia/Thunderbird-Email-Parser which seemed to be able to retrieve the actual attachment data but it required the entire Thunderbird user profile folder as an input argument. With this, I decided to write a quick & dirty Python script to dump all our needed files with volatility.
First, I retrieved the filepaths we needed under ~/.thunderbird/<profile_name>/
by copying-and-pasting the output of
|
|
into thunderbird.txt
, which will end up looking something like this:
Second, we make the output directories we need with mkdir -p
.
Finally, we run the below script to dump the files:
|
|
And then now we can run thunderbird_parser_v1.0.py
specifying the Thunderbird user profile folder:
|
|
which will give us a nice spreadsheet as well as individual .eml
files.
We are now able to carve out our Base64-encoded (specified by Content-Transfer-Encoding
) invoice.zip
file from UMDCTF Invoice_5.eml
, decode it back into a .zip
, and open the invoice.pdf
within using the password we found earlier of bigchungus4life
.
Flag: UMDCTF-{M3g4_Ch4#g4$}
Phillip 3
Philip was starting to write a vault for flags? I don’t know what that means, but he told me its going to be secure from my memory forensic antics. Total rubbish, lets show him who’s l33t here!
Note: the dwarf and system map are the same for all Phillip challenges
hxxps://drive.google.com/drive/folders/1tRYkwA-gyuAkqF5W8kVjAFKrtGRqVjPx?usp=sharing
author: drkmrin78
score: 7/10
Standard procedure is to list processes with linux_psaux
, and flag-vault
with process ID 9793
catches our eye.
|
|
linux_bash
shows us that flag-vault
was compiled from flag-vault.c
.
|
|
Let’s grep for these files and dump them for inspection.
|
|
Source code of flag-vault
shows that console input is stored in a linked-list data structure where each node contains a char
.
|
|
Since malloc
is used to dynamically allocate memory for each node (a.k.a link, line 11
), this data will be stored on the heap. To locate the memory address of the heap, we use linux_proc_maps
for the flag-vault
process:
|
|
We can now dump the heap with [heap]
’s Start
memory address and eyeball the flag directly from the dumped data:
|
|
Flag: UMDCTF-{V0l$h311_isCool}
Protocol One and Zero
We have noticed some suspicious pings on localhost that appear to hide a message. Can you recover the message?
author: azeemsm
score: 4/10
Attached: protocol_one_and_zero.pcapng
We are given a network capture so let’s open it in Wireshark. The capture contains a bunch of ICMP ping requests and replies so let’s just filter for only requests since replies should just echo back the same data payload contained in requests.
So with the display filter icmp.type == 8
, notice that the data transmitted usually either ends in a whole bunch of 00
s or ff
s.
This seems to be a form of binary encoding (as also alluded to by the challenge title), so let’s extract that data with pyshark via a simple script and we get the flag:
|
|
Flag: UMDCTF-{b1n_p1Ng_P0ng}
Steganography
Coldplay’s Flags
I just downloaded Coldplay’s latest song and noticed that my song file seems a bit odd. Can you help me figure out what’s up with my file?
Note: For the password, think words, not characters
hxxps://drive.google.com/drive/folders/1o58KD8CcCI5kTuHH8e56noPUAazRBGNh?usp=sharing
author: amanthanvi score: 5/10
We are given flags.wav
which is audio of the song Coldplay - Flags except that its spectrogram differs slightly from the official copy. I attempted to do phase inversion and ran various steg tools but it proved to be futile.
I decided to randomly try binwalk on it and hey look, we obtain two .zip
files with one containing hint.txt
and the other being encrypted and holding flag.txt
.
hint.txt
appears to tell us that the password is in some format with some strange numbers.
|
|
This should refer to the password required for the encrypted .zip
with the flag. Let’s carve out the encrypted .zip
portion from 246D04E.zip
with a hex editor by deleting the second .zip
that follows after, and we can confirm that it is indeed password-protected. This can also be done by binwalk that we used earlier.
This is where I got stuck. I thought the numbers indicated some kind of charset or string length, but fortunately my teammate TheMythologist
immediately identified them as timestamps, which suddenly made a lot of sense because we were given a song file. The logical thing to do was to listen to the song lyrics at each timestamp and identify the words to be used to form the final password. This sounded simple until we realized that the lyrics did not align nicely with the timestamp boundaries and we couldn’t get the right password. My other teammate fawl
thus made this beautiful python script to generate some possible word combinations based on the lyrics:
|
|
I added some more words to the list because it still initially didn’t work, used zip2john to create a hash from the encrypted .zip
and used hashcat to bruteforce based on our generated wordlist.
|
|
|
|
We get the password can_tchaikovsky_talk_to_skeletons_by_a_ouija?
, which makes sense because it wasn’t nonsensical like the other combinations we generated. And so we get flag.txt
from the .zip
!
Flag: UMDCTF-{PY07r_11Y1CH_7CH41K0V5KY}
OSINT
Nikolai 1
My friend Nikolai went off to school in Wyoming this year and he hasn’t been responding to my texts. I’m worried about him since he has no family or friends out there. Can you find out what he has been up to?
author: matlac
score: 4/10
Google searches for these kind of challenges usually don’t give you anything, so I guess the way is to just search on various social media platforms. I knew beforehand that Twitter could filter tweets based on location, so let’s try that with nikolai near:"Wyoming"
Those tweets are relatively recent and the tweeter does sound like someone who has gone off the radar. Looking at @MercatorNikolai
’s older tweets, we see that he has been using and contributing to OpenStreetMap.
He indicates that his OSM account is linked in his bio, but this information was later removed due to apparent trolls. We can use the Wayback Machine at https://archive.org/web/ to see if any past webpages with his OSM account link was archived.
Checking out the snapshot on Mar 25 which is before he cleaned his bio, we find the original link to his OSM account https://openstreetmap.org/user/NikolaiM99 where the flag resides.
Flag: UMDCTF-{4_m4pp3r5_p4r4d153}
Nikolai 2
Nikolai’s school recently contacted his parents since he hasn’t been seen in his dorm or classes for over a week. They know you are an OSINT CHAD and asked for your help. Can you figure out where he ran off to?
Flag Format: UMDCTF-{20_W_34th_St_New_York_NY_10001}
P.S. If you enjoy this challenge you might also enjoy https://www.tracelabs.org/
Hint: All of the accounts you found in Nikolai 1 may be important for this solve
Warning, you only have five guesses
author: matlac
score: 10/10
With Nikolai’s changesets contributed on OSM, we are basically able to trace the trail he took: he went southwards from Laramie to Colorado Springs. This also checks out with his OSM diary indicating his travel to Colorado.
Let’s retrieve the coordinates of 38.8920,-104.8146
of his latest changeset 102759933
and plug it into Google Maps for friendlier indication of nearby amenities and features.
Remember that according to his tweets,
- there is a gas station within walking distance
- there is a Domino’s within walking distance
- there is a chair outside his room with no balcony
- he stays at a lodge/motel
Consolidating those bits of information, we can easily identify the place he is staying to be Aspen Lodge. We see the chair outside the room and the Domino’s Pizza nearby.
Flag: UMDCTF-{3990_N_Nevada_Ave_Colorado_Springs_CO_80907}
Vacation
My mom told me she went to this amazing brewing company in the Carribbean and when I asked her the name of the place, she sent me a picture of her ship. Can you help me find the name of this brewing company?
Flag format: UMDCTF-{City_Companyname}
Note: Companyname = first part of the company name
hxxps://drive.google.com/drive/folders/14eh2f13z32Uf7WFVNHWqHGnXE0P8y8G-?usp=sharing
author: itsecgary
score: 5/10
Zooming in we can make out the words “Rum Therapy” for the establishment in front of the Royal Carribean ship. Googling that, we get an image from Tripadvisor of the same location with the iconic ship which denotes the place to be “Rum Therapy Bar and Treatment Center, St. Lucia”
We put that into Google Maps and we can see that the brewery next to it is the Antilla Brewing Company.
Flag: UMDCTF-{Castries_Antillia}
Justin 2
My friend is in danger and this was the only picture he could send me. Can you find the name of the street he is on? ex. UMDCTF-{Memory_Lane}
hxxps://drive.google.com/drive/folders/1nfFmXuEMRuCOY6BvAAox1AWQPSCqgIhn?usp=sharing
author: itsecgary
score: 5/10
In the image we can see Cyrillic characters on the signage to the right as well as a vehicle registration plate number of A686KY154
. The 154
at the end turns out to be the regional code for Novosibirsk Oblast.
From here I struggled with reverse-image-searching to find the location, so I eventually had the idea to try to identify the unique tall structure depicted in the center. I used the superior yandex.ru’s image search and cropped out the street and cars which would only have polluted our results with noise. I also specified “Novosibirsk Oblast” as an additional search term.
After much trawling through the results, I found what seemed to be the same structure! The linked post from where the image originates points us to the ice skating rink at Spartak stadium in Novosibirsk.
By going to Spartak stadium in Google Maps and circling around the perimeter of the stadium in Street View, we identify the street in the picture to be Ulitsa Kamenskaya.
Flag: UMDCTF-{Ulitsa_Kamenskaya}
Justin 3
Justin only gave us this camera’s live feed and said “Hey guys look! I’m on TV!” Can you find the name of the street he’s on?
format: UMDCTF-{Memory_Lane}
we do not own any IP found besides the one listed below
curl hxxp://chals5.umdctf.io:8000
author: itsecgary
score: 6/10
We are given a webpage with an embedded streetcam livefeed. Checking out the HTML source, we see that this livestream is coming from http://136.169.226.46/1589793911/embed.html?token=xxxxx
through the iframe
’s src
attribute.
Let’s search up the IP address on Shodan.io, which tells us that it is related to something called Ufanet.
Googling that, we find http://maps.ufanet.ru which essentially shows you a map of all public livecams that the organization Ufanet owns.
Using the identifier 1589793911
from the iframe
src
URL we saw earlier to construct http://maps.ufanet.ru/ufa#1589793911 , we are able to view the specific previously-embedded livefeed on the official site! This gives us the official camera name of “Остановка Советская площадь Камера 2”.
We can then plug in the location stated in the camera name into Google Maps (2 locations are returned, but the other Sovetskaya Square result is not in Ufa but in another city), and visually cross-reference our location in Google Maps with the map provided at http://maps.ufanet.ru/. The “Smart stops” filter is used for ufanet’s map to show us bus stops.
We then now turn on the “Camera” filter to show us the various cameras for these bus stops around “Soviet Square” and we can find the exact one towards the west. Looking back at Google Maps, the street that it lies on is Ulitsa Pushkina.
Flag: UMDCTF-{Ulitsa_Pushkina}
MemeCTF 2 Electric Boogaloo
9c222530fc5822720b24a18e0c5200957fcbe169589915c963e765c99c7f5f3a
author: t0pc4r
score: 5/10
We google the given hash/hex data and find a Github repository by UMD-CSEC themselves.
In ./old_files/data/
we can see what’s reminiscent of files inside a typical .git
directory.
After downloading all these files, we can use pigz
to deflate the objects under ./old_files/data/objects
(in my screenshot I renamed the data
folder to .git
). One of the objects contains the flag.
Flag: UMDCTF-{f0r_th3_m3m3}
Misc
ChungusBot
I wonder if ChungusBot has the flag.
Make sure to join the discord for the challenge!
hxxps://discord.gg/dDnQncKqzVauthor: itsecgary
score: 3/10
Since ChungusBot#0421
’s status tells us to check out their code, I tried searching Github and was successful.
To summarize, ChungusBot consists of a main chungus.py
and 4 extensions under ./cogs/
:
chungusboi.py
chungy.py
flag.py
gagagaga.py
Each of these extensions are responsible for handling a command sent via DM to the bot and performing some actions or checks. To retrieve the flag, commands need to be sent in a sequence and within a time limit.
First, chungusboi.py
takes in a kyle
command and writes the current time tick count with a newline character to a user-specific file. Current newline character count == 1.
|
|
Second, flag.py
takes in a yeeee
command and checks if there has been 1 newline character already written into the user-specific file. If it does, it will append the current time tick count with another newline character into the same user-specific file. Current newline character count == 2.
|
|
Third, chungy.py
takes in a mcchungus
command and checks if there are 2 newline characters already written into the user-specific file. If it does, it will use the same process as earlier to append data. Current newline character count == 3.
|
|
Fourth, gagagaga.py
takes in a chungusisgod
command and checks for 3 newline characters already present in the user-specified file. If it does, it will use the same process as earlier to append data. Current newline character count == 4.
|
|
Fifth, gagagaga.py
also takes in a giveittome
command which calculates the time difference between the time tick count in the 1st step and that in the 4th step, and checks if this time difference is less than 15. So if we have sent our sequence of commands within 15 seconds, the bot will then send us the flag.
|
|
No scripting is needed because we can send fast enough manually.
Flag: UMDCTF-{I_th1nk_y0u_4r3_th3_b0t_n0w_sh3333333333sh}
John’s Return
I received this network traffic from John, but I don’t what he’s trying to say? Can you figure it out?
author:t0pc4r
score: 7/10
Attached: received.pcapng
Open the .pcapng
file in Wireshark and we can see a capture of some Wireless 802.11 traffic. At the beginning, we can spot that there is the 802.11 authentication process with a EAPOL 4-way handshake for WPA-PSK. After that, data sent is encrypted. This documentation was very helpful in familiarizing me with the protocol: https://www.cisco.com/c/en/us/support/docs/wireless-mobility/80211/200527-Fundamentals-of-802-11-Wireless-Sniffing.html#anc60
Since we have the 4-way handshake captured, we just need to know the SSID name and the passphrase for the WLAN to decrypt the traffic. This is mentioned further down in the documentation linked above: https://www.cisco.com/c/en/us/support/docs/wireless-mobility/80211/200527-Fundamentals-of-802-11-Wireless-Sniffing.html#anc63. The SSID is known to be linksys
as shown in packet #1. To bruteforce the password, we can use hcxpcaptool
from hxctools
to convert received.pcapng
into a format for hashcat to crack.
|
|
Run hashcat with the standard rockyou.txt
wordlist to crack the password as chocolate
|
|
We can now specify this password chocolate
to be used as a WPA decryption key in Wireshark’s Preferences, with key-type wpa-pwd
.
The plaintext is our flag :)
Flag: UMDCTF-{wh3r3_j0hn}
Satelite
My friend from Russia sent me this message, but all I see are cryllic characters?
author: itsecgary
score: 2.5/10
Attached: message.txt
We are given a text file which appears to be filled with the famous Lorem Ipsum text as Cyrillic characters. Based on the tone of uncertainty in the challenge description’s question, I hypothesized that there may be non-Cyrillic characters hidden within the ocean of text. I used a simple regular expression of [^a-zA-Z0-9\-_{}]+
to remove all characters that do not belong to the UMDCTF{} flag format. As suspected, what remained was the flag.
Flag: UMDCTF-{RIP_sPutN1k_1962}
Web
The Matrix
Oh no! It looks like the robots have taken over! Infilitrate their site and save the world! But beware, they only allow one of them to access it.
curl hxxp://chals5.umdctf.io:4000
author: t0pc4r score: 3/10
If we visit /the-matrix
, we are redirected to /403
which gives us an error message that the page is for robots only.
My first thought is that this could be something related to manipulating the User-Agent
HTTP header field to make us appear as if we were a bot.
With that idea, I used Burp Intruder to send requests to /the-matrix
with different User-Agent
values.
Payloads like WordChampBot
successfully give us the flag (I chose this because it is the shortest).
Flag: UMDCTF-{r0b0t_r3b3ll!0n}
The Matrix Reloaded
Good job, you got rid of the robots. Bad news is that it looks like they fled to Iceland and have even higher security! Can you infilitrate >their site? But beware, they only allow one of them to access it.
curl hxxp://chals5.umdctf.io:4001
author: t0pc4r
score: 4/10
Setting Accept-Language
to is
which is the country code for Iceland allows us to access the page and retrieve the flag.
Flag: UMDCTF-{1c3l@nd1c_d0m1n@t!0n}
The Matrix Revolutions
The robots are done with your tricks. They’re sick of hiding in plain site. Now they’re going to hide in the shadows so no one, not even you can find them. You’ll have to find how their site works. I have a feeling there’s more to it than what we can see.
curl hxxp://chals5.umdctf.io:4002
author: t0pc4r score: 5/10
The flag is supposedly somewhere hidden, so I used Burp Suite’s directories and files scanner to bruteforce for content.
Funnily enough, hidden request paths in the form of incrementing numbers were discovered. Each response seems to contain one character of the flag.
We can save the server responses, extract it by removing content matching the basic regex of .+:.+|\n|HTTP.+
and we are left with the flag.
Flag: UMDCTF-{r0b0t5_43v3r}
IOT Project
IoT is so cool and secure! Check out my project from April 7 at hxxps://azeemsm-umdctf.github.io/
author: azeemsm
score: 5/10
Azeem should have a Github for his projects since he has a github.io page.
In his repository, there is a short piece of Arduino code that simply prints ring!
to the serial port upon a doorbell ring. Nothing special.
|
|
The more important script is program.py
. A secret key is read from a file (line 8
) and then used to send a POST request to an IFTTT Webhook endpoint /ring2/
each time the doorbell rings (line 25
).
|
|
Commit history showed that the secret key file maker.key
was originally uploaded to the repository with the value of iWEKorMwH5rgGjyHb4jzedP9m9LA7yNkTZ0dvfzDSUO
, and the POST request was originally sent to the /ring/
endpoint where we could also specify the email address to receive from the IFTTT Webhook via the value1
parameter.
We try triggering this old /ring/
endpoint and supplying an email of our own, and we successfully get an email with the flag.
|
|
Flag: UMDCTF-{g!t_h00k3d}
IOT Project 2
Yeah im such a good engineer, got another project in just under a week later on the 13th. My resume is going to look so good with all these projects! Check out my project at hxxps://azeemsm-umdctf.github.io/ (don’t get the account suspended or there will be disqualifications)
author: azeemsm
score: 6/10
In the source code of the .github.io
blog, it is mentioned that there are extra notes in robots.txt
. These notes hint that the parameters value1=normal text
and value2=hashtag
are used for the toaster to tweet.
Keeping that in mind, I just searched Twitter for "normal text"
, sorted by Latest and it returned a pretty conspicuous account. The account’s bio had the flag in hexadecimal format.
Flag: UMDCTF-{tw3et!ng_4nd_t0@st1ng}
Return of the Flag Bay
We loved the flag bay so much, that we decided to bring it back. Although, something is a bit different about this one. We can’t figure out which username and password is correct from the list of users. Can you help us figure it out?
curl hxxp://chals5.umdctf.io:4004
author: WittsEnd2
score: 7/10
A login page means that there could be SQL injection vulnerabilities, so let’s test some payloads.
Sending username='; S
gives an SQL error, suggesting that the SQL SELECT statement used is vulnerable.
Sending username=';''A OR '1'='1';
showed that the OR
operator was filtered out. This is fine though, because we can use ||
in place of OR
since it is not blacklisted and removed.
Thus, we can do an authentication bypass with username='|| '1'='1';#
, which succeeds because '1'='1'
is always true
and the password check condition is commented out with #
. The flag is returned Base64-encoded.
Flag: UMDCTF-{84y_w425_3p150d33_23v3n93_0f_7h3_f149_84y}
Top of the Charts
I found this site which seems to boast about itself too much. It claims to be above everything else but I’m not so sure. I think the success has gone to its head.
curl hxxp://chals5.umdctf.io:4003
author: t0pc4r score: 5/10
Sending a HEAD request specified with -I
for curl.exe
gets you the flag. It’s a guessy challenge for those who do not already have prior knowledge of the different possible HTTP request methods - they wouldn’t be able to pick up the hint in the challenge description.
Flag: UMDCTF-{h3@d1ng_t0w@rd5_th3_l1ght}
Thanks for reading!