現在地

ネットワーク診断の現場から(netcat編・その2)

はじめに

今回はnetcatを利用して、Webサーバーのレスポンスヘッダーから得られる情報を収集してみましょう。レスポンスヘッダー内にはさまざまな情報がありますが、ここでは「バナー取得」および「内部IPアドレスの漏えい」について紹介します。

前回に引き続き、本稿の実行例ではLinux(CentOS 6)を利用しています。また対象のWebサーバーとしては、Apache HTTP Server(以下Apache)を想定しています。

バナー取得

バナーとは、サービスが出力するメッセージのうち、ソフトウェアの名称やバージョン情報が含まれるものを指します。外部からバナーが取得可能な場合、そこには攻撃者にとって有益な情報が含まれることがあるため注意が必要です。

例を見てみましょう。以下の実行例では、Webサーバーであるtest.example.comの80/tcp(http)にnetcatで接続し、HEADリクエストを送信してレスポンスヘッダーを確認しています。

$ nc test.example.com 80
HEAD / HTTP/1.0

HTTP/1.1 200 OK
Date: Thu, 03 Mar 2016 05:50:45 GMT
Server: Apache/2.2.19 (Unix)
Last-Modified: Sat, 20 Nov 2004 20:16:24 GMT
Accept-Ranges: bytes
Content-Length: 44
Connection: close
Content-Type: text/html

$

レスポンスヘッダー内の、Serverヘッダーに注目してください。 Server: Apache/2.2.19 (Unix) という文字列がバナーです。こうしてバナーを取得することで、このホストではApacheのバージョン2.2.19がUNIX環境で動作していることが分かります。

このような情報は攻撃者へのヒントとなるため、バナーが表示されないように設定してみましょう。Apacheのバナーを隠蔽するには、設定ファイル(httpd.conf)のServerTokensディレクティブに、「ProductOnly」という値を指定します。

ServerTokens ProductOnly

この設定により、Serverヘッダーの出力をプロダクト名のみにすることができます。

なおProductOnlyは省略して、以下のように「Prod」とだけ書いても構いません。一般的にはこの省略形がよく利用されます。

ServerTokens Prod

設定ファイルを修正してApacheを再起動すれば、以下のように Server: Apache というプロダクト名のみの表示となり、バナーが隠蔽できていることが確認できます。

$ nc test.example.com 80
HEAD / HTTP/1.0

HTTP/1.1 200 OK
Date: Thu, 03 Mar 2016 05:57:11 GMT
Server: Apache
....(省略)....

なお設定変更後、正しくバナーが隠蔽されているかを確認する際、Webブラウザを利用することはあまりおすすめできません。

Webブラウザでは、通常はレスポンスのボディ部のみ表示されるため、レスポンスヘッダーを確認することができません。レスポンスヘッダー閲覧のためにWebブラウザに組み込む開発ツールやアドオンも、ブラウザキャッシュの影響で設定変更前と同じ結果が返り、思わぬ勘違いをすることがあるため、注意が必要です。

一方、netcatを利用すれば生データ(raw data)をそのまま扱いますから余計な加工はされませんし、ブラウザキャッシュの心配も無用です。シェルスクリプトを利用してチェックツールを作ることも簡単です。このため、バナーを確認する際にはnetcatがよく利用されます。

X-Powered-Byヘッダー

Webサーバーで注目されるバナーとしては、先ほどのServerヘッダー以外に、X-Powered-Byヘッダーが挙げられます。いくつかのソフトウェアがこのヘッダーを出力しますが、主にPHPのバージョン情報が取得可能なヘッダーとして知られています。

$ nc test.example.com 80
HEAD /list.php HTTP/1.0

HTTP/1.1 200 OK
Date: Thu, 10 Mar 2016 17:00:23 GMT
Server: Apache
X-Powered-By: PHP/5.3.11
Connection: close
Content-Type: text/html

$

上記の例では、X-Powered-Byヘッダーを確認することで、PHPのバージョン5.3.11が利用されていることが分かります。なお、X-Powered-ByヘッダーはPHPファイル(上記の例では/list.php)へのアクセス時にのみ表示されるため、皆さんが自分の環境を確認する際には、PHPファイルへHEADリクエストを送信してください。

PHPのバナーは、設定ファイル(php.ini)のexpose_phpディレクティブに、「Off」を指定することで隠蔽できます。

expose_php = Off

この設定を行うと、次のようにX-Powered-Byヘッダー自体が出力されなくなり、バナーを隠蔽することができます。

$ nc test.example.com 80
HEAD /list.php HTTP/1.0

HTTP/1.1 200 OK
Date: Thu, 10 Mar 2016 17:03:13 GMT
Server: Apache
Connection: close
Content-Type: text/html

$

バナーの隠蔽について

ここまで紹介してきたように、基本的にバナーは隠蔽し、バージョン情報は外部から取得できないようにすることをおすすめします。しかしバナーを隠すべきかどうかというのは昔から賛否両論あり、隠すことには意味がないという主張もあります。何かと議論の火種になるため、ここで補足しておきましょう。

「バナーを隠したところで、利用しているソフトウェアのバージョンが古い場合、本質的なセキュリティ問題は解決しないのだから意味がない」というのはよく聞かれる反対論です。これは確かにその通りで、まずはソフトウェアを最新版にすることが基本的なセキュリティ対策として重要です。「古いバージョンを使っていることが分からないように、バナーを隠蔽する」というのでは本末転倒です。

しかしバナーを隠すことによるメリットには、「攻撃対象として選定されにくくなる」という点もあります。たとえばSHODAN(*1)に代表されるように、特定のバナー情報からインターネット上に存在するホストを検索できるWebサービスは、2016年現在、既に多く存在します。

(*1) SHODAN: https://www.shodan.io/

攻撃者が攻撃対象を選定する際、バナーが隠蔽されているホストと、バナーが表示されるホストがあれば、バナーが表示されてプロダクト名やバージョン情報が詳細に分かるホストを攻撃対象に選ぶのは自然な流れでしょう。またバナーが隠蔽されている場合、既知の脆弱性を試すにしても、当てずっぽうに攻撃を行う必要があり効率的ではありません。バナーを隠蔽することで、攻撃者による攻撃機会を少しでも減らすことができるわけです。

また、そもそも必要のない情報は、なるべく外部に公開しないというのはセキュリティ対策において基本的な考え方です。たとえばあなたの自宅の鍵のメーカーや型番は、公開してもすぐに何か問題が生じるというわけではありませんが、そもそも必要がないのなら公開しないに越したことはないでしょう。バナーも同様です。積極的に開示する必要がない情報は、隠蔽する方が望ましいでしょう。

内部IPアドレスの漏えい

Webサーバーのレスポンスヘッダーから得られる情報として、続いてはネットワーク診断の現場で時折見られる「内部IPアドレスの漏えい」の例を紹介しましょう。これはインターネット経由でWebサーバーにアクセスする際に、ホストが内部で利用しているプライベートIPアドレスが見えてしまうという事例です。

ここでは例として、インターネット経由でtest.example.comというWebサーバーにアクセスするケースを考えます。アクセスするURLは、 http://test.example.com/img/ としましょう。このURLに対して、以下のようにnetcatを利用して/imgというパスにHEADリクエストを送ってみます。

$ nc test.example.com 80
HEAD /img HTTP/1.0

HTTP/1.1 301 Moved Permanently
Date: Thu, 03 Mar 2016 05:42:05 GMT
Server: Apache
Location: http://192.168.2.66/img/
Connection: close
Content-Type: text/html; charset=iso-8859-1

$

上の例を見ると、test.example.com宛てのグローバルIPアドレスに接続したのに、Locationヘッダーに 192.168.2.66 というプライベートIPアドレスが表示されています。これが内部IPアドレスの漏えいです。プライベートIPアドレスが見えたからといってすぐに何かの攻撃に結びつくわけではありませんが、内部のネットワーク構成を推測されることから、外部に公開しない方が良い情報であることは確かです。

この事象の原因として、Apacheの場合ではServerNameディレクティブに正しい値を設定していないことが挙げられます。ServerNameディレクティブは、デフォルトのhttpd.confでは以下のようにコメントアウトされています。上記の例も、このデフォルト状態での応答を示したものです。

#ServerName www.example.com:80

このコメントアウトを外して正しいホスト名(ここではtest.example.com)を記述し、設定を反映させるためにApacheを再起動してください。次の例で分かるように、同じリクエストに対しても、LocationヘッダーにプライベートIPアドレスではなくホスト名が表示されるようになったことが確認できます。

$ nc test.example.com 80
HEAD /img HTTP/1.0

HTTP/1.1 301 Moved Permanently
Date: Thu, 03 Mar 2016 05:46:10 GMT
Server: Apache
Location: http://test.example.com/img/
Connection: close
Content-Type: text/html; charset=iso-8859-1

$

内部IPアドレスがなぜ表示されるのか

上記の例はInternet Explorerなど現在のWebブラウザの一般的な設定では再現せず、netcatを利用してリクエストを手打ちすると発生する事例です。なぜこうなるのかを理解するには、

  1. URLの末尾にスラッシュ(/)を付けた場合と付けない場合での動作の違い
  2. Hostヘッダーの有無による動作の違い

という2つの知識が必要です。少々細かい話になりますが、HTTPプロトコルへの理解を深めるための良い教材でもありますから、以下に解説しましょう。

URLの末尾スラッシュ

先ほど、http://test.example.com/img/ というURLを考えましたが、ここで末尾のスラッシュを抜かして http://test.example.com/img にアクセスするとどうなるでしょうか。通常のWebブラウザでは違いはなく、http://test.example.com/img/ というスラッシュ付きのアクセスと同様に見えることと思います。

しかしこの際、WebブラウザとWebサーバーの間では次の図のような通信が行われています。

末尾にスラッシュがないURLへのアクセス

つまり、ディレクトリに対して末尾のスラッシュを抜かしたアクセスは、

  1. /imgというファイルをリクエストする
  2. そのようなファイルはないため、代わりに/img/というディレクトリへLocationヘッダーを利用してリダイレクトする
  3. 改めて/img/というディレクトリへアクセスする

というのが内部の動きとなっています。今回のケースでは、こうしてLocationヘッダーによりリダイレクトが発生することが重要な点です。

Hostヘッダーの有無による動作の違い

現在、一般的なWebブラウザはHTTPリクエストをHTTP/1.1という規格で送信します。このHTTP/1.1はHostヘッダーが必須であるため、Webブラウザは入力されたURLからホスト名を取り出して、Hostヘッダーを付けて送信します。LocationヘッダーによるリダイレクトではHostヘッダーの値がホスト名として使われることが一般的であるため、結果としてHTTP/1.1では、このケースでの内部IPアドレスの漏えいは発生しません。

一方、HTTP/1.0規格ではHostヘッダーは不要です。Hostヘッダーがない場合にLocationヘッダーに使われるホスト名は、Apacheの場合にはServerNameディレクティブで設定された値となります。ServerNameは未設定時はホストのIPアドレスがデフォルト値となります(*2)から、この結果として、外部からのリクエストに対して、WebサーバーのプライベートIPアドレスが入ったLocationヘッダーが組み立てられたわけです。

(*2) そのIPアドレスが逆引きできる場合には、逆引きしたホスト名になります

Hostヘッダーがない場合の内部IPアドレスの漏えい

おわりに

今回は、netcatを利用してWebサーバーのレスポンスヘッダーから情報取得を行う方法を解説しました。皆さんもご自身で管理されているWebサーバーから、どのような情報が収集できるか確認してみてください。

次回は、netcatで行う簡単なポート開放チェックの方法を紹介する予定です。

Writer Profile

大角 祐介