Wednesday, April 27, 2016

The PCAP Contest - Covert channel detection

NOTE: this was originally a Linkedin post, but at the bottom of this blog post are one line solutions that came in after the original post.

In April 2016 SANS released a PCAP riddle. The winner was:


Patrick Mooney, US Department of State, holder of various GIAC certifications, and exploring new potential employment options for Fall 2016. Read on to find out why you really want to hire this guy.

I am the chair of SANS Boston 2016 and asked my friend, Judy Novak, to help create a PCAP with a riddle. We talked about the options and settled for a covert channel.

When the first email went out 4/20/16  to 101k addresses in our cybersecurity focused database, we mentioned the riddle and I also posted about it on Linkedin, Facebook, Twitter, No solutions. 4/25/16, I mentioned it to the GIAC Advisory Board and in less than an hour, I received this message.

Bad checksums:

tcpdump -r Boston2016.pcap -Annvvts 0 | grep bad | awk ' { print $7 } ' | cut -c3-10 | xxd -r -p
Save the date, SANS Boston starts August 1, 2016. Another notable event occurred August 1, but in 1981. The rock music video channel MTV made its debut. The first person to decode this and show up and send the message to stephen@sans.edu will receive a prize. Best of luck to you, Judy Novak.

Bad checksums is where we embedded the secret message. Some programs and security monitoring tool do not check checksums so you can embed a message.
The command line, which is quite an elegant solution, spit out the message. We asked Patrick what his analysis process was and this is what he said.

Sure thing. I first looked at the packet capture in Wireshark to get a quick sense of what Wireshark thought the protocols in use were. Seeing that they were a series of DNS questions and answers the first thing that came to mind was some sort of covert channel or tunneling variant. The messages themselves on the surface all look valid and fairly simple so if there was a covert channel in there it would be in transaction IDs, sequence numbers or counters, or some other part of the protocol that can be manipulated by the sender.

My initial look at the packets was in Windows so I moved the file over to a linux VM and took a more raw look at the PCAP in tcpdump. The first thing that jumped out at me was the bad UDP checksums on the sent DNS requests, something that certainly qualifies as a field that can be manipulated but still results in otherwise valid looking packets. The inserted checksums were also suspiciously within the ASCII printable character range ... not as random looking as one would expect a real checksum to be. So I made a quick and dirty commandline to pull out the bad checksums from the tcpdump display I had started with, isolate the spoofed checksums, and then use xxd to convert the checksums to ASCII.

Jon Mark Allen also solved the problem and this is his methodology:

Thanks for pointing out the puzzle!
I'm afraid my process was fairly boring, and not the most elegant. But
it didn't take very long to complete. :-)

I opened the pcap in Wireshark and saw that the only packets were DNS
queries and responses. So I expanded the raw data column at the bottom
and started scrolling, looking for changes in the hex or ASCII sections.
The word patterns began to stick out to me, so I created a display
filter and used tshark to output only the UDP checksum fields on query
packets.

The raw output was 147 lines like this:
0x00007420
I'm sure scapy would have been more elegant, but my bash pipe experience
is still faster for me - especially on smaller tasks like this. So I
piped the output to cut and tr to create a raw string of hex, and then
used the python one-liner to convert to text.
tshark -r Boston2016.pcap -T text -Tfields -e udp.checksum -2 -R \
"dns.flags == 0x0100" | cut -c 7- | tr -d "\n" | \
python -c "import sys; import binascii;
print binascii.unhexlify(sys.stdin.read());"

That command yielded the following text:
Save the date, SANS Boston starts August 1, 2016. Another notable event
occurred August 1, but in 1981. The rock music video channel MTV made
its debut. The first person to decode this and show up and send the
message to stephen@sans.edu will receive a prize. Best of luck to you,
Judy Novak.

Ugly as all-get-out, but effective. :-)


And I was only going to highlight two analysts, but I am a softy, here is the 3rd:


Analyst: Jordan Wigley
File: Boston2016.pcap
Notes:
Noted that the DNS requests appeared to be valid, and resolved IP stayed consistent for a given domain.

Compared packets for a given domain, to look for any subtle differences.
Discovered that the UDP Checksum field on each DNS request seemed to be changing to unusual values on each request.

Filtered on just the requests in Wireshark using udp.dstport == 53
Noticed that if you looked at the DNS requests in order of occurrence, that the ASCII value of the UDP Checksum bytes appeared to be part of some data exfiltration or other message.

Going through each packet to pull out those bytes revealed the following message:
Save the date, SANS Boston 2016 starts August 1, 2016. Another notable event occurred August 1, but in 1981. The rock music video channel MTV made its debut. The first person to decode this and show up and send the message to stephen@sans.edu will receive a prize. Best of luck to you, Judy Novak..



UPDATE 4/27/16 Now people are sending in one line solutions - amazing, also a cautionary word to the tshark folks, stabilize your parsing.

Luis Rocha
The solution is already known but a one liner is also cool. Great work Judy!

$tshark -nnr Boston2016.pcap -Y "dns.flags == 0x0100"  -T fields -e
udp.checksum | sed 's/^..//'  | tr -d '\n' | xxd -r -p

Mark Stingley, (referring to the solution above, using TShark 1.8.2.)
Typo in the example. Should be:

tshark -nnr Boston2016.pcap -R "dns.flags == 0x0100"  -T fields -e
udp.checksum | sed 's/^..//'  | tr -d '\n' | xxd -r -p

Luis Rocha 
I think it depends on the tshark version.
On my version of tshark using -R as display filter I get the following 
warning:
"-R without -2 is deprecated. For single-pass filtering use -Y"

$tshark -v
TShark 1.10.2 (SVN Rev 51934 from /trunk-1.10)

Evan H. Dygert
My version of tshark (1.12.4) is slightly different as it outputs the 
checksum in decimal, not hex. I ended up doing the following:

tshark -n -r Boston2016.pcap -Y 'dns.flags.response == 0' -T fields -e 
udp.checksum | while read -r; do printf '%x' $REPLY; done | xxd -r -p

Matt Bennet posted an approach to look at hex frequency:
tshark -n -r Boston2016.pcap -Y 'dns.flags.response == 0' -T fields -e udp.checksum | sed 's/0x0000//' | fold -w2 | sort | uniq -c | sort -nr

Austin Taylor
#python3
from scapy.all import *
pcap = rdpcap('/Users/austin.taylor/Downloads/Boston2016.pcap')
b''.join([binascii.unhexlify(hex(pcap[i]['UDP'].chksum)[2:].encode('utf-8')) for i in range(0, len(pcap)) if pcap[i]['IP'].dst=='192.168.1.1'])


Still more solutions :)

Julio Auto
>>> a=rdpcap('Boston2016.pcap')
>>> blab=''
>>> for c in a[::2]:
...   blab=blab+(hex(c[UDP].chksum)[2:])
... 
>>> blab
'536176652074686520646174652c2053414e5320426f73746f6e207374617274732041756775737420312c20323031362e20416e6f74686572206e6f7461626c65206576656e74206f636375727265642041756775737420312c2062757420696e20313938312e202054686520726f636b206d7573696320766964656f206368616e6e656c204d5456206d616465206974732064656275742e2054686520666972737420706572736f6e20746f206465636f6465207468697320616e642073686f7720757020616e642073656e6420746865206d65737361676520746f207374657068656e4073616e732e6564752077696c6c20726563656976652061207072697a652e2042657374206f66206c75636b20746f20796f752c204a756479204e6f76616b2e'
>>> blab.decode('hex')
'Save the date, SANS Boston starts August 1, 2016. Another notable event occurred August 1, but in 1981.  The rock music video channel MTV made its debut. The first person to decode this and show up and send the message to stephen@sans.edu will receive a prize. Best of luck to you, Judy Novak.'

Sean Johnstone
=====
SANS BOSTON CHALLENGE LAB NOTES
=====

Many DNS requests. Rapid. 294 requests/replies in 0.34s
SRC_IP: 192.168.11.23
DST_IP: 192.168.1.1
DNS responses appear correct -- Does not appear to be an attempt to return falsified results.
Does not appear that the purpose of challenge is to spot malicious techniques. Hidden data likely.
Transaction IDs do not appear to translate to anything HEX > ASCII -- 25979d11f4eb into %— ôë
Checksum validation is disabled ****
Data is hidden in sending checksum: HEX > ASCII 536176652074 -- Save t
DNS responses do not hold any message. Output akin to Transaction IDs.

MESSAGE IS HEX > ASCII WITHIN SENDING CHECKSUM

Need to automate, to hell with approx. 150 requests.

Unsure how to exract specific fields within a packet using TCPDUMP, solution will be death-by-grep translated.

sean@sean-VirtualBox:~$ sudo tcpdump -r Boston20161.pcap src 192.168.11.23
01:33:32.291613 IP 192.168.11.23.22830 > 192.168.1.1.domain: 9623+ A? tools.ietf.org. (32)
- Need expanded output

sean@sean-VirtualBox:~$ sudo tcpdump -c 5 -vv -XX -r Boston20161.pcap src 192.168.11.23
01:33:32.291613 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 60)
    192.168.11.23.22830 > 192.168.1.1.domain: [bad udp cksum 0x5361 -> 0x6a8d!] 9623+ A? tools.ietf.org. (32)
0x0000:  4ce6 7640 db2d b4b5 2fd8 dc89 0800 4500  L.v@.-../.....E.
0x0010:  003c 0001 0000 4011 ed47 c0a8 0b17 c0a8  .<....@..G......
0x0020:  0101 592e 0035 0028 5361 2597 0100 0001  ..Y..5.(Sa%.....
0x0030:  0000 0000 0000 0574 6f6f 6c73 0469 6574  .......tools.iet
0x0040:  6603 6f72 6700 0001 0001                 f.org.....
- Better, can grep on 'cksum 0x'

sean@sean-VirtualBox:~$ sudo tcpdump -c 5 -vv -XX -r Boston20161.pcap src 192.168.11.23 | grep -o -E 'cksum 0x[a-f0-9]{4}'
cksum 0x5361
- Need to trim off start of output

sean@sean-VirtualBox:~$ sudo tcpdump -vv -XX -r Boston20161.pcap src 192.168.11.23 | grep -o -E 'cksum 0x[a-f0-9]{4}' | grep -o -E '[a-f0-9]{4}$'
- BINGO, now to translate.


sudo tcpdump -vv -XX -r Boston20161.pcap src 192.168.11.23 | grep -o -E 'cksum 0x[a-f0-9]{4}' | grep -o -E '[a-f0-9]{4}$'| xxd -r -p

Save the date, SANS Boston starts August 1, 2016. Another notable event occurred August 1, but in 1981.  The rock music video channel MTV made its debut. The first person to decode this and show up and send the message to stephen@sans.edu will receive a prize. Best of luck to you, Judy Novak.


1 comment:

  1. PowerShell:

    PS C:\Users\User\Desktop> $msg="";[regex]::matches((Get-Content .\Boston2016.pcap),'\xC0\xA8\x01{2}.{2}\x00\x35\x00.(..)') | % { $msg+=$_.Groups[1].Value };$msg
    Save the date, SANS Boston starts August 1, 2016. Another notable event occurred August 1, but in 1981. The rock music video channel MTV made its debut. The first person to decode this and show up and send the message to stephen@sans.edu will receive a prize. Best of luck to you, Judy Novak .

    ReplyDelete