LoginSignup
0
0

More than 1 year has passed since last update.

Scapyでpcapファイルからデータを抽出する

Posted at

scapyの勉強をしていた時にpcapファイルに含まれるファイルを全て抽出できないかと思い立ち、とりあえず作ってみました。その際の知識もを含めてメモとして残します。

インストール

pipを使ってインストールが可能です。

pip3 install scapy

基本編

下の構文でライブラリを読み込みます

from scapy.all import *

ファイルの読み込みは、rdpcapを使います。

p = rdpcap('test.pcap')

pcapデータを全て見る時は、showメソッドを使います。

p.show()
出力例
0000 Ether / IP / UDP / DNS Qry "b'www.qiita.com.'" 
0001 Ether / IP / UDP / DNS Ans "13.230.63.181" 

パケット1個1個の内容を見る時は、パケット番号を指定してshowメソッドを使います。

p[0].show()
出力例
###[ Ethernet ]### 
  dst       = xx:xx:xx:xx:xx:xx
  src       = xx:xx:xx:xx:xx:xx
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     ........
###[ UDP ]### 
        sport     = 59228
        dport     = domain
        ........
###[ DNS ]### 
           id        = 55997
           qr        = 0
           opcode    = QUERY
           ........

指定したプロトコルがパケットに入っているかを判別します。プロトコルが入っていればtrueを返します。

'DNS' in p[0]

パケットから指定したプロトコルの内容を取り出します。

p[0]['DNS']
出力例
<DNS  id=55997 qr=0 opcode=QUERY aa=0 tc=0 rd=1 ra=0 z=0 ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 qd=<DNSQR  qname='www.qiita.com.' qtype=A qclass=IN |> an=None ns=None ar=<DNSRROPT  rrname='.' type=OPT rclass=512 extrcode=0 version=0 z=0 rdlen=None |> |>

パラメータは、下のような構文で取り出せます。

p[0]['DNS'].qr

応用編

DNS応答から名前解決した結果を取り出します。シノニムも元のFQDNにします。

p = rdpcap('test.pcap')
cnv = lambda x:x if type(x) == str else x.decode()
dnsdata = { cnv(x['DNSRR'][y].rdata):cnv(x['DNSRR'][y].rrname) for x in p if 'DNSRR' in x for y in range(x['DNS'].ancount) }
dns = lambda x:x if not x in dnsdata else dns(dnsdata[x])
print({ r:dns(a) for r,a in dnsdata.items() })
出力例
{'13.230.63.181': 'www.qiita.com.', '54.92.35.84': 'www.qiita.com.', '13.113.37.17': 'www.qiita.com.'}

パケットのバイト数を、(送信元のIPアドレス,送信先のIPアドレス)毎に集計します。

p = rdpcap('test.pcap')
t = {}
for y in [ ((x['IP'].src,x['IP'].dst),len(x)) for x in p if 'IP' in x ]:
    t[y[0]] = y[1] if not y[0] in t else t[y[0]] + y[1]
print(t)
出力例
{('192.168.99.99', '54.92.35.84'): 10984, ('54.92.35.84', '192.168.99.99'): 130283}

TCPのペイロードを、(送信元のIPアドレス,送信元のポート番号,送信先のIPアドレス,送信先のポート番号)毎にファイルとして取り出します。1つのTCPセッションで複数のファイルを送っていた場合は、1つのファイルに全てつながって入りますので、binwalkなどでファイル分割をしてください。

p = rdpcap('test.pcap')
cnv = lambda x:x if type(x) == str else x.decode()
dnsdata = { cnv(x['DNSRR'][y].rdata):cnv(x['DNSRR'][y].rrname) for x in p if 'DNSRR' in x for y in range(x['DNS'].ancount) }
dns = lambda x:x if not x in dnsdata else dns(dnsdata[x])
t = {}
for y in [ ((x['IP'].src,x['TCP'].sport,x['IP'].dst,x['TCP'].dport),[i,x['Raw'].load]) for i,x in enumerate(p) if ('TCP' in x) and ('Raw' in x) ]:
    t[y[0]] = y[1] if not y[0] in t else [t[y[0]][0],t[y[0]][1] + y[1][1]]
    with open('summary.txt','w') as f1:
        for k,v in t.items():
            n = str(v[0])+'.bin'
            f1.write(n+'  --  '+dns(k[0])+':'+str(k[1])+' -> '+dns(k[2])+':'+str(k[3])+'\n')
            with open(n,'wb') as f2:
                f2.write(v[1]) 

さいごに

本当にとりあえず作ったものなので、使い方によっては望みのデータが取り出せない場合があるかもしれません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0