Trellix Advanced Research Centerでは、ある脆弱性を調査していたところ、Pythonのtarfileモジュールに脆弱性があることを偶然発見しました。当初、私たちは新しいゼロデイ脆弱性を発見したと思っていました。この問題を掘り下げていくうちに、実はこれがCVE-2007-4559であることに気づきました。この脆弱性は、tarfile モジュールの extract および extractall 関数におけるパストラバーサル攻撃であり、攻撃者は TAR アーカイブ内のファイル名に「…」シーケンスを追加することで、任意のファイルを上書きすることが可能です。
この脆弱性の影響を調査する過程で、何十万ものリポジトリがこの脆弱性を受けていることが判明しました。この脆弱性は、当初は6.8とされていましたが、ほとんどの場合、攻撃者がファイル書き込みからコードを実行できることを確認することが出来ました。以下のビデオでは、Universal Radio Hackerを悪用してコード実行をすることができた方法を紹介しています。
このブログの目的は、この脆弱性の技術的な詳細を掘り下げ、攻撃者がこの脆弱性のエクスプロイトを書くことがいかに簡単であるかをお伝えすることです。また、ASTモジュールを活用し、ソースコード中のtarfile脆弱性を自動的に検出するツールを書く過程も探ります。最後に、私たちがどのように人気のあるオープンソースリポジトリを悪用し、パストラバーサル攻撃を使ってコード実行を行う検証を行ったかについて説明します。
tarfile の脆弱性
tarfile は、複数の異なるファイルと、後に tarfile のアーカイブを解除するために使用されるメタデータの集合体です。tar アーカイブに含まれるメタデータには、ファイル名、サイズ、ファイルのチェックサム、 ファイルがアーカイブされたときの所有者に関する情報などが含まれますが、これらに限定されるものではありません。Pythonのtarfileモジュールでは、この情報はTarInfoクラスで表現され、tarアーカイブのすべての「メンバー」に対して生成されます。これらのメンバーは、ディレクトリ、シンボリックリンク、ファイルなど、ファイルシステム内のさまざまな種類の構造を表すことができます。
図 1: ファイル名を使用したパス結合
上の画像は、tarfileモジュールのextract関数のコードの一部です。このコードでは、ファイルを抽出して、ファイルシステムに書き込む関数に渡される前に、ファイル名がどのように作成されるかを示しています。このコードでは、TarInfoオブジェクトの情報を明示的に信頼し、extract関数に渡されるパスとTarInfoオブジェクトの名前を結合して、攻撃者がディレクトリトラバーサル攻撃を実行することを可能にしています。
図 2: アーカイブ メンバーを介した Extractall ループ
extractall 関数は この関数に依存しているため、上記で見たように、extractall 関数もディレクトリトラバーサル攻撃に対して脆弱です。
tarfileの悪用
攻撃者がこの脆弱性を利用するためには、ファイル名に「…」とオペレーティングシステムのセパレータ(「/」または「\」)を追加し、ファイルが展開されるはずのディレクトリをエスケープする必要があります。Pythonのtarfileモジュールを使えば、まさにこれが可能です。
図 3: 悪意のあるアーカイブの作成
tarfileモジュールにより、ユーザーはtarアーカイブに追加される前にファイルのメタデータを解析し、変更するために使用できるフィルターを追加することができます。これにより、攻撃者は上記のわずか6行のコードでエクスプロイトを作成することができます。
Creosoteの構築
tarfileモジュールがまだ脆弱であることを発見した後、私たちは脆弱性の範囲を評価できるように、自動的にリポジトリにある脆弱性をチェックする方法を探しました。この実施のため、私たちはCreosoteを作成しました。これは、ディレクトリを再帰的に検索して.pyファイルを探し、見つかったらそれを解析するPythonスクリプトです。ファイルを分析した後、Creosoteは脆弱性を含む可能性のあるファイルを出力し、信頼度に基づいて3つのカテゴリ(脆弱、おそらく脆弱性、潜在的に脆弱)にソートします。
Pythonコードを解析するために、CreosoteはPythonのastライブラリを活用し、テキストを粗く解析してスクリプトの間隔を把握するのではなく、ソースコード内の構造をトラバースして脆弱性を検出することができます。Creosoteは、astライブラリとNodeVisitor構造を使用して、Attributeノードに属するものだけを分析することにより、脆弱性とは無関係と思われる、多くのextractおよびextractall関数を素早くフィルタリングすることが可能です。extractとextractallはどちらもインスタンスメソッドであり、アーカイブオブジェクトとともに常にコードベースに表示されるため、この区別が可能です(例:tar.extractall())。
Attributeノードを見つけた後、Creosoteは、この脆弱性を分析する際にチームが発見した最も一般的な2つのコードパターンを探します。
図 4: 脆弱な Extractall
Creosote は、extractall で属性ノードを見つけると、後戻りし、 open も呼び出されたかどうかを確認し、第2引数、またはオープニングモードが「r」に設定されているかどうかを確認します。いくつの基準にヒットしたかによって、スクリプトは行を脆弱、おそらく脆弱性、または潜在的に脆弱とマークします。
図 5: 脆弱な抽出ループ
もう 1 つのよくあるケースは、ファイル内のすべてのメンバーを反復処理するときに、for ループ内で抽出が発生することです。前のケースでは、ast表現ではなく行を見るだけで済みましたが、ループではメンバーを様々な方法でループさせることができるため、より難しくなっています。Universal Radio Hackerから取得した以下のスニペットでは、enumerate関数で列挙されたメンバーをforループでループしています。中間解釈を活用することで、Creosoteはgetmembersによるループが、どのような形で現れるかを検出することができます。
図 6: URH の脆弱な Extract ループ
tarfileの脆弱性を利用した実戦的な取り組み
Spyder IDEは、Python用に書かれたフリーでオープンソースの科学環境であり、WindowsとmacOSで実行することができます。
Creosote の実行中に、Spyder リポジトリに脆弱性があることを発見しました。
図 7: Spyder のCreosote出力
図 8: Spyder の脆弱なコード
コードベースを調べたところ、ユーザーが変数エクスプローラー内で .spydata ファイルをインポートするたびに、 load_dictionary関数が呼び出されることがわかりました。Spydata ファイルは、異なるプロジェクトやスクリプト間で変数を保存および転送するために使用され、複数のユーザー間で共有することができます。
図 9: Spyder 変数エクスプローラー
データのインポート ボタンを使用して悪意のあるファイルをアップロードできることがわかったので、それをテストする必要がありました。このプロセスの最初のステップは、抽出ディレクトリがどこにあるかを見つけることでした。extractallを呼び出す前に、プログラムが作成した一時フォルダーで、chdirを呼び出すことがわかります。chdirは、現在の作業ディレクトリを渡されたフォルダーに変更します。これは、Spider が一時フォルダに展開しようとしていることを示しています。mkdtempの機能を調べたところ、Windows では関数がC:\Users\
アップロードされたファイルがどこに到達するかを理解したところで、ディレクトリ トラバーサル攻撃を使用して、ディレクトリの外に出られるかどうかを確認します。これを行うために、 C:\Users\
図 10: AppData の新しいファイル
.spydata ファイルをインポートすると、 AppDataディレクトリ内に hacked.txt ファイルがあることがわかります。これは、攻撃が機能したことを意味しますが、Spyder に表示されるエラーも表示されます。
図 11: Spyder エラー メッセージ
現在、2 つの目標があります。エラーが表示されることなく IDE を活用することと、そして、システムの書き込みをコード実行に変えることです。幸運なことに、私たちが受け取ったエラーメッセージには、この2つの問題を解決するのに役立つ詳細事項がありました。それは、例外と、例外を発生させたコードの行を示してくれますが、それはたまたま extractall 呼び出しの直後の行でした。ざっと見たところ、プログラムは、 .spydata ファイルから 1 つの .pickle ファイルが抽出されたことを想定していることがわかります。また、プログラムによって実行されるpythonファイルは、AppDataLocalの下に存在しています。したがって、管理者権限を必要とせずに変更/上書きできることにより、コード実行ができる問題を解決するのに役立ちます。
コードベースに目を通した後、コードを追加するのに最適な場所は、mainwindow.pyであると判断しました。なぜなら、このコードはアプリケーションが開かれたときに常に実行され、メイン ウィンドウが作成される前に実行されますが、アプリケーションが実行できるかどうかを確認した後に実行されたからです。次に、ファイルをコピーし、新しい .spydata ファイルを作成する前に、メッセージ ボックスをポップアップするコードを追加しました。今回は、変数インポーター用の有効な .pickle ファイルを追加しました。
図 12: 成功通知コード
新しい .spydata ファイルをインポートした後、IDE は有効な変数をロードし、プログラムは、エラー メッセージを投げるのではなく、中断せずに続行します。プログラムを再び開くと、プログラムの開始時にプログラムしたポップアップが表示されます。
図 13: エクスプロイトの成功
コードの実行はそれ自体で壊滅的な被害をもたらしますが、私たちはそれだけで終わらせたくありませんでした。以下のデモビデオで、攻撃されたユーザーをソーシャルエンジニアリングして、攻撃者が管理者権限で、コードを実行できるようにするためのコードを追加した方法をご覧ください。
tarfileエクスプロイトにより、攻撃者は、Windows以外にも、ファイルの書き込みをコード実行にエスカレートさせることができます。LinuxとDocker上で動作するITインフラ管理サービスであるPolemarchをどのようにエクスプロイトできたか、以下のビデオをご覧ください。
上記で示したように、この脆弱性は驚くほど簡単に悪用することができ、複雑なセキュリティに関する知識はほとんど必要ありません。この事実と、この脆弱性が広く出回っていることから、Pythonのtarfileモジュールは、世界中のインフラを脅かす大規模なサプライチェーンの問題になっています。Trellixのチームは、可能な限り多くのオープンソースリポジトリにパッチを適用し、またクローズドソースリポジトリをスキャンする方法を提供することで、この問題をリードしています。私たちは、世界中のコードベースのセキュリティを強化するための試みに、皆様が参加されることを望んでいます。
本記事およびここに含まれる情報は、啓蒙目的およびTrellixの顧客の利便性のみを目的としてコンピュータ セキュリティの研究について説明しています。Trellixは、脆弱性合理的開示ポリシーに基づいて調査を実施しています。記載されている活動の一部または全部を再現する試みについては、ユーザーの責任において行われるものとし、Trellixおよびその関連会社はいかなる責任も負わないものとします。
※本ページの内容は2022年9月21日(US時間)更新の以下のTrellix Storiesの内容です。
原文: Tarfile: Exploiting the World With a 15-Year-Old Vulnerability
著者: Kasimir Schulz