Fetch the Flag CTF 2022 解説:Logster
2022年11月10日
0 分で読めますFetchに参加してくれてありがとう! 参加してくれた数千人のプレイヤーの皆さん、Fetch the Flag CTFにご参加いただき、おめでとうございます。また、チャレンジを作成し、テストし、解説記事を書いてくれたSnykerの皆さんにも心から感謝します!
Snykの2022年Fetch the Flagに参加し、Logsterチャレンジの答えを探しているなら、ここがぴったりです。一緒に解決策を見ていきましょう!
まずは偵察フェーズから
このフェーズでは、攻撃者が脆弱な標的を特定し、悪用方法を探ります。今回提示されているのは、あるWebサイトへのリンクです。開始するために必要なのは、侵入経路が1つだけです。

まずリンクを確認し、http://logster.c.ctf-snyk.io/にアクセスします。これはWebサイトをスキャンできるサイトです。

https://www.cnn.com/を試してみましょう。ヘッダーが表示されます。

そこから、チャレンジの説明(lookup)とプログラミング言語(Java)を手がかりに、Log4Shellを扱っていると推測できます。
トンネリングを始めましょう!
まず、カスタムヘッダーを設定するExpress Webサーバーを作成し、ngrokトンネルを使ってサーバーをローカルで実行してから、外部に公開します。その後、スキャンして何が起きるか確認しましょう!
Expressサーバーの設定方法がわからない場合は、この手順に公式ドキュメントが役立ちます。

ポート3000でリクエストを処理するExpressサーバーを作成し、('PWN', 'pwn')でカスタムヘッダーを設定します。
次のコマンドで実行します。node express.js:

次に、ngrok http 3000コマンドでngrokトンネルを作成します。マシンでの設定方法は、ngrokの公式ドキュメントを参照してください。

転送用リンクをコピーしてWebサイトに貼り付け、スキャンします。ngrokコンソール(http://localhost:4040/)を見ると、express.jsファイルで指定したヘッダーがそのまま返されていることがわかります

Log4Shell形式のペイロードヘッダーを設定してみましょう。express.jsファイルに戻り、ヘッダーを('${java:version}', 'pwn')に変更します。

サーバーを再起動し、Webサイトをもう一度スキャンします。500 Internal Server Errorが発生します。ログを見ると、ヘッダー名は有効なHTTPトークンでなければならないとわかります。

Expressでは無効なヘッダーは使えません。$や{}は有効な文字ではありません。そのため、これを回避する必要があります。接続のたびにカスタムレスポンスを返すソケットサーバーを作成すれば回避できます。
ソケットサーバーは次のようになります。ソケットで待ち受け、接続ごとにレスポンスを書き戻します。この場合はJavaのバージョンも含めます。このカスタムヘッダーを挿入し、評価されるか確認します。

node index.jsコマンドでサーバーを起動し、ngrok tcp 3000コマンドでngrokトンネルをTCPトンネルに変更します。TCPトンネル機能を使うには、ngrokのアカウントが必要です。

Forwardingリンクをコピーします。TCP部分は含めずにWebサイトに貼り付け、先頭にhttps://を追加してからスキャンします。カスタムヘッダーが評価されていることがわかります。lookupが実行され、Javaのバージョンが返されました。lookupが機能することが確認できました。

次はLog4Shellエクスプロイトを設定します。
Log4Shellとは?
CVE-2021-44228(Log4Shellとも呼ばれます)は、Apache Log4j 2のほぼすべてのバージョンに影響する、認証不要のリモートコード実行(RCE)脆弱性です。2021年12月9日、このゼロデイ脆弱性のニュースは、公開されていた概念実証(POC)とともに、情報セキュリティコミュニティに広まりました。
Log4Shellの脆弱性について詳しく知りたい方は、Snyk Learnの無料レッスンをご覧ください。
POC
次の手順では、この公開されているPOCを使います。このリポジトリには、攻撃の実行に必要なものがすべて含まれています。
プロジェクトをGit cloneし、Evil.javaクラスに移動します。このチャレンジで使う実際のペイロードを作成するため、内容を変更する必要があります。ルートディレクトリ内のすべてのファイルを一覧表示します。Fileオブジェクトを作成してファイル一覧を取得し、各ファイル名を出力します。

次のコマンドでDockerイメージをビルドします。
次のコマンドでngrok TCPサーバーを起動します。

次のコマンドでngrok HTTPサーバーを起動します。ngrok http 8888

次のコマンドでDockerコンテナをリモートで実行します。

ただし、その前にLDAPサーバーの接続先を正しいForwardingリンクに設定する必要があります。ポート8888で動作しているHTTPサーバーのリンクをコピーして貼り付けます
ポート9999で動作しているTCPサーバーのアドレスも、ソケットファイルindex.jsに含める必要があります。ここでは、実際のLog4Shellペイロードを含むヘッダーを送信します。先ほど変更したEvilクラスを配信しています。

次のコマンドでソケットサーバーを再起動します。node index.js
もう一度、このコマンドを実行します。

ターミナルに同じ出力が表示されるはずです。

Webサイトに戻ると、ルートディレクトリ内のファイル一覧が表示され、フラグがあることを確認できます!

フラグを表示するため、最後にもう一度ペイロードを変更します。Evilクラスに戻ります。このコードを使うと、フラグを読み込んでファイルの内容を出力できます。

変更を反映するには、Dockerコンテナを再実行する必要があります。もう一度スキャンすると、フラグファイルの内容が表示されます!

Logsterのまとめ
このエクスプロイトは単純で、ライブラリも広く使われていたため、脆弱性の公表後、セキュリティ担当者は対応に追われました。当初、Log4Shellの緩和策として推奨されていたのはバージョン2.16へのアップグレードでしたが、残念ながら、このバージョンにもサービス拒否攻撃につながる脆弱性が見つかりました。現在推奨されているのは、バージョン2.17へのアップグレードです。
修正に関する推奨事項を詳しく知りたい方は、Log4Shell修正チートシートをご覧ください。新しい情報が入り次第、継続的に更新しています。
LogsterやCTFの他のチャレンジを楽しんでいただけたなら幸いです :) 他のフラグをどう見つけたか知りたいですか?Fetch the Flagの解答ページで、解き方をご覧ください。



