キャンセル
次の結果を表示 
次の代わりに検索 
もしかして: 
cancel
2523
閲覧回数
10
いいね!
0
コメント
Tomonobu Okada
Cisco Employee
Cisco Employee

Scapy とは

Scapy は Python で書かれたパケット操作ツールで、パケットの作成やキャプチャ・デコードをしたりすることができます。本記事では、モバイルパケットコアで使用されている GTP や PFCP への適用方法を見ていきたいと思います。Scapy を使用することにより大量のパケットデータを自動的に解析するといったことが可能になります。

 

インストール

インストールは簡単なので、詳細は以下のサイトを参照してください。

https://github.com/secdev/scapy

基本的なステップは以下のとおりです。

$ git clone https://github.com/secdev/scapy.git
$ cd scapy
$ sudo python setup.py install

GTP や PFCP の解析に必要なライブラリは scapy/contrib 配下にあります。

❯ ls scapy/contrib/ | grep -E "gtp|pfcp"
gtp.py
gtp_v2.py
pfcp.py

 

パケットをデコードする

まずは Python のインタラクティブシェルを使ってパケットをデコードしてみたいと思います。

❯ ./run_scapy
INFO: Can't import matplotlib. Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
INFO: Can't import python-cryptography v1.7+. Disabled WEP decryption/encryption. (Dot11)
INFO: Can't import python-cryptography v1.7+. Disabled IPsec encryption/authentication.

                     aSPY//YASa
             apyyyyCY//////////YCa       |
            sY//////YSpcs  scpCY//Pp     | Welcome to Scapy
 ayp ayyyyyyySCP//Pp           syY//C    | Version 2.4.3.dev699
 AYAsAYYYYYYYY///Ps              cY//S   |
         pCCCCY//p          cSSps y//Y   | https://github.com/secdev/scapy
         SPPPP///a          pP///AC//Y   |
              A//A            cyP////C   | Have fun!
              p///Ac            sC///a   |
              P////YCpc           A//A   | To craft a packet, you have to be a
       scccccp///pSP///p          p//Y   | packet, and learn how to swim in
      sY/////////y  caa           S//P   | the wires and in the waves.
       cayCyayP//Ya              pY/Ya   |        -- Jean-Claude Van Damme
        sY/PsY////YCc          aC//Yp    |
         sc  sccaCY//PCypaapyCP//YSs
                  spCPY//////YPSps
                       ccaacs
                                       using IPython 7.9.0
>>> pkts = rdpcap("../s5.pcap")
>>> pkts.summary()
Ether / IP / UDP 192.168.3.1:30016 > 192.168.3.2:gtp_control / Raw
Ether / IP / UDP 192.168.3.2:gtp_control > 192.168.3.1:30016 / Raw
Ether / IP / UDP 192.168.3.1:30016 > 192.168.3.3:gtp_control / Raw
Ether / IP / UDP 192.168.3.3:gtp_control > 192.168.3.1:30016 / Raw
Ether / IP / UDP 192.168.3.3:gtp_control > 192.168.3.1:gtp_control / Raw
Ether / IP / UDP 192.168.3.1:gtp_control > 192.168.3.3:gtp_control / Raw

s5.pcap は GTPv2 パケットを含む PCAP ファイルですが、デフォルトの状態では Raw を表示され正しくデコードされていません。GTP パケットをデコードするためには、scapy.contrib.gtp を import する必要があります。

>>>  from scapy.contrib.gtp import *
>>> pkts = rdpcap("../s5.pcap")
>>> pkts.summary()
Ether / IP / UDP 192.168.3.1:30016 > 192.168.3.2:gtp_control / GTPHeader / GTPV2CreateSessionRequest
Ether / IP / UDP 192.168.3.2:gtp_control > 192.168.3.1:30016 / GTPHeader / GTPV2CreateSessionResponse
Ether / IP / UDP 192.168.3.1:30016 > 192.168.3.3:gtp_control / GTPHeader / GTPV2CreateSessionRequest
Ether / IP / UDP 192.168.3.3:gtp_control > 192.168.3.1:30016 / GTPHeader / GTPV2CreateSessionResponse
Ether / IP / UDP 192.168.3.3:gtp_control > 192.168.3.1:gtp_control / GTPHeader / GTPV2CreateBearerRequest
Ether / IP / UDP 192.168.3.1:gtp_control > 192.168.3.3:gtp_control / GTPHeader / GTPV2CreateBearerResponse

今度は GTP パケットの内容が正しくデコードされました。PFCP も同様に、scapy.contrib.pfcp を import するとデコードすることができます。

>>> from scapy.contrib.pfcp import *
>>> pkts = rdpcap("../pfcp-sample.pcap")
>>> pkts.summary()
Ether / IPv6 / UDP 2001:10:1:200::1:8805 > 2001:10:1:200::101:8805 / PFCP / PFCPHeartbeatRequest
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:8805 / PFCP / PFCPHeartbeatResponse
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:8805 / PFCP / PFCPHeartbeatRequest
Ether / IPv6 / UDP 2001:10:1:200::1:8805 > 2001:10:1:200::101:8805 / PFCP / PFCPHeartbeatResponse
Ether / IPv6 / UDP 2001:10:1:200::1:50007 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionEstablishmentRequest
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50007 / PFCP / PFCPSessionEstablishmentResponse

これでデコードされたパケットの中身を見ることができます。pkts[17][PFCP] は、ファイル内の18番目のパケットの PFCP プロトコル・スタックにアクセスするということ意味しています。

>>> pkts[17].summary()
'Ether / IPv6 / UDP 2001:10:1:200::1:50007 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionEstablishmentRequest'
>>> pkts[17][PFCP].show()
###[ PFCP (v1) Header ]###
  version= 1
  spare_b2= 0x0
  spare_b3= 0x0
  spare_b4= 0x0
  MP= 1
  S= 1
  message_type= session_establishment_request
  length= 887
  seid= 0x0
  seq= 1280
  priority= 1
  spare_p= 1
###[ PFCP Session Establishment Request ]###
     \IE_list\
      |###[ IE F-SEID ]###
      |  ietype= F-SEID
      |  length= 25
      |  spare= 0x0
      |  v4= 0
      |  v6= 1
      |  seid= 0x4000000000001
      |  ipv6= 2001:10:1:200::1
      |  extra_data= ''
--- 省略 ---

これでパケットに含まれる各データに簡単にアクセスできるようになりました。

>>> pkts[17][PFCP]["IE F-SEID"].seid
1125899906842625

 一点注意事項として、PFCP 内の IE に一部 Cisco 独自の実装が使われているので、そのような IE は IE not implemented として表示されます。

      |   |###[ IE FAR ID ]###
      |   |  ietype= FAR ID
      |   |  length= 4
      |   |  id= 32770
      |   |  extra_data= ''
      |   |###[ IE not implemented ]###
      |   |  ietype= 207
      |   |  length= 9
      |   |  data= 'internet\x00'

 

プログラムを作成する

シンプルなものですが、PFCP パケットの summary と SEID を表示するコードを作成してみます。パケットが UDP かつ 8805 ポートを使用して、SEID を持っていれば summary と SEID を表示します。

#!/usr/bin/env python3

from scapy.all import *
from scapy.contrib.pfcp import *
import sys

pcap_file = sys.argv[1]
pkts= rdpcap(pcap_file)
PFCP_PORT = 8805

for packet in pkts:
    if not packet.haslayer(UDP):
        continue
    if (packet[UDP].sport == PFCP_PORT) or (packet[UDP].dport == PFCP_PORT):
        if packet["PFCP (v1) Header"].seid != None:
            print(packet.summary() + " seid: %x" % packet[PFCP]["PFCP (v1) Header"].seid)
実行結果
❯ ./show_pfcp.py ../pfcp-sample.pcap
Ether / IPv6 / UDP 2001:10:1:200::1:50007 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionEstablishmentRequest seid: 0
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50007 / PFCP / PFCPSessionEstablishmentResponse seid: 4000000000001
Ether / IPv6 / UDP 2001:10:1:200::1:50007 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionModificationRequest seid: 14000000000001
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50007 / PFCP / PFCPSessionModificationResponse seid: 4000000000001
Ether / IPv6 / UDP 2001:10:1:200::1:50007 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionModificationRequest seid: 14000000000001
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50007 / PFCP / PFCPSessionModificationResponse seid: 4000000000001
Ether / IPv6 / UDP 2001:10:1:200::1:50007 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionModificationRequest seid: 14000000000001
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50007 / PFCP / PFCPSessionModificationResponse seid: 4000000000001
Ether / IPv6 / UDP 2001:10:1:200::1:50007 > 2001:10:1:200::101:8805 / PFCP seid: 14000000000001
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50007 / PFCP / PFCPSessionDeletionResponse seid: 4000000000001
Ether / IPv6 / UDP 2001:10:1:200::1:50014 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionEstablishmentRequest seid: 0
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50014 / PFCP / PFCPSessionEstablishmentResponse seid: 8000000000003
Ether / IPv6 / UDP 2001:10:1:200::1:50014 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionModificationRequest seid: 10000000000000
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50014 / PFCP / PFCPSessionModificationResponse seid: 8000000000003
Ether / IPv6 / UDP 2001:10:1:200::1:50014 > 2001:10:1:200::101:8805 / PFCP / PFCPSessionModificationRequest seid: 10000000000000
Ether / IPv6 / UDP 2001:10:1:200::101:8805 > 2001:10:1:200::1:50014 / PFCP / PFCPSessionModificationResponse seid: 8000000000003
途中で新しいセッションになり SEID が変わった様子が確認できます。
作り込み次第では複雑な解析を自動化できますので、ぜひ試してみてください。
 
Getting Started

検索バーにキーワード、フレーズ、または質問を入力し、お探しのものを見つけましょう

シスコ コミュニティをいち早く使いこなしていただけるよう役立つリンクをまとめました。みなさんのジャーニーがより良いものとなるようお手伝いします