Search This Blog

Sunday, April 10, 2011

How to filter and dump in clear text http requests and responses from the network dump using the cli program tshark

There are many programs that allow us to save network traffic into a file for later analyze. Once you have the file(s) we could like to quickly investigate the data inside and verify what we sent and what we revived.

If we are interested, let's say only in the HTTP traffic than the command line 'tshark' has only limited capabilities in a way to present us the data for review and investigation.

We can still play with the various options: '-Tfields' and multiple '-e' but still don't get the complete headers output.

The complete list that can be used with '-e' can be found here .
Alternatively we can experiment with the '-Tpdml' that will create alike XML file. But even with all this flexibility we still can't print a custom name header like in this curl request bellow:

curl -H "Rado: my_value" -v -o /tmp/page.html http://rtomaszewski.blogspot.com/2011/04/tshark-in-network-troubleshooting.html

To solve this little problem we have created a small program written in python. It takes the output from 'tshark -S -V' and parses it to present the data in a way we want.

Example how to use it:
# tshark -r /tmp/net.pcap -R http -V | parse.py -d
# tshark -r /tmp/net.pcap -R http -V | parse.py 
# tshark -nn -s0 -i any -w /tmp/net.pcap  -f tcp -R http -l -S -V | parse.py
# tshark -nn -s0 -i any -w /tmp/net.pcap  -f tcp -R http -l -S -V | parse.py -d

An example output from the 'parse.py' when running on the command line:

$ curl -H "Rado: my_value" -v -o /tmp/page.html http://rtomaszewski.blogspot.com/2011/04/tshark-in-network-troubleshooting.html 
* About to connect() to rtomaszewski.blogspot.com port 80 (#0)
*   Trying 209.85.229.132... connected
* Connected to rtomaszewski.blogspot.com (209.85.229.132) port 80 (#0)
> GET /2011/04/tshark-in-network-troubleshooting.html HTTP/1.1
> User-Agent: curl/7.19.7 (i486-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: rtomaszewski.blogspot.com
> Accept: */*
> Rado: my_value
> 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< ETag: "b6d5837e-31bb-4473-95af-da3c1d466295"
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Server: GSE
< Age: 1202
< Date: Sun, 10 Apr 2011 19:14:00 GMT
< Expires: Sun, 10 Apr 2011 19:14:00 GMT
< Last-Modified: Sun, 10 Apr 2011 19:03:05 GMT
< Cache-Control: public, must-revalidate, proxy-revalidate, max-age=0
< Transfer-Encoding: chunked
< 
{ [data not shown]
100 49993    0 49993    0     0  28925      0 --:--:--  0:00:01 --:--:-- 57529* Connection #0 to host rtomaszewski.blogspot.com left intact

* Closing connection #0
# tshark -nn -s0 -i wlan0 -w /tmp/net.pcap -R http -f tcp -S -V | ./parse.py  
Running as user "root" and group "root". This could be dangerous.
Capturing on wlan0
Internet Protocol, Src: 192.168.43.111 (192.168.43.111), Dst: 209.85.229.132 (209.85.229.132)
Transmission Control Protocol, Src Port: 38391 (38391), Dst Port: 80 (80), Seq: 1, Ack: 1, Len: 226
    [Stream index: 1]
    GET /2011/04/tshark-in-network-troubleshooting.html HTTP/1.1\r\n
    User-Agent: curl/7.19.7 (i486-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15\r\n
    Host: rtomaszewski.blogspot.com\r\n
    Accept: */*\r\n
    Rado: my_value\r\n

Internet Protocol, Src: 209.85.229.132 (209.85.229.132), Dst: 192.168.43.111 (192.168.43.111)
Transmission Control Protocol, Src Port: 80 (80), Dst Port: 38391 (38391), Seq: 49070, Ack: 227, Len: 1375
    [Stream index: 1]
    HTTP/1.1 200 OK\r\n
    Content-Type: text/html; charset=UTF-8\r\n
    ETag: "b6d5837e-31bb-4473-95af-da3c1d466295"\r\n
    X-Content-Type-Options: nosniff\r\n
    X-XSS-Protection: 1; mode=block\r\n
    Server: GSE\r\n
    Age: 1202\r\n
    Date: Sun, 10 Apr 2011 19:14:00 GMT\r\n
    Expires: Sun, 10 Apr 2011 19:14:00 GMT\r\n
    Last-Modified: Sun, 10 Apr 2011 19:03:05 GMT\r\n
    Cache-Control: public, must-revalidate, proxy-revalidate, max-age=0\r\n
    Transfer-Encoding: chunked\r\n

2 packets captured
The program can be downloaded form here: parse.py Additionally the source code of this short tool can be seen here:
#!/usr/bin/python 
#
## tested on python 2.6.5
#
# author : radoslaw tomaszewski

import sys
import re
import inspect


class ParseTsharkOut:
  no=0
  debugYes=0 
    
  ipRe=None
  tcpRe=None
  protRe=None
  
  ipInfo=[]
  tcpInfo=[]
  protInfo=[]
  
  auxStart=0
  tcpAuxStart=0

  protAux=1
  
  def __init__(self):
    self.ipRe="Internet Protocol,(.*)$"
    self.tcpRe=["Transmission Control Protocol,(.*)$", "    (\[Stream index:.*)$"]
    self.protRe=["Hypertext Transfer Protocol", "    ([^\[ ].*)$", "^$| *(\\\\r|\\\\n)"]
    
  def debug(self, s):
    if self.debugYes : 
      parent=inspect.stack()[1][3]
      #parent=inspect.stack()
      print("debug:[" + str(parent) + "] " +  s.rstrip())
  
  def usage(self):
    print("todo")   
  
  def ipParse(self,s):
    self.debug(s)

    tmp=re.match(self.ipRe, s)
#    tmp=re.match("..", s)
    if tmp is None :
       return 0
    else:
       self.ipInfo.append(tmp.group(0))
       return 1
       
  def tcpParse(self,s):
    self.debug(s)
    ret=0

    tmp=re.match(self.tcpRe[self.tcpAuxStart], s)
    if tmp is None :
       return 0
    else:
       self.tcpInfo.append(tmp.group(0))
       
       ret=self.tcpAuxStart
       self.tcpAuxStart=(self.tcpAuxStart + 1 ) % 2
       
       return ret
  
  def protParse(self,s):
    self.debug(s)

    if ( self.protAux ) :
       if re.match(self.protRe[0], s):
         self.protAux=0
         return 0
         
    else :
       if re.match(self.protRe[2], s):
         self.protAux=1
         self.show()
         return 1

       tmp=re.match(self.protRe[1], s)
       if tmp is None :
         return 0
       else:
         self.protInfo.append(tmp.group(0))
         return 0
    
  def parse(self, s):
    funcs=[self.ipParse, self.tcpParse, self.protParse]
    
    if funcs[self.auxStart](s):
      self.auxStart= ( self.auxStart + 1 ) % 3 
  
  def show(self):
    self.debug("start")
    
    for i in self.ipInfo:
      print(i)
      
    for i in self.tcpInfo:
      print(i)

    for i in self.protInfo:
      print(i)  
      
    print("")
      
    self.ipInfo=[]
    self.tcpInfo=[]
    self.protInfo=[]      
  
  def main(self):
    try:
      if sys.argv[1] == '-d':
        self.debugYes=1
        self.debug("debuging is turn on")
    except (IndexError):
      None 
      
    self.debug("main start")

    for l in sys.stdin:
      self.parse(l)  
      
    return 0  
      
  

if __name__ == "__main__":
        sys.exit(ParseTsharkOut().main())


aaa

No comments:

Post a Comment