はじめに

Pythonのライブラリである NetfilterQueue を使用すると、ファイアウォールと組み合わせてパケットをインターセプトすることが出来る。
また、インターセプトしたパケットは好きに変更することが出来る。
本稿では、NetfilterQueue と scapy を使用して ping の応答パケットを傍受、変更してみる。

インストール

必要なパッケージのインストール

$ sudo apt install python3-dev libnetfilter-queue-dev

netfilterqueue をインストールする。

$ pip3 install netfilterqueue

ファイアウォールの設定

netfilterqueue を使用して、パケットを操作するには、Netfilterの設定をしなくてはならない。
以下では、iptablesコマンドを使用してキュー1に受信したicmpパケットを入れる設定を施している。

# iptables -A INPUT -p icmp -j NFQUEUE --queue-num 1
# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
NFQUEUE    icmp --  0.0.0.0/0            0.0.0.0/0            NFQUEUE num 1

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination  

NetfilterQueueを使用してみる

# test.py
from netfilterqueue import NetfilterQueue

def callback(packet):
  print(packet.get_payload_len()) # パケットの長さを表示
  print(packet.get_payload()) # パケットの中身をバイト型で表示

  packet.accept() # パケットを許可する

  # パケットをドロップする場合は以下
  # packet.drop()

def main():
  nfqueue = NetfilterQueue()

  nfqueue.bind(1, callback) # キューID 1 にバインド

  try:
    nfqueue.run()
  except KeyboardInterrupt:
    pass

  nfqueue.unbind()

if __name__ == '__main__':
  main()

上記を実行し、pingを送信する。

$ ping google.com -c 1
PING google.com (172.217.25.78) 56(84) bytes of data.
64 bytes from nrt13s50-in-f14.1e100.net (172.217.25.78): icmp_seq=1 ttl=49 time=2.83 ms

--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 2.832/2.832/2.832/0.000 ms

すると以下の出力になり、受信したパケットをみることが出来る。

# python3 test.py
84
b'E\x00\x00T\x00\x00\x00\x001\x01\xb7s\xac\xd9\x19N\n\x00\x02\x0f\x00\x00\xba\xcf e\x00\x01\x01\x15\xd8Z\x00\x00\x00\x00\x86\x87\x06\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'

パケットを操作する

以下は、受信したパケットの送信元をグーグルからヤフーに変更してホストに渡すプログラムである。

from netfilterqueue import NetfilterQueue
from scapy.all import *

def callback(packet):
  pkt = IP(packet.get_payload())

  ip = IP(src="yahoo.co.jp", dst=pkt["IP"].dst)
  icmp = ICMP(type=pkt["ICMP"].type, id=pkt["ICMP"].id, seq=pkt["ICMP"].seq)
  raw = pkt["Raw"]

  packet.set_payload(bytes(ip/icmp/raw))

  packet.accept()

def main():
  nfqueue = NetfilterQueue()

  nfqueue.bind(1, callback)

  try:
    nfqueue.run()
  except KeyboardInterrupt:
    pass

  nfqueue.unbind()

if __name__ == '__main__':
  main()

上記を実行し、google.com に ping を送信すると以下のようになり、f1.top.vip.ssk.yahoo.co.jp から応答があったかのように見える。

$ ping google.com -c 1
PING google.com (172.217.25.78) 56(84) bytes of data.
64 bytes from f1.top.vip.ssk.yahoo.co.jp (182.22.59.229): icmp_seq=1 ttl=64 time=3.01 ms

--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 3.018/3.018/3.018/0.000 ms

0件のコメント

コメントを残す

アバタープレースホルダー

メールアドレスが公開されることはありません。 が付いている欄は必須項目です