Rubyでポートスキャンツールを作るとこうなってしまう


Rubyの学習のためポートスキャンツールを作ります。

Pythonにはscapyという便利なライブラリーがあります。
Rubyにそのようなものがあるのか調べてませんしわからないので、スクラッチで作ることになります。
調査を怠けた以上これは致し方ないです。


ソケット作成


synスキャンを行うためrawsocketを使う必要があります。
Rubyでは以下のようにしてraw socketを作成します。
c言語どほとんど変わりないはありませんでした。
アドレスファミリー、ソケットタイプ、プロトコルを指定します。

tcpヘッダを自分で編集するための設定として
ソケットタイプにSOCK_RAW
プロトコルにIPPROTO_TCP
を指定します。

TCPヘッダーの作成


ヘッダーの作成方法に関しては僕が知らないだけでもっといいやり方があるかもしれません。

今回は以下の方法で作成しました。

TCPはパケットの内容が壊れていないかを判定するためチェックサムを計算しますが、その時に擬似ipヘッダーというものを加えます。
これは正しい通信相手からのパケットかどうかを判断するためだそうです。

諸々のデータを決定してpackで文字列にします。
packに渡している「n2N2C2n3」は値の型と数を表しています。
「n2」は2byteの値を2個、
「N2」は4byteの値を2個、
「C2」は1byteの値を1個、
「n3」は2byteの値を3個といった具合に配列の値を文字列に変換してくれます。
ですのでtcpヘッダーの構成を考えると「n2N2C2n3」をpackに渡すことになります。

特別なことはしていません。

チェックサムの計算


パケットのチェックサムを計算する関数です。

2byte単位で計算していきます

スキャン


1から65535までのポートを対象にスキャンを開始します。
ひとつのポートにつき10回までスキャンを試みます。

以下の終了条件を満たすまでパケットを送り続けます。

  1. 10回パケットの送受信をする
  2. syn,ackブラグがたったパケットを受信する
  3. フラグ上記の②以外の状態のパケットを受信する


項目として十分ではないかもしれませんが、ポートスキャナーとして最低限の動きはしてくれると思います。

パケットからヘッダーを抽出


ターゲットからパケットを受信したあと、そこからipヘッダーとtcpヘッダーを取得します。

パケットを送信する際にpackを使用して文字列にして送信しました。
今回は文字列に対しunpackを使用して配列を取得します。

全体


ソースコード全体はこうなりました。

PortScannerとしてクラスを作成しました。

動作確認


以下のようにスキャンします。


実行するときのコマンドと結果はこうなります。

感想


Pythonに似ている気がします。
Pythonでも作ってみたいと思います。
ほとんど変わらないかと。