技術者ブログ

クラウド型WAF「Scutum(スキュータム)」の開発者/エンジニアによるブログです。
金床“Kanatoko”をはじめとする株式会社ビットフォレストの技術チームが、“WAFを支える技術”をテーマに幅広く、不定期に更新中!

2018年11月

        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  
  • お問い合わせはこちら
Scutum開発者/エンジニアによる技術ブログ WAF Tech Blog

WAFとHTTPリクエストスマグリング

HRSとは

2018年の7月に、「XSS due to the header Transfer-Encoding: chunked」というタイトルでPHPの脆弱性報告がありました。

https://bugs.php.net/bug.php?id=76582

日本語の情報源としては徳丸さんによるこちらの記事が参考になります。

この脆弱性は下記のように、HTTPリクエストヘッダ内に一見矛盾していたり、明確でない内容が含まれている場合の挙動についてのものでした。

Transfer-Encoding: chunked
Content-Length: 25
 

この問題はHTTPリクエストスマグリング(HTTP Request Smuggling、以下HRS)と呼ばれていて、今から13年前、2005年に知られたものです。筆者は今から11年前に「ウェブアプリケーションセキュリティ」という本(通称:金床本)を上梓しましたが、その中で第12章がHTTPリクエストスマグリングの解説に当てられています。

hrs_kanatoko

Transfer-Encoding: chunkedとContent-Lengthの両方がリクエスト中に存在するケースというのはHRSの基本中の基本で、2018年になってPHPほどメジャーなソフトウェアにこの脆弱性が出てきたというのは個人的にガックリきました。

しかし、上記でリンクした脆弱性情報のページおよび徳丸さんの記事どちらにおいてもHRSという脆弱性の分類、名前が登場していないことから、意外とHRSは知名度が低いのかもしれません。

HRS実例

改めて調べてみたところ、HRSの実例はかなり多いようです。

Squidでは典型的なContent-Lengthのパターンではなく

When absolute-URI is provided Host header should be ignored

となっており、リクエスト行の絶対URIで指定されたHostと、リクエストヘッダ内のHostフィールドの値が異なる場合の問題を指しているようで興味深いです。

WAFとHRS

HRSはどちらかというとウェブアプリケーションの問題ではなくサーバ実装の問題であり、ウェブサーバやプロキシサーバ、ミドルウェアの開発者が注意する必要があります。

Scutumのようなプロキシサーバとして動作するWAFも例外ではありません。特にWAFの場合、HRSによってリクエストやパラメータのパース処理でウェブサーバ側と異なる解釈をしてしまうと、見つけるべき文字列を完全に見逃してしまう、いわゆるEvasionが可能となってしまい致命的な脆弱性となります。

Scutumでは初期よりHRS対策については注意していて、Transfer-EncodingとContent-Lengthが両方あるものや、Content-Length、Host、Content-Typeが2行以上あるもの、また上記のSquidのパターンなどに対応しています。

そのため、今回新たに見つかったPHPのHRSについても、Scutumではゼロデイで防御が可能な状態でした。

HRSと誤検知

上記のようにScutumではContent-Typeが複数行ある場合にブロックしますが、まれに誤検知が起こる場合があります。この場合、リクエストを送ってくるのは標準的なブラウザではなく、プログラマが手作りしたようなアプリケーションであるケースが多いようです。おそらくsetContentTypeのような関数を呼び出すべきところ、addHeader( "Content-Type" )...のようなことをしているのかな?と考えています。

パース実装の違い

HRSはHTTPリクエストのパースにおける問題ですが、WAFにとって似たような問題として、リクエストボディ部のパース解釈があります。ScutumではContent-Typeが複数行ある場合には明示的にブロックしてしまいますが、仮にWAFにおいてこれを通してしまう場合には、ウェブサーバ側がどのContent-Typeを選択するのかによって、ボディ部の内容の解釈が異なってしまいます。

一方ではXMLと書かれていて、もう一方ではJSONと書かれている場合などには、まるで異なるパーサが動作することになるため、Evasionのチャンスが生まれてしまいます。この場合、念の為両方のパーサを走らせ、両方のパース結果に対してWAFとしての検査を実施する、というのもアリかもしれません。

また、例えば単に「XMLをパースする」と言っても、実装によってパース結果が異なってくる場合があります。あるXMLパーサ実装はDOCTYPEを無視するので、わざとエラーのあるDOCTYPEを入れ込むことで、多くのXMLパーサ実装ではパースエラーとなるが、そのXMLパーサのみはパースに成功する、という例を見たことがあります。この場合、もしウェブアプリケーションがDOCTYPEを無視するパーサを使っており、一方でWAFが標準的なパーサを使っていれば、WAFのEvasionが可能となってしまいます。Scutumではこのようなケースについても注意して対応しています。

このようにWAFにとってHTTPリクエストを含むパースの問題は非常に気を使うところで、難しい面があります。ImpervaというWAFがContent-TypeなしのリクエストでEvasion可能だったという問題についても、私は「そういうのは本当にありえるよね...」と感じました。

クラウド時代とHRS

最近はCDNや、クラウドサービスが用意してくれるアプリケーション層のロードバランサーなどが昔よりも多く使われるようになりました。これはつまり、ブラウザとウェブサーバの間にプロキシサーバが挟まるケースが増えていることを意味します。したがって、経路中のどこかでHRSの脆弱性が入り込む可能性が増えてきただろうと考えられます。

残念ながらHRSはソフトウェア同士の組み合わせで起こることが多く、またどのような攻撃ベクターが成立するのかについてもケースバイケースであることから、自身のシステムにHRSの脆弱性があるのかどうかは腕の良い技術者が実際に調べてみるしかありません。今のところSQLインジェクション等に比べれば目立った被害報告はきかれないように感じますが、引き続き注意すべき問題であると思います。