Windows10にScapyをインストールする

Windows10 + Pythonでパケットを扱うライブラリを探してみたところ、Scapyが良さそうでした。

 
そこで、Scapyをインストールしようとしたところ、いくつかハマったところがあったため、メモを残しておきます。

 
なお、本当はPython3で使いたかったのですが、後述の通り、今のところWindowsのPython3で使うのは難しそうでした。

そのため、今回はPython2系のScapyを使うことにしました。

 
長いので、以下目次です。

 

環境

 
WindowsでScapyを使うには、WinPcapが必要そうでした。
WinPcap - Home

ただ、Windows10の場合、WinPcap for Windows 10(Win10Pcap)もありました。 Win10Pcap - WinPcap for Windows 10

ドキュメントを見ると、

  • Win10Pcap は従来の WinPcap の DLL とバイナリ互換があります。
  • x86 および x64 の両方で 「Compatible with Windows 10」 ロゴを取得しました。

などの記載があったため、今回はWin10Pcapを使うことにしました。

公式サイトより、Win10Pcap-v10.2-5002.msiをダウンロード・インストールします。インストール先はデフォルトのままで問題ないようです。
Win10Pcap ダウンロード - WinPcap for Windows 10

 

OK: Python2.7.11 + GitHubのScapy

Python2系のScapyをWindowsにインストールする方法は、いくつかのサイトで目にしました。

 
ただ、現在のGitHubにあるソースコードからインストールすれば、dnetへの依存がなく、Scapyだけで動くようでした。

 
そこで、今回はGitHubからのインストールを試してみます。

# ディレクトリ作成
D:\Sandbox>mkdir scapy2_installation
D:\Sandbox>cd scapy2_installation

# virtualenv環境作成
D:\Sandbox\scapy2_installation>virtualenv -p c:\python27\python.exe env
D:\Sandbox\scapy2_installation>env\Scripts\activate

# GitHubからインストール
(env) D:\Sandbox\scapy2_installation>pip install git+https://github.com/secdev/scapy.git
...
Successfully installed scapy-2.3.2.dev0

# インストール結果の確認
(env) D:\Sandbox\scapy2_installation>pip list
pip (7.1.2)
scapy (2.3.2.dev0)
setuptools (18.2)
wheel (0.24.0)

 
以上で環境ができたため、Googlepingを飛ばして実行確認します。

D:\Sandbox\scapy2_installation\runner.py

# -*- coding: utf-8 -*-
from scapy.all import *

# ICMPパケットの作成
request=IP(dst='www.google.com')/ICMP()
request.show()

# ICMPパケットの送出
response = sr1(request)

# 結果の表示
response.show()

 
実行結果は以下の通りとなり、正しく動作していることが確認できました。

(env) D:\Sandbox\scapy2_installation>python runner.py
WARNING: No route found for IPv6 destination :: (no default route?)
###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = icmp
  chksum    = None
  src       = 192.168.***.***
  dst       = Net('www.google.com')
  \options   \
###[ ICMP ]###
     type      = echo-request
     code      = 0
     chksum    = None
     id        = 0x0
     seq       = 0x0
Begin emission:
FATAL Bad Memory Block.
FATAL Bad Memory Block.
Finished to send 1 packets.
....*
Received 5 packets, got 1 answers, remaining 0 packets
###[ IP ]###
  version   = 4L
  ihl       = 5L
  tos       = 0x0
  len       = 28
  id        = 0
  flags     =
  frag      = 0L
  ttl       = 49
  proto     = icmp
  chksum    = 0x8f5
  src       = 216.58.221.164
  dst       = 192.168.***.***
  \options   \
###[ ICMP ]###
     type      = echo-reply
     code      = 0
     chksum    = 0x0
     id        = 0x0
     seq       = 0x0

 
ここまでで本題は終了ですが、試してみてダメだったパターンも以下に残しておきます。

 

NG: Python2.7.11 + PyPIのScapy

当初GitHubからのインストールを知らなかったため、前述のサイトを参考にPyPIのScapyをインストールしてみました。
zlorb/scapy: Scapy Install for Windows with Python 2.7

そのサイトには

Minimum requirement seems to be pywin32 and winpcap.

と書かれていたものの、pywin32無しでも行けないかなと思い、まずはScapyからインストールすることにしました。

D:\Sandbox>mkdir scapy2_ng
D:\Sandbox>cd scapy2_ng
D:\Sandbox\scapy2_ng>virtualenv -p c:\python27\python.exe env
D:\Sandbox\scapy2_ng>env\Scripts\activate
(env) D:\Sandbox\scapy2_ng>pip install scapy

 
この時点で上記で作ったPythonスクリプト(runner.py)を実行してみます。

(env) D:\Sandbox\scapy2_ng>python runner.py
Traceback (most recent call last):
  File "runner.py", line 2, in <module>
    from scapy.all import *
...
  File "D:\Sandbox\scapy2_ng\env\lib\site-packages\scapy\arch\pcapdnet.py", line 30, in <module>
    import pcapy as pcap
ImportError: No module named pcapy

pcapyパッケージが無さそうでした。

 
pcapyのインストール方法は、公式のGitHub Wikiに画像入りで案内がありました。
Compiling Pcapy on Windows Guide · CoreSecurity/pcapy Wiki

ただ、今回はvirtualenv + pipを使っているため、PyPIからインストールしてみます。

(env) D:\Sandbox\scapy2_ng>pip install pcapy
...
    running build_ext
    building 'pcapy' extension
    error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat). Get it from http://aka.ms/vcpython27

Microsoft Visual C++ Compiler for Python 2.7がないため、ビルドできないようでした。

 
そこで、Download Microsoft Visual C++ Compiler for Python 2.7 from Official Microsoft Download Centerから(VCForPython27.msi)をダウンロード・インストールし、再度PyPIからインストールしてみます。

(env) D:\Sandbox\scapy2_ng>pip install pcapy
...
  pcapdumper.cc(11) : fatal error C1083: Cannot open include file: 'pcap.h': No such file or directory
  error: command 'C:\\Users\\think\\AppData\\Local\\Programs\\Common\\Microsoft\\Visual C++ for Python\\9.0\\VC\\Bin\\cl.exe' failed with exit status 2

pcap.hファイルが無いというエラーメッセージに変わりました。

 
調べてみたところ、以下のstackoverflowより、WinPcap Developer's Packがないことが分かりました。
python - trouble installing pcapy on windows 7 - cannot open include file: 'pcap.h' - Stack Overflow

 
そこで、Developer's Packを利用してインストールしてみます。

# Developer's Packのダウンロード
(env) D:\Sandbox\scapy2_ng>bitsadmin.exe /TRANSFER devpack http://www.winpcap.org/install/bin/WpdPack_4_1_2.zip 
D:\Sandbox\scapy2_ng\WpdPack_4_1_2.zip
DISPLAY: 'devpack' TYPE: DOWNLOAD STATE: TRANSFERRED
PRIORITY: NORMAL FILES: 1 / 1 BYTES: 775788 / 775788 (100%)
Transfer complete.

# PowerShellを経由したzipファイルの解凍
D:\Sandbox\scapy2_ng>powershell expand-archive D:\Sandbox\scapy2_ng\WpdPack_4_1_2.zip .

# --global-optionによるDeveloper's Packを使ったインストール
(env) D:\Sandbox\scapy2_ng>pip install pcapy --global-option=build_ext --global-option="-LD:\Sandbox\scapy2_ng\WpdPack\Lib" --global-option="-ID:\Sandbox\scapy2_ng\WpdPack\Include

# 確認
(env) D:\Sandbox\scapy2_ng>pip list
pcapy (0.10.10)
pip (7.1.2)
scapy (2.3.2)
setuptools (18.2)
wheel (0.24.0)

 
再度実行したところ、dnetが無いというエラーになりました。

(env) D:\Sandbox\scapy2_ng>python runner.py
...
ImportError: No module named dnet

 
PyPIを見たところパッケージがありました。
dnet 1.12 : Python Package Index

そのため、pipでdnetをインストールしようとしたところ、エラーになりました。

(env) D:\Sandbox\scapy2_ng>pip install dnet
Collecting dnet
  Could not find a version that satisfies the requirement dnet (from versions: )
No matching distribution found for dnet

 
GitHubを見たところ、releaseがありました。
dugsong/libdnet: Automatically exported from code.google.com/p/libdnet

そのため、releaseからインストールしてみましたが、

(env) D:\Sandbox\scapy2_ng>pip install https://github.com/dugsong/libdnet/archive/libdnet-1.12.zip
Collecting https://github.com/dugsong/libdnet/archive/libdnet-1.12.zip
  Downloading https://github.com/dugsong/libdnet/archive/libdnet-1.12.zip
     / 1.1MB 312kB/s
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 18, in <module>
    IOError: [Errno 2] No such file or directory: 'path\\to\\appdata\\local\\temp\\pip-u_j8nk-build\\setup.py'

setup.pyが無いようで、エラーとなりました。

 
自分でビルドするのは手間だったので、バイナリを配布しているところを探してみたところ、いくつかありました。

 
配布されているバイナリに差がないか、fcivを使って調べてみます。
可用性とは、ファイル チェックサム整合性検証ユーティリティの説明

結果は、

# オリジナル
C:\Users\think\Downloads>D:\PortableApps\fciv\fciv.exe C:\Users\think\Downloads\dnet-1.12.win32-py2.7.exe -sha1
//
// File Checksum Integrity Verifier version 2.05.
//
7635b04d8363a9fde19fd1548926318aee916337 c:\users\think\downloads\dnet-1.12.win32-py2.7.exe

# GitHubの-2なし
C:\Users\think\Downloads>D:\PortableApps\fciv\fciv.exe "C:\Users\think\Downloads\dnet-1.12.win32-py2.7 (1).exe" -sha1
//
// File Checksum Integrity Verifier version 2.05.
//
7635b04d8363a9fde19fd1548926318aee916337 c:\users\think\downloads\dnet-1.12.win32-py2.7 (1).exe

# Githubの-2
C:\Users\think\Downloads>D:\PortableApps\fciv\fciv.exe C:\Users\think\Downloads\dnet-1.12.win32-py2.7-2.exe -sha1
//
// File Checksum Integrity Verifier version 2.05.
//
7635b04d8363a9fde19fd1548926318aee916337 c:\users\think\downloads\dnet-1.12.win32-py2.7-2.exe

と、いずれも同じようでした。

 
そのため、easy_installを使って、exe形式のパッケージをvirtualevn環境へインストールします。

# インストール
(env) D:\Sandbox\scapy2_ng>easy_install http://dirk-loss.de/scapy/dnet-1.12.win32-py2.7.exe
...Finished processing dependencies for dnet==1.12

# 確認
(env) D:\Sandbox\scapy2_ng>pip list
dnet (1.12)
pcapy (0.10.10)
pip (7.1.2)
scapy (2.3.2)
setuptools (18.2)
wheel (0.24.0)

 
再度実行してみます。

(env) D:\Sandbox\scapy2_ng>python runner.py
...
AttributeError: 'module' object has no attribute 'ex_name'

またエラーとなりました。

このエラー原因を探してみたところ、冒頭のstackoverflowにたどり着き、GitHubからインストールすれば良いということが分かりました。

 

NG: Python3.5.1 + PyPIのscapy-python3(scapy3k)

Python3でScapyを扱う方法がないかを探してみたところ、Scapyからforkしたscapy-python3(scapy3k)がありました。
phaethon/scapy: Network packet and pcap file crafting/sniffing/manipulation/visualization security tool (based on scapy) with python3 compatibility

いくつかの改善と互換性維持があり、OSのサポート状況については、

Currently, works on Linux, Darwin, Unix and co. Using python 3.4 on Ubuntu and FreeBSD for testing. Windows support in progress.

とのことでした。

試してみます。

# virtualenv準備
D:\Sandbox>mkdir scapy3k_ng
D:\Sandbox>cd scapy3k_ng
D:\Sandbox\scapy3k_ng>virtualenv -p c:\python35-32\python.exe env
D:\Sandbox\scapy3k_ng>env\Scripts\activate

# インストール
(env) D:\Sandbox\scapy3k_ng>pip install scapy-python3
(env) D:\Sandbox\scapy3k_ng>pip list
pip (7.1.2)
scapy-python3 (0.18)
setuptools (18.2)
wheel (0.24.0)

# 実行
(env) D:\Sandbox\scapy3k_ng>python runner.py
WARNING: Windows support for scapy3k is currently in testing. Sniffing/sending/receiving packets should be working with WinPcap driver and Powershell. Create issues at https://github.com/phaethon/scapy
Traceback (most recent call last):
  File "runner.py", line 2, in <module>
    from scapy.all import *
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\all.py", line 16, in <module>
    from .arch import *
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\__init__.py", line 88, in <module>
    from .windows import *
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\windows\__init__.py", line 198, in <module>
    ifaces.load_from_powershell()
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\windows\__init__.py", line 149, in load_from_powershell
    for i in get_windows_if_list():
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\windows\__init__.py", line 90, in get_windows_if_list
    current_interface['name'] = value.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0x83 in position 0: ordinal not in range(128)

エラーとなりました。

 
次に、現時点での最新コミットa7cd488b51e29c48430afffe4810aa13bffe62f7を指定してpipでインストールしてみます。
Install specific git commit with pip - Stack Overflow

# アンインストール
(env) D:\Sandbox\scapy3k_ng>pip uninstall scapy-python3
...
Proceed (y/n)? y
  Successfully uninstalled scapy-python3-0.18

# インストール
(env) d:\Sandbox\scapy3k_ng>pip install git+https://github.com/phaethon/scapy.git@a7cd488b51e29c48430afffe4810aa13bffe62f7
Collecting git+https://github.com/phaethon/scapy.git@a7cd488b51e29c48430afffe4810aa13bffe62f7
  Cloning https://github.com/phaethon/scapy.git (to a7cd488b51e29c48430afffe4810aa13bffe62f7) to c:\users\think\appdata\local\temp\pip-8q2a980a-build
  Could not find a tag or branch 'a7cd488b51e29c48430afffe4810aa13bffe62f7', assuming commit.
Installing collected packages: scapy-python3
  Running setup.py install for scapy-python3
Successfully installed scapy-python3-0.18

 
ちなみに、メッセージの中にCould not find a tag or branch 'xxx', assuming commit.とありますが、該当commitでインストールされているようです。

試しにver0.9のコミットで試してみました。

# インストール
(env) d:\Sandbox\scapy3k_ng>pip install git+https://github.com/phaethon/scapy.git@5ca348345d0c36dab8e853c34940b6f8851f3c30
...
  Could not find a tag or branch '5ca348345d0c36dab8e853c34940b6f8851f3c30', assuming commit.
...
Successfully installed scapy-python3-0.9

# 確認
(env) d:\Sandbox\scapy3k_ng>pip list
...
scapy-python3 (0.9)
...

 
話を戻して、Pythonスクリプトを実行してみます。

(env) d:\Sandbox\scapy3k_ng>python runner.py
WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6
###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = icmp
  chksum    = None
  src       = 192.168.10.101
  dst       = Net('www.google.com')
  \options   \
###[ ICMP ]###
     type      = echo-request
     code      = 0
     chksum    = None
     id        = 0x0
     seq       = 0x0
Begin emission:
WARNING: No route found (no default route?)
WARNING: No broadcast address found for iface lo0

ERROR: --- Error sending packets
Traceback (most recent call last):
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\windows\__init__.py", line 325, in sndrcv
    pks.send(p)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\pcapdnet.py", line 398, in send
    sx = bytes(cls()/x)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\packet.py", line 289, in __bytes__
    return self.build()
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\packet.py", line 357, in build
    p = self.do_build()
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\packet.py", line 346, in do_build
    pkt = self.self_build()
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\packet.py", line 337, in self_build
    p = f.addfield(self, p, val)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\fields.py", line 79, in addfield
    return s+struct.pack(self.fmt, self.i2m(pkt,val))
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\layers\l2.py", line 95, in i2m
    return MACField.i2m(self, pkt, self.i2h(pkt, x))
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\layers\l2.py", line 89, in i2h
    x = conf.neighbor.resolve(pkt,pkt.payload)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\layers\l2.py", line 38, in resolve
    return self.resolvers[k](l2inst,l3inst)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\layers\inet.py", line 739, in <lambda>
    conf.neighbor.register_l3(Ether, IP, lambda l2,l3: getmacbyip(l3.dst))
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\layers\l2.py", line 73, in getmacbyip
    nofilter=1)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\sendrecv.py", line 385, in srp1
    a,b=srp(*args,**kargs)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\sendrecv.py", line 367, in srp
    s = conf.L2socket(iface=iface, filter=filter, nofilter=nofilter, type=type)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\pcapdnet.py", line 321, in __init__
    self.ins = open_pcap(iface, 1600, 0, 100)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\windows\__init__.py", line 225, in <lambda>
    pcapdnet.open_pcap = lambda iface,*args,**kargs: _orig_open_pcap(pcap_name(iface),*args,**kargs)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\pcapdnet.py", line 251, in <lambda>
    open_pcap = lambda *args,**kargs: _PcapWrapper_pypcap(*args,**kargs)
  File "D:\Sandbox\scapy3k_ng\env\lib\site-packages\scapy\arch\pcapdnet.py", line 215, in __init__
    self.iface = create_string_buffer(device.encode('ascii'))
AttributeError: 'NoneType' object has no attribute 'encode'
.............................
Received 279 packets, got 0 answers, remaining 1 packets
Traceback (most recent call last):
  File "runner.py", line 15, in <module>
    response.show()
AttributeError: 'NoneType' object has no attribute 'show'

パケットは作れているようですが、パケット送信のところでエラーとなっているようです。

 
ワーニングでNo broadcast address found for iface lo0が出ていたので、

response = sr1(request, iface='???')

のようにインタフェースを指定した送信を試してみます。

Windowsにおけるネットワークインタフェース名が分からないため、netifacesパッケージを使って確認します。
Netifaces - Alastair’s Place

インタフェースを列挙するスクリプト

import netifaces

ifs = netifaces.interfaces()
for i in ifs:
    print("{interface}'s settings: {result}"
        .format(interface=i, result=netifaces.ifaddresses(i)))

を作り実行してみたところ、

(env) d:\Sandbox\scapy3k_ng>python nw_interface.py
{304C6D5B-xxx-xxx-xxx-xxx}'s settings: {-1000: [{'addr': '5c:xx:xx:xx:xx:xx'}], 2: [{'addr': '169.254.108.111'}], 23: [{'addr':'fe80::xxx'}]}
{5DC64577-xxx-xxx-xxx-xxx}'s settings: {-1000: [{'addr': '00:xx:xx:xx:xx:xx'}], 2: [{'addr': '169.254.95.112'}], 23: [{'addr':'fe80::xxx'}]}
{D492A34B-xxx-xxx-xxx-xxx}'s settings: {-1000: [{'addr': '00:xx:xx:xx:xx:xx'}], 2: [{'broadcast': '192.168.xxx.xxx', 'netmask':'255.255.255.0', 'addr': '192.168.xxx.xxx'}], 23: [{'addr': 'fe80::xxx'}]}
...

という結果を得ました。

ただ、ここで取得できたD492A34B-xxx-xxx-xxx-xxxの値をifaceへ渡してもエラーが出て動作しませんでした。

以上よりWindowsの場合ifaceに何を設定すればよいか分からなかったため、Python3でScapyを使うのは諦めました。