Scapy を用いて SN実験2 で実装した TCP サーバに SYN Flood 攻撃をしてみた.

こんにちは.あらい大先生です.

先週のブログで,TCP 通信が行われる際に サーバとクライアントとの間で 3-way handshake が行われていることを確認しました.
今回のブログでは,この 3-way handshake を悪用して SYN Flood 攻撃を行ってみます.

注意

SYN Flood 攻撃を行いたい場合,攻撃の対象となるサーバを自分で用意しましょう.
同意なく他人が保有するサーバへ SYN Flood 攻撃を行った場合,電子計算機損壊等業務妨害罪 [1] に問われる恐れがあります!

SYN Flood 攻撃とは?

まずは SYN Flood 攻撃について復習しましょう.

SYN Flood 攻撃とは,悪意のあるクライアントがサーバへ SYN パケットを大量に送信する攻撃です.
通常の 3-way handshake とは異なり,クライアントからの ACK パケットの返信が無いため,サーバでは ACK パケットの受信待ちが大量に発生します.
これにより,正当なクライアントからの通信を受付できなくなります.

方針1:simpleTCPclient の改造

最初に思いついたアイデアは,
「simpleTCPclient.c の SYN パケットを送信する処理を悪用する」
です.

そのためには,simpleTCPclient.c から SYN パケットを送信する処理を特定できれば良さそうです.
さっそく simpleTCPclient.c のソースコードを確認すると,26 ~ 27行目に「サーバに接続」というコメントと connect() が見つかります(著作権の都合で,申し訳ありませんがソースコードを公開することはできません…).
この connect() が 3-way handshake に関わっていると思われます.

そこで,”man 2 connect” とコマンドを打って connect システムコールの仕様を確認してみましょう.
すると,以下の説明が見つかります.

The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr.

Linux Programmer's Manual

“... connects the socket …” とあるように,connect() は,自身のソケットと相手のソケットを接続する処理を行うようです.
また,27 行目より後の処理が「サーバからデータを受信」となっているので,connect() が一連の 3-way handshake を行っていると思われます.

念のため,connect() が行われた直後までに サーバ と クライアント との間に流れたパケットをキャプチャしてみましょう.
ただし,このまま simpleTCPserver と simpleTCPserver を実行すると,”HELLO” の送受信や通信の終了も行われてしまい,紛らわしくなります.
そのため,simpleTCPserver.c の accept() と write() (“HELLO” を送信する処理) との間に scanf() 等を追加して入力待ちを発生させるようにします.
また,connect() や accept() が実行されたことを分かりやすくするために,printf() も追加します.

書き換えたプログラムを実行した結果を以下の画像に示します.
左がクライアントで,右がサーバです.

画像1:プログラムを実行した結果

scanf() により,サーバは "HELLO" を送信する前で入力待ちが発生しています.
これにより,クライアントもメッセージの受信待ちが発生しています.

画像2:Wireshark によるパケットキャプチャの結果

画像 1, 2 のとおり,クライアントが connect() を呼び出した直後に 3-way handshake が完了していました.

SYN Flood 攻撃は 3-way handshake を完了させない攻撃なので,connect() を SYN Flood 攻撃へ悪用することは難しそうです.

方針2:Scapy で SYN Flood 攻撃を行うプログラムを書く.

simpleTCPclient を改造するのは難しそうなので,
「SYN パケットだけを送信するプログラムを作る」
という方針に変更します.

Python で SYN Flood 攻撃を行うプログラムを作りたい場合,Scapy というパケットを自作するライブラリを利用すると良いそうです.
実際,[2] ではルータに対して SYN Flood 攻撃を行う方法が紹介されていました.
そのため,この記事を参考にして以下のプログラムを書きました.

from scapy.all import *

target_ip = "192.168.56.101"
target_port = 12345

ip = IP(src="192.168.56.1", dst=target_ip)
tcp = TCP(sport=RandShort(), dport=target_port, flags="S")
p = ip / tcp

send(p, loop=1, verbose=0)

このプログラムの実行者が「攻撃者」となります.
そのため,先週のネットワークの構成に「攻撃者」が追加されます.

役割マシンOSIPアドレスポート番号
攻撃者物理Windows192.168.56.1/24p0
クライアントWSLDebian192.168.56.1/24p1
サーバVMDebian192.168.56.101/2412345

攻撃者が Python プログラムを実行したら,サーバで netstat コマンドを打ち,TCP 通信の状態を確認してみます.
そうすると,以下のような出力が得られると思います.

cysec@debian:~$ netstat -nto4
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       Timer
tcp        0      0 192.168.56.101:12345    192.168.56.1:61091      SYN_RECV    on (6.80/3/0)
tcp        0      0 192.168.56.101:12345    192.168.56.1:3824       SYN_RECV    on (6.80/3/0)
tcp        0      0 192.168.56.101:12345    192.168.56.1:30037      SYN_RECV    on (6.80/3/0)
tcp        0      0 192.168.56.101:12345    192.168.56.1:50939      SYN_RECV    on (6.80/3/0)
tcp        0      0 192.168.56.101:12345    192.168.56.1:38484      SYN_RECV    on (1.83/1/0)

今回の場合,Local Address がサーバ,Foreign Address が攻撃者 の IP アドレスとポート番号に対応しています.

サーバ の 12345 番ポートを用いて TCP 通信を行っているソケットは,いずれも SYN_RECV,すなわち「SYN パケットを受信して SYN/ACK パケットを返信した」という状態になっています.
そのため,「攻撃者は SYN パケットのみを大量に送信している」と言えそうです.

次に,simpleTCPclient を実行して クライアント と サーバ との 通信を試みます.
SYN Flood 攻撃が成功しているなら,クライアント と サーバ との通信に時間が掛かるか,失敗するはずです.

simpleTCPclient を実行した結果を以下の画像に示します.

サーバで ACK パケットの受信待ちの状態を表す SYN_RECV が大量に発生しているにも関わらず,クライアントは "HELLO" を受信することができました.

どうも SYN Flood 攻撃に失敗しているようです.
もしかしたら,サーバで SYN Flood 攻撃を防御する設定が有効になっているのかもしれません.

SYN Flood 攻撃に関する記事を調べてみたところ,SYN Flood 攻撃の対策の一つに SYN Cookies [3] があるようです.
また,ほとんどの Linux ディストリビューションで SYN Cookies がデフォルトで有効になっているようです.

今回の実験で使用した Debian VM の /proc/sys/net/ipv4/tcp_syncookies の値を確認してみたら,1 (有効) となっていました.
そこで,/proc/sys/net/ipv4/tcp_syncookies の値を 0 として実験してみました.
その結果を以下の画像に示します.

クライアント は サーバ と 3-way handshake を行えず,"HELLO" を受信することができませんでした.
SYN Flood 攻撃に成功したようです.

おわりに

今回は SN実験2 で実装した TCP サーバに SYN Flood 攻撃をしてみました.

SYN Flood 攻撃を成功させることが最低限の目標だったので,SYN Cookies への理解が不十分なまま実験を進めてしまいました.
そのため,Wireshark を用いて SYN cookies が機能している様子を観測し,その結果を別のブログに書くかもしれません.

参考

  1. デジタル庁:刑法,e-Gov法令検索,入手先〈https://elaws.e-gov.go.jp/document?lawid=140AC0000000045〉(参照 2022-09-01).
  2. Abdou Rockikz:How to Make a SYN Flooding Attack in Python,Python Code,入手先〈https://www.thepythoncode.com/article/syn-flooding-attack-using-scapy-in-python〉(参照 2022-08-25).
  3. Wikipedia:SYN cookies,入手先〈https://ja.wikipedia.org/wiki/SYN_cookies〉(参照 2022-08-26).

コメントを残す

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