Friday, May 23, 2014

debuging the tcpdump - tcpdump -d

Recently in a discussion relating to BPF filters a colleague (thanks Jamie) sent me the link (http://www.tcpdump.org/papers/bpf-usenix93.pdf). However, I figured I would get around to reading it eventually. While addressing some other issues, Brian Dyson on the SANS mailing list suggested I look at the debug option of tcpdump (tcpdump -d) to verify the filter is working. He also provided an example so I can get started. I must admit, I was shocked to see the debug option. I mean, I use tcpdump on a regular basis. I even go through the man pages if I need to verify something. However, for whatever reason, I never noticed and or used the debug option. So I decided to dig (sorry debug) a little deeper.

So without further ado, let's walk through 2 examples

Example 1
let's try a filter that only shows traffic for host 10.0.0.1

root@securitynik:~# tcpdump -d host 10.0.0.1
(000) ldh      [12]
(001) jeq      #0x800           jt 2 jf 6
(002) ld       [26]
(003) jeq      #0xa000001       jt 12 jf 4
(004) ld       [30]
(005) jeq      #0xa000001       jt 12 jf 13
(006) jeq      #0x806           jt 8 jf 7
(007) jeq      #0x8035          jt 8 jf 13
(008) ld       [28]
(009) jeq      #0xa000001       jt 12 jf 10
(010) ld       [38]
(011) jeq      #0xa000001       jt 12 jf 13
(012) ret      #65535
(013) ret      #0


Let's break this down
(000) ldh      [12]
This says to load a half word (2 bytes) for the EtherType at offset 12.

(001) jeq      #0x800           jt 2 jf 6
If an EtherType of 0x0800 (IP) is detected, then jump to 2 else jump 6
Let's assume Ethertype 0x0800 is detected, so let's jump to 2. 

(002) ld       [26]
At offset 26, we will load a word (4 bytes) for our source IP.

(003) jeq      #0xa000001       jt 12 jf 4
If the 4 bytes allocated in (002) equals source IP 0xa000001 (10.0.0.1) then jump to 12 if not jump to 4. 
When we jump to 12 we see - (012) ret      #65535. This basically says to capture all traffic.
If the packet contains a source IP of 10.0.0.1, we should be seeing traffic on the screen or being written to a file.
However, if (003) was false, we would then need to move to 4. Let's do that.

(004) ld       [30]
At offset 30, we will load a word (4 bytes) for our destination IP

(005) jeq      #0xa000001       jt 12 jf 13
If the 4 bytes allocated in 4 equals destination IP 0xa000001 (10.0.0.1) then jump to 12 if not jump to 13.
When we jump to 12 we see - (012) ret      #65535. This basically says to capture all traffic.
This time, if the destination has IP 10.0.0.1, we should be seeing traffic on the screen or being written to a file.
So if (005) was false, we would then need to move to 13 - (013) ret      #0. At this point there is no data to return as the return pointer is 0 

(006) jeq      #0x806           jt 8 jf 7
If the half word (2 bytes) allocated in (000) eq 0x0806 - ARP - then jump to 8 if this is not so, then jump to 7

(007) jeq      #0x8035          jt 8 jf 13
if the half word (2 bytes) allocated in (000) eq 0x8035 - RARP - then jump to 8 if this is not so, then jump to 13

(008) ld       [28]
At offset 28, we will load a word (4 bytes) for checking the source ARP/RARP value

(009) jeq      #0xa000001       jt 12 jf 10
If the 4 bytes allocated for ARP/RARP source address in (008) equals 0xa000001 then jump to 12 if not jump to 10

(010) ld       [38]
At offset 38, we will load a word (4 bytes) for checking the destination ARP/RARP value

(011) jeq      #0xa000001       jt 12 jf 13
If the 4 bytes allocated for ARP/RARP destination address in (008) equals 0xa000001 then jump to 12 if not jump to 10

(012) ret      #65535
This says to return 65535 Bytes, virtually all traffic

(013) ret      #0
This says return 0 bytes as this would be false


example 2

What does it look like when we would not like to see traffic from host 10.0.0.1

root@securitynik:~# tcpdump -d not host 10.0.0.1
(000) ldh      [12]
(001) jeq      #0x800           jt 2 jf 6
(002) ld       [26]
(003) jeq      #0xa000001       jt 12 jf 4
(004) ld       [30]
(005) jeq      #0xa000001       jt 12 jf 13
(006) jeq      #0x806           jt 8 jf 7
(007) jeq      #0x8035          jt 8 jf 13
(008) ld       [28]
(009) jeq      #0xa000001       jt 12 jf 10
(010) ld       [38]
(011) jeq      #0xa000001       jt 12 jf 13
(012) ret      #0
(013) ret      #65535


Basically this seems to go through the same process. However, the differences can be seen at (012) and (013). In the case of not, (012) returns 0 bytes while (013) returns all other traffic.

The above definitely gave me a new perspective on tcpdump. As the title of the blog states, "Learning By Practising" so if someone reading this blog thinks I missed something, please feel free to drop me a comment so I can make any necessary corrections.



Additional Readings:
http://www.tcpdump.org/manpages/tcpdump.1.html
https://www.kernel.org/doc/Documentation/networking/filter.txt
http://en.wikipedia.org/wiki/EtherType
http://docs.oracle.com/cd/E19455-01/806-3773/806-3773.pdf
http://www.linuxalgorithm.com/1607463/

No comments:

Post a Comment