Hacktober 2020 CTF Writeup
I’m super excited to be writing my first CTF challenge writeup! This CTF was a lot of fun, and I learned some new skills!
If you have questions about a challenge or one of my explanations feel free to poke me: @CharCharBonkles
Table of Contents (The challenges I solved):
- Linux
- Programming
- Stego
- Cryptography
- SQL
- OSINT
- Traffic Analysis
Linux⌗
Talking to the Dead 1⌗
First, log in to the SSH Server using the given credentials:
ssh hacktober@env.hacktober.io
Then, figure out what’s in our current directory, and use the linux find command to locate the flag.
Cat the file and submit the flag!
flag{cb07e9d6086d50ee11c0d968f1e5c89418c}
Talking to the Dead 2⌗
Log in and poke around… This time, run ls -al
to get a bit more information than we did last time…
flag{728ec98bfaa302b2dfc2f716d3de7869f3eadcbf}
Talking to the Dead 3⌗
This challenge is a little more complicated… First, let’s find the flag!
This time, the flag is in someone else’s documents folder. Let’s try to cat it:
Hmmmmmm, that didn’t work. We don’t have the correct permissions. Only spookyboi and members of the spookyboi group can access the flag 1 :
We aren’t in the spookyboi group either:
We have to figure out how to log in as the spookyboi user… If we look at the challenge titles, there’s another challenge that might give us some information on spookyboi… Check out Past Demons and then come back!
Now we have spookyboi’s password: zxcvbnm
, and can su to his user and read the flag!
flag{445b987b5b80e445c3147314dbfa71acd79c2b67}
Talking to the Dead 4⌗
This challenge writeup is by one of my teammates, @Geeg007!
So obviously its READ questions first…
Ohh there are ssh detials provided aha that saves dude from bruteforcing (weak passwords)
So let’s login.
hehe we’re IN, so i’m laying hands where possible
So i searched and aha FIRST sight at flag4.txt And yes it’s in /root directory so let’s goooo!!!
find / -name flag4.txt
Ahhh I thought I had you (flag4.txt)… I probably need root access to view this file!
So let’s cd to / and look for setuid bits using:
find . -perm /4000 &2>/dev/null
So everything looks pretty standard yeah? Not quite - I’m interested in finding out what ouija is in this box…
So cat ./usr/local/bin/ouija
apparently gave us a clue for how to use the setUID binary.
Because the ouija
binary has extra permissions, we can use it to view the contents of flag4.txt even though our user doesn’t have permissions!
flag{4781cbff13df6622565d45e790b4aac2a4054dc}
Gotcha!!! Thanks to CyberUp & Cyber Hacktics for this wonderful challenge. Also to my teammates CharCharBinks (C), J0hn_W1ck & HarleyHacker for having me in the team also providing moral & technidcal support. LOVE YA
Programming⌗
Message in an Array⌗
At first, I didn’t see the code in the challenge description, but when I did I copied it to vistual studio code to make it more readable:
This code looks like c++, and it creates an array of strings of length 4:
string[] str = new string[4] {"DEADFACE", "Nothing", "Stop", "Will"};
And then it prints the contents of the array in a specific order:
Console.WriteLine("{1} {3} {2} {0}", str);
When we re-order the words from the string in the order specified in the Console.WriteLine
statement, we get:
Nothing Will Stop Deadface
So our flag is:
flag{Nothing Will Stop DEADFACE}
Remember that programming array indices start at zero!
Stego⌗
Ghost Hunter⌗
Because the challenge description mentioned that it was intercepted on the Ghost Town forum, I decided to look around to find more information. On one of the threads, I found this comment:
https://www.ghosttown.xyz/t/haunted-pictures/33/7
Then I searched google until I found a stego tool that worked!
http://manytools.org/hacker-tools/steganography-encode-text-into-image/
flag{8862a805a3140996343da91bdcbda79e}
Blasphemy⌗
The challenge description mentions “some kind of tool” and the most common steganography tool for .jpg files is steghide!
I always have to look up how exactly to use steghide, and I usually wind up on this page: http://steghide.sourceforge.net/documentation.php
flag{950634ccc97ca3ef03e22c759a356973}
Cryptography⌗
Shameless plug: I wrote this blog post on beginner CTF Cryptography, and it has more information about all of the ciphers used in the challenges that I solved!
Hail Caesar!⌗
The challenge name and the attached image (a code wheel) are both clues to the type of cipher used to encrypt the message! The correct cipher for this challenge is the caesar cipher.
I used this tool to decrypt the message: http://rumkin.com/tools/cipher/caesar.php
Our flag is:
BOO SCARED YOU
Down the Wrong Path⌗
The attached image contains the following text:
RMTLOBBTERSUXT
EBOLOOOHWGORTA
METSKIUETEFNAC
EREPYATNATOETK
Because the text is arranged in columns (rows) it’s likely that the cipher used for this challenge is columnar transposition.
This is the tool I used to solve this challenge:
https://www.boxentriq.com/code-breaking/columnar-transposition-cipher
The spacing was a bit off, but the top result is what we’re looking for!
remember to tell spookyboi about the new targets of our next attack
Because the challenge asks for the intended recipient, our flag is:
spookyboi
Cover your Bases⌗
Again, the challenge title is a hint! “Bases” is referring to base 64 encoding. So, all we have to do is use a base64 decoding tool to get the flag!
ZmxhZ3tzaG91bGRhX21hZGVfdGhpc19vbmVfaGFyZGVyfQ==
The tool I used is: https://simplycalc.com/base64-decode.php
flag{shoulda_made_this_one_harder}
SQL⌗
Have I mentioned that I love databases? If you want some foundational information about databases (with a sprinkling of SQL injection), check out An Introduction to Relational Databases for Hackers by yours truly!
Past Demons⌗
First, let’s figure out what kind of database we’re dealing with by using the linux file
command:
The database dump file we have is for sqlite3.x and fortunately kali linux comes with sqlite 3 installed!
Using the information from this webpage, we can load the .db file into sqlite and run queries! I was super lazy and didn’t want to use a join, so I just ran two separate queries:
select * from passwd;
and
select * from users;
In the users table, spookyboi’s primary key is 8, so if we match that with the 8th password hash we should have spookyboi’s password hash…
But the challenge asks for spookyboi’s password, so we have to crack it… My go-to first stop for cracking hashes is crackstation.
Using the hash from the database as input: 59DEA36D05AACAA547DE42E9956678E7
And voila! We have spookyboi’s password!
flag{zxcvbnm}
Address Book⌗
This SQL challenge involves another type of database dump! According to the linux file
command, this is just UTF-8 encoded text… With very long lines… So, I opened it up in good ole VS Code:
I know my screenshot is really small, but using information from the intel page (luciafer’s first and last name) I used the built in search function to locate Lucia’s email address:
flag{luciafer.b4vr0n@shallowgraveu.com}
Calisota⌗
Before we can complete this challenge, we have to Load the MySQL Dump file into a DMBS so we can run queries. Once that’s done, we can start querying the database!
Disclaimer: there were scoring issues for this challenge so I didn’t end up getting points for it but I believe I did get the correct answer! Without further ado, here’s my solution!
First, let’s take a look at the fields in the users table:
select * from users limit 10;
And then, let’s take a look at the states table:
select * from states limit 10;
Now that we know the contents of the users table and the states table, we can write a query to join the two tables together. This will make sure we’re pulling the right information out of the tables we’re interested in before we start filtering and counting:
SELECT users.username, states.state_abbrev FROM users
INNER JOIN states ON users.state_id=states.state_id
LIMIT 10;
We’re getting usernames and state abbreviations, so far so good! Let’s add some conditions to our query - we want students from only CA and MN:
SELECT users.username, states.state_abbrev FROM users
INNER JOIN states ON users.state_id=states.state_id
WHERE state_full='California' OR state_full='Minnesota';
Now our results are limited to users from CA and MN… But the challenge asks for the count!
So now we use the builtin SQL count()
function:
SELECT count(*) FROM users
INNER JOIN states ON users.state_id=states.state_id
WHERE state_full='California' OR state_full='Minnesota';
Voila! That query should have been a correct answer! However, because the entire query is the answer, there are many many different ways we could have solved this question… And only one right answer :(
Body Count, Null and Void, Fall Classes⌗
Body Count⌗
Before we can complete this challenge, we have to Load the MySQL Dump file into a DMBS so we can run queries. Once that’s done, we can start querying the database!
Let’s take a look at the users table:
select * from users limit 10;
Now that we know what the users table looks like, we can run the following query to get the number of rows (or records) from the users table:
select count(*) from users;
Flag{900}
Null and Void⌗
Before we can complete this challenge, we have to Load the MySQL Dump file into a DMBS so we can run queries. Once that’s done, we can start querying the database!
This challenge asks us to identify a single command to figure out which fields in the users table can be null.
My first attempt worked, but it was not considered correct:
The DESCRIBE
command was the correct answer for this challenge:
flag{middle,DESCRIBE}
Fall Classes⌗
Before we can complete this challenge, we have to Load the MySQL Dump file into a DMBS so we can run queries. Once that’s done, we can start querying the database!
First, let’s run a couple queries to figure out what kind of data we’re dealing with:
The data we’re slooking for is in the term_courses table - it represents a many to many relationship between courses and terms. We’re looking for the number of courses being offered for FALL2020 which means that our term_id must equal 2. We also don’t want any duplicates:
SELECT COUNT(DISTINCT course_id) from term_courses where term_id=2;
flag{401}
90’s Kids⌗
Before we can complete this challenge, we have to Load the MySQL Dump file into a DMBS so we can run queries. Once that’s done, we can start querying the database!
First, let’s take a look at the users table, and fiddle around with extracting parts of the date field into separate fields so we can filter our results:
Now that we know how to extract information from the date field, we can pull out the month and year separately, which will make writing our WHERE
clause much easier:
select username, EXTRACT(YEAR FROM dob) as year, EXTRACT(MONTH FROM dob) as month from users WHERE ((EXTRACT YEAR FROM dob) >= 1990 AND (EXTRACT YEAR FROM dob) <= 1999) AND EXTRACT (MONTH FROM dob) = 10;
Now that we’ve verified that we’re getting correct results (only years in the 1990’s and October or 10 for the month) we can clean up our query and count:
SELECT COUNT(username) FROM users WHERE ((EXTRACT YEAR FROM dob) >= 1990 AND (EXTRACT YEAR FROM dob) <= 1999) AND EXTRACT (MONTH FROM dob) = 10;
Bonus screenshot: the full result set:
flag{32}
Jigsaw⌗
This challenge asks us to match a specific pattern, and what better way to match a very specific pattern than regex! Let’s start with the information we know and what we need to know to write some regex, and then a SQL query to give us our answer!
First, let’s create some regex to match the specific pattern we’re given:
Condition | Regex | Explanation |
---|---|---|
The first two characters are K R or I | [KRIkri]{2} | We need both upper and lower case because the first letter of the name will be uppercase and the second letter will be lowercase. |
Wildcard - any character except newline | . | Pretty self explanatory - the . character represents any character except newline. |
Three letters | [a-z]{3} | This regex matches any letter, three times. |
The last letter is e-n inclusive | [e-n] | This group matches the letters e-n only once. |
So our full regex statement is: ^[KRIkri]{2}.[a-z]{3}[e-n]{1}
Regex is tricky, here are my favorite tools/cheatsheets:
Here’s the “regexplanation”2 for the expression I wrote for this challenge:
If we read the information carefully we can infer that the total length of the last name is seven characters:
- Two first letters
- One wildcard
- Three more letters
- One last letter
The appropriate SQL query that makes use of all this information is:
SELECT first, last, username from users where last REGEXP '^[KRIkri]{2}.[a-z]{3}[e-n]{1}' AND LENGTH(last)=7;
flag{image.wa1k3624}
For more information on using regex with MySQL:
https://dev.mysql.com/doc/refman/8.0/en/regexp.html
https://www.geeksforgeeks.org/mysql-regular-expressions-regexp/
https://www.guru99.com/regular-expressions.html
Loading the MySQL Dump⌗
We need to be able to load the MySQL Dump file into a DBMS to be able to solve several challenges, and there’s enough content so I decided to break this out into its own section!
First, start the MySql Service and make sure your version is compatible - the same major version should do!
Then, start the service again with --skip-grant-tables
because I didn’t want to bother with the “what in the world is my MySQL root password” dance…
Then, log in as root because I like to live on the edge (VM Snapshots encourage risky behavior):
mysql -u root
Create a database to load our data into, and then switch to it:
CREATE DATABASE hacktober;
USE hacktober;
Finally, load the MySQL Dump file into our new database:
SOURCE /path/to/MySQL_DumpFile/shallowgraveu.sql
OSINT⌗
Creeping 1⌗
Let’s be honest… We love some good ole internet creeping! The best place to find information about people is facebook… Unfortunately, you have to be logged into an account to be able to solve these challenges. I googled Ali Tevlin’s handle (alitevlin) that I found on the intel page, and came up with this informaiton from his facebook page:
flag{F. Kreuger Financial}
Creeping 2⌗
Ali Tevlin’s job title is listed under his place of work:
flag{Senior Acquisitions Supervisor}
Creeping 3⌗
Let’s find his birthday! It is also listed on facebook:
flag{17 06 1973}
Traffic Analysis⌗
Time to show wireshark some love!
Remotely Administrated Evil⌗
Remotely Administrated Evil⌗
The challenge description gives us several clues for what to look for - the most notable being that our answer will be contained in a URL. Let’s filter our traffic for just HTTP Traffic:
http
Our flag is the file name:
Flag{solut.exe}
Remotely Administrated Evil 2⌗
Another day, another pcap! now we’re looking for post-infection traffic, specifically a MYDDNS domain that the malware communicates with. Let’s build a bit off of our last challenge to find the traffic we’re looking for. Because of the malicious download that we’ve already identified, we know the ip address of the compromised host!
172.16.1.219
Now we build a traffic filter:
ip.addr == 172.16.1.219
Set your wireshark preferences to resolve DNS for you:
Then, just scroll through the traffic until you see something related to MYDDNS. You could probably write a filter for this, but at the time I had no idea what type of traffic would be related to MYDDNS so I just went for it.
flag{solution.myddns.me}
Remotely Administrated Evil 3⌗
Now we have the challenge of identifying the type of malware infection! We know several critical pieces of information:
- The initial delivery method (download url)
- A probable C2 Server
- We could probably even extract the malicious file!
Let’s see what virustotal says about our initial download url:
I poked around for a bit and eventually arrived at this report:
https://bazaar.abuse.ch/sample/b16b3d99441f078e081e2ac0a8f0121ce4dab264bf434e353d1e00a57e54d3aa/
flag{netwire}
Evil Corp’s Child⌗
Evil Corp’s Child⌗
We’ve got a lot of traffic but not a lot of clues… A very common method of malware delivery is over HTTP (as seen in the last challenge) so let’s start there:
http
That’s interesting…. the only HTTP request has a… jpg file? But that doesnt look malicious! Let’s extract the file and see what it really is:
file picture2.jpg
The linux file command confirms our suspicions… The image file is actually a windows executable!
flag{picture4.png}
They tried to pull a fast one on us…
Evil Corp’s Child 2⌗
This challenge description gives us quite a lot to go on! We know that our malware will be communicating from our compromised IP from the last challenge 192.168.1.91
and that the traffic we’re looking for is over the same port as HTTPS, or port 443
.
Building our wireshark filter from this information:
ip.addr == 192.168.1.91 && tcp.port == 443
We also want to look at traffic after our initial infection, so we’ll start looking after packet No. 231
This traffic looked suspect, and as it happens it’s the right address!
flag{213.136.94.177}
Evil Corp’s Child 3⌗
For this challenge, we have to hunt down certificate! We’re given the ip address that provides the certificate: 37.205.9.252
.
Let’s filter our traffic by that address and look for a key exchange:
ip.addr == 37.205.9.252
The bulk of the traffic that we see right away is TLSv1.2. We’re looking for information about a certificate, so it makes sense to look in the packet that says it has certificate information
We’re looking for the locality name, so we have to drill down a bit further:
There it is! LocalityName=Mogadishu
flag{Mogadishu}
Evil Corp’s Child 4⌗
I’ll take malware strain identification for 100, Alex!
Fortunately, we have a malware sample from Evil Corp’s Child - Part 1 that we can upload to virus total! Behold, it’s Dridex!
flag{Dridex}
An Evil Christmas Carrol⌗
An Evil Christmas Carrol 1⌗
This time we’re looking for a malicious .dll file that was downloaded over HTTP. So, let’s filter for http traffic!
http
There’s our .dll file!
flag{july22.dll}
An Evil Christmas Carrol 2⌗
We’re looking for another C2 domain, this time the post-infection traffic is over HTTPS and our infected host is 10.0.0.163
:
tcp.port == 443 && ip.addr == 10.0.0.163
We should also enable domain resolution:
Here’s our filtered traffic, we’re looking for post-infection traffic so we’ll start looking after packet No. 529:
Now that’s what I call a sketchy looking domain…
flag{vlcafxbdjtlvlcduwhga.com}
An Evil Christmas Carrol 3⌗
Once again, we’re looking for the type of malware infection. Using logic, and brain cells, we can guess that the domain is pretty important because that’s what we had to find for the last challenge. Looking it up on virustotal, we get some domain information (which isn’t all that useful):
However, if we scroll down to the google results, we find a link to the Malware Bazaar:
flag{zloader}
The Cranberry Defense Team put forth a great effort! 179th out of 1062 isn’t bad!
-
Image generated with https://www.regexplained.co.uk/ ↩︎