
TCPポートスキャナー、SYNパケットを非同期に大量送信し、5分未満でインターネット全体をスキャンします。
これはインターネット規模のポートスキャナです。1台のマシンから1秒間に1000万パケットを送信し、5分未満でインターネット全体をスキャンできます。
使い方(パラメータ、出力)は、最も有名なポートスキャナである nmap と似ています。迷ったら、それらの機能のいずれかを試してみてください。多くのマシンの広範囲スキャンをサポートする機能は対応していますが、単一マシンの詳細スキャンは対応していません。
内部的には、scanrand、unicornscan、ZMap などのポートスキャナと同様の非同期送信を使用しています。より柔軟で、任意のポート範囲とアドレス範囲を指定できます。
注: masscan は独自の アドホック TCP/IP スタック を使用しています。単純なポートスキャン以外の操作を行うと、ローカルの TCP/IP スタックと競合する可能性があります。つまり、異なる IP アドレスから実行するために --src-ip オプションを使用するか、--src-port を使用して masscan が使用するソースポートを設定し、さらに内部ファイアウォール(pf や iptables など)を設定して、それらのポートを OS の他の部分から隔離する必要があります。
このツールは無料ですが、開発への寄付を検討してください: Bitcoin ウォレットアドレス: 1MASSCANaHUiyTtR3bJ2sLGuMw5kDBaj4T
Debian/Ubuntu では、以下のような手順になります。実際には C コンパイラ(gcc や clang など)以外の依存関係はありません。
sudo apt-get --assume-yes install git make gcc
git clone https://github.com/robertdavidgraham/masscan
cd masscan
make
これにより、プログラムは masscan/bin サブディレクトリに配置されます。
インストールするには(Linux 上で)以下を実行します:
make install
ソースは多数の小さなファイルで構成されているため、マルチスレッドビルドを使用するとビルドが大幅に高速化されます。ただし、Raspberry Pi では 2GB を超えるメモリが必要になり(失敗する可能性があります)、すべてのスレッドを使用する代わりに -j4 のような小さい数を使用した方がよい場合があります。
make -j
Linux が主要なターゲットプラットフォームですが、コードは他の多くのシステム(Windows、macOS など)でも問題なく動作します。追加のビルド情報を以下に示します:
make と入力make と入力gmake と入力cc src/*.c -o bin/masscanmacOS では、x86 バイナリは ARM エミュレーション下でも同様に高速に動作するようです。
使い方は nmap と似ています。ネットワークセグメントの特定のポートをスキャンするには:
# masscan -p80,8000-8100 10.0.0.0/8 2603:3001:2d00:da00::/112
これにより:
10.x.x.x サブネットと 2603:3001:2d00:da00::x サブネットをスキャンします<stdout> に出力を表示しますオプションの完全なリストを表示するには、--echo 機能を使用します。これにより、現在の設定がダンプされて終了します。この出力は、プログラムへの入力として再利用できます:
# masscan -p80,8000-8100 10.0.0.0/8 2603:3001:2d00:da00::/112 --echo > xxx.conf
# masscan -c xxx.conf --rate 1000
Masscan はポートが開いているかどうかを検出するだけではありません。TCP 接続を完了し、そのポートのアプリケーションと対話して、簡単な「バナー」情報を取得することもできます。
Masscan は以下のプロトコルのバナーチェックをサポートしています:
これに関する問題は、masscan が実行中のシステムとは別の独自の TCP/IP スタックを持っていることです。ローカルシステムがプローブ対象から SYN-ACK を受信すると、RST パケットで応答し、masscan がバナーを取得する前に接続を切断します。
これを防ぐ最も簡単な方法は、masscan に別の IP アドレスを割り当てることです。これは以下のいずれかの例のようになります:
# masscan 10.0.0.0/8 -p80 --banners --source-ip 192.168.1.200
# masscan 2a00:1450:4007:810::/112 -p80 --banners --source-ip 2603:3001:2d00:da00:91d7:b54:b498:859d
選択するアドレスはローカルサブネット上にあり、他のシステムで使用されていない必要があります。Masscan は間違いを警告しますが、数分間他のマシンの通信を妨害する可能性があるため、注意してください。
WiFi などの場合、これが不可能なこともあります。そのような場合は、masscan が使用するポートをファイアウォールでブロックできます。これにより、ローカルの TCP/IP スタックはパケットを見ることができなくなりますが、masscan はローカルスタックをバイパスするため、引き続きパケットを見ることができます。Linux では次のようになります:
# iptables -A INPUT -p tcp --dport 61000 -j DROP
# masscan 10.0.0.0/8 -p80 --banners --source-port 61000
おそらく、Linux がソースポートとして選択する可能性のあるポートと競合しないポートを選択する必要があります。Linux が使用する範囲を確認し、その範囲を再設定するには、次のファイルを確認します:
/proc/sys/net/ipv4/ip_local_port_range
最新の Kali Linux(2018年8月)では、その範囲は 32768 から 60999 なので、32768 未満または 61000 以上のポートを選択する必要があります。
iptables ルールの設定は、次回の再起動までしか持続しません。iptables-save や iptables-persistent などを使用して、ディストリビューションに応じて設定を保存する方法を調べる必要があります。
Mac OS X および BSD でも同様の手順が必要です。回避すべき範囲を調べるには、次のようなコマンドを使用します:
# sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last
FreeBSD および古い MacOS では、ipfw コマンドを使用します:
# sudo ipfw add 1 deny tcp from any to any 40000 in
# masscan 10.0.0.0/8 -p80 --banners --source-port 40000
新しい MacOS および OpenBSD では、pf パケットフィルターユーティリティを使用します。
次の行を追加するためにファイル /etc/pf.conf を編集します:
block in proto tcp from any to any port 40000:40015
その後、ファイアウォールを有効にするには、次のコマンドを実行します:
# pfctl -E
ファイアウォールが既に実行中の場合は、次のコマンドでルールをリロードするか、再起動します:
# pfctl -f /etc/pf.conf
Windows は RST パケットで応答しないため、これらの手法は必要ありません。ただし、masscan は独自の IP アドレスを使用するように設計されているため、厳密に必要でない場合でも、可能な限りそのように実行する必要があります。
--heartbleed チェックなど、他のチェックでも同じことが必要です。これらはバナーチェックの一種です。
小規模な内部ネットワークには便利ですが、このプログラムは実際にはインターネット全体を念頭に置いて設計されています。次のようになります:
# masscan 0.0.0.0/0 -p0-65535
インターネット全体をスキャンするのは良くありません。第一に、インターネットの一部はスキャンに悪影響を及ぼします。第二に、一部のサイトはスキャンを追跡し、あなたを禁止リストに追加し、有用なインターネットの部分からファイアウォールで遮断される可能性があります。したがって、多くの範囲を除外する必要があります。範囲をブラックリストまたは除外するには、次の構文を使用します:
# masscan 0.0.0.0/0 -p0-65535 --excludefile exclude.txt
これにより、結果がコマンドラインに出力されるだけです。代わりにファイルに保存したいでしょう。そのためには、次のようなものを使用します:
# masscan 0.0.0.0/0 -p0-65535 -oX scan.xml
これにより、結果が XML ファイルに保存され、データベースなどに簡単にダンプできます。
ただし、これはデフォルトのレート 100 パケット/秒でしか動作しないため、インターネットのスキャンには永遠に時間がかかります。次のように速度を上げる必要があります:
# masscan 0.0.0.0/0 -p0-65535 --max-rate 100000
これによりレートが 100,000 パケット/秒に増加し、インターネット全体(除外範囲を除く)を 1 ポートあたり約 10 時間(全ポートをスキャンする場合は 655,360 時間)でスキャンします。
このコマンドラインで注目すべき点は、これらがすべて nmap 互換のオプションであることです。さらに、nmap 互換の「不可視」オプションも自動的に設定されます: -sS -Pn -n --randomize-hosts --send-eth。同様に、XML ファイルの形式も nmap に触発されています。もちろん、プログラムの非同期的性質が問題への根本的に異なるアプローチにつながるため、多くの違いがあります。
上記のコマンドラインは少し面倒です。すべてをコマンドラインに置く代わりに、ファイルに保存することもできます。上記の設定は次のようになります:
# My Scan
rate = 100000.00
output-format = xml
output-status = all
output-filename = scan.xml
ports = 0-65535
range = 0.0.0.0-255.255.255.255
excludefile = exclude.txt
この設定ファイルを使用するには、-c を使用します:
# masscan -c myscan.conf
これにより、スキャンを繰り返すときにも簡単になります。
デフォルトでは、masscan は最初に設定ファイル /etc/masscan/masscan.conf を読み込みます。後続の設定パラメータは、このデフォルト設定ファイルの内容を上書きします。私はここに "excludefile" パラメータを記述して、忘れることがないようにしています。自動的に動作します。
デフォルトでは、masscan はかなり大きなテキストファイルを生成しますが、他の形式に簡単に変換できます。サポートされている出力形式は 5 つあります:
xml: パラメータ -oX <filename> を使用するだけです。
または、パラメータ --output-format xml と --output-filename <filename> を使用します。
binary: これは masscan の組み込み形式です。ファイルサイズがはるかに小さくなるため、インターネットをスキャンしてもディスクが満杯になりません。ただし、解析する必要があります。コマンドラインオプション --readscan はバイナリスキャンファイルを読み取ります。--readscan を -oX オプションと一緒に使用すると、結果ファイルの XML バージョンが生成されます。
grepable: これは Nmap の -oG 出力の実装で、コマンドラインツールで簡単に解析できます。パラメータ -oG <filename> を使用するだけです。または、パラメータ --output-format grepable と --output-filename <filename> を使用します。
json: 結果を JSON 形式で保存します。パラメータ -oJ <filename> を使用するだけです。または、パラメータ --output-format json と --output-filename <filename> を使用します。
合理的であれば、nmap ユーザーにとって使い慣れたものにするためにあらゆる努力が払われていますが、本質的には異なります。Masscan は多数のマシンの広範囲スキャンに調整されており、nmap は単一のマシンまたは小規模範囲の集中スキャン向けに設計されています。
2 つの重要な違いは次のとおりです:
-p <ports> を指定する必要がありますnmap が使用する変則的なサブネット範囲(10.0.0-255.0-255 など)ではありません。masscan は、次の設定が永続的に有効になっていると考えることができます:
-sS: SYN スキャンのみを実行します(現在、将来変更される可能性があります)-Pn: ホストに ping を実行しません。これは非同期動作の基本です-n: DNS 解決は行われません--randomize-hosts: スキャンは常に完全にランダム化され、これは変更できません--send-eth: 生の libpcap を使用して送信します追加の nmap 互換設定のリストが必要な場合は、次のコマンドを使用します:
# masscan --nmap
このプログラムはパケットを非常に高速に送出します。Windows または VM からは 300,000 パケット/秒を処理できます。Linux(仮想化なし)では、160 万パケット/秒を処理します。これは、ほとんどのネットワークを溶かすのに十分な速度です。
なお、溶かすのは自分のネットワークだけです。ターゲット IP アドレスがランダム化されているため、遠くのネットワークを圧倒することはありません。
デフォルトでは、レートは 100 パケット/秒に設定されています。レートを 100 万に上げるには、--rate 1000000 のようなものを使用します。
IPv4 インターネットをスキャンする場合、多数のサブネットをスキャンすることになるため、多くのパケットが送出されていても、各ターゲットサブネットが受信するパケットレートは低くなります。
ただし、IPv6 スキャンの場合、数十億のアドレスを持つ単一のターゲットサブネットに集中する傾向があります。したがって、デフォルトの動作ではターゲットネットワークを圧倒します。ネットワークは、masscan が生成できる負荷の下でクラッシュすることがよくあります。
このセクションでは、プログラムの主要な設計上の問題について説明します。
ファイル main.c には、予想通り main() 関数が含まれています。また、transmit_thread() 関数と receive_thread() 関数も含まれています。これらの関数は意図的にフラット化され、詳細にコメントが付けられているため、それぞれの関数を一行ずつステップ実行するだけでプログラムの設計を読むことができます。
これは非同期設計です。言い換えれば、nginx Web サーバーと Apache の関係のように、nmap に対するものです。独立した送信スレッドと受信スレッドがあり、それらは互いにほぼ独立しています。scanrand、unicornscan、ZMap に見られるのと同じ種類の設計です。
非同期であるため、基盤となるパケット送信が許す限り高速に動作します。
Masscan と他のスキャナの主な違いは、ターゲットをランダム化する方法です。
基本原理は、ゼロから始まりプローブごとに 1 ずつ増加する単一のインデックス変数を持つことです。C コードでは、これは次のように表現されます:
for (i = 0; i < range; i++) {
scan(i);
}
インデックスを IP アドレスに変換する必要があります。すべての「プライベート」IP アドレスをスキャンしたいとします。それは次のような範囲のテーブルになります:
192.168.0.0/16
10.0.0.0/8
172.16.0.0/12
この例では、最初の 64k のインデックスが 192.168.x.x に追加されてターゲットアドレスが形成されます。次に、次の 1600 万のインデックスが 10.x.x.x に追加されます。残りの範囲のインデックスは 172.16.x.x に適用されます。
この例では、3 つの範囲しかありません。インターネット全体をスキャンする場合、実際には 100 以上の範囲があります。これは、多くのサブ範囲をブラックリストまたは除外する必要があるためです。これにより、目的の範囲が数百の小さな範囲に分割されます。
これにより、コードの最も遅い部分の 1 つが発生します。1 秒間に 1000 万パケットを送信し、プローブごとにインデックス変数を IP アドレスに変換する必要があります。これを解決するために、少量のメモリ内で「二分探索」を行います。このパケットレートでは、アルゴリズムの効率よりもキャッシュの効率が支配的になり始めます。理論的にはもっと効率的な手法はたくさんありますが、それらはすべて非常に多くのメモリを必要とするため、実際には遅くなります。
インデックスから IP アドレスに変換する関数を pick() 関数と呼びます。使用時には次のようになります:
for (i = 0; i < range; i++) {
ip = pick(addresses, i);
scan(ip);
}
Masscan は IP アドレス範囲だけでなく、ポート範囲もサポートしています。つまり、インデックス変数から IP アドレスとポートの両方を選択する必要があります。これは非常に簡単です:
range = ip_count * port_count;
for (i = 0; i < range; i++) {
ip = pick(addresses, i / port_count);
port = pick(ports, i % port_count);
scan(ip, port);
}
これにより、コードの別の高コスト部分が発生します。除算/剰余命令は、x86 CPU で約 90 クロックサイクル、つまり 30 ナノ秒かかります。1 秒間に 1000 万パケットのレートで送信する場合、パケットあたりわずか 100 ナノ秒しかありません。これをこれ以上最適化する方法は見当たりません。幸いなことに、2 つのそのような操作を同時に実行できるため、上記のように 2 つ実行しても、1 つ実行するのとコストは変わりません。
上記のパフォーマンス問題には実際には簡単な最適化がありますが、それらはすべて i++、つまりスキャンを通じてインデックス変数が 1 つずつ増加するという事実に依存しています。実際には、この変数をランダム化する必要があります。スキャンする IP アドレスの順序をランダム化しないと、この速度に耐えられないターゲットネットワークを攻撃してしまいます。トラフィックをターゲット全体に均等に分散する必要があります。
ランダム化する方法は、単にインデックス変数を暗号化することです。定義上、暗号化はランダムであり、元のインデックス変数と出力の間に 1 対 1 のマッピングを作成します。つまり、範囲を線形に処理する一方で、出力 IP アドレスは完全にランダムになります。コードでは次のようになります:
range = ip_count * port_count;
for (i = 0; i < range; i++) {
x = encrypt(i);
ip = pick(addresses, x / port_count);
port = pick(ports, x % port_count);
scan(ip, port);
}
これにも大きなコストがかかります。範囲はきれいな 2 のべき乗ではなく予測不可能なサイズであるため、AND (&) や XOR (^) のような安価なバイナリ手法を使用できません。代わりに、MODULUS (%) のような高価な操作を使用する必要があります。現在のベンチマークでは、変数の暗号化に 40 ナノ秒かかっています。
このアーキテクチャにより、多くの優れた機能が可能になります。たとえば、「シャード」をサポートしています。5 台のマシンをそれぞれスキャンの 5 分の 1、つまり range / shard_count を実行するように設定できます。シャードは複数のマシン、または同じマシン上の複数のネットワークアダプタ、さらには(必要に応じて)同じネットワークアダプタ上の複数の IP ソースアドレスにすることができます。
または、暗号化関数に「シード」または「キー」を使用して、スキャンするたびに異なる順序を取得することもできます(例: x = encrypt(seed, i))。
また、プログラムを終了して現在の i の値を記憶しておき、後で再開することでスキャンを一時停止することもできます。開発中によく行います。インターネットスキャンで問題が発生した場合、 を押してスキャンを停止し、バグを修正した後に再開します。
もう 1 つの機能は、再送信/リトライです。インターネット上ではパケットが失われることがあるため、2 つのパケットを連続して送信できます。ただし、1 つのパケットをドロップするものは、直後に続くパケットもドロップする可能性があります。したがって、コピーを約 1 秒間隔で送信する必要があります。これは簡単です。すでに rate 変数(送信レート(パケット/秒))があるため、再送信関数は単に i + rate をインデックスとして使用します。いつの日か、インターネットの調査を行い、「連続」、「1 秒」、「10 秒」、「1 分」の再送信をこのように区別して、何がドロップされるかに違いがあるかどうかを確認したいと思っています。
非同期手法は「c10k 問題」の解決策として知られています。Masscan は次のレベルのスケーラビリティである「C10M 問題」向けに設計されています。
C10M の解決策は、カーネルをバイパスすることです。Masscan の主要なカーネルバイパスは 3 つあります:
Masscan は PF_RING DNA ドライバを使用できます。このドライバは、カーネルの関与なしに、ユーザーモードメモリからネットワークドライバに直接パケットを DMA 転送します。これにより、低速な CPU でも、ハードウェアが許す最大レートでパケットを送信できます。コンピュータに 8 枚の 10 Gbps ネットワークカードを搭載すると、1 秒間に 1 億パケットを送信できる可能性があります。
Masscan は、TCP 接続からバナーを取得するための独自の組み込み TCP スタックを持っています。つまり、コンピュータに十分なメモリがあれば、1000 万の同時 TCP 接続を簡単にサポートできます。
Masscan には「ミューテックス」がありません。最新のミューテックス(別名 futex)はほとんどがユーザーモードですが、2 つの問題があります。最初の問題は、キャッシュラインが CPU 間で素早く往復することです。2 番目の問題は、競合が発生すると、カーネルへのシステムコールが実行され、パフォーマンスが低下することです。プログラムの高速パス上のミューテックスは、スケーラビリティを著しく制限します。代わりに、Masscan は「リング」を使用して、受信スレッド内のユーザーモード TCP スタックが送信スレッドに干渉せずにパケットを送信する必要がある場合など、処理を同期します。
WindowsとMacはパケット送信に最適化されておらず、毎秒約30万パケットしか処理できませんが、Linuxは毎秒150万パケットを処理できます。おそらく、それでも必要な速度より速いでしょう。
脆弱性に対して報奨金が提供されています。詳細はVULNINFO.mdファイルを参照してください。このプロジェクトは、strcpy()のような安全でない関数の代わりに、safe_strcpy()のような安全な関数を使用しています。このプロジェクトには自動化された単体回帰テスト(make regress)が含まれています。
入出力を、ポートスキャンを行うすべての人が(または行うべき人が)慣れ親しんでいるnmapのように見せるために、多大な努力が払われています。
MasscanはIPv6をサポートしていますが、特別なモードはなく、両方が同時にサポートされています。(-6オプションはありません。常に利用可能です。)masscanの使用例では、IPv4アドレスが表示されている場所にIPv6アドレスを入力するだけです。同じスキャンでIPv4アドレスとIPv6アドレスを同時に含めることができます。出力には、特別なマークなしで、同じ場所に該当するアドレスが含まれます。
IPv6アドレス空間は非常に広いことを覚えておいてください。DHCPv6経由で割り当てられたサブネットの最初の64kアドレスを除き、大きな範囲をスキャンすることはおそらく避けたいでしょう。代わりに、他のソースから取得したファイル(--include-file filename.txt)に保存された大きなアドレスリストをスキャンすることになるでしょう。他の場所と同様に、このファイルにはIPv4アドレスとIPv6アドレスの両方のリストを含めることができます。私が使用しているテストファイルには800万のアドレスが含まれています。そのサイズのファイルは、起動時に読み込むのに数秒余分にかかります(masscanはスキャン前にアドレスをソートし、重複を削除します)。
masscanには独自のネットワークスタックが含まれていることに注意してください。したがって、masscanを実行するローカルマシン自体はIPv6を有効にする必要はありませんが、ローカルネットワークはIPv6パケットをルーティングできる必要があります。
毎秒200万パケットを超えるためには、Intel 10ギガビットイーサネットアダプタと、ntopの"PF_RING ZC"として知られる特別なドライバが必要です。MasscanはPF_RINGを使用するために再ビルドする必要はありません。PF_RINGを使用するには、以下のコンポーネントをビルドする必要があります:
libpfring.so (installed in /usr/lib/libpfring.so)pf_ring.ko (their kernel driver)ixgbe.ko (their version of the Intel 10-gbps Ethernet driver)libpcap.soのバージョンをビルドする必要はありません。
Masscanがアダプタ名がenp1s0のようなものではなくzc:enp1s0のようなものであることを検出すると、自動的にPF_RING ZCモードに切り替わります。
より詳細な議論はPoC||GTFO 0x15にあります。
プロジェクトには組み込みの単体テストが含まれています:
$ make test
bin/masscan --selftest
selftest: success!
これにより、コードの多くの難しい部分がテストされます。ビルド後にこれを行うべきです。
パフォーマンスをテストするには、ローカルルーターに過負荷をかけないように、次のようなコマンドを捨てアドレスに対して実行します:
$ bin/masscan 0.0.0.0/4 -p80 --rate 100000000 --router-mac 66-55-44-33-22-11
偽の--router-macはパケットをローカルネットワークセグメント内に留め、インターネットに出ていかないようにします。
また、送信オーバーヘッドなしでプログラムがどれだけ速く動作するかを示す「オフライン」モードでテストすることもできます:
$ bin/masscan 0.0.0.0/4 -p80 --rate 100000000 --offline
この2番目のベンチマークは、オーバーヘッドがほぼゼロのPF_RINGを使用した場合のプログラムの実行速度の目安を示します。
ちなみに、ランダム化アルゴリズムはCPU上で慢性的に遅い演算である「整数演算」を多用します。最新のCPUはこの計算を実行する速度が2倍になり、masscanが大幅に高速化されました。
このツールはRobert Grahamによって作成されました: email: [email protected] twitter: @ErrataRob
Copyright (c) 2013 Robert David Graham
このプログラムはフリーソフトウェアです。あなたはこれを、フリーソフトウェア財団によって発行されたGNU Affero General Public Licenseのバージョン3、またはそれ以降のバージョンの条項に基づいて、再配布および/または変更することができます。
このプログラムは、有用であることを期待して配布されていますが、いかなる保証もありません。商品性または特定目的への適合性の暗黙の保証も含め、一切の保証はありません。詳細については、GNU Affero General Public Licenseを参照してください。
あなたはこのプログラムとともにGNU Affero General Public Licenseのコピーを受け取ったはずです。受け取っていない場合は、https://www.gnu.org/licenses/を参照してください。
list: これは、1行に1つのホストとポートのペアを持つ単純なリストです。パラメータ -oL <filename> を使用するだけです。または、パラメータ --output-format list と --output-filename <filename> を使用します。形式は次のとおりです:
<port state> <protocol> <port number> <IP address> <POSIX timestamp>
open tcp 80 XXX.XXX.XXX.XXX 1390380064