ログイン新規登録

Qiitaにログインしてダークテーマを使ってみませんか?🌙

ログインするとOSの設定にあわせたテーマカラーを使用できます!

0

この記事は最終更新日から1年以上が経過しています。

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

投稿日

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]) 

さいごに

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

新規登録して、もっと便利にQiitaを使ってみよう

  1. あなたにマッチした記事をお届けします
  2. 便利な情報をあとで効率的に読み返せます
  3. ダークテーマを利用できます
ログインすると使える機能について

コメント

この記事にコメントはありません。

いいね以上の気持ちはコメントで

記事投稿キャンペーン開催中
Qiita×Findy記事投稿キャンペーン 「自分のエンジニアとしてのキャリアを振り返ろう!」
~
0