Nmap
nmapはGordon Lyonによって書かれたセキュリティスキャナである。ポートスキャン機能だけでなく、OSやバージョンの検出機能、サービスおよびそのバージョンの検出機能など、多くの機能を兼ね備えている。
nmapはGordon Lyonによって書かれた、非常によく知られたセキュリティスキャナである。名前は、ネットワーク上にどのような機器やサービスが動いているかという、ネットワークの地図を作成すること (Network Mapper) に由来する。ポートスキャン機能だけでなく、特定ポートで動作するサービスアプリケーション(daemon類)の種類とバージョンを検出する機能、TCP/IP stack fingerprintingを用いたOSおよびそのバージョンを検出する機能など、多数の機能を備えており、2010年現在のバージョンでは、指定可能な引数は100種類を越える。また、Luaスクリプト言語で記述されたスクリプトを解するスクリプトエンジン「Nmap Scripting Engine」が用意されており、これを用いてスキャン動作を利用者がより柔軟に取り扱える仕組みが備わっている。
セキュリティ関連の書籍で取り上げられることも多く、LinuxQuestion.org主催のネットワークアプリケーション部門のベストアプリケーション賞(ユーザー投票に基づく)を5年以上連続して受賞しているなど、多数の高評価を得ている。
このようなツールがセキュリティ分野以外で取り上げられることは少ないが、「マトリックス リローデッド」でトリニティが脆弱なSSHサーバーを発見する際にnmap(バージョンは2.54BETA25)を用いていることはセキュリティ分野の人々の間ではよく知られており、このことはnmap作者のサイトやセキュリティ界最大コミュニティポータルであるsecurityfocus.comなどで紹介された。nmap作者は、馬鹿げた3Dアニメーションで取り繕ったようなハッキング場面を用いる演出の映画が多い中、マトリックスのそのハッキング場面を見て大きな衝撃を受けたと語っている。また、nmapはこの映画以外にも複数の映画において、ハッキング場面(例:ダイ・ハード4.0)や、登場人物がハッカーであることを演出する場面(例:バトル・ロワイアル)などで使用されており、これらの画像はnmap作者によってカタログ化されている。
nmapの誕生は、作者のGordon Lyon(当時はFyodorという名前を使っていた)がPhrackにポートスキャナを投稿するところから始まる。Fyodorは当時、ポートスキャナーを探していたが、当時のポートスキャナーはどれも自分に合わないものばかりであったことから、自分が使いたいものを作ろうと考え、そうして出来上がったものがnmapの初期版である。そして作成後、自分以外にもこのツールを使いたい人がいれば使って欲しいという想いでPhrackに投稿、そのツールが1997年にPhrack 51号にソースコード付きで掲載され、nmapが世界に知れ渡ることになった。Phrack 51号への投稿の段階で、その時点で発見されていた複数のポートスキャン方法(TCP SYNスキャン、TCP FINスキャン、タイニーIPフラグメントなど)に対応していた。
その後、FyodorはPhrack 54号でOSおよびそのバージョンを検出するアイデアを発表する。もちろんnmapに実装の上である。この発表までは、OSの検出手法といえば、サービスプログラムから返される文字列タイプのバナーを確認するというものであった。例えば、対象サーバーにtelnet接続した場合に表示される
といった文字列である。このバナー表示を信じればこのシステムはFreeBSDということになる。対象OSが何であるかという情報は、ネットワーク攻撃においては重要な情報であり、それが故、昨今ではバナーを隠すことはごく普通に行われていることである。nmapではTCP/IP stack fingerprintingと呼ばれる手法を用いてOSとバージョンを特定する。これは、OSごとにTCP/IPスタックの実装が微妙に異なることを用いて、ポートスキャン同様のパケットに対する挙動を基に、OSおよびそのバージョンを特定するというものである。一例を挙げると、TCP FINスキャンはBSD由来のTCP/IPスタックで有効に働き、Windowsには有効に働かないといった違いがある。このような挙動の違いを集めることで、対象OSおよびそのバージョンを特定できる可能性があるわけである。
初期にはCが用いられていたが、後にC++を用いるようになった。また、上記はいずれもIPv4を対象としているが、後にIPv6やSCTPにも対応するようになった。
このように多数の機能を備えたセキュリティスキャナであるが、更に、Luaスクリプト言語で記述されたスクリプトを解するスクリプトエンジン「Nmap Scripting Engine」(NSEと略される)が実装されることとなる。NSEを用いずとも様々なスキャンが可能なnmapであるが、NSEを用いることで、スキャン動作の自動化、より多角的な診断を行うことができるようになる。
これら、nmapの歴史の大半は付属資料にも記されている。
TCP connect()スキャン
TCPのconnect()システムコールを用いたスキャン手法である。実際に対象ポートへの接続を試み、接続成功ならopenと判断するもの。最大の利点は、rawパケットを送出する必要がないため、rawパケットを送出するために必要な環境、つまりUnix系OSであればroot権限、Windowsであればadministrator権限やWinPCAPを必要としないことである。欠点は、実際に対象ポートへの接続を試みるため、対象ホストで動作するサービスプログラムに接続確立を示すログが残る可能性があることや、後述のTCP SYNスキャンに比べてパケット制御の自由度が低いためにスキャン効率が低くなることなどが挙げられる。
TCP SYNスキャン
TCPにおける3ウェイ・ハンドシェイクの最後のFINパケットを送出しない(代わりにRSTを送出する)手法である。対象ポートへの接続を試みるものの、最後のパケットを送出しない、つまりコネクション確立を途中で止めてしまうことから、half-openスキャンとも呼ばれる。前述のTCP connect()スキャンに比べて、対象ホストで動作するサービスプログラムに接続確立を示すを示すログが残らない点(もちろん、OS自身を守るタイプのパケットフィルタ型ファイアウォール、例えばipfirewallやiptablesなどには捕捉される可能性がある)、connect()システムコールを用いずrawパケットを用いる関係でスキャン効率が改善される点などが優位点となる。また、TCP connect()スキャン以外の他のスキャンと比較して、open、closed、filteredの3種を区別可能な唯一のスキャン手法でもある。
SYNに対してSYN/ACKが返ってくればopen、RSTが返ってくればclosed、タイムアウトやICMP到達不能エラー応答があればfilteredと判断することになる。
TCP FINスキャン、TCP Nullスキャン、TCP Xmasスキャン
TCP FINスキャンとは、FINだけを立てたパケットを送出し、その挙動を確認する手法である。前述の、接続を確立する、あるいは接続確立を途中で止めるといった方法とは全く異なり、接続未確立状態で送られてくることのないFINパケットをいきなり投げ、その挙動を確認するという手法である。そのため、対象ホストで動作するサービスプログラムで接続確立を示すログが残る可能性はない。このスキャン手法は、nmapが掲載されるより前のPhrack 49号に掲載されたもので、当時の侵入検知システムでは検出できるものが少なかったことから、TCPステルススキャンとも呼ばれていた。nmapは初期版からTCP FINスキャンに対応していた。
TCPの仕様であるRFC 793には、FINだけを立てたパケットを受けると、openポートであればrejectし、closedポートであればRSTを返す旨が記されている。これに準拠したシステム、それはTCP FINスキャンを発見したUriel Maimonが「bad net code in the BSD code」と表現している通り、BSDをベースとするシステムの多くでは、RSTが返ってくればclosed、応答がなければopenもしくはfilteredと判断可能である。ICMP到達不能エラー応答があればfilteredと判断可能である。加えて、ほとんどがclosedで、ごく一部がopenもしくはfilteredということであれば、そのごく一部はopenである可能性が高いとも判断可能である。この手法と同じ原理を用いたものとして、Nullスキャン(FINの代わりに、フラグを全く立てないパケットを用いる)やXmasスキャン(FINの代わりにFIN/PSH/URGの3つのビットを立てたパケットを用いる)が後のバージョンで対応されるが、その本質はTCP FINスキャンと同じである。
この手法の欠点は、応答がない場合にopenとfilteredを区別できないことである。また、RFC 793に準拠しないためにこの手法が使えないシステムが少なからず存在する(代表的にはWindowsなど)という欠点もある。
TCP SYNスキャンやTCP FINスキャン時のIPフラグメント指定
タイニーIPフラグメント攻撃と呼ばれる手法である。本来IPフラグメントとは、一度に送りきれない大きなサイズのデータを分割して送るために設けられている機能であり、分割によるオーバーヘッドを最小限とするため、通常は分割不要な最大サイズを選択することになる。しかし、分割サイズの最小値については厳しい制限はなく、最小フラグメント値である8オクテット(パケットサイズは、IPヘッダの最大サイズである60オクテットを加算して68オクテット)までであれば小さく分割することが可能である。TCPヘッダを8オクテット+残りという形で2つのフラグメントに分割すると、SYNやFINなどのフラグは第2フラグメントに含まれることとなる。そして、TCP SYNスキャンやTCP FINスキャンなどにおいて、第1セグメントにフラグが含まれない可能性があることを想定していないファイアウォールを回避できてしまう可能性があるというものである。このようなことを想定してこの機能は設けられた。
作者は当時、この機能を用いる際には注意しなければいけないと述べていた。というのも、nmapがPhrackに投稿された当時は、第1セグメントにフラグが含まれていないパケットを適切に処理できずに異常終了するようなシステム(パケットアナライザ)が存在したためである。
このスキャン手法は、FTPプロトコル仕様に含まれている、FTPプロクシアクセスをスキャンに流用するというものである。FTPプロトコルには、他のFTPサーバーに対するプロクシとして動作する機能が仕様に含まれている。サーバーがFTPプロクシ機能をサポートし、その機能が有効となっている場合、FTPサーバーにログイン(anonymousでも構わない)することができれば、そのサーバーを経由して他のサーバーにFTP接続することが可能となる。
昨今ではFTPプロクシ機能が有効になっているサーバーは少ないが、nmapが登場した頃は有効になっているサーバーは多かった。そして、同じ組織が持つFTPサーバと他のサーバの間には厳重なファイアウォールが設けられることは少なかった。このような事情から、有効となっているFTPサーバーにログイン(anonymousでも構わない)することができれば、そのFTPサーバーを経由して同じセグメント内に属する他のサーバーに対してポート指定でプロクシログインを試みることで、中間ルータ上のファイアウォールを迂回して、ポートのopen/closedを判定できる可能性があるというものである。
TCP ACKスキャン
初期版に含まれていないスキャン手法の一つで、openとclosedを区別しないという特徴を持つスキャン手法である。ACKのみが立っているパケットを送出し、それに対する挙動でファイアウォールの挙動を確認するというものである。
ACKパケットに対してRSTが返されればopenもしくはclosed、タイムアウトやICMP到達不能エラーであればfilteredと判別可能である。
初期版に含まれていないスキャン手法の一つで、一部のOSに見られる、openポートの返信パケットとclosedポートの返信パケットとの間でウィンドウサイズが異なるという実装に基づいて、openとclosedを判定するというものである。
TCP Maimonスキャン
初期版に含まれているスキャン手法の一つで、FIN/ACKパケットに対する挙動を確認するというものである。RFC 793に準拠したシステムでは、FIN/ACKパケットに対してRSTを返すこととなっているが、一部のOS(BSDベースのシステムの多く)ではopenポートの場合にRST返答が行われないということに基づいてopenとclosedを区別する。
なお、Maimonという名前は、このスキャン手法を発見し、Phrack 49号で発表したUriel Maimonに由来する。
これまでに挙げられている、TCPフラグをセットする手法のスキャンはあくまでお仕着せのものであるが、nmapではこれらのフラグ類を個別に指定して送る機能が後期のバージョンで実装された。
UDP write() / UDP recvfrom()スキャン
write()システムコールを用いてUDP送信、recvfrom()システムコールを用いてUDP受信を行う手法である。通常、UDP送信を行う際はsendto()システムコールを用いるのが一般的であるが、NetcatなどのUDPを取り扱う他のツール同様、nmapでもwrite()システムコールを用いている。
今日では、IP通信の大半はTCPであり、UDPは使用比率上はかなりTCPに劣る。DNS、SNMP、DHCPなどのようにUDPを使用するプロトコルがないわけではないが、一部のセキュリティ専門家(監査や攻撃の立場にある人)はこれらに気を配る必要がないとすら述べているほどである。しかし、それは間違いであると、nmap作者は語っている。例えばrpcbindが用いる(公式文書などで解説されていない)高い番号のポート番号などは、興味深いものであるとnmap作者は例示している。
UDPはコネクションレスなプロトコルであるがために、TCPにくらべると判定が難しいものとなる。openポートからの応答は(相手のサービスに対して適切なリクエストを行っていないという理由から)大抵の場合期待できず、filteredポートは当然ながら破棄されるため、これらの場合にはタイムアウトまで待たされることとなる。closedポートはICMP port unreachableなどを受信することで判別可能であるが、これらの応答パケットは送信レートや一定時間辺りの送信可能パケット数が制限されていることが多いため、複数のUDPポートをスキャンする際には、これらの理由からスキャンに時間がかかることになる。
ICMP echoスキャン
nmapはポートスキャナではなくセキュリティスキャナであるため、ICMP echoスキャン機能、つまりはpingによる死活確認機能も当然ながら初期版から備えている。対象サーバーが複数に渡る場合、並列でスキャンすることも可能である。
デフォルトでは、他のスキャン機能を用いる際、ICMP echoスキャンも事前に行われ、生存が確認できているサーバーのみがスキャン対象となる。しかし、pingに応答しないようにフィルタリングされたサーバーも存在し、そのような場合には事前の生存確認に失敗することとなる。nmapではそのような場合のために、事前の生存確認を行わない機能、対象サーバーをテキストファイルで指定する機能が後期のバージョンに搭載された。
初期版には含まれていなかった機能で、SCTP(RFC 4960)におけるポートスキャンである。
nmapのスキャンの特徴の一つに、スキャン速度の自動調整機能が挙げられる。これは、相手サーバーからの応答状況に応じて、スキャン速度を調整するというものである。nmapでは、パケット破棄されることが前提となるような特殊なパケットを送出するケースが多い上、OSおよびバージョン検出機能などのように、単一のスキャン機能で複数のパケットを送出するケースも多くある。そのため、nmap作者は処理速度、パフォーマンスという要素を重要視している。
単にパケットを送出する間隔を短くするだけでは、相手サーバーの処理能力以上のパケットを投げてしまう可能性がある。こうなるとパフォーマンスの向上には繋がらない上に、相手の侵入検知システムによってスキャンパケットが弾かれる可能性もある。このような状況を避けつつもパフォーマンスを維持するため、相手サーバーからの応答状況に応じてスキャン速度は自動的に調整されるようになっている。また、時間に関する各種パラメータのいくつかはオプション引数で指定可能となっている。
nmapが単なるポートスキャナではなくセキュリティスキャナと呼ばれる所以となる機能の一つが、OSおよびそのバージョンを特定する機能である。これは、Phrack 54号で発表された。既にTCP FINスキャンで説明したように、BSDベースのTCP/IPスタックは他のシステムと異なる応答を返す場合がある。このように、OSごとにTCP/IPスタックの実装が微妙に異なることを用いて、ポートスキャン同様のパケットを送出、それらのパケットに対する挙動を基に、OSおよびそのバージョンを特定するというものである。
この手法が確立されるまで、OSやそのバージョンを特定する方法といえばアプリケーションサービスのバナーなどに頼るしかなかったが、この手法では単にopenポートとclosedポートが1つずつあれば、確認が可能となる。nmapは様々なパケットを送出し、それに対する応答パケットの特徴を確認、その結果を多数の(2010年時点では1000以上の)OSおよびバージョン情報に付き合わせて、応答パケットの特徴との適合状況を出力する。完全に1つのバージョンに特定されるとは限らず、可能性のある複数のOSが%表記で結果表示されることもある。
nmapには、Luaスクリプト言語で記述されたスクリプトを解するスクリプトエンジン「Nmap Scripting Engine」が実装されている。このエンジンの実装により、nmapが行う各種スキャンをスクリプト記述することができるようになっており、これによってスキャンの自動化、一括化、利用者レベルでのスキャン挙動の調整が可能となっている。