Archive for the ‘Packet Decoding’ category

ICMPv6 Challenge – Answers

December 13th, 2009

The challenge was: “Write a tcpdump/windump filter that will capture ICMPv6 Multicast Listener packets.” I have an extensive write up on what makes the answer so complex. If you know IPv6 and just want the answer, skip to the end.

First, Some Background

Steinar made some comments to the previous posts and was 100% on track. If you read them and thought “Wow, that sounds really messy”, you understand the scope of the problem as well. :)

Protocol Vs. Next Header Field

With IPv4 we had the options field. This could cause the IP header to grow from 20 bytes to as large as 60 bytes in size. With IPv6, there is no longer an options field and the header is fixed at 40 bytes in size. When options are required, we use extension headers to identify them. This throws an interesting curve ball at us because with IPv4 the protocol field (byte 9) would (almost) always identify the upper level transport (TCP, UDP, etc.). With IPv6 the next header field (byte 6) might identify the upper layer transport, or it might identify an extension header which will include some number of options.

Here’s a list of some IPv6 extension headers you might run into, as well as the RFCs that define them:

Option # Option Description RFC
0 Hop-by-Hop 2460
6 TCP 793
17 UDP 768
43 Routing 5095
44 Fragmentation 2460
50 ESP 4303
51 AH 4302
58 ICMPv6 4443
59 No next header 2460
60 Destination options 2460
135 Mobility 3775

IPv6 does not limit the number of extension headers you can use in a single packet.There is however a published “recommended order” as to how the headers should be laid out. The order is:

  • IPv6 Header
  • Hop-by-Hop Options
  • Routing Header
  • Fragment Header
  • AH
  • ESP
  • Destination Options
  • Mobility Header
  • TCP/UDP/ICMPv6

Note this list is “recommended” but not mandatory. An IPv6 host must be able to process the headers in what ever order they were received. This means you will probably find vendors following this list but not attackers. I’ve personally seen devices start acting really odd when you mess with the header order. In fact I’ve run across quite a bit of “IPv6 compatible code” which can’t deal if the preferred order is not used.

Chasing The Protocol Header

So with IPv6 we can have multiple headers behind the IPv6 header. If this sounds like a new concept, it is actually not. In fact you’ve probably worked with it already. When you deploy IPSec the two possible security protocols are ESP and AH. These were actually borrowed from IPv6 and massaged to work on IPv4. Both AH and ESP include a next header field to identify what type of packet they are protecting.This is referred to as protocol chaining, as you effectively have multiple headers sitting behind the layer 3 protocol header.

So to figure out what upper level transport (TCP, UDP, etc.) is being used, you may have to search through multiple headers before you find the answer. This is referred to as “chasing the header“, and tcpdump/Windump give us a filter option to perform this task. You may be fimiliar with the proto filter. In the IPv4 world, if I say:

ip proto tcp

That filter reads “check byte 9 of the IPv4 header and if the value is equal to 6 (protocol value for TCP), match on the packet”. This filter is not as effective in the IPv6 world of course because byte 6 of the IPv6 header might identify the upper layer transport, or it might just identify an optional extension header that is being used. To solve this problem, the protochain filter was introduced. Writing:

ip6 protochain tcp

Reads as “Check byte 6 of the IPv6 header to see if the value is equal to 6. If instead you find a value which identifies an optional extension header, check the extension header’s next header field for a value of 6. If you find more optional extension headers, keep repeating the last test till you find the last extension header”.

Pretty simple to write in English, but this is a nightmare to implement in code. Most optional extension headers are variable in length which just adds to the complexity. I’ve done some testing with Scapy and you can actually see the difference in performance when protochain gets invoked. In fact you could probably do a pretty good job of DoSing an IDS/IPS by forcing it to process a lot of useless extension headers.

Writing our filter

So our first problem in writing the challenge filter is that the ICMPv6 header may not appear right after the IPv6 header. We have to watch out for optional extension headers. In fact RFC 2710 states: “All MLD messages described in this document are sent with a link-local IPv6 Source Address, an IPv6 Hop Limit of 1, and an IPv6 Router Alert option [RTR-ALERT] in a Hop-by-Hop Options header.” This means our multicast listener packet is required to have a Hop-by-Hop extension header with the Router Alert option set. With this in mind, our first check should be:

ip6 protochain icmp6

To ensure we are only looking at ICMPv6 packets. Now it is just a matter of checking to see if the type field (byte 0) is set to 130 (Multicast Listener Query) or 131 (Multicast Listener Report).This brings us to our second problem however. In the IPv4 world I can do a:

icmp[0]= <type value of interest>

If I try this with icmp6 I get:

[root@fubar ~]# tcpdump -nn icmp6[0]=130
tcpdump: IPv6 upper-layer protocol is not supported by proto[x]

In other words, I can’t use offsets with icmp6 to search for specific values. Windump and tcpdump are advertised as IPv6 compatible, but don’t expect to get all the same functionality you have with IPv4. YUCK!

So what do we do? We’ll have to fall back on referencing the value from an ip6 offset. In other words, we’ll have to measure through the IPv6 header, through the required Hop-by-Hop header, and into the ICMPv6 header to see if the type field is set to 130 or 131. Some things to take into consideration:

  • IPv6 header is fixed at 40 bytes in size
  • Hop-by-Hop header is variable, but 4 bytes with Router Alert set
  • The type field is byte 0 within the ICMPv6 header

So here is what we end up with:

ip6 protochain icmp6 and (ip6[44]=130 or ip6[44]=131)

Whew! We finally got it! Or did we?

Q: What happens if the packet has additional extension headers?

A: Our filter will not work.

Q: What if the Hop-by-Hop header has more options set than Router Alert?

A: Our filter will not work.

Q: Can we fix the above two problems?

A: Not till tcpdump/Windump filtering adds IF/THEN loop support.

So if we want to capture normal ML traffic, the above filter will work fine. If however we want to insure we catch attacker trickiness as well, the filter is not going to fly.

What if we try something like this:

tcpdump -nn -s 1500 -x ip6 protochain icmp6 | grep -i multicast > multicast.txt

and then just use Wireshark’s text2cap tool to convert it to Libpcap format? The problem here is we will only get the header info. Grep will match the summary line which contains the word “Multicast” but then skip all the Hex below it which is the actual contents of the packet.

So the final answer is: “Can’t get theya from haya” ;)

So what if you really need to be able to see this traffic? Until support for IPv6 matures, the only 100% method is to grab all ICMPv6 traffic and then manually sort through it.

At least that’s my view on this. If anyone can actually come up with a 100% working solution, I would love to hear it.

IP Lookup Completed

December 10th, 2009

Just finished a new tool called IP Lookup that I’ve submitted to the Apple App store. With any luck it will see the light of day over the next week or so.

I know, there are plenty of TCP/UDP port references out there. I’ve tried to make this the most complete list available. There are currently over 12,000 entries and I’m still growing the list.

One of the features I’m really psyched about is the real time searching. As you type in what you are looking for, the list is filtered in real time so you can see the results.

screenshot-2

More info can be found at my Mobile Security Hack site.

And now back to your commercial free educational material. ;)

ICMPv6 Challenge – Hints

December 9th, 2009

OK, here’s a hint to point you in the right direction.

The challenge was: “Write a tcpdump/windump filter that will capture ICMPv6 Multicast Listener packets.”

Sounds easy, right?

With a little help from Google you’ll find that the “type” for Multicast listener is 130, and the ICMPv6 type field is the first byte in the header. So this should be as easy as:

tcpdump -nn -p -v -s 0 icmp6[0]=130

however if you run the command you’ll get back:

tcpdump: IPv6 upper-layer protocol is not supported by proto[x]

In other words, you can use “icmp6″ to see all ICMPv6 packets, but you can’t use it to filter on any of the ICMPv6 header fields.

So we need a “Plan B”. Figure out plan B and you’ve solved the challenge. :)

ICMPv6 Challenge

December 4th, 2009

Building on the IPv6 challenge from last time, I have a new one for you: Write a tcpdump/windump filter which will capture ICMPv6 Multicast Listener packets.

That’s it! Pretty easy, right? ;)

Weekend Challenge – Answers

December 3rd, 2009

Well its now Thursday so I figured its time to post the answers to last weekend’s challenge. ;)

First, why should you even care about IPv6 if you have not started deploying it? I felt much the same way till I found IPv6 being used as a covert communication channel within a client’s network. The data was then being pushed out to the Internet via Teredo. If you are not familiar with the technique, Scott Hogg has some excellent posts on the topic.

So even if you are not currently using IPv6, it pays to start cutting the cure on the technology as well as watching for it on your local network.

So to review, the challenge was:

Write a tcpdump or Windump filter that will capture all traffic with a source IPv6 address of 2001:db8::10 through 2001:db8::20.

There are a couple of caveats with writing this filter. The first few I covered in the last post. The final one, which I knew but never really thought was a problem till I started working with IPv6 pretty heavily, is that tcpdump/Windump will only let you use 1, 2 or 4 byte masks. So while we would love to solve this with an initial filter statement of “ip6[8:14]=”, we can’t because we’re limited to 4 bytes. There is in fact a way to get around this, but I’ll come back to it.

So here’s the filter I’ve been working with:

(ip6[8:4]=0x20010db8 and ip6[12:4]=0 and ip6[16:4]=0 and (ip6[20:4]>=0×0010 and ip6[20:4]<=0050))

Bit long, but it works. Elizabeth came up with a solution that is far more elegant than my own:

src net 2001:db8::/122 and ip6[23] >= 0×10 && ip6[23] <= 0×20

So by starting with the Libpcap format, she’s able to combine my first three statements into one. Not to be a size queen, but that makes her solution is much shorter than mine. In this case that’s a good thing. :)

That’s about it. I’ll post another IPv6 type challenge tomorrow.

Weekend Challenge – Hint

December 1st, 2009

Wow, the sound of crickets is deafening. Surely someone has the skills to get us through this dilemma?  ;)

OK, some hints to get you through the challenge. Let’s start by solving this as an IPv4 address and then we’ll work our way into IPv6. Assume the address range we want to capture is 192.168.1.10 – 192.168.1.20. The big problem is the IPs are not on an even byte boundary. We could do something like:

src net 192.168.1.0/27

but that would give us addresses .0 – .31, more IPs than we actually wanted to see. To solve this problem we’ll need to use some operators and primitives.  One possibility is:

(ip[12]=192 and ip[13]=168 and ip[14]=1 and (ip[15]>=10 and ip[15]<=20))

Starting with the inner most brackets, the above statement reads “byte 15 must be greater than or equal to 10, but it also must be less than or equal to 20. If this statement is true, make sure byte 12 is equal to 192, byte 13 is equal to 168 and byte 14 is equal to 1.”

Can we shorten this expression? Absolutely! First we must convert it to Hex however. Why Hex? If I write a statement such as “ip[12:2]=” tcpdump will assume that the result will be a 16-bit number, not two 8-bit numbers. This is why you can write something like “tcp[2:2]=12345″ and have it work. tcpdump converts the two bytes into a 16-bit value and matches it against the value you specified. By converting to Hex we avoid this problem. So:

192.168.1.10 = 0xC0A8010A

192.168.1.20 = 0xC0A80120

Now we simply write our expression:

ip[12:4]>=0xC0A8010A and ip[12:4]<=0xC0A80120

That’s all there is to it.

While IPv4 uses 4 byte addresses, IPv6 uses 16 bytes. Because the addresses are so long, we write them in Hex to save some space. So the addresses I gave you in the challenge were:

2001:0db8:0000:0000:0000:0000:0000:0010

2001:0db8:0000:0000:0000:0000:0000:0020

Notice I didn’t initially write them that way. There’s a few conventions you can use to save space when writing an IPv6 address. First, we can truncate leading zeroes. So:

2001:0db8:0000:0000:0000:0000:0000:0010

becomes:

2001:db8:0000:0000:0000:0000:0000:10

Now, see all those zeroes in the middle? We can chop them out too. When you see “::” that means to fill in that space with enough zeroes to expand the address back out to 16 bytes. So add in this trick as well and we get:

2001:db8::10

Far easier to write. The caveat is you can only remove one group of zeroes with the double colon trick. Consider the following address:

2001::1234::10

We have no idea where to place the byte sequence “1234″ in the address. It start anywhere from byte 6 through byte 12.

When working with IPv4, tcpdump and Windump use the protocol keyword “ip”, as shown in the above examples. The IPv6 compliment to that is “ip6″. Where’s the source address field in the IPv6 header? Well I can’t give you all there answers or it is no longer a “challenge” :)

Weekend Challenge

November 27th, 2009

Here’s another challenge to test your bit wienie skills:

Write a tcpdump or Windump filter that will capture all traffic with a source IPv6 address of 2001:db8::10 through 2001:db8::20. Pretty easy, right? If you have not tried it, your going to find that tcpdump/Windump throws a few curves at you.

To check your work, here’s a capture file:

ipv6-icmp

The file contains a mix of source IPv6 addresses. Obviously your filter should only display the specified range of addresses.

The winner gets to inspire awe and admiration in lesser geeks.  ;)

Oh where, oh where can WScale be?

November 20th, 2009

If this challenge seemed harder than it should be,you are on the right track. ;)

I ran across this problem when writing my Packet Decode tool. I have to say, it was a cool exercise for me, as I never really thought about creating tcpdump and Wireshark filters for every possible IP, TCP, UDP and ICMP field and/or value. By far the TCP options field is the most “broken” from a packet decode perspective than any other IP field.

First let’s talk about how the TCP options should have been implemented. If you look at the IPv4 options field, it begins with a “Type” identifier. If you are interested in a specific IP option, it is just a matter of checking this field for the right bit combination. Had the TCP options been implemented this way, this challenge would have been pretty straight forward.

Just about all TCP options have a “Kind” and a “Length” field, both of which are 1 byte in size. The exceptions are “End of Option List” and “No-Operation” which only have a Kind field, and thus are one byte in size. Here’s a list of the common TCP options:

tcp-options

Page 15 of RFC 793 tells us “The TCP header (even one including options) is an integral number of 32 bits long.” In other words, the TCP header size in bytes must be evenly divisible by four (20 bytes, 24 bytes, etc.). If you look at the list of TCP options, only “maximum segment size” is divisible by four. So the use of any other options are going to require padding.

How the padding should be applied is a bit unclear. If we look at page 26 of RFC 1323 we find this:

APPENDIX A:  IMPLEMENTATION SUGGESTIONS

   The following layouts are recommended for sending options on non-SYN
   segments, to achieve maximum feasible alignment of 32-bit and 64-bit
   machines.

       +--------+--------+--------+--------+
       |   NOP  |  NOP   |  TSopt |   10   |
       +--------+--------+--------+--------+
       |          TSval   timestamp        |
       +--------+--------+--------+--------+
       |          TSecr   timestamp        |
       +--------+--------+--------+--------+

Note the NOP padding appears before the timestamp option, not at the end like you might expect. Also note the RFC specifically says this is for “non-SYN segments” and that it is “recommended”, not required. Seems however that most operating systems follow this recommendation and always place padding before the Kind and Length bytes. I’ve checked Windows, Linux, Mac, various hardware, etc. and they all put the padding at the beginning.

So we can count on this being the “standard”, right? Not quite.  Page 17 of RFC 793 describes NOP this way:

        This option code may be used between options, for example, to
        align the beginning of a subsequent option on a word boundary.
        There is no guarantee that senders will use this option, so
        receivers must be prepared to process options even if they do
        not begin on a word boundary.

In other words, its not just that NOP may or may not show up at the beginning, NOP might not be used at all! It is entirely legal to layout the TCP option field with no NOP padding and just use End of Option List as filler at the end to achieve the proper boundary.

So what do we end up with for a filter? If we count on NOP before the option we end up with a filter that looks like this:

tcp[13]&2=2 and tcp[12]&240>80 and ((tcp[20]=1 and tcp[21:2]=0×0303) or (tcp[24]=1 and tcp[25:2]=0×0303) or (tcp[28]=1 and tcp[29:2]=0×0303) or (tcp[32]=1 and tcp[33:2]=0×0303) or (tcp[36]=1 and tcp[37:2]=0×0303) or (tcp[40]=1 and tcp[41:2]=0×0303) or (tcp[44]=1 and tcp[45:2]=0×0303) or (tcp[48]=1 and tcp[49:2]=0×0303) or (tcp[52]=1 and tcp[53:2]=0×0303) or (tcp[56]=1 and tcp[57:2]=0×0303))

To break down what this filter is doing:

  • Only check SYN & SYN/ACK packets:  tcp[13]&2=2
  • TCP header is greater than 20 bytes (options are set): tcp[12]&240>80
  • Check the first byte of each four byte boundary for NOP: tcp[20]=1, tcp[24=1, ...
  • Check the next two bytes to see if Kind=3 and Length=3: tcp[21:2]=0×0303, tcp[25:2]=0×0303, …

If however we want to ensure that we catch all possibilities in case a system does not implement NOP we end up with:

tcp[13]&2=2 and tcp[12]&240>80 and (tcp[20:2]=0×0303 or tcp[21:2]=0×0303 or tcp[22:2]=0×0303 or tcp[23:2]=0×0303 or tcp[24:2]=0×0303 or tcp[25:2]=0×0303 or tcp[26:2]=0×0303 or tcp[27:2]=0×0303 or tcp[28:2]=0×0303 or tcp[29:2]=0×0303 or tcp[30:2]=0×0303 or tcp[31:2]=0×0303 or tcp[32:2]=0×0303 or tcp[33:2]=0×0303 or tcp[34:2]=0×0303 or tcp[35:2]=0×0303 or tcp[36:2]=0×0303 or tcp[37:2]=0×0303 or tcp[38:2]=0×0303 or tcp[39:2]=0×0303 or tcp[40:2]=0×0303 or tcp[41:2]=0×0303 or tcp[42:2]=0×0303 or tcp[43:2]=0×0303 or tcp[44:2]=0×0303 or tcp[45:2]=0×0303 or tcp[46:2]=0×0303 or tcp[47:2]=0×0303 or tcp[48:2]=0×0303 or tcp[49:2]=0×0303 or tcp[50:2]=0×0303 or tcp[51:2]=0×0303 or tcp[52:2]=0×0303 or tcp[53:2]=0×0303 or tcp[54:2]=0×0303 or tcp[55:2]=0×0303 or tcp[56:2]=0×0303 or tcp[57:2]=0×0303 or tcp[58:2]=0×0303)

The difference with this filter is that we are checking Kind=3 and Length=3 all the way through the options field (as Elizabeth suggested).

Can either of these filters generate false positives? Absolutely! Two possibilities:

  1. The value of Timestamp may match the pattern we are looking for.
  2. The filter assumes a 40 byte option field. It could be less with these values in the payload.

So which filter should you use? The first will generate fewer false positives but miss systems that are RFC compliant but different from the norm. The second will always catch Window Scale if it has been set, but the chance of a false positive is higher.

I’m going to designate Elizabeth as the winner of the challenge. A few others were just as close but she was the only one with the guts to post her train of thought in the comments. I’m going to award a second prize to Jeff who came up with this solution partially kidding around:

tcpdump -nn | grep ‘wscale ‘ > wscale-matches.txt

This will not generate an actual packet capture, but you could do a:

tcpdump -nn -X -s 0 | grep ‘wscale ‘ > wscale-matches.txt

And then run the output through txt2cap to get it back into pcap format. He didn’t follow the challenge specifically, but you’ve gotta give kudos for thinking outside the box as this fixes all false positive issues. ;)

Elizabeth and Jeff, I’ll be contacting you both via e-mail. Congrats!

TCP Options – Final clue

November 19th, 2009

I’ve had one thread post and four e-mails that are soooooo close to the right answer. Here’s one last clue to hopefully get folks over the final hurdle.

I mentioned the helpful tshark command. Here’s the output:

C:\testing>tshark -n -r linux-syn.cap -T fields -e tcp.options
02:04:05:b4:04:02:08:0a:02:47:4a:a8:00:00:00:00:01:03:03:05

So what you have above is the TCP options section (byte 20 and higher) of the test packet. The Window Scale option is the last option in the list.

I know writing this filter is not easy. In fact that’s why I turned it into a challenge. It is possible however. ;)

TCP Options Challenge – clues

November 18th, 2009

Earlier I posted a challenge to write a tcpdump/Windump filter that would capture packets that have the TCP option “Window Scale” set. Some folks are close, but I wanted to post a few hints. Also, I have no problem with you e-mailing me directly, but to win the challenge you have to post the answer to the comments section. That way there is no question as to who found the answer first.

All TCP options are specified by a “Registry Kind” value (similar to the ICMP “Type” field). In the case of Window Scale, that value is 3. Also, all TCP options except for NOP contain a secondary field called “Length”. This defines how many bytes the options is using, including the “Registry Kind” byte. In the case of Window Scale the length value is always 3. So we have:

  • 1 byte for Registry Kind
  • 1 byte for Length
  • 1 byte for the actual WScale value

Hint 2: If you have never drilled into the TCP Options field, tshark has a cool option:

tshark -n -r capture-file.cap -T fields -e tcp.options

This will output the entire TCP options field in Hex so you can at least see what it looks like.

Final clue, I’ve posted a Linux SYN packet which sets WScale to 5 for you to use to check your filter.

linux-syn

Good luck!

Chris