使用Python解压缩数据包的gzip有效负载

时间:2015-05-19 17:39:02

标签: python gzip packet scapy compression

我目前正在开发一个带有.pcap文件的程序,并使用scapy包将所有数据包分离出来。我想解压缩使用gzip包压缩的有效负载。我可以判断有效负载是否被gzip压缩,因为它包含

Content-Encoding: gzip

我正在尝试使用

fileStream = StringIO.StringIO(payload)
gzipper = gzip.GzipFile(fileobj=fileStream)
data = gzipper.read()

解压缩有效负载,其中

payload = str(pkt[TCP].payload)

当我尝试这样做时,我收到错误

IOError: Not a gzipped file

当我打印第一个有效载荷时,我得到了

HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=utf-8
P3P: CP="NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND"
Vary: Accept-Encoding
Content-Encoding: gzip
Date: Sat, 30 Mar 2013 19:23:33 GMT
Content-Length: 15534
Connection: keep-alive
Set-Cookie: _FS=NU=1; domain=.bing.com; path=/
Set-Cookie: _SS=SID=F2652FD33DC443498CE043186458C3FC&C=20.0; domain=.bing.com; path=/
Set-Cookie: MUID=2961778241736E4F314E732240626EBE; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: MUIDB=2961778241736E4F314E732240626EBE; expires=Mon, 30-Mar-2015 19:23:33 GMT; path=/
Set-Cookie: OrigMUID=2961778241736E4F314E732240626EBE%2c532012b954b64747ae9b83e7ede66522; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: SRCHD=D=2758763&MS=2758763&AF=NOFORM; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: SRCHUID=V=2&GUID=02F43275DC7F435BB3DF3FD32E181F4D; expires=Mon, 30-Mar-2015 19:23:33 GMT; path=/
Set-Cookie: SRCHUSR=AUTOREDIR=0&GEOVAR=&DOB=20130330; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/

?}k{?H????+0?#!?,_???$?:?7vf?w?Hb???ƊG???9???/9U?\$;3{9g?ycAӗ???????W{?o?~?FZ?e ]>??<??n????׻?????????d?t??a?3?
?2?p??eBI?e??????ܒ?P??-?Q?-L?????ǼR?³?ׯ??%'
?2Kf?7???c?Y?I?1+c??,ae]?????<{?=ƞ,?^?J?ď???y??6O?_?z????_?ޞ~?_?????Bo%]???_?????W=?

有关其他信息,这是一个隔离的数据包,因为它包含来自项目提供的示例.pcap文件的Content-Encoding:gzip。

1 个答案:

答案 0 :(得分:2)

为了解码压缩的HTTP响应,您只需要解码响应 正文 ,而不是标题。

您的案例中的payload是整个TCP有效负载,即整个HTTP消息,包括标题和正文。

HTTP消息(请求和响应)是RFC 822消息(与电子邮件消息(RFC 2822)所基于的通用消息格式相同)。

822消息的结构非常简单:

  • 零个或多个标题行(由:分隔的键/值对),由CRLF终止
  • 空行(CRLF(回车,换行,'\r\n'
  • 邮件正文

您现在可以自己解析此消息以隔离正文。但我宁愿建议您使用Python已经为您提供的工具。 httplib模块(Python 2.x)包含HTTPMessage类,httplib内部用于解析HTTP响应。它并不意味着直接使用,但在这种情况下我可能仍然会使用它 - 它将为您处理一些HTTP特定的细节。

以下是如何使用它来分隔正文和标题:

>>> from httplib import HTTPMessage
>>>
>>> f = open('gzipped_response.payload')
>>>
>>> # Or, if you already have the payload in memory as a string:
... # f = StringIO.StringIO(payload)
...
>>> status_line = f.readline()
>>> msg = HTTPMessage(f, 0)
>>> body = msg.fp.read()

HTTPMessage类的工作方式与rfc822.Message类似:

  • 首先,您需要读取(或丢弃)状态行(HTTP/1.1 200 OK),因为它不是RFC822消息的一部分,并且不是标题。

  • 然后使用打开文件的句柄并将HTTPMessage参数设置为seekable来实例化0。文件指针存储为msg.fp

  • 实例化后,它会调用msg.readheaders(),它会读取所有标题行,直到遇到空行(CRLF)。
  • 此时,msg.fp已经前进到标题结束并且正文开始的位置。因此,您可以致电msg.fp.read()阅读邮件的其余部分 - 正文。

之后,解压缩gzipped主体的代码才有效:

>>> body_stream = StringIO.StringIO(body)
>>> gzipper = gzip.GzipFile(fileobj=body_stream)
>>> data = gzipper.read()
>>>
>>> print data[:25]
<!DOCTYPE html>
<html>