28
29

More than 1 year has passed since last update.

Scapyって知ってる?

Last updated at Posted at 2022-06-01

概要

ScapyはPythonで記述されたコンピューターネットワーク用のパケット生成ツールである。今回はそのScapyを使用してのパケット作成から送信、Wiresharkでの確認までをまとめていく。

参考

ネットワークの勉強をするに当たって、上記の二つにはかなりお世話になった。

Scapyを触ってみる前にまず、そもそもプロトコルとは?

通信をする上で守らなければいけないお約束のこと。
各種のプロトコルはOSI参照モデルの7レイヤーによって以下のように分類されている。

層(レイヤー)         名称 規格(プロトコル) 概要         利用例
7 アプリケーション層         HTTP,FTP,DNS,SMTP,POPなど 個々のアプリケーション www,メール
6 プレゼンテーション層            SMTP,FTP,Telnetなど データの表現形式 HTML
5 セッション層 TLS,NetBIOSなど 通信手段 HTTPS
4 トランスポート層 TCP,UDP,NetWare/IPなど エンド間の通信制御 TCP,UDP
3 ネットワーク層 IP,ICMPなど データを送る相手を決め最適な経路で送信 IP
2 データリンク層 PPP,ARP,RARP,Ethernetなど 隣接する機器同士の通信を実現 Ethernet
1 物理層 RS-232,UTP,無線 物理的な接続、電気信号 UTPケーブル,光ファイバーケーブル

Scapyでのパケットの作り方

Scapyでパケットを作る上で、実は上記の7レイヤーが非常に重要になってくる。
実際パケットを作るのは物凄く簡単で、次のように/区切りにするだけなのだが順序が大事で、低いレイヤーから順番に並べる必要がある。Ether()/IP()/TCP()

パケットの送受信

パケットの送受信についても7レイヤーが重要になっており、ここが少しトリッキーである。

  • send()
    レイヤー3でパケットを送信
  • sendp()
    レイヤー2でパケットを送信
  • sr()
    レイヤー3でパケットを送信し、レスポンスを返す(応答をすべて受信)
  • sr1()
    レイヤー3でパケットを送信し、その応答の1つ目をレスポンスとして返す
  • srp()
    レイヤー2でパケットを送信し、レスポンスを返す(応答をすべて受信)
  • srp1()
    レイヤー2にでパケットを送信し、その応答の1つ目をレスポンスとして返す
  • srflood()
    レイヤー3でパケットを送信し続ける
  • srpflood()
    レイヤー2でパケットを送信し続ける

pがついてる関数はレイヤー2でパケットを送信

例えば、TCPパケットを作って送信したい場合、TCPはレイヤー3に位置するのでsend関数を使用して次のように送信することができる。send(Ether()/IP()/TCP())

ちなみに、間違ったレイヤーで送信しようとすると以下のような表示になり、いつまでも送信が完了しない。

Finished sending 1 packets.
..................................................................................................................................................................

成功していれば以下のようなログが出力される。

.
Sent 1 packets.

実装編

実際にパケットを作ってみる。

環境構築

# Pythonのバージョンを確認
python --version
> Python 3.7.3

# scapyのインストール(macOS)
> pip3 install --pre scapy

# Wiresharkのダウンロード(3.6.5)
https://www.wireshark.org/download.html

ARPパケット

ARPとは?

  • Address Resolution Protocolの略であり、IPアドレスからEthernetのMACアドレスの情報を得られるプロトコル。

併せて覚えておきたいARPテーブルとは?

  • ARPによって割り出したIPアドレスとMACアドレスの対応表。
  • 通信を行う度に毎回問い合わせを行うのは非効率なため、一度ARPで調べたデータはOSなどが専用の一時的な記憶領域に保管しておき、次に必要になったらそこから調べる。
  • ARPテーブルは、arp -aコマンドで確認できる。
> arp -a
? (192.168.0.1) at f8:b7:97:f3:38:52 on en0 ifscope [ethernet]
? (192.168.0.3) at 76:88:93:fb:55:c6 on en0 ifscope [ethernet]
? (192.168.0.4) at 8:6d:41:be:6f:7c on en0 ifscope [ethernet]

実装

「192.168.0.101を持っているのは誰で、MACアドレスは何ですか?」とブロードキャストMACアドレス宛(ff:ff:ff:ff:ff:ff)に送信。 

from scapy.all import *

####################
# IPv4 ARP Request #
####################

# 送信先のIPv4アドレス
DST_IP_V4 = "192.168.0.101"

def arp():
    pkt = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(op=1, pdst=DST_IP_V4)
    srp1(pkt)

ICMPパケット

ICMPとは?

  • Internet Control Message Protocolの略であり、IPプロトコルの「エラー通知」や「制御メッセージ」を転送するためのプロトコル。

豆知識

  • 皆さんお馴染みのpingはこのICMPプロトコルを使用したプログラム。
  • pingが通らない問題が発生した場合、ファイアウォールがICMPプロトコルの送受信を制限している可能性があるので確認してみると良い。

実装

from scapy.all import *

##########################
# IPv4 ICMP Echo Request #
##########################

# 送信先のIPv4アドレス
DST_IP_V4 = "192.168.0.101"

def icmp():
    pkt = Ether() / IP(dst=DST_IP_V4) / ICMP()
    srp1(pkt)

SNMPパケット

SNMPとは?

  • Simple Network Management Protocolの略であり、ルータ、スイッチ、サーバなどTCP/IPネットワークに接続された通信機器に対し、ネットワーク経由で監視、制御するためのアプリケーション層プロトコル。

実装

from scapy.all import *

#############
# IPv4 SNMP #
#############

# 送信先のIPv4アドレス
DST_IP_V4 = "192.168.0.101"

#dportは 161 で固定
def snmp():
    pkt = Ether() / IP(dst=DST_IP_V4)/UDP(dport=161)/SNMP(version=0,community="public",PDU=SNMPnext(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.2699.1.2"))]))
    sendp(pkt)

SSDPパケット

SSDPとは?

  • Simple Service Discovery Protocolの略であり、ネットワーク上の機器を自動的に発見・接続するUPnP(Universal Plug and Play)で用いられるプロトコル。

このパケットをScapyで作るには、payload部分を自作する必要がある。

実装

from scapy.all import *

#############
# IPv4 SSDP #
#############

#送信元のIPv4アドレス
SRC_IP_V4 = "192.168.0.10" 

#dstは 239.255.255.250 で固定
#sport、dportは 1900 で固定
def ssdp():
    payload = "M-SEARCH * HTTP/1.1\r\n" \
    "Host: 239.255.255.250:1900\r\n" \
    "ST: upnp:rootdevice\r\n" \
    "Man:\"ssdp:discover\"\r\n" \
    "MX:1\r\n\r\n" \

    pkt = IP(src=SRC_IP_V4,dst="239.255.255.250") / UDP(sport=1900, dport=1900) / payload
    send(pkt)

DNSパケット

DNSとは?

  • Domain Name Systemの略であり、ドメイン名(コンピュータを識別する名称)をIPアドレスに自動的に変換してくれるアプリケーション層プロトコル。

実装

from scapy.all import *

############
# IPv4 DNS #
############

def dns():
    pkt = IP(dst="8.8.8.8") / UDP() / DNS(rd=1,qd=DNSQR(qname="www.google.com"))
    sr1(pkt)

mDNS(Bonjour)パケット

mDNSとは?

  • Multicast Domain Name Serviceの略であり、ローカルネットワーク内でホスト名からIPアドレスを割り出すために用いられるプロトコル。

実装

from scapy.all import *

######################
# IPv4 mDNS(Bonjour) #
######################

#送信先のNetBIOS名
NAME = "RNP583879001982"

#dstは 224.0.0.251 で固定
#sport、dportは 5353 で固定
def mdns():
    pkt = IP(dst="224.0.0.251") / UDP(sport=5353,dport=5353) / DNS(rd=1,qd=DNSQR(qname=NAME+".local", qtype='A'))
    send(pkt)

Wiresharkでパケットキャプチャ

せっかくScapyでパケットを作ったので、ちゃんとそのパケットが飛んでいるのか確認してみる。

試しに上記で作成したDNSのパケットをキャプチャしてみると、ちゃんと飛んでいて更に応答が返ってきているのが分かる。面白い。
image.png

表示フィルター

以下の赤枠の小窓に、条件構文を直接入力することによってディスプレイをフィルタリングすることができる。
image.png

  • プロトコル(以下など)
    • tcp
    • udp
    • icmp
    • arp
  • IPアドレス
    • 送信元IP: ip.src==xxx.xxx.xxx.xxx
    • 送信先IP: ip.dst==xxx.xxx.xxx.xxx
    • 送信元/送信先両方: ip.addr==xxx.xxx.xxx.xxx
  • ポート番号
    • TCP: tcp.port==xxx
    • UDP: udp.port==xxx
  • 組み合わせ
    • 例)mdns&&ip.src==xxx.xxx.xxx.xxx

豆知識

パケット解析などに用いられるWiresharkだが、無線LANのキャプチャには実はWindowsは向かない。Macを使用すべき。
Windowsで無線LANをキャプチャする場合、米国Riverbed Technology社のAirPcapという製品が必要になるのだが、2017年に製造・販売が終了したので中古市場でも入手困難+高額。一方でMacはAirPcap使用の必要がなく、Wiresharkのみで無線LANのキャプチャが可能だ。
image.png

最後に

今回はScapyを使ってIPv4のパケットをいくつか作ってみたが、IPv6のパケットも作れるので今後そちらについても書いてみたいと思う。ネットワークモジュールなどのテスト(異常系パケットをわざと作って送ったり、大量のパケットを送りつけるなど)にもScapyは使用できるのでとても便利だ。

28
29
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
28
29