9447 CTF Recon 1 & 2 Writeups

Last weekend I was lucky enough to play with the talented Montreal-based capture-the-flag (CTF) team DCIETS in the 9447 online CTF event. For those of you who are not familiar with these events, CTFs are competitions where teams are presented with security-related challenges that they need to solve in order to win points. Challenges are usually grouped into categories or tracks such as web and binary exploitation, reverse engineering, crypto-breaking, steganography, and forensics. The team that solves the most challenges wins the right to brag and in some cases win cool prizes or cash.

This year's 9447 CTF was exceptional. One of the tracks that I most enjoyed was the miscellaneous track that contained two challenges named Recon 1 & Recon 2. The premise of the challenge was that an attacker had compromised your website. A log file from the compromised web server was given as a starting point and you had to achieve two objectives:

  1. Find the website of the attacker.
  2. Find the attacker's full name.

Recon 1

The first task was to find the attacker's website. Two IP addresses appeared in the log file provided, and, and they both appeared to be attempting to login to the administrative console of the affected web server. Here's a snippet of the web server log: - - [15/Nov/2015:16:01:30 +0000] "POST /login HTTP/1.1" 200 5613 "-" "Python-urllib/2.7" - - [15/Nov/2015:16:01:31 +0000] "POST /login HTTP/1.1" 200 5613 "-" "Python-urllib/2.7" - - [15/Nov/2015:16:01:32 +0000] "POST /login HTTP/1.1" 200 5613 "-" "Python-urllib/2.7" - - [15/Nov/2015:16:01:32 +0000] "GET /admin HTTP/1.1" 403 283 "-" "curl/7.35.0" - - [15/Nov/2015:16:01:33 +0000] "GET /admin HTTP/1.1" 403 283 "-" "curl/7.35.0" - - [15/Nov/2015:16:01:33 +0000] "POST /login HTTP/1.1" 200 5613 "-" "Python-urllib/2.7" - - [15/Nov/2015:16:01:34 +0000] "POST /login HTTP/1.1" 200 5613 "-" "Python-urllib/2.7"

Since we were looking for the attacker's website, the first thing we tried to do is navigate to each of the IP addresses in a web browser over HTTP and HTTPS. was the only IP address that responded to my initial requests but I got a brief message:

This gave us the impression that the web server may have been using virtual hosting. Virtual hosting allows more than one domain or website to be hosted by the same web server. A web server would differentiate between a request for foo.com or bar.com by inspecting the HTTP Host header in the body of the HTTP request.

At this point we did the simplest thing which was to perform a reverse DNS lookup for using nslookup:

$ nslookup
Non-authoritative answer:	name = www.williestoleyour.pw.

This step revealed that the IP address resolved to www.williestoleyour.pw and sure enough when we navigated to this domain in my web browser we were presented with an actual web page:

However, after browsing through the page's source code and looking at it in the browser, we noticed that there was no flag. Flag's were of the format 9447{something_unique_here} and all we could find as an interesting artifact was an email. At first, we tried sending an email to the address listed on the web page to see if we'd get an out-of-office reminder. No such luck. Then we performed a historical whois lookup using DomainTools and DomainBigData but the domain name had privacy guard enabled which meant that ownership details were redacted. Finally, we turned towards the Internet's greatest asset - the Internet Archive's WayBack Machine.

The WayBack Machine is the Google of online web page history. It allows you to take a trip down memory lane so your kids can see how Microsoft.com looked like when they first went online and offered Visual Basic 5. In this case, we used the WayBack Machine to view the revision history of http://www.williestoleyour.pw and sure enough there was an entry from November 15th of this year. Browsing the archived version of the website revealed another email address - info@dynamiclock.pw:

At this point we simply navigated to http://dynamiclock.pw in our web browsers and sure enough, there it was, the first flag:

Recon 2

At this point we were tasked with finding the attacker's full name. The site only had his first name - William. We tried several techniques to try and identify the attacker's full name that failed to yield any results:

  1. Historical domain whois lookups using both DomainTools and BigDataDomain.
  2. Password resets and contact imports on a number of popular social networks (LinkedIn, Twitter, Facebook, etc.) using the emails identified earlier in Recon 1 (info@williestoleyour.pw and info@dynamiclock.pw) as well as other email addresses based on the attacker's first name (bill@..., willie@..., william@..., etc.).
  3. Sending an email to info@dynamiclock.pw to check for an out-of-office reminder.
  4. Filling in the contact form on http://dynamiclock.pw to check for a name in the confirmation email.
  5. Checking different DNS record types (i.e. SOA, TXT) for both domains to check for any interesting artifacts.
  6. Interrogating the inbound mail servers for both domains using the VRFY command.
  7. Inspecting the SSL certificate for any additional information.

Alas, nothing worked - but after performing all these tests we noticed something peculiar. Unlike williestoleyour.pw, dynamiclock.pw was sitting behind CloudFlare services. CloudFlare is a cloud-based service that offers various features like infrastructure anonymization and denial of service mitigation. These days it is increasingly being used by the online criminal and terrorist groups to anonymize their online infrastructure.

At this point it seemed clear that the goal of this challenge was to first de-anonymize the server. After having our small eureka moment, we looked at the meta-data within the confirmation email we received after filling in the contact form on dynamiclock.pw. Bingo!

Hidden in plain sight, the server's real IP address was embedded in the email message's meta-data - Opening our web browser and navigating directly to we were presented with a directory listing containing a contact card -- dynamicWarl0ck.vcf:

The contact card only revealed the attacker's first name, but now we were armed with an additional piece of information which would most likely be the user's online alias - dynamicWarl0ck. At this point we headed over to CheckUsernames to see where that alias was being used on the Internet. CheckUsernames checks over 300 sites including social networks, blogs, forums, developer networks and reports whether the desired username is available. Sure enough, dynamicWarl0ck was taken on several sites, including GitHub:

After navigating to the attacker's GitHub page, we saw the attacker's first name again (William) and found a comment in their bio indicating that they moved to BitBucket:

Navigating to the attacker's BitBucket page we found a code repository named dynamics. Finally, after digging through the commit history of the repository, we found the final flag (in green, below):

Final Thoughts

The 9447 CTF organizers did a fantastic job of putting together a great reconnaissance and forensics challenge that demonstrated the importance and relevance of open source intelligence in information security. By using various open source intelligence techniques and leveraging minor information leaks we were able to circumvent a number of hurdles including virtual hosting and server anonymization which eventually allowed us to identify our perpetrator. In many ways, the methodology used to solve this challenge mimics the methodologies being used by real world attackers or penetration testers to penetrate an enterprise perimeter. If your organization is inadvertently leaking information to the Internet then rest assured that this information will significantly increase an attacker's chances of successfully compromising your environment.

Finally, many thanks to the 9447 CTF team for organizing this event and the DCIETS team for allowing me to join their team. It was a pleasure and I'm looking forward to participating in next year's event!