皆さん、こんにちは!Webセキュリティの世界へようこそ。今回は、CTF(Capture The Flag)で遭遇した、脆弱性とその攻略方法について、皆さんとシェアしたいと思います。それは、Server-Side Template Injection (SSTI)。特に、Pythonの軽量WebアプリケーションフレームワークであるWerkzeugが動いているサーバーでの事例をご紹介します。
概要:一瞬の隙を突く、SSTIの脅威
今回のCTFでは、あるWebアプリケーションにアクセスしたところ、サーバー情報として「Werkzeug/3.0.3 Python/3.8.10」と表示されていました。ヒンチがSSTIと表示されていたので、試行錯誤の末、以下のコマンドを入力することで、サーバー内部のファイル構成を確認することができました。
{{request.application.__globals__.__builtins__.__import__('os').popen('ls').read()}}
さらに、この情報をもとに、私はフラグファイルの中身を、以下のコマンドで読み取ることに成功したのです!
{{request.application.__globals__.__builtins__.__import__('os').popen('cat flag').read()}}
この記事では、この一連の方法がどのようにして成功したのか、その背景にあるSSTIの仕組み、そしてWerkzeugとPythonの組み合わせにおける注意点について、初心者の方にも分かりやすく解説していきます。
この記事で解説すること
- SSTI(サーバーサイドテンプレートインジェクション)とは何か、そしてなぜ危険なのか。
- 今回のCTFチャレンジの詳細と、脆弱性を突くために使用した具体的なコマンド。
- 脆弱性攻撃に成功したコマンドの各部分の詳細な機能解説。
- Werkzeug/3.0.3とPython/3.8.10という環境がこの脆弱性の存在にどのような意味を持つのか。
- SSTI脆弱性からWebアプリケーションを保護するための実践的な対策。
- CTFを通じてセキュリティについて学ぶことの重要性。
SSTI(サーバーサイドテンプレートインジェクション)とは?その危険性
SSTI、すなわちサーバーサイドテンプレートインジェクションとは、Webアプリケーションがユーザーからの入力を適切に処理せずに、サーバー側のテンプレートエンジンに直接埋め込んでしまうことで発生するセキュリティ上の脆弱性です。テンプレートエンジンは、テンプレートと動的なデータを組み合わせてWebページを生成する仕組みですが、SSTI攻撃を受けると、攻撃者は悪意のあるコードを注入し、サーバー上で実行することが可能になります[参考]。
この脆弱性が悪用されると、情報漏洩、Webサイトの改ざん、最悪の場合にはサーバーの完全な制御を奪われるリモートコード実行といった深刻な事態を引き起こす可能性があります。特に、Flaskフレームワークでよく利用されるJinja2のようなテンプレートエンジンは、適切に扱わないとSSTIの脆弱性を生み出す可能性があります。
SSTIとXSSの違い
SSTIは、クライアントサイドで発生するクロスサイトスクリプティング(XSS)と混同されやすいですが、その性質は大きく異なります。以下の表に、それぞれの主な違いをまとめました[参考]。
特徴 | SSTI (サーバーサイドテンプレートインジェクション) | XSS (クロスサイトスクリプティング) |
標的 | サーバー側のテンプレートエンジン | クライアント側(ユーザーのブラウザ) |
注入箇所 | サーバー側のテンプレート、多くの場合テンプレート変数へのユーザー入力 | Webページコンテンツ、多くの場合ページに表示されるユーザー入力 |
実行場所 | サーバー上 | ユーザーのブラウザ上 |
影響 | リモートコード実行、データ漏洩、サーバー制御 | ユーザーセッションの窃取、Webサイトの改ざん、ユーザーのリダイレクト |
このように、SSTIはサーバー側でコードが実行されるため、XSSよりもさらに深刻な影響を及ぼす可能性があることが理解できます。
CTFで発見された脆弱性の詳細:Werkzeug/3.0.3、Python/3.8.10
今回のCTFで標的となったサーバーは、軽量なPython WSGI(Web Server Gateway Interface)ライブラリであるWerkzeugのバージョン3.0.3と、Pythonのバージョン3.8.10で運用されていました。Werkzeugは、Flaskをはじめとする多くのPython製Webアプリケーションフレームワークの基盤として利用されており、WebアプリケーションとWebサーバー間の通信を円滑に行うための様々なツールを提供しています。特定のバージョン情報が公開されている場合、攻撃者は既知の脆弱性や、そのバージョン特有の挙動を悪用する可能性があります。
脆弱性を突いたコマンドの解説
今回、脆弱性を突くために使用したコマンドは以下の2つです[参考]。
{{request.application.__globals__.__builtins__.__import__('os').popen('ls').read()}}
{{request.application.__globals__.__builtins__.__import__('os').popen('cat flag').read()}}
これらのコマンドがどのようにしてサーバー内部の情報にアクセスし、最終的にフラグファイルの読み取りに成功したのかを詳しく見ていきましょう。
1. サーバー内部を覗き見するコマンド:{{request.application.__globals__.__builtins__.__import__('os').popen('ls').read()}}
このコマンドは、Werkzeugが利用するテンプレートエンジンを通じてPythonのコードを実行しています 2。それぞれの部分がどのような役割を果たしているのかを順に解説します。
{{ ... }}
: これは、テンプレートエンジンがこの中身をPythonのコードとして評価し、実行するための構文です。request
: WerkzeugのRequest
オブジェクトにアクセスします。このオブジェクトは、HTTPリクエストに関する様々な情報(ヘッダー、ボディなど)を保持しており、WSGI環境をより扱いやすくラップしたものです。application
:request
オブジェクトの属性の一つで、実行中のWerkzeugアプリケーションのインスタンスを参照します。__globals__
: 現在のモジュールにおけるグローバル変数を格納した辞書にアクセスします。これには、組み込み関数も含まれています。__builtins__
: Pythonの組み込み関数や例外などに直接アクセスするためのモジュールです。import
関数もこの中に含まれています。__import__('os')
: 文字列 ‘os’ を引数として__import__
関数を呼び出すことで、Pythonのos
モジュールを動的にインポートします。os
モジュールは、オペレーティングシステムとやり取りするための様々な機能を提供します。.popen('ls')
:os
モジュール内のpopen
関数を呼び出し、引数として与えられたコマンド(ここではls
、つまりサーバー上のファイルやディレクトリの一覧を表示するコマンド)をシェルで実行します 16。.read()
: 実行されたls
コマンドの標準出力を読み取ります。
この一連の処理により、サーバー上でls
コマンドが実行され、その結果がWebページに表示されることになります。
2. 秘密のベールを剥ぐコマンド:{{request.application.__globals__.__builtins__.__import__('os').popen('cat flag').read()}}
最初のコマンドでサーバー内部のファイル構成を確認した結果、flag
という名前のファイルが存在することを発見しました。CTFでは、このファイルに正解となるフラグが格納されていることが多いため、その内容を確認するために、ls
の部分をcat flag
に変更した以下のコマンドを実行しました 20。
.popen('cat flag')
: サーバー上でcat flag
コマンドを実行します。cat
コマンドは、指定されたファイルの内容を標準出力に出力するコマンドです。
このコマンドを実行した結果、私はCTFのフラグを手に入れることができました。これは、テンプレートエンジンにおける適切な入力サニタイズメントの欠如により、任意のOSコマンドが実行可能になった典型的なSSTIの悪用例と言えます。
なぜこの環境で脆弱性が存在したのか?WerkzeugとPythonのバージョンについて
今回のサーバー環境がWerkzeug/3.0.3とPython/3.8.10であったことは、このSSTI脆弱性が悪用可能であった背景として考慮すべき点です。
Werkzeug 3.0.3について調査したところ、過去のバージョンではリモートコード実行(RCE)の脆弱性が報告されていましたが、3.0.3では一部修正されています[参考]。例えば、CVE-2024-34069という脆弱性は、デバッガーが有効になっている特定の条件下でコード実行が可能になるものでしたが、3.0.3で修正されています[参考]。しかし、バージョン3.0.3自体にも、リソース枯渇やディレクトリトラバーサルの脆弱性が報告されています。今回のCTFで悪用されたのは、Werkzeug自体の特定の脆弱性というよりも、アプリケーションにおけるテンプレートエンジンの不適切な利用によるSSTIである可能性が高いと考えられます。
一方、Python 3.8.10も、いくつかの既知のセキュリティ脆弱性を含んでいます。これらの脆弱性は、今回のSSTI攻撃に直接的に関係しているとは限りませんが、古いバージョンのソフトウェアを使用することのリスクを示唆しています。
一般的に、ソフトウェアのバージョンが古いほど、既知の脆弱性が多く存在する可能性があり、攻撃者にとって格好の標的となります。そのため、フレームワークやプログラミング言語は常に最新の安定版にアップデートし、セキュリティパッチを適用することが非常に重要です。
SSTIからWebアプリケーションを守るための対策
SSTIの脅威からWebアプリケーションを保護するためには、開発者は以下の対策を講じる必要があります。
- 入力のサニタイズと検証: ユーザーから提供されたデータは常に悪意のあるものとみなし、テンプレートに組み込む前に厳格な検証とサニタイズ処理を行い、危険な文字やパターンを排除します。
- コンテキストに応じたエスケープ: テンプレートエンジンのネイティブなエスケープメカニズムを利用して、特殊文字を適切にエンコードし、コードとして解釈されるのを防ぎます。
- 安全なテンプレートエンジンの利用: 脆弱性が報告されているテンプレートエンジンの利用は避け、セキュリティアップデートが頻繁に行われている信頼性の高いものを選択しましょう。
- 動的なテンプレート構築の回避: ユーザー入力に基づいて動的にテンプレートを生成する処理は、意図しない脆弱性を生み出す可能性があるため、極力避けるべきです。
- コンテンツセキュリティポリシー(CSP)の導入: CSPヘッダーを設定することで、スクリプトの読み込み元を制限し、SSTI攻撃の影響を軽減できます。
- 定期的なセキュリティ監査: 定期的にWebアプリケーションの脆弱性診断を実施し、潜在的なリスクを早期に発見し、対策を講じることが重要です。
- フレームワークとプログラミング言語のアップデート: Werkzeug、Python、およびその他の依存関係を常に最新の安定版に保ち、セキュリティパッチを適用します。
- 最小権限の原則: Webアプリケーションは、必要最小限の権限で実行するように設定します。
- Webアプリケーションファイアウォール(WAF)の導入: WAFを利用することで、SSTIを含む一般的なWeb攻撃を検知し、防御することができます。
たび友|サイトマップ
関連webアプリ
たび友|サイトマップ:https://tabui-tomo.com/sitemap
けん友:https://kentomo.tabui-tomo.com
ピー友:https://pdftomo.tabui-tomo.com