Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2019-16784-POC — PyInstaller CVE-2019-16783 用の概念実証エクスプロイト | Kitploit
ツール/GitHubGitHub/ckrielle/cve-2019-16784-poc
特権昇格脆弱性分析エクスプロイト学習と教育ペイロード開発バイナリエクスプロイトラボと実践
GitHubckrielle/cve-2019-16784-poc

CVE-2019-16784-POC

PyInstaller CVE-2019-16783 用の概念実証エクスプロイト

リポジトリを見る
2年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2019-16784 POC

これは、--onefile オプションに存在する Windows PyInstaller バージョン 3.6 未満の脆弱性に対する私のPOCです。攻撃者は、pyinstaller バイナリで使用される Python インタプリタ DLL がインポートする DLL をハイジャックすることで、コマンド実行や可能性として LPE を達成できます。脆弱性と悪用プロセスの簡単な説明を以下に示します。Alter Solutions が脆弱性を発見し、PagedOut #3 (PDF の 55 ページ) にその発見について執筆してくれたことに感謝します。

脆弱性

この脆弱性は、実行されたバイナリの実行時において PyInstaller が作成するディレクトリの生成が脆弱だったために発生しました。PyInstaller はユーザーの一時ディレクトリに _MEI*PIDX* ディレクトリを構築し、そこに Python コードを PE 実行可能ファイルにパッケージ化するために使用される Python インタプリタ DLL など、さまざまなものを配置します。

このプロセスの問題点は、NT AUTHORITY\SYSTEM 用に構築されたディレクトリが C:\Windows\Temp だったため、ディレクトリの推測とその中への書き込みが可能だったことです。そのため、例えば Python インタプリタが実行された際に DLL ハイジャックが可能でした。こちらがこの脆弱性を修正したコミットです。開発者は、標準的な API 関数だけに頼るのではなく、ディレクトリ作成をより細かく制御するために独自の関数を実装しました。

悪用プロセス

今回が初めての POC だったため、途中で遭遇したいくつかの問題について説明します。

テスト環境のセットアップ

まず、この POC の環境セットアップは特に難しくはありませんでした。必要なのは正しいパッケージバージョンだけだからです。しかし、インストール時にクラッシュが発生しました。

root@kitploit:~
Traceback (most recent call last):
  File "c:\users\ckrielle\appdata\local\programs\python\python38\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
...
  File "c:\users\ckrielle\appdata\local\programs\python\python38\lib\site-packages\PyInstaller\building\utils.py", line 653, in <genexpr>
    strip_paths_in_code(const_co, new_filename)
  File "c:\users\ckrielle\appdata\local\programs\python\python38\lib\site-packages\PyInstaller\building\utils.py", line 660, in strip_paths_in_code
    return code_func(co.co_argcount, co.co_kwonlyargcount, co.co_nlocals, co.co_stacksize,
TypeError: an integer is required (got type bytes)

少し検索した結果、私の Python バージョンに問題があることがわかりました(Python 3.8.10 を使用しています)。Python のバージョンが原因で、他の 3.8.x バージョンをインストールしようとしても、インストーラが既存の Python38 を見つけてエラーを返すため、困難でした。別の 3.8 バージョンをビルドしようとも試みましたが、Visual Studio 2015 が必要で(私には 2022 しかありません)、うまくいきませんでした。最終的に Python 3.7.5 をダウンロードすることにし、これは正常に動作しました。そこで、3.7 バージョン用の仮想環境を作成しました。

環境のセットアップは、すでに準備ができている場合から、正しくセットアップするのにかなりの時間がかかる場合までさまざまであることを理解しました。重要ではありますが、ターゲットを実際に悪用する楽しみを奪ってしまう可能性もあります。

エクスプロイトの作成

悪用プロセスには 2 つのステップがあります。PyInstaller でパッケージ化されたプロセスのディレクトリを見つけることと、そこにエクスプロイト DLL を書き込むことです。最初の部分では、標準の WINAPI 関数 (CreateToolhelp32Snapshot、Process32First、Process32Next) を使用して PID を見つけることができます。これはスムーズに動作しました。その後、_MEI ディレクトリの最後の番号を見つける必要があります。元のエクスプロイトでは、GetFileAttributesA 関数を使用し、返されたステータスコードが FILE_ATTRIBUTE_DIRECTORY かどうかを確認することを提案しています。しかし、これは私には機能しませんでした。私の解決策は、すべてのディレクトリ候補にファイルを作成し、ファイルが正常に作成された場合、そのディレクトリが存在すると判断することでした。何らかの理由で、GetFileAttributesA から返されたファイルのステータスは FILE_ATTRIBUTE_ARCHIVE だったため、それをチェックしています。先に進む前に、PID を検索する際のループは、読み込みが行われる前に DLL を注入できるように、ターゲットプロセスが実行されたときに DLL を注入するためです。

DLL については、Python インタプリタ (python37.dll) がインポートする DLL をハイジャックする必要があります。インタプリタがインポートする DLL を確認するには、PE-Bear で DLL を開きます。インポートされているシステム DLL の 1 つは version.dll です。そこで、独自の DLL を作成し、Windows ローダーの検索順序を悪用して、PyInstaller でパッケージ化されたプロセスの一時ディレクトリに配置します。そうすることで、DLL をインポートする際に正しい DLL ではなく、悪意のある DLL をインポートするようになります。

python37.dll のインポート

しかし、これだけでは機能しません。その理由は、Python インタプリタが version.dll から呼び出す関数(画像では具体的には VerQueryValueW)のインポートが解決されないためです。そのためプログラムがクラッシュします。この問題を解決するには、DLL プロキシを行う必要があります。簡単に言うと、悪意のある DLL が元の DLL の関数をエクスポートするように構成し、元の DLL をリネームして持ってきて、それをロードしてその関数を呼び出せるようにします。そのため、エクスプロイトでは、コード実行を可能にする DllMain を持つ悪意のある DLL をコンパイルします。version.dll のすべての関数をエクスポートし、元のシステム version2.dll をコピーして同じディレクトリに配置します。これにより、version.dll は関数呼び出しを version2.dll に転送できます。これらの DLL を用意したら、あとはそれらをプロセスのディレクトリにコピーし、コード実行を待つだけです。DLL プロキシ/ハイジャックの詳細な説明については、こちらの記事をお読みください。

悪意のある version.dll のエクスポート関数

今振り返ると、これらの手順はすべて簡単で明白ですが、POC を開発しているときはそうではありませんでした。少し前までは、エクスプロイトのプロセスを理解するのに少し時間がかかり、コーディングを始めてからより理解が深まりました。DLL については、Alter Solutions の POC リポジトリで示唆されている方法で自分でコンパイルしようとしました。彼らはコード実行用の別の DLL と、プロキシ用の別の DLL を持っており、実行時に payload.dll をロードしていました(DllMain はロード時に呼び出されます)。しかし、私はそれを正しくコンパイルできませんでした。結局、上記の記事を読んだ後、DLLProxyProject リポジトリを使用することにしました。これは目的の DLL をコンパイルし、一般にプロキシ目的の DLL を生成するために使用できます。その DLLMain.cpp ファイルをコピーし、exports.h ヘッダーファイルを使ってコンパイルしようとしました。実行はできたものの、以下のエラーが発生しました。

root@kitploit:~
Fatal Python error: init_sys_streams: can't initialize sys standard streams
OSError: [WinError 6] The handle is invalid

Current thread 0x00002ea8 (most recent call first):

このエラーは Utils.cpp ファイルがあれば回避できる可能性があったため、DLL のコンパイルにはそのプロジェクトをそのまま使用することにしました(完全に自分でできた方が良かったのですが)。

ターゲットの悪用

環境をセットアップした後(psexec を使用して NT AUTHORITY\SYSTEM シェルを取得)、エクスプロイトを実行し、ターゲットバイナリを実行すると、管理者としてコード実行ができました。

POC 成功

最後に

これは非常に素晴らしい経験であり、やり遂げてよかったと思っています。他の CVE 向けの POC ももっと作りたいと考えており、この脆弱性は初めてのターゲットとして完璧でした。脆弱性の説明を読むのは興味深く、POC を実装する際の主な難しさは、著者が説明しなかった部分(意図的にか否かにかかわらず)を埋めることと、読んでいる内容を理解することにあると理解しました。これは単純な脆弱性だったため、理解に多くの労力を費やす必要はありませんでした。もう少し POC をいくつか作成した後、メモリ破壊脆弱性の POC にも挑戦しようと考えています。

ツールをダウンロード