パート 4

パストラバーサル

たいていの Web アプリケーションは画像や CSS ファイルなどの静的リソースを提供しています。 そして多くの場合アプリケーションは単純にファイルをフォルダにいれて提供しています。 気を付けなければ、アクセスが許可されていない他のフォルダからファイルを読みこむパストラバーサル攻撃を使うことができます。 例えば Windows や Linux で .. が親ディレクトリーを表すように、 もしパスに ../ を入れると親ディレクトリーに “抜ける” ことができます。

攻撃者がファイルシステム構造を知っている場合、 彼らはインストールディレクトリから /etc へトラバースする URL を作成することができます。 例えば、Picasa がパストラバーサルに対して脆弱だった場合 (実際は違います) 、 サーバが Unix 系のシステムを使用していると、以下のようにパスワードファイルを検索できます:

http://www.picasa.com/../../../../../../../etc/passwd

パストラバーサルによる情報漏えい

both 実行中の Gruyere サーバから ``secret.txt`` を読む方法をみつけてください。

驚くべきことに、多くの場合この攻撃は不要です: 多くの場合、アプリケーションのデフォルトの設定をまったく変えずにインストールされているため、 攻撃者が最初に試みるのはデフォルト値です。

ヒント

ヒント 1

これは Gruyere がリソースファイルをどこに保存していて、 secret.txt ファイルがどこにあるかを知っている必要があるため、 ブラックボックス攻撃ではありません。 ソースコードを見る必要はまったくありません。

ヒント

ヒント 2

サーバは URL で指定されたリソースファイルをどのように見つけますか ? いくつかのブラウザでは許可されていない URL へのリクエストを作成するためには、 cURL や Web プロクシを使うことができます。

ノート

攻撃方法と解決方法

攻撃方法 は、 secret.txt を以下の URL で読むことができます:

http://google-gruyere.appspot.com/123/../secret.txt

Firefox や Chrome などのいくつかのブラウザーは URL内の ../ を最適化します。 しかし攻撃者は、その最適化をしない cURL、Web プロクシ、またはブラウザなどのツールを利用するので、 これはまったくセキュリティの防御とはなりません。 しかし、アプリケーションの脆弱性を確認するためにこれらのブラウザの 1 つでテストした場合は、 防御されていると思いこんでしまうしれません。

解決方法 は、リソースディレクトリ以外のファイルへのアクセスを防ぎます。 リソースフォルダーから抜け出すには “../” や “~” などの様々な方法があるので、 ファイルパスのバリデーションには注意が必要です。 最も堅牢な防御方法は、提供するリソースファイルを限定することです。 一覧をハードコードすることもできますし、 もしくはアプリケーション起動時にリソースをクローリングし、動的にファイル一覧を作成することもできます。 また、そのファイルへのリクエストのみに限定します。 アプリケーションの高速化のためにインメモリにキャッシングするなどの最適かも可能です。 パスをバリデーションしたい場合は、 URL 内で同じ文字を表す方法は多数あるため、 URL ではなく、最終的なパスに対してバリデーションする必要があります。 注意: ファイルパーミッションの変更は機能しません。Gruyere はそのファイルを読める必要があります。

パストラバーサルによるデータの操作

both 実行中の Gruyere サーバ上の ``secret.txt`` を置き換える方法を見つけてください

ヒント

ヒント 1

これもまた、Gruyere がアップロードしたファイルを保存するために使用するディレクトリ構造を知っている必要があるため、 ブラックボックス攻撃ではありません。

ヒント

ヒント 2

ユーザ brie でログインしてファイルをアップロードした場合、 サーバはそれをどこに保存しますか ? サーバをだまし、 ../secret.txt にファイルをアップロードできますか ?

ノート

攻撃方法と解決方法

攻撃方法 は、新しく .. という名前のユーザを作成し、 secret.txt というファイルをアップロードします。 おそらく brie/../.. というユーザ名で作成してもいいでしょう。

解決方法 は、 ユーザ名を利用する前に危険な文字をエスケープ (それを安全な文字に置換) します。 前章で、ユーザ名で許可する文字は制限する必要があると述べましたが、 “.” が危険な文字とは思わなかったかも知れません。 Windows サーバ固有の脆弱性もあるので注意してください。 ユーザ名 Gruyere がそうですが、Windows 上ではファイル名の大文字と小文字は区別されません。 これにより、``brie`` や BRIE など、 大文字と小文字が異なるだけのユーザ名を作成すると、 もう 1 人のユーザのファイルを攻撃することができます。 そのため、安全でない文字をエスケープするだけではなく、 ユーザ名を他のユーザと見分けるためにコンバートする必要があります。 または、各ユーザに一意な ID を割り当てることにより、すべての問題を解決することができます。

おっと! これだけでは完全な問題の解決にはなりません。 適切な場所に対して上記の解決策を適用したとしても、まだ攻撃する方法があります。 それを見つけることができますか ?

ヒント

ヒント

アップロードするファイル名に制限はありますか ? この攻撃を実行するためには cURL や Web プロクシを利用する必要があるかもしれません。

ノート

その他の攻撃方法と解決方法

驚くべきことに、 ../secret.txt というファイルをアップロードすることができます。 Gruyere はこの攻撃を防御していません。 たいていのブラウザはそのようなファイルをアップロードできませんが、 cURL や その他のツールでは可能です。 ファイルを書きこむ際も、ファイルを読むのと同じような保護が必要です。

一般的に、アプリケーションファイルとユーザのデータを同じ場所に保存すべきではありませんが、 それだけではユーザが ../ をファイルパスに混入させることができるため攻撃からの防御とはなりません。 攻撃者はあらゆる方法でファイルシステムの root へトラバースし、 その後アプリケーションの保存場所 (もしくは Python インタプリタ自体) に行き着きます。

サービス拒否 (DoS)

サービス拒否 (DoS) 攻撃は、サーバをサービスの提供が不能な状態にします。 一般的名 DoS 攻撃は、サーバが処理できる以上のリクエストを送信します。 サーバは攻撃によるリクエストの処理に時間を使い、 正当なリクエストを処理する時間が少ししかなくなります。 この攻撃を Gruyere に対して実行すると、App Engine への攻撃と解釈されます。

攻撃者はサーバをクラッシュさせるリクエストを送信したり、 メモリを使い果たさせたり、 なんらかの方法で正当なリクエストを失敗させるなど、 サーバのバグを利用したリクエストにより、サーバを停止させることができます。 次のチャレンジでは、 Gruyere のバグを利用した DoS 攻撃を実行します。

DoS - サーバ停止

最も単純なサービス拒否は、サービスを停止しさせます。

both サーバを停止する方法をみつけてください。

ヒント

ヒント

管理者はどのようにサーバを停止しますか ? サーバ管理用のページは manage.jtl です。

ノート

攻撃方法と解決方法

攻撃方法 は、 http://google-gruyere.appspot.com/123/quitserver へのリクエストを作成します。 管理者としてログインする必要はありません。

これは他の例に共通するバグです。 サーバは特定の URL へのアクセスを、管理者ではないアクセスからブロックしていますが、 その一覧は URL /quitserver ではなく /quit が含まれています。

解決方法 は、 /quitserver を管理者しかアクセスできない URL に追加します:

_PROTECTED_URLS = [
    "/quitserver",
    "/reset"
]

おっと! これだけでは完全な問題の解決にはなりません。 reset URLが一覧に含まれています。これにアクセスする方法がわかりますか ?

ヒント

ヒント

注意深く URL を見て、それが保護されるか確認してください。

ノート

その他の攻撃方法と解決方法

攻撃方法 は、 http://google-gruyere.appspot.com/123/RESET を利用します。 保護したい URL は大文字と小文字が区別されます。 要件を満たすかチェックするために文字列を大文字にします。 これは状態のチェックが実際の使用と異なるという、古典的な確認/利用に関するバグです。

解決方法 は、保護したい関数内でセキュリティチェックします。 それは確実に実行されるため、セキュリティチェックをスキップすることはできません。

DoS - Overloading the Server

black box リクエストを処理する際、サーバに過負荷をかける方法を見つけてください。

ヒント

ヒント 1

テンプレートをアップロードするとこれを実行できるようになります。

ヒント

ヒント 2

すべてのページで menubar.jtl テンプレートをインクルードしています。 このテンプレートを利用し、サーバに過負荷をかけさせる方法が分かりますか ?

ノート

攻撃方法と解決方法

攻撃方法 は、以下を含むファイル menubar.jtl を作成します:

[[include:menubar.jtl]]DoS[[/include:menubar.jtl]]

パストラバーサル攻撃を利用し、 ../resources というのユーザを作成し、 resources ディレクトリーにアップロードしてください。

解決方法 は、前述したパストラバーサルとテンプレート更新を防御します。

注意: 上記攻撃の実行後、 リセットボタン を押す必要があります。

サービス拒否についてさらに詳しく

XSS や XSRF の脆弱性は明確ですが、サービス拒否攻撃は広義にわたります。 サービスを停止させることや、 メールの受信箱をあふれさせメールを受信できなくする等の意味もあります。 以下を考慮してください:

  • もし悪に貪欲なら、 どれぐらい速くアプリケーションを停止させたり、リソースを食い潰すことができますか ? 例えば、ユーザはアプリケーションにハードドライブごとアップロードできますか ? 攻撃者の思考パターンを考えると、アプリケーションの DoS 攻撃対象を特定する助けになります。 さらに、アプリケーション内で演算やメモリを大量に消費するタスクを考え、 適切な場所へ安全措置を施します。 入力値をサニタイジングチェックします。
  • 攻撃を受けた時に検知できるように、 またユーザへの割り当てと、 ユーザのスモール・サブセットが他を枯渇させることができない限度率で制限できるように適切な場所でモニタリングします。 乱暴ですが、いつも以上にメモリを搭載したり、待ち時間を長くしたり、リクエストやコネクション数を増やします。

コード実行

もし攻撃者がリモートからサーバで任意のコードを実行できるなら、たいていはもうゲームオーバーです。 攻撃者はプログラムの実行をコントロールでき、 コンピュータ上に新しくシェルを開けるようにするでしょう。 通常、ここからサーバが動作している全てのマシーンを攻撃する (危険な状態にする) のは難しくありません。

情報漏えいやサービス拒否と同じように、リモートからのコード実行には秘訣や特定の防御策はありません。 プログラムはユーザからの入力値を処理する前に可能な限りチェックする必要があり、 また関数は最小限の特権で実装します。 このトピックはちょっとした短いパラグラフの正義ではなく、 これがたぶんセキュリティバグが可能とする最も恐ろしい結果であり、 上記のどの攻撃にも勝ることを知っておいてください。

コード実行へ挑戦

white box コード実行の攻撃を見つけてください。

ヒント

ヒント

前 2 つの攻撃が必要です。

ノート

攻撃方法と解決方法

攻撃方法 は、 jtl.py (もしくは jsanitize.py ) を複製し、攻撃用のコードを追加します。 ../jtl.py というファイルをアップロードするか、 .. というユーザを作成して jtl.py をアップロードします。 そして http://google-gruyere.appspot.com/123/quitserver を表示し、サーバを終了させます。 サーバ再起動時にコードが実行されます。

この攻撃は Gruyere は Gruyere ディレクトリ内のファイルの読み込みと書き込み両方の権限を有しているのが原因です。 アプリケーションは可能な限り最小限の特権で動作させる必要があります。

なぜ gruyere.py でなく jtl.pyjsanitize.py を攻撃したのでしょうか ? 攻撃者に選択肢がある場合、通常アプリケーションそのものではなくインフラを攻撃します。 インフラはそうアップロードしないでしょうし、気がつきにくいでしょう。 python.exe がトロイで置き換えられたか最後に確認したのはいつですか ?

解決方法 は、前 2 つの解決方法です。

コード実行についてさらに詳しく

リモートからのコード実行への防御は 1 つだけでなく、複雑ですが、 いくつか防御するための方法があります:

  • 最小限の特権管理e: アプリケーションの実行は、必要最小限の特権で実行します。
  • アプリケーションレベルチェック: eval()system() 関数のような、 ユーザが入力した任意のコードを直接評価するコマンドの仕様を避けます。 その代わりに、ユーザの入力は開発者が許可するコマンドセットからの選択式にしてください。
  • 境界値チェック: C++ のような安全でない言語 (え...?) では、適切な境界値チェックをします。 危険な関数 は避けてください。 Python や Java のような安全な言語もネィティブライブラリーを利用しているので注意してください。