Holiday Hack 2015, Part 1

Gnome in Your Home - The 2015 SANS Holiday Hack Challenge

Our first tasks:

Answer the following

  1. Which commands are sent across the Gnome’s command-and-control channel?
  2. What image appears in the photo the Gnome sent across the channel from the Dosis home?

After obtaining our pcap from Josh Dosis, it’s time to do a quick analysis of what’s in our pcap! Opening the pcap in wireshark, a few things immediately jump out.

  1. The pcap contains a bunch of data we probably don’t need. ARP and broadcast traffic are something we can probably not worry about, given the context of our investigation.
  2. It appears that after eliminating our unneeded traffic, all that’s left is a bunch of DNS requests.
  3. Scrolling down a few lines, it appears that there are a large number of DNS requests going back and forth between our gnome and sg1.atnascorp.com, presumably our C2 server.
  4. Interestingly, the requests don’t appear to be just queries, but actual data embedded in the queries! It would also appear that the data is obfuscated in some manner. First glance says it looks a bit like base64 encoding, but it’s hard to say for certain just by looking at it.
  5. Now that we have a decent idea of what we’re dealing with, it’s time to see if our suspicions are correct. Looking through the first few packets in our now filtered view, the data in the text field in our DNS responses seems to be repeating a pattern. TXT: Tk9ORTo=
  6. This text shows up several times in our next few packets, indicating its probably not random. There’s a good chance it’s a delimiter, a command, or something else intentionally being sent to our gnome.
  7. Because BURP suite is almost perpetually open, it’s an easy place to try and see if we might be able to decode the text. It looks like it might be base64 encoding, so might as well give it a shot.
  8. Turns out we’re right! The string decodes to “None:” Not a terribly exciting string, but proof that we’re on the right track and now we know we’re dealing with base64 encoded data, which should help us deal with the rest of the data.
  9. Now that we know what we’re dealing with, its time for a different approach. Manually copying and pasting all the data in our DNS responses into burp would SUCK! Fortunately all the heavy lifting has already been done for us with the use of SCAPY. Scapy is an amazing library for dealing with network traffic and we can quickly read in our pcap with rdpcap().
  10. Scapy has a TON of built in functionality and you can decide just how much work you want to do yourself or how much you want to let the library do, but for my part I’m partial to letting it do as much as it can. We already know that we’re really only interested in one part of the conversation in our pcap, the Request Responses to our DNS queries from both the gnome and the C2 server.
  11. Opening up the Scapy console (type scapy in the console) allows us to tinker with our pcap a bit and make sure we’re getting the correct data. By looking at just the DNS Request Response layer of our packets, we get a nice summary from scapy telling us that there are 617 packets in our pcap that contain DNS Request Responses.
  12. To see the structure of the individual packet, we’ll need to open up the packets a bit so we can extract the data we’re looking for. To do this, we need to use the show() command for an individual packet, which will show the entire packet with all its layers and data. (screenshot clipped for relevant data).
  13. While this will work, it’s a bit messy. We can trim this to our relevant data by looking at only the request response portion of our dns query. We can see quite clearly that the string we decoded early shows up in the rdata field of the query response.
  14. To extract our data, all we need to do is isolate the rdata field! Modifying our previous loop to replace show() with the field we want (rdata), we get the strings containing our rdata text, the stuff we’re really interested in in the first place!
  15. Now that we’ve got the data to decode, it’s a simple matter to throw it into a python script to extract and decode all the data and dump it into a file. Note the [1:0] of the string split before decoding. This is because the raw string looks like b’string’ instead of ‘string’, which will give a decoding error. Removing the ‘b’ gives us only the base64 encoded data.
import base64
from scapy.all import *
packets = rdpcap("giyh-capture.pcap")

with open("dump.txt", "wb") as f:
    for pkt in packets[DNSRR]:
        data = pkt[DNSRR].rdata
        data = str(base64.b64decode(data[1:]))
        print(data)
        f.write(data)

While this works, you’ll notice that in the first part of file, the commands sent to the gnome, show with the exec: prefix. This is fine, as we can easily read and understand what’s going on here. However, more than 50% of our dump starts with the FILE: prefix, followed by a bunch of gibberish.

There are also a few lines which contain start or stop transmitting commands, which we also need to filter out. These lines do give us a key piece of data though. The first line to contain the ‘FILE:’ string also contains the name of the file, ==‘FILE:/root/Pictures/snapshot_CURRENT.jpg’.== Since we know we’re looking for a jpg, we can now do a bit of file carving to extract the image from the data.

JPGs, like many other file types have a “magic number”, which denotes the start and end of the files. While not all files adhere to this, it’s a very good place to start. In the case of a .jpg, the file is started with the pattern FF D8 and terminated with the pattern FF D9.

Reviewing the dump.txt file, we can see that just by filtering out a few lines and the “FILE:” string, we should be able to isolate our image. Modifying our script to dump only the jpg….

import base64
from scapy.all import *

packets = rdpcap("giyh-capture.pcap")

with open("gnome_snap.jpg", "wb") as f:
    for pkt in packets[DNSRR]:
        data = pkt[DNSRR].rdata
        data = str(base64.b64decode(data[1:]))
        if "FILE:" in data and "START_STATE" not in data and "STOP_STATE" not in data and "CURRENT" not in data:
            data = re.sub("FILE:", "", data)
            print(data)
            f.write(data)

opening our newly carved out gnome_snap.jpg…

gnome

Creepy. However, we can clearly see the text at the bottom of the image, which will allow us to move on to part 2 of the Holiday Hack 2015 Challenge.