Tornado: StaticFileHandlerは、静的ファイルルートの外にあるシンボリックリンクを辿り、パスのトラバーサルを許してしまう。
### 概要
StaticFileHandlerを使用している場合、認証されていない攻撃者が、静的ファイルルートディレクトリ内に配置されたシンボリックリンクを介して、サーバーのファイルシステムから任意のファイルを読み出すことができる。 ユーザーがアップロードしたコンテンツを提供するアプリケーション、または、シンボリックリンクを作成するビルド/デプロイメントパイプライン(例:npm link、webpack、Dockerボリュームのマウント、CDN同期ツール)によって静的ディレクトリが構築されているアプリケーションは、この脆弱性の影響を受ける。 攻撃者が、静的ファイルルートの外を指すシンボリックリンクを作成したり、既存のシンボリックリンクを悪用したりすることで、/etc/passwd、秘密鍵、設定ファイル、またはアプリケーションの機密情報などの機密ファイルを取得できる可能性がある。
### 詳細
この脆弱性は、tornado.web.StaticFileHandlerに存在し、特に[tornado/web.py](vscode-webview://1grdaaa6v64itrol06qu70pq3d1b9h9im5c3npvvc9snaprc1q9f/tornado/web.py)内の以下の2つのメソッド間の相互作用に起因する:
- [get_absolute_path](https://github.com/tornadoweb/tornado/blob/0ca3c5f8279d402b245718d16522bc18a8f5d958/tornado/web.py#L2932) は、要求されたパスを解決するために`os.path.abspath()`を使用する。
- [validate_absolute_path](https://github.com/tornadoweb/tornado/blob/0ca3c5f8279d402b245718d16522bc18a8f5d958/tornado/web.py#L2935) は、ルートに対して同じ`os.path.abspath()`を使用し、その後、文字列のプレフィックスチェックを実行する。
`os.path.abspath()`は、.および..のセグメントを正規化するが、シンボリックリンクを解決しない。 その結果、`/var/www/static/link`のようなパスは、`link`が実際にどこを指しているかにかかわらず、`startswith("/var/www/static/")`のチェックを通過する。
その直後、`os.path.exists()`と`os.path.isfile()`は、**シンボリックリンクを辿る**ため、最終的に開かれるファイルはシンボリックリンクのターゲットとなる。 修正するには、両方のメソッドで`os.path.abspath()`を`os.path.realpath()`に置き換える必要がある。 これにより、シンボリックリンクのターゲットの実際のパスが、文字列表現だけでなく、ルートに対して検証されるようになる。
### PoC (概念実証)
_脆弱性を再現するための、具体的な設定の詳細を含む完全な手順です。_
前提条件:Python 3.x、Tornadoがインストールされていること。
1. 環境の作成
```
mkdir -p /tmp/static
echo "DB_PASSWORD=s3cr3t" > /tmp/secret.conf
ln -s /tmp/secret.conf /tmp/static/config.conf
```
2. 最小限の脆弱なサーバー (server.py):
```
import tornado.web, tornado.ioloop
app = tornado.web.Application([
(r"/static/(.*)", tornado.web.StaticFileHandler, {"path": "/tmp/static"}),
])
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
```
3. 脆弱性の悪用方法:
`curl http://localhost:8888/static/config.conf`
### 影響
StaticFileHandlerを使用するアプリケーションは、以下の条件の場合、脆弱性の影響を受ける可能性があります。
- 静的ファイルディレクトリ内に、そのディレクトリ外へのシンボリックリンクが含まれている場合(ビルドツールでよく発生します)。
- アプリケーションが、シンボリックリンクを除去せずに、静的ファイルディレクトリへのファイルアップロードを許可している場合。
認証されていないリモート攻撃者は、プロセスユーザーが読み取れるファイルであれば、どのようなファイルでも読み取ることができます。これには、アプリケーションの秘密情報、TLSの秘密鍵、データベースの認証情報、/etc/shadow、SSH鍵、またはソースコードが含まれる可能性があります(プロセスのファイルシステム権限によって異なります)。
影響を受けるパッケージ:
- pip (Python) tornado: 影響を受けるバージョンは6.5.8以下、6.5.9で修正済み。