29.11.10

Packet Payloads, Encryption and Bacon

I received an email from a private mailing list recently, asking for some help in reviewing the contents of a packet capture file:

“I have a 2.5 GB pcap file which I want to verify that it contains only encrypted content. […] I’m wondering if anyone knows of a way that I can accomplish this using Windump or some other Windows utility.”


This kind of analysis happens frequently when performing a black-box pentest against a protocol.  Over the years I’ve used a couple of techniques to evaluate the content of packet captures to determine if the traffic is encrypted or just obfuscated.

Strings and Other Fun Unix Tools

The strings utility can be used to evaluate the contents of a packet capture to pull out any content that is within the ASCII character set.  First, for a packet capture I know to contain unencrypted content:

root@bt:~# strings capture1.dump | more
,7G9
I\3S
{#_3#\
HnL2`
o:|?
4"D
Ke6
RO*t
xtB,}X
981fh)
5JcA
84+
(P;u
'n]Ii
--More--
This content isn't particularly illustrative, since these strings aren't ASCII words or other content that would immediately identify the presence of unencrypted traffic. We can modify the strings command to only show longer strings by adding the "-n" argument:
root@bt:~# strings -n 8 capture1.dump | more
:Azf`^Y/
UOV;uqbe-
BRW00234DDA2223
BRW00234DDA2223
BRW00234DDA2223
BRW00234DDA2223
BRW00234DDA2223
BRW00234DDA2223
jwright-x300
MSFT 5.0
jwright-x300
MSFT 5.0
Og{7n_S!
jwright-x300
--More--

This is more interesting, allowing us to easily recognize plaintext strings representing hostnames and Windows client traffic. It's not always this easy though; consider the case of obfuscated traffic, even something as simple as XOR with a fixed value. This would obscure the presence of plaintext strings, but not actually be encrypted.


Packet Payload Histogram


We have a golden rule with encryption: encrypted content should be indistinguishable from random content.  This is an attribute we can use to visually assess the bytes of a packet payload.  A packet payload histogram tool reads through a packet capture and counts how frequently each byte of packet payload occurs.  My pcaphistogram tool identifies TCP and UDP packets, counting the payload data and creating a gnuplot-compatible script to graph the results.  Lets look at an example using the capturte1.dump packet capture:

root@bt:~# perl pcaphistogram.pl capture1.dump | gnuplot
Skipping non-ip packet.
Unknown IP Protocol: 50. Skipping packet.
Skipping non-ip packet.
Unknown IP Protocol: 80. Skipping packet.
root@bt:~# ls -l capture1.png
-rw-r--r-- 1 root root 2685 Nov 29 12:48 capture1.png
root@bt:~#

The capture1.png file is displayed below.


capture1


The “+” signs map out the frequency of each byte of the packet capture with frequency on the Y-axis and the byte values themselves (in hex) on the X-axis.  We can see a cluster of various byte values around 0x61, which coincides with the lowercase ASCII character set.  With this content, we can easily determine that the packet capture is not encrypted.


By comparison, let’s look at an encrypted packet capture example:


capture2


Here the byte values are very narrowly distributed, with very little variation in frequency from one byte to the next.  This pattern is unlike the prior unencrypted pattern, but it is still difficult to ascertain if this content is encrypted.  We know the content appears random, which is an attribute of encrypted traffic, so it is likely to be encrypted, but it could also be just random traffic.


A third example is shown below.


capture3


This is another unencrypted packet capture, but the content is obfuscated using a static XOR key.  No ASCII strings would be present in the packet capture, but from the packet content variance we can ascertain that this data is not encrypted.


The pcaphistogram tool has served me well for many assessments, but lately I’ve been favoring a different approach.



Entropy Analysis with Ent


Ent is a simple yet very useful tool that reads from a specified file and performs several tests to evaluate the content of the data including:



  • Entropy: The information density of the file content in a number of bits per byte.
  • Chi-Square-Test: Measures the percentage of data randomness.
  • Arithmetic Mean: Calculates the mean of the values in the file divided by the file length.
  • Monte Carlo Value for Pi: Uses successive sequences of 24-bit X and Y coordinates to graph a square and measure the radius of an inscribed circle attempting to calculate the value of Pi.  Random content will produce a product very close to the actual value of Pi.
  • Serial Correlation Coefficient: Measures the extent where each byte in the file depends on the previous byte.

Ent is not installed by default on Backtrack and unlikely to be present by default in other distributions.  On Backtrack, you can install Ent by running “apt-get install ent”.


Using Ent is very simple.  For example, dumping data from the Linux /dev/urandom device and evaluating it with Ent displays the following content:

root@bt:~# dd if=/dev/urandom bs=16384 count=1000 of=rand.bin
1000+0 records in
1000+0 records out
16384000 bytes (16 MB) copied, 6.28625 s, 2.6 MB/s
root@bt:~# ent rand.bin
Entropy = 7.999989 bits per byte.

Optimum compression would reduce the size
of this 16384000 byte file by 0 percent.

Chi square distribution for 16384000 samples is 245.34, and randomly
would exceed this value 50.00 percent of the times.

Arithmetic mean value of data bytes is 127.4926 (127.5 = random).
Monte Carlo value for Pi is 3.141788853 (error 0.01 percent).
Serial correlation coefficient is -0.000268 (totally uncorrelated = 0.0).


Ent reports that the entropy for this file is more than 7.999 bits per byte, which is very random.  A second example reading from a dictionary file:

root@bt:~# ent /pentest/passwords/wordlists/bt4-password.txt
Entropy = 5.083091 bits per byte.

Optimum compression would reduce the size
of this 32952523 byte file by 36 percent.

Chi square distribution for 32952523 samples is 318231422.65, and randomly
would exceed this value 0.01 percent of the times.

Arithmetic mean value of data bytes is 86.6330 (127.5 = random).
Monte Carlo value for Pi is 4.000000000 (error 27.32 percent).
Serial correlation coefficient is 0.180351 (totally uncorrelated = 0.0).


This time we have a very different result, indicating significantly less entropy.  We can use this same technique to review the content of a packet capture to solve the problem posed at the beginning of this article.  First we need to extract the payload data out of the packet capture; this is straightforward with Scapy:

root@bt:~# scapy
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
INFO: No IPv6 support in kernel
WARNING: No route found for IPv6 destination :: (no default route?)
Welcome to Scapy (2.1.0)
>>> fp = open("payloads.dat","wb")
>>> def handler(packet):
... fp.write(str(packet.payload.payload.payload))
...
>>> sniff(offline="capture1.dump",prn=handler,filter="tcp or udp")

Here we created an output file "payloads.dat" and used the Scapy sniff() function to read from "capture1.dump", using the Berkeley Packet Filter syntax to process only TCP or UDP traffic, calling the function "handler" for each packet in the capture file.  The handler() function simply writes a string representation of the packet.payload.payload.payload (that's the original packet, Ethernet -> IP -> TCP (or UDP) payload) to the "payloads.dat" file.  Next we can assess the payloads.dat file with Ent:

root@bt:~# ent payloads.dat
Entropy = 5.216871 bits per byte.

Optimum compression would reduce the size
of this 2461696 byte file by 34 percent.

Chi square distribution for 2461696 samples is 24219040.94, and randomly
would exceed this value 0.01 percent of the times.

Arithmetic mean value of data bytes is 91.6014 (127.5 = random).
Monte Carlo value for Pi is 3.977878630 (error 26.62 percent).
Serial correlation coefficient is 0.187293 (totally uncorrelated = 0.0).
Ent is telling us the content is not encrypted in each of the tests; not even close. Let's look at capture2.dump:
>>> fp = open("payloads.dat","wb")
>>> sniff(offline="capture2.dump",prn=handler,filter="tcp")
<Sniffed: TCP:3840 UDP:8 ICMP:0 Other:0>

Repeating the Ent analysis with the results from the 2nd packet capture reveals the following:

root@bt:~# ent payloads.dat
Entropy = 7.999926 bits per byte.

Optimum compression would reduce the size
of this 2912256 byte file by 0 percent.

Chi square distribution for 2912256 samples is 299.50, and randomly
would exceed this value 5.00 percent of the times.

Arithmetic mean value of data bytes is 127.5390 (127.5 = random).
Monte Carlo value for Pi is 3.139916271 (error 0.05 percent).
Serial correlation coefficient is 0.001657 (totally uncorrelated = 0.0).

As expected, Ent reveals that the 2nd capture has a very high entropy level with all tests indicating the high degree of randomness in the payloads.dat file.


Finally, just to validate our earlier analysis for the obfuscated data in capture3.dump, one last analysis exercise:

>>> fp = open("payloads.dat","wb")
>>> sniff(offline="capture3.dump",prn=handler,filter="tcp")
<Sniffed: TCP:2626 UDP:0 ICMP:0 Other:4>

And our analysis with Ent:

# ent payloads.dat
Entropy = 4.914504 bits per byte.

Optimum compression would reduce the size
of this 2914852 byte file by 38 percent.

Chi square distribution for 2914852 samples is 56249721.62, and randomly
would exceed this value 0.01 percent of the times.

Arithmetic mean value of data bytes is 168.2762 (127.5 = random).
Monte Carlo value for Pi is 1.609483582 (error 48.77 percent).
Serial correlation coefficient is 0.927980 (totally uncorrelated = 0.0).
Again we show that the obfuscated data, despite not looking like unencrypted data, is not encrypted.

Wrapping Up


Evaluating the content of a packet capture is a common task for a pentest, though it can be equally useful for incident response analysis for unknown protocols, or perhaps even forensic analysis.  Both pcaphistogram and Ent gave us the answers we needed to answer the opening question.  I generally use Ent for my own analysis purposes, though I’ll re-run the data through pcaphistogram when I’m doing reporting since the output of pcaphistogram is much more interesting to look at and easier to understand than explaining the Chi Square Distribution test.






IMG_0167

In my SANS Ethical Hacking Wireless course, we leverage tools such as pcaphistogram and Ent for evaluating proprietary wireless technologies over WiFi and ZigBee/IEEE 802.15.4 networks, as well as attacking Bluetooth, DECT and more.  I’m teaching next in New Orleans the week of 1/20/2011 – 1/25/2011; come check it out!  New Orleans is one of my favorite places in the world for the food, culture and history.  If you are planning on attending, let me know and I’ll coordinate reservations for Arnaud’s for a dining and music experience you’ll always remember.


Bacon


IMG_0189Everything’s better with bacon.  Seriously.


-Josh

22.9.10

OpenBSD Timestamps

It’s not breaking news that OpenBSD strives to be at the forefront of security. It appears that their TCP timestamp option behavior reflects this as well. The purpose of the TCP timestamp is to measure roundtrip times as well as to act as an extension to the TCP sequence numbers by disambiguating two segments that arrive simultaneously, have identical TCP sequence numbers, but contain different TCP timestamps such as in the case of wrapping TCP sequence numbers. The likelihood of this happening is slim to none, however, if it does, the segment with the later timestamp is favored while the one with the older timestamp is dropped. I’ve found a variety of different OS-specific behaviors regarding old TCP timestamps that offer a wealth of opportunities for IDS/IPS evasion.

Most operating systems employ a TCP timestamp behavior where the sender’s value reflects the number of clock ticks since the last reboot. A clock tick is a vague concept described in RFC 1323 as “The timestamp value to be sent is to be obtained from a (virtual) clock that we call the "timestamp clock". Its values must be at least approximately proportional to real time…”. Now, think about this in terms of security. A high TCP timestamp divulges that the host has not been rebooted in a while. Now, let’s say there is a patch released on MS Tuesday for a new Windows remote exploit. Further, installation of this patch requires a reboot. An attacker searching for victim hosts could gain some valuable reconnaissance just from a TCP timestamp if he/she could communicate with a potential target host via TCP.

OpenBSD must have seen the possible leakage of information from the TCP timestamp so they now randomize the first timestamp on every new TCP/IP session. They increment the timestamp in subsequent segments in the session to meet the standard of approximating the passage of time for accurate round trip time measurement (RTTM). But, they eliminate the possibility for the TCP timestamp to be used to reflect the uptime since last reboot.

Let’s take a look at the difference between the more conventional incremental Windows TCP timestamp and the randomized OpenBSD timestamp. I sent five SYNs in rapid succession to a Windows host first and then to an OpenBSD host to examine the TCP timestamp values in the returned SYN/ACK. I’ve edited the tcpdump output to contain only the pertinent information to save space. As you can see the Windows host 75.101.150.118 generates incremental TCP timestamp values.

Now, look at the OpenBSD random timestamp values from host 142.244.12.42.

While this is impressive in itself, I believe OpenBSD has relegated the use of TCP timestamps exclusively for RTTM and not for the almost useless Protection of Wrapped Sequence Numbers (PAWS) that distinguishes between old and new timestamps. As far as I’m concerned the RTTM is the only reason to support TCP timestamps so I’m pleased if this is the case. I say “if this is the case” since I don’t have an accessible OpenBSD to send my Scapy generated traffic so I have to believe that the Netcraft association of www. openbsd.org and www.bsd.org with OpenBSD/NetBSD OS is correct. My only hesitation is that there may be some kind of device that exists between the sending and receiving boxes that acts as a proxy or somehow permutes the TCP timestamp from the actual host. But, I tried two different hosts that reside on different networks to help bolster my confidence that I’m communicating with actual OpenBSD hosts.

My experiment is to try to get the receiving host to drop all segments after the initial SYN by assigning them a lower timestamp. Using Scapy, I place a timestamp value of 100 on the SYN and 0 on all subsequent ones. First, let’s look at how Windows handles this. It never acknowledges any data I send to it, echoes the expecected timestamp of "ecr 100", and even attempts to resend the SYN/ACK in the final segment to give me another chance to send an appropriate higher timestamp in my initial ACK. This is the expected behavior and conforms to RFC 1323 specification.

Conversely, take a look at the same traffic sent to an OpenBSD host 142.244.12.42. It happily accepts and echoes the old timestamp value of 0 and returns the requested web page, albeit in reverse order, meaning it accepted the segment with the old timestamp carrying the web request.

In an effort to corroborate the behavior above, I wanted to test another OpenBSD host – www.bsd.org - that belongs to a totally different network address block with different devices standing between my network and the web server. As you can see host 192.231.225.11 parrots this same behavior of ignoring the old timestamp.

Initially, I thought there might be something wrong with the traffic I was sending. I know some operating systems require you to echo the timestamp they issue in order to receive subsequent segments. I typically don’t do this because it’s a few more lines of code, but I added the code to echo the server’s timestamps and I still witnessed the behavior of OpenBSD ignoring old timestamps. If this is indeed the case, I think OpenBSD has made a good, and as usual, innovative decision to support only the useful features of the TCP timestamp.



3.9.10

My Mistake - Suricata Reassembles on All TCP Ports

Yesterday I erroneously blogged that Suricata does not perform TCP stream reassembly on non-standard ports. The script I used to test this in live mode had an incorrect TCP reset sequence number on it and an alert was not generated. When I corrected this, I did indeed see an alert.

My apologies for reporting this and my apologies to the Suricata team. To be clear - Suricata performs TCP stream reassembly on all TCP ports. I am about to correct yesterday's blog by deleting the misinformation.

2.9.10

Suricata TCP Evasions



If you’re currently using the Open Source intrusion detection/prevention system Suricata, I urge you to upgrade to the recently released version 1.0.2 as soon as possible. In my recent research, I've found more than half a dozen TCP evasions in code from prior versions.

In my experience with Open Source intrusion detection systems like Snort, accurate and thorough TCP reassembly is extremely difficult. Snort's TCP stream reassembly code has transitioned from being pretty lame and rudimentary (see Stick and Snot attacks) into to a flawed stream4 implementation, finally evolving into a solid and comprehensive stream5 module--over a decade later.

I've been interested in Suricata's stream reassembly code since they offered their first beta release over a year ago. When they released their first non-beta stable 1.0 release this past July, I felt it was finally fair game to try some evasions. Unfortunately, it was fairly easy to find them. Some, like the failure to properly perform TCP checksum validation, were trivial; others like the one discussed below took more poking.

My intent was to find evasions that were more or less universal – not affiliated with a particular operating system (AKA target-based). I crafted the evasion techniques with Scapy and sent them to a destination operating system running Linux first and later Windows Vista. Obviously, TCP evasions are most dangerous when Windows is the destination host since Windows is still the most prevalent OS. In all fairness, I ran any TCP evasion that I discovered against Suricata later against a current version of Snort – 2.8.6.1. Snort alerted on all of the techniques that successfully evaded Suricata.

Let’s examine one of the several Suricata TCP evasions I was able to uncover in versions prior to 1.0.2. Suricata uses Snort rules. Assume that the following Snort rule exists and is configured for use:

alert tcp any any -> any 80 (msg:"EVILSTUFF alert"; flow:to_server, established; content: "EVILSTUFF"; http_uri; sid:1234; )

This rule looks for the content of "EVILSTUFF" in an HTTP URL.

First, here is the Scapy code that I used. I'm not going to go over the specifics of the code since I covered how to create the client side of the code in the blog post on an unusual response from a bad acknowledgement on the last segment of the three-way handshake. The code for this evasion shares many of the concepts and some of the code.



Now, let's take a look at the client side traffic that the the Scapy code generated.



Segment 1 represents a SYN with a crafted Initial Sequence Number (ISN) of 10. The next crafted segment 2 shows the acknowledgement of the server's SYN/ACK. Next, I reset the connection in segment 3. This should be the end of tracking this session.

Segment 4 is a SYN sent about 5 seconds after the reset and is identical to the first SYN, except it uses an ISN of 11. Segment 5 completes the acknowledgement of the three-way handshake from the new session and segments 6 and 7 contain the malicious split content of "EVILSTUFF". Suricata fails to alert here; we assume this is because it gets confused after improperly closing/cleaning up after the first session and mistakenly considers the new session as a continuation of old one. It doesn't track the new session SYN with the ISN of 11 and when the malicious content is sent later—with a sequence number one more than Suricata expects—it creates a gap in sequence numbers for Suricata. Suricata cannot properly reassemble the malicious content since there is a missing sequence number before it, causing the evasion.

The failure to properly close one session and distinguish it from a new one is neither a trivial nor a target-based issue. So please make sure that you upgrade right away if you are currently using Suricata.

Additionally, if you have or are considering dumping Snort in favor of Suricata, my advice is: Don't do it yet! Suricata is a work in progress. I don't mean to diminish the hard work of some very talented people, but the product needs to mature before I would consider using it as my exclusive means of IDS/IPS. And please note that I've scrutinized only a specific aspect of the product and have found what I consider to be substantial issues. The Suricata team has fixed the issues I reported, so the stream reassembly has improved.

In the interest of full disclosure, I worked at Sourcefire on the Vulnerability Research Team for about 5 years. Specifically, I did research on Snort's current stream reassembly preprocessor known as stream5. Steve Sturges translated the research and improved stream4 to produce stream5. It was at Sourcefire that I learned Scapy and began to use it to try to evade other companies' TCP stream reassembly as well as help build a regression suite to ensure that code changes to stream5 or other modules didn't accidentally introduce unintended consequences. So, yes – I am somewhat biased in my preferences for Snort; I very much appreciate the opportunities presented to me at Sourcefire and I have an abundance of loyalty and allegiance to this day. But, I've got no current financial or other investment in Sourcefire, so I've nothing to gain monetarily from exposing Suricata's TCP reassembly issues.

I'd like to thank Todd Wease, who used to work for Sourcefire on the Snort team, for validating the evasions I found and for examining the code to help me understand the logic issues. And, I'd like to thank Jen Harvey, Co-Founder at Voxilate, for reviewing this post and cleaning it up so it is coherent.

As a final note: You, too, can attempt to find evasions such as these in your IDS/IPSes packet-crafting with Scapy. There’s still time and room to sign up for my Power Packet Crafting Using Scapy course in Las Vegas at the end of September. Please come join me in Las Vegas in September!