僕が調べたApacheバージョン判定の小ネタ
皆さんこちらのブログをご覧になられましたでしょうか?
Apache HTTP Serverのバージョンを当てる方法 | MBSD Blog
Apache HTTP Serverのバージョンが秘匿されていたとしても、脆弱性の修正や、仕様変更による応答差分を確認することによって、バージョンを特定することができるよというMBSDさんの記事です。
この記事には私も知らなかったテクニックも載っていて非常に勉強になりました!
実際の脆弱性診断の現場でもこのようなテクニックは結構使われていまして、Apache HTTP Serverであればかなり古いですが他にも以下の二つの脆弱性なども脆弱性が修正されているかどうかによる応答差分で、バージョンの判定が可能だったかなーと記憶しています。
CVE-2006-3918
JVNDB-2006-000441 - JVN iPedia - 脆弱性対策情報データベース
CVE-2007-6203
JVNDB-2007-001017 - JVN iPedia - 脆弱性対策情報データベース
さて、MBSDさんのブログを読んでいて、そういえば私も以前たまたま見つけて、あんまり出回ってなかった(当時調べたんですがあんまり情報とかなかったと記憶しています)Apache HTTP Serverバージョン判定の小ネタがあったのを思い出したので、折角なので今回ブログに書こうかと思います。
最初に書いておきますが、かなり古いバージョンの判定ができるってだけなので、今となっては正直実用性0だと思います。
まあちょっとした小ネタとして読んでいただければ幸いですw
TRACEメソッドとは?
皆さんはTRACEメソッドというものをご存知でしょうか?
HTTP 1.1(RFC2616)にて定義されているHTTPメソッドの一つであり、デバッグなどの目的で利用されるもので、HTTPリクエストの内容をHTTPレスポンスとしてクライアントにそのまま返すというものです。
Cross-Site Tracingという本メソッドを利用する攻撃手法が存在するため、セキュリティスキャナなどでは、Webサーバー側で本メソッドが有効になっていると良く指摘項目として検出します。
しかしながら、現行のブラウザでは上記の攻撃手法は対策されており、現在ではこのメソッドが有効であっても大した実害はないといえます。
こちらについては徳丸さんが以下の記事にて詳しく解説されています。
ちなみに本メソッドはApacheの設定変更で簡単に無効化することができます。
さて、このTRACEメソッドですが、Apache HTTP Serverではサーバ側にて本メソッドを無効にしている場合の応答結果が、実はあるバージョンを境に変化しています。
これを利用することでApache HTTP Serverのバージョンを判定することが可能です。
試してみよう!
論より証拠ということで、応答内容の変化を確認してみましょう。
以下のコマンド(以前検証した際、togakushiさんにご指導いただいたシェル芸を記載しています)を実行してApache HTTP Serverの2.2系を全部ソースインストールして、バージョンごとに別々のポートで起動させてみます。
for i in {0..34}; do wget http://archive.apache.org/dist/httpd/httpd-2.2.${i}.tar.gz;tar xf httpd-2.2.${i}.tar.gz; pushd httpd-2.2.${i}; ./configure --prefix=/opt/httpd/2.2.${i};make;make install;sed -i "s/Listen 80/Listen $((2000+${i}))/" /opt/httpd/2.2.${i}/conf/httpd.conf; echo "TraceEnable Off" >> /opt/httpd/2.2.${i}/conf/httpd.conf; /opt/httpd/2.2.${i}/bin/apachectl start; popd; done
※実行するのであれば、事前にwgetやgccなどはインスコしてください。
ちなみにconfファイルに「TraceEnable Off」を書き込んで全部TRACEメソッドは無効な状態としてApache HTTP Serverを起動しています。
nmap -sS -sV -n -p 2000-2034 ServerIP
とかやってnmapを実行してやるともりもりバージョンが表示されるので結構壮観です。
こちらを使えばMBSDさんのブログに記載したあった内容の検証もはかどりそうですw
さて次にpythonで簡単ですが以下のような各ポートにTRACEメソッドを打ち込んで、HTTPレスポンスのステータスコードを表示させるようなスクリプトを作ってみました。
import requests for i in range(0, 35): url="http://ServerIP:"+str(2000+i) try: r = requests.request('TRACE', url) print("2.2."+str(i)+":"+str(r.status_code)) except requests.exceptions.RequestException: print("no version")
このスクリプトを実行すると以下のような結果となります。
2.2.0:403 no version 2.2.2:403 2.2.3:403 2.2.4:403 no version 2.2.6:403 no version 2.2.8:405 2.2.9:405 2.2.10:405 2.2.11:405 2.2.12:405 2.2.13:405 2.2.14:405 2.2.15:405 2.2.16:405 2.2.17:405 2.2.18:405 2.2.19:405 2.2.20:405 2.2.21:405 2.2.22:405 2.2.23:405 2.2.24:405 2.2.25:405 2.2.26:405 2.2.27:405 no version 2.2.29:405 no version 2.2.31:405 2.2.32:405 no version 2.2.34:405
というわけで、2.2.6と2.2.8を境に応答結果が、403から405へと変化していることが確認できます。
さらに、2.2.6と2.2.8のソースを比較して調査してみた結果、「modules/http/http_filters.c」のコードに以下のような差分があることを確認しました。
ステータスコード 403(HTTP_FORBIDDEN)からステータスコード 405(HTTP_METHOD_NOT_ALLOWED)を返すように修正されていますね。
まとめ
というわけで、TRACEメソッドを無効化している際のサーバー側の応答結果にてApache httpdが2.2.6以下であるかということが判別できるわけです(ドヤァ)
まあ、だからどうしたって感じですよね…。
あと「僕の」とかって書きましたが、他にも脆弱性診断とかやってらっしゃる方だったら気づいていた方も多かったのではないでしょうか。
脆弱性診断を実施していると結構色々なバージョンのApacheに出会うため、以前この応答差分にたまたま気が付いて、気になってちょっと色々検証してみましたという感じでした。
正直今となっては相当古いバージョンが判別できるってだけの小ネタなので、飲み会のときのネタぐらいにしていました。
MBSDさんのブログが面白くて触発されたのと、MBSDさんのブログ中にも記載がありますが、Apache httpd 2.2.XのEOLが2017年12月と発表されているため今回このネタの供養の意味も込めて記事を書かせていただきました。