ASIS CTF Quals 2014 WriteUps

Robin François
Blog cybersécurité

A team of Navixia engineers took part in the Iranian ASIS CTF Quals 2014, which ended on May 10, 2014.

There were more than 30 challenges to complete and 300 teams participated.

Here is our traditional contribution to the community, a writeup on the three following Forensics challenges :

  • Forensics 100 challenge - Toq Toq
  • Forensics 150 - Postscript in PCAP in PCAP
  • Forensics 175 - Prying Ears

Forensics 100 - Toq Toq

In this challenge, we were given a PCAP file. Taking a close look, we can see that some HTTP requests to 87.107.123.4 get responses with very interesting HTTP content:

For example, on the screenshot, we can see that the content is queried on port 24931 and we get a directory listing indicating that a file named first_part_of_flag exists on the server. We need to find the other parts of the flag.When filtering using the following Wireshark filter, we can see interesting results:

data-text-lines contains flag and ip.addr==87.107.123.4

In short, we get the following information:

  • First part of flag on port 24931
  • Second part of flag on port 19760
  • Third part of flag on port 3695
  • Fourth part of flag on port 31054
  • Last part of flag on port 8799

Let's just get the flag parts and score! ...

# curl http://87.107.124.4:24931/first_part_of_flag
curl: (28) connect() timed out!

No easy scoring for us... We need to get back to work. We then try to only filter traffic involving the 87.107.123.4 IP address and look at what we have.

Some ping/ICMP traffic and then lots of SYNs on various ports. This looks like some port knocking technique to open the HTTP ports.

For each flag part, we need to perform a port knocking mechanism involving sending SYN packets to several TCP port before making an HTTP request to the now open port.

For example, to get the second part of the flag, we need to:

  • Knock on port 42304
  • Knock on port 53768
  • Knock on port 3297
  • HTTP request to port 19760

Now, to get the flag, we just need to write a small scrip to implement this logical process. We will use the scapy python library to perform the port knocking and curl for the HTTP request part:

#!/usr/bin/python
from scapy.all import *
import random
import requests
conf.verb=0
base_URL = "http://87.107.123.4:"
def knock(ports):
    print "[*] Knocking on ports"+str(ports)
    for dport in range(0, len(ports)):
    ip = IP(dst = "87.107.123.4")
    SYN = ip/TCP(dport=ports[dport], flags="S", window=14600, options=[('MSS',1460)])
    send(SYN)
def get_flag_part(port,part):
    command = ["curl", "-s" ,base_URL+str(port)+"/"+part+"_part_of_flag"]
    p = subprocess.Popen(command, stdout=subprocess.PIPE)
    result = p.communicate()[0]
    return result.strip()
flag=''
ports = [9264,11780,2059,8334]
port = 24931
knock(ports)
flag_part = get_flag_part(port,"first")
flag = ''.join([flag,flag_part]
print flag_part
ports = [42304,53768,3297]
port = 19760
knock(ports)
flag_part = get_flag_part(port,"second")
flag = ''.join([flag,flag_part])
print flag_part
ports= [23106,4250,62532,11655,33844]
port=3695
knock(ports)
flag_part = get_flag_part(port,"third")
flag = ''.join([flag,flag_part])
print flag_part
ports= [49377,48116,54900,8149]
port=31054
knock(ports)
flag_part = get_flag_part(port,"fourth")
flag = ''.join([flag,flag_part])
print flag_part
ports= [16340,59991,37429,60012,15397,21864,12923]
port=8799
knock(ports)
flag_part = get_flag_part(port,"last")
flag = ''.join([flag,flag_part])
print flag_part
print "Flag: %s" % flag

Forensics 150 - (Postscript in PCAP in PCAP)

We were presented (again) with a PCAP file. Let's take a look at what HTTP objects Wireshark can extract from this file:

We export all the files to a folder. Some bash-fu to quickly look at interesting files:

# file * | grep -v "HTML" | grep -v "ASCII" | grep -v "data"

AlienVault(27).gif: Dyalog APL
AlienVault(33).gif: DOS executable (COM)
AlienVault(42).gif: DOS executable (COM)
favicon(1).ico:     MS Windows icon resource - 1 icon
favicon.ico:        MS Windows icon resource - 2 icons, 32x32, 256-colors
myfile:             tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 65535)

The myfile looks juicy as it is a PCAP file inside our first PCAP file. But if we try to open it:

# tshark -r myfile
tshark: The file "myfile" appears to be damaged or corrupt.
(pcap: File has 356738353-byte packet, bigger than maximum of 65535)

Fortunately, there is pcapfix. We can use the commandline version or the online version. After fixing the myfile PCAP, we can have a look at its content.

In forensics, one of the first things to do when looking at a PCAP is to take a look at the Conversation panel ("Statistics" -> "Conversations"). If we look at the TCP conversations and order them by "Bytes" exchanged, we can see 3 interesting TCP conversations. Looking at the TCP stream is even more interesting: Clearly, we have something to look into here. We can save each TCP stream to a file.

Now we have 3 files but we don't know how to read them. If we look at the destination port of the TCP stream, we see it is port 9100 which is commonly used for printing.

Printers usually handle PostScript (.ps) files. Let's rename our files and try to open it with a PS viewer (e.g. GhostScript Viewer). It works!

By manually checking every file, we finally get our flag.

Forensics 175 - Prying ears

We were presented (AGAIN!) with a PCAP file. After some investigation, we can see that a lot of DNS traffic is performed by a machine (192.168.11.4) to 192.168.110.2. By carefully looking at its queries, we can see strange query names (to [hexadecimal].asis.io). It looks like a DNS tunnel thing.

Let's filter the DNS packets. We have to be careful and only keep the DNS packets that the nameserver has correctly answered (no "No such name answer"). If we do not filter these requests (as we were not doing properly when solving this challenge), resulting file when decoding will not be valid.

We use the following wireshark filter to only get good answers (filtering on dns.flags) and removing DNS answers to legitimate names:

dns.flags == 0x8180 and dns.qry.name matches "[0-9a-f]{14}.asis.io"

After filtering, we are left with only 194 DNS responses and we can use Wireshark to export only the filter packets ("File" -> "Export Specified Packets").

We can then use some bash-fu to get only the hexadecimal parts of the DNS answers.

# strings dns_tunnel.pcap | grep -P "^[0-9a-f]{14}$" | tr -d "
" > dns.hex
# cat dns.hex
89504e470d0a1a0a0000000d4948...

At the beginning of the dns.hex file, we can recognize the hexadecimal header of a PNG file (89 50 4E 47) so we try to decode dns.hex and write it to a PNG file:

#!/usr/bin/python
file_hex = open('dns.hex','r').read()
open('img.png','w').write(file_hex.decode('hex'))

We get a fine looking PNG with the flag: