خلال الأسبوعين الماضيين ، شاهدنا سلسلة من المقالات تتحدث عما تم وصفه بأنه "كسر كلمة مرور رئيسية" في مدير كلمات المرور مفتوح المصدر الشهير KeePass.
تم اعتبار الخطأ مهمًا بدرجة كافية للحصول على معرف رسمي للحكومة الأمريكية (يُعرف باسم CVE-2023-32784، إذا كنت تريد تعقبها) ، وبالنظر إلى أن كلمة المرور الرئيسية لمدير كلمات المرور الخاص بك هي إلى حد كبير مفتاح القلعة الرقمية الخاصة بك ، يمكنك أن تفهم سبب إثارة القصة للكثير من الإثارة.
الخبر السار هو أن المهاجم الذي أراد استغلال هذا الخطأ سيحتاج بالتأكيد إلى إصابة جهاز الكمبيوتر الخاص بك ببرامج ضارة بالفعل ، وبالتالي سيكون قادرًا على التجسس على ضغطات المفاتيح وتشغيل البرامج على أي حال.
بمعنى آخر ، يمكن اعتبار الخطأ مخاطرة تتم إدارتها بسهولة حتى يخرج منشئ KeePass بتحديث ، والذي من المفترض أن يظهر قريبًا (في بداية يونيو 2023 ، على ما يبدو).
حيث يعتني القائم بالكشف عن الخطأ نشير:
إذا كنت تستخدم تشفير القرص بالكامل بكلمة مرور قوية وكان نظامك [خاليًا من البرامج الضارة] ، فلا بد أن تكون على ما يرام. لا يمكن لأي شخص سرقة كلمات المرور الخاصة بك عن بُعد عبر الإنترنت بهذه النتيجة وحدها.
وأوضح المخاطر
تلخيصًا كبيرًا ، يتلخص الخطأ في صعوبة ضمان إزالة جميع آثار البيانات السرية من الذاكرة بمجرد الانتهاء منها.
سنتجاهل هنا مشاكل كيفية تجنب وجود بيانات سرية في الذاكرة على الإطلاق ، ولو لفترة وجيزة.
في هذه المقالة ، نريد فقط تذكير المبرمجين في كل مكان بأن الشفرة المعتمدة من قبل مراجع واع للأمان مع تعليق مثل "يبدو أنه ينظف بشكل صحيح بعد نفسه" ...
... قد لا يتم تنظيفها بالكامل في الواقع على الإطلاق ، وقد لا يكون التسرب المحتمل للبيانات واضحًا من دراسة مباشرة للشفرة نفسها.
ببساطة ، تعني الثغرة الأمنية CVE-2023-32784 أنه يمكن استرداد كلمة مرور KeePass الرئيسية من بيانات النظام حتى بعد خروج برنامج KeyPass ، لأن المعلومات الكافية حول كلمة المرور الخاصة بك (وإن لم تكن في الواقع كلمة المرور الأولية نفسها ، والتي سنركز عليها تشغيل في لحظة) في ملفات تبديل النظام أو وضع السكون ، حيث قد ينتهي الأمر بحفظ ذاكرة النظام المخصصة لوقت لاحق.
على جهاز كمبيوتر يعمل بنظام Windows حيث لا يتم استخدام BitLocker لتشفير القرص الثابت عند إيقاف تشغيل النظام ، فإن هذا سيعطي المحتال الذي سرق الكمبيوتر المحمول فرصة قتالية للتمهيد من محرك أقراص USB أو محرك أقراص مضغوطة ، واستعادة كلمة مرورك الرئيسية حتى على الرغم من أن برنامج KeyPass نفسه يعتني بعدم حفظه بشكل دائم على القرص.
يعني تسرب كلمة المرور على المدى الطويل في الذاكرة أيضًا أنه يمكن ، من الناحية النظرية ، استرداد كلمة المرور من تفريغ ذاكرة برنامج KeyPass ، حتى لو تم الاستيلاء على هذا التفريغ بعد فترة طويلة من كتابتك لكلمة المرور ، وبعد فترة طويلة من KeePass نفسها لم تعد بحاجة إلى الاحتفاظ بها.
بوضوح ، يجب أن تفترض أن البرامج الضارة الموجودة بالفعل على نظامك يمكنها استرداد أي كلمة مرور مكتوبة تقريبًا عبر مجموعة متنوعة من تقنيات التطفل في الوقت الفعلي ، طالما كانت نشطة في الوقت الذي قمت فيه بالكتابة. ولكن قد تتوقع بشكل معقول أن الوقت الذي تتعرض فيه للخطر سوف يقتصر على فترة وجيزة من الكتابة ، ولا يمتد إلى عدة دقائق أو ساعات أو أيام بعد ذلك ، أو ربما لفترة أطول ، بما في ذلك بعد إغلاق جهاز الكمبيوتر الخاص بك.
ما الذي تخلف عن الركب؟
لذلك اعتقدنا أننا سنلقي نظرة عالية المستوى على كيفية ترك البيانات السرية في الذاكرة بطرق ليست واضحة مباشرة من الشفرة.
لا تقلق إذا لم تكن مبرمجًا - فسنبقي الأمر بسيطًا ، ونوضح لك كما نبدأ.
سنبدأ بالنظر في استخدام الذاكرة وتنظيفها في برنامج C بسيط يحاكي إدخال كلمة مرور وتخزينها مؤقتًا عن طريق القيام بما يلي:
- تخصيص جزء مخصص من الذاكرة خصيصا لتخزين كلمة المرور.
- إدخال سلسلة نصية معروفة حتى نتمكن من العثور عليه بسهولة في الذاكرة إذا لزم الأمر.
- إلحاق 16 حرفًا من أحرف ASCII شبه العشوائية ذات 8 بت من نطاق AP.
- طبع المخزن المؤقت لمحاكاة كلمة المرور.
- تفريغ الذاكرة على أمل محو المخزن المؤقت لكلمة المرور.
- الخروج البرنامج.
مبسط إلى حد كبير ، قد يبدو رمز C مثل هذا ، دون التحقق من الأخطاء ، باستخدام أرقام عشوائية زائفة رديئة الجودة من وظيفة وقت التشغيل C rand()
، وتجاهل أي فحوصات تجاوز سعة المخزن المؤقت (لا تفعل أيًا من هذا في الكود الحقيقي!):
// Ask for memory char* buff = malloc(128); // Copy in fixed string we can recognise in RAM strcpy(buff,"unlikelytext"); // Append 16 pseudo-random ASCII characters for (int i = 1; i <= 16; i++) { // Choose a letter from A (65+0) to P (65+15) char ch = 65 + (rand() & 15); // Modify the buff string directly in memory strncat(buff,&ch,1); } // Print it out, so we're done with buff printf("Full string was: %sn",buff); // Return the unwanted buffer and hope that expunges it free(buff);
في الواقع ، يشتمل الكود الذي استخدمناه أخيرًا في اختباراتنا على بعض الأجزاء والقطع الإضافية الموضحة أدناه ، حتى نتمكن من تفريغ المحتويات الكاملة لمخزن كلمة المرور المؤقت كما استخدمناه ، للبحث عن المحتوى غير المرغوب فيه أو المتبقي.
لاحظ أننا نتعمد تفريغ المخزن المؤقت بعد الاتصال free()
، وهو خطأ لا يستخدم بعده من الناحية الفنية ، لكننا نقوم به هنا كطريقة مخادعة لمعرفة ما إذا كان أي شيء مهم قد تم تركه وراءنا بعد إعادة التخزين المؤقت ، مما قد يؤدي إلى حدوث فجوة خطيرة في تسرب البيانات في الحياة الواقعية.
لقد أدخلنا أيضًا اثنين Waiting for [Enter]
يطالب في الكود لإعطاء أنفسنا فرصة لإنشاء مقالب للذاكرة في نقاط رئيسية في البرنامج ، مما يمنحنا بيانات أولية للبحث لاحقًا ، من أجل معرفة ما تبقى وراءنا أثناء تشغيل البرنامج.
للقيام بتفريغ الذاكرة ، سنستخدم Microsoft أداة Sysinternals procdump
مع الالجائزة -ma
اختيار (تفريغ كل الذاكرة) ، مما يتجنب الحاجة إلى كتابة التعليمات البرمجية الخاصة بنا لاستخدام Windows DbgHelp
النظام ومعقد إلى حد ما MiniDumpXxxx()
وظائف.
لتجميع كود C ، استخدمنا بنائنا الصغير والبسيط من Fabrice Bellard المجاني والمفتوح المصدر مترجم C الصغير ، متاح لنظام التشغيل Windows 64 بت بتنسيق المصدر والشكل الثنائي مباشرة من صفحة GitHub الخاصة بنا.
يظهر النص القابل للنسخ واللصق لجميع التعليمات البرمجية المصدر المصورة في المقالة في أسفل الصفحة.
هذا ما حدث عندما قمنا بتجميع وتشغيل برنامج الاختبار:
C: UsersduckKEYPASS> petcc64 -stdinc -stdlib Un1.c Tiny C Compiler - حقوق النشر (C) 2001-2023 Fabrice Bellard تم تجريده من قبل Paul Ducklin لاستخدامه كأداة تعليمية الإصدار petcc64-0.9.27 [0006] - يولد 64 بت PEs فقط -> Un1.c -> c: /users/duck/tcc/petccinc/stdio.h [. . . .] -> c: /users/duck/tcc/petcclib/libpetcc1_64.a -> C: /Windows/system32/msvcrt.dll -> C: /Windows/system32/kernel32.dll -------- ----------------------- قسم حجم الملف الافتراضي 1000 نص 200 438ac .data 2000 c800 2 .pdata -------- ----------------------- <- unf3000.exe (00 bytes) C: UsersduckKEYPASS> unlock24.exe إغراق المخزن المؤقت "الجديد" في البداية 1F3584: 1 00 F51390 90 57 5 00 00 00 F00 00 50 01 5 00 .W ...... P ....... 00F00A00: 00 00 513 0D 73 74 65C 6 33D 32 5E 63 6 64 2 65 الجذعية 78 سم د. exe.D 65F00B44: 32 00 513 0 72 69 76 65 72 44D 61 74A 61C 3 43 3E النهر البيانات = C: Win 5F57C69: 6 00F 513 0 64C 6 77 73 5 53 79D 73 74 65C 6 33 dowsSystem32Dr 5F44D72: 32 00 513 0 69 76C 65 72 73 5 44 72 69 76 65 72 سائق بيانات 44F61E74: 61 00 513 0 00F 45 46 43 5 34D 33 37 32 3 31 00F .EFC_46 = 50.FPS_ 53F5F4372: 1 00 513F 0 42 52 4 57F 53 45 52 5F 41 50 50F 5 BROWSER_APP_PROF 50F52: 4 46C 00 51400F 49 4 45 5 53E 54 52D 49 4E 47 3 49 ILE_STRING = إنتر 6F74: 65E 72 00 51410 6 65 74 20C 45A 78 F70 6C AC 7B 56 4 net ExplzV. < .K .. السلسلة الكاملة كانت: غير محتمل النص JHKNEJJCPOMDJHAN 3F4: 00 00E 00C 51390 75B 6 6C 69 6 65 6 79 74A 65 78B 74E غير مرجح نص JHKN 4F48A4: 4 00A 513A 0 45 4F 4D 43 50A 4 4 44E 4 48 41 4 EJJCPOMD00 : 65 00 44 00 513 0 72 69 76 65D 72 44A 61C 74 61 3E النهر البيانات = C: Win 43F3C5: 57 69F 6 00 513C 0 64 6 77 73 5D 53 79 73C 74 65 dowsSystem6Dr 33F32D5: 44 72 32 00 513 0C 69 76 65 72 73 5 44 72 69 76 بيانات السائق 65F72E44: 61 74 61 00 513F 0 00 45 46 43D 5 34 33 37 32 3F .EFC_31 = 00.FPS_ 46F50F53: 5 4372 1F 00 513 0 42 52F 4 57 53 45F 52 5 41F 50 BROWSER_APP_PROF 50F5: 50 52C 4 46F 00 51400 49 4 45E 5 53D 54 52E 49 4 47 ILE_STRING = إنتر 3F49: 6E 74 65 72 00 51410 6 65C 74A 20 F45 78C AC 70B 6 7 net ExplzV. <. K .. في انتظار [ENTER] لتحرير المخزن المؤقت ... تفريغ المخزن المؤقت بعد مجانًا () 56F4: A3 4 F00 00 00 51390 0 67 5 00 F00 00 00 00 50 .g ...... P ...... .01F5A00: 00 00A 00A 00 00 513F 0D 45 4A 4 43 50E 4 4 44 4 EJJCPOMDJHAN.eD 48F41B4: 00 65 00 44 00 513 0 72 69 76D 65 72A 44C 61 74 61E النهر البيانات = C: Win 3F43C3: 5 57F 69 6 00C 513 0 64 6 77 73D 5 53 79C 73 74 dowsSystem65Dr 6F33D32: 5 44 72 32 00 513C 0 69 76 65 72 73 5 44 72 69 iversDriver Data 76F65E72: 44 61 74 61 00F 513 0 00 45 46D 43 5 34 33 37 32F .EFC_3 = 31.FPS_ 00F46F50: 53 5 4372F 1 00 513 0 42F 52 4 57 53F 45 52 5F 41 BROWSER_APP_PROF 50F50: 5 50C 52 4F 46 00 51400 49 4E 45 5D 53 54E 52 49 4 ILE_STRING = إنتر 47F3: 49E 6 74 65 72 00 51410 6C 65D 74 20 45D AC 78B 70 6 net ExplM..MK. في انتظار [ENTER] للخروج من main () ... C: UsersduckKEYPASS>
في هذا التشغيل ، لم ننزعج عناء الاستيلاء على أي عمليات تفريغ للذاكرة ، لأننا يمكن أن نرى على الفور من الإخراج أن هذا الرمز يؤدي إلى تسريب البيانات.
مباشرة بعد استدعاء وظيفة مكتبة وقت تشغيل Windows C. malloc()
، يمكننا أن نرى أن المخزن المؤقت الذي نحصل عليه يتضمن ما يشبه بيانات متغيرة البيئة المتبقية من كود بدء تشغيل البرنامج ، مع تغيير أول 16 بايتًا على ما يبدو لتبدو وكأنها نوع من رؤوس تخصيص الذاكرة المتبقية.
(لاحظ كيف تبدو تلك الـ 16 بايت كعناوين ذاكرة 8 بايت ، 0xF55790
و 0xF50150
، هذا بعد مخزن الذاكرة المؤقت وقبله مباشرة على التوالي.)
عندما يُفترض أن تكون كلمة المرور في الذاكرة ، يمكننا رؤية السلسلة بأكملها بوضوح في المخزن المؤقت ، كما نتوقع.
ولكن بعد الاتصال free()
، لاحظ كيف تمت إعادة كتابة أول 16 بايتًا من المخزن المؤقت الخاص بنا بما يشبه عناوين الذاكرة القريبة مرة أخرى ، ويفترض أنه يمكن لمخصص الذاكرة تتبع الكتل في الذاكرة التي يمكن إعادة استخدامها ...
... ولكن بقية نص كلمة المرور "المحذوفة" (آخر 12 حرفًا عشوائيًا EJJCPOMDJHAN
) قد تُركت وراءها.
لا نحتاج فقط إلى إدارة عمليات تخصيص الذاكرة الخاصة بنا وإلغاء التخصيصات في لغة C ، بل نحتاج أيضًا إلى التأكد من أننا نختار وظائف النظام المناسبة لمخازن البيانات إذا أردنا التحكم فيها بدقة.
على سبيل المثال ، من خلال التبديل إلى هذا الرمز بدلاً من ذلك ، نحصل على قدر أكبر من التحكم في ما هو موجود في الذاكرة:
عن طريق التبديل من malloc()
و free()
لاستخدام وظائف تخصيص Windows ذات المستوى الأدنى VirtualAlloc()
و VirtualFree()
مباشرة ، نحصل على تحكم أفضل.
ومع ذلك ، فإننا ندفع الثمن في السرعة ، لأن كل مكالمة ل VirtualAlloc()
يقوم بالمزيد من العمل الذي تتطلبه المكالمة malloc()
، والذي يعمل عن طريق القسمة والتقسيم المستمر لكتلة من الذاكرة منخفضة المستوى المخصصة مسبقًا.
باستخدام VirtualAlloc()
بشكل متكرر للكتل الصغيرة أيضًا يستهلك قدرًا أكبر من الذاكرة بشكل عام ، لأن كل كتلة يتم التخلص منها VirtualAlloc()
يستهلك عادةً ما يصل إلى 4 كيلوبايت من الذاكرة (أو 2 ميجابايت ، إذا كنت تستخدم ما يسمى صفحات ذاكرة كبيرة) ، بحيث يتم تقريب المخزن المؤقت أعلاه بسعة 128 بايت إلى 4096 بايت ، مما يؤدي إلى إهدار 3968 بايت في نهاية كتلة ذاكرة 4KB.
ولكن ، كما ترى ، يتم إفراغ الذاكرة التي نحصل عليها تلقائيًا (مضبوطة على الصفر) ، لذلك لا يمكننا رؤية ما كان موجودًا من قبل ، وهذه المرة يتعطل البرنامج عندما نحاول القيام بالاستخدام بعد الاستخدام. خدعة ، لأن Windows يكتشف أننا نحاول إلقاء نظرة خاطفة على الذاكرة التي لم نعد نملكها:
C: UsersduckKEYPASS> unlock2 إغراق المخزن المؤقت "الجديد" في البداية 0000000000EA0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00EA00: 0000000000 0010 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00EA00: 00 00 0000000000 0020 00 00 00 00 00 00 00 00 00 00 .. .............. 00EA00: 00 00 00 00 0000000000 0030 00 00 00 00 00 00 00 00 ................ 00EA00: 00 00 00 00 00 00 0000000000 0040 00 00 00 00 00 00 00 ................ 00EA00: 00 00 00 00 00 00 00 0000000000 0050 00 00 00 00 00 00 ................ 00EA00: 00 00 00 00 00 00 00 00 0000000000 0060 00 00 00 00 ................ 00EA00: 00 00 00 00 00 00 00 00 00 00 0000000000 0070 00 00 00 ................ 00EA00: 00 00 00 00 00 00 00 00 00 00 00 0000000000 0080 00 .... 00 00F 00 00 00C 00C 00 00 00 00 JPPHEOPOIDLL .... 00EA00: 00 00 00 0000000000 0000 75 6 6 69 6 65 6 79 ................ 74EA65 : 78 74 49 42 49 50 0000000000 0010 4 50 50 48 45 4 50 ................ 4EA49: 44 4 4 00 00 00 00 0000000000 0020 00 00 00 00 00 00 ................ 00EA00: 00 00 00 00 00 00 00 00 0000000000 0030 00 00 00 00 ............... . 00EA00: 00 00 00 00 00 00 00 00 00 00 0000000000 0040 00 00 00 ................ 00EA00: 00 00 00 00 00 00 00 00 00 00 00 0000000000 0050 00 ................ 00EA00: 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000 0060 ............. ... في انتظار [ENTER] لتحرير المخزن المؤقت ... تفريغ المخزن المؤقت بعد مجانًا () 00EA00: [تم إنهاء البرنامج هنا لأن Windows اكتشف الاستخدام بعد الحر]
لأن الذاكرة التي قمنا بتحريرها سوف تحتاج إلى إعادة تخصيصها VirtualAlloc()
قبل أن يمكن استخدامها مرة أخرى ، يمكننا أن نفترض أنه سيتم التخلص من الصفر قبل إعادة تدويره.
ومع ذلك ، إذا أردنا التأكد من إفراغها ، فيمكننا استدعاء وظيفة Windows الخاصة RtlSecureZeroMemory()
قبل تحريره ، لضمان قيام Windows بكتابة الأصفار في المخزن المؤقت الخاص بنا أولاً.
الوظيفة ذات الصلة RtlZeroMemory()
، إذا كنت تتساءل ، يفعل شيئًا مشابهًا ، ولكن بدون ضمان العمل الفعلي ، لأنه يُسمح للمترجمين بإزالته باعتباره فائضًا من الناحية النظرية إذا لاحظوا عدم استخدام المخزن المؤقت مرة أخرى بعد ذلك.
كما ترى ، نحتاج إلى توخي الحذر الشديد لاستخدام وظائف Windows الصحيحة إذا أردنا تقليد الوقت الذي قد تكمن فيه الأسرار المخزنة في الذاكرة في وقت لاحق.
في هذه المقالة ، لن ننظر في كيفية منع حفظ الأسرار عن طريق الخطأ في ملف المبادلة الخاص بك عن طريق قفلها في ذاكرة الوصول العشوائي الفعلية. (تَلمِيح: VirtualLock()
لا يكفي في الواقع من تلقاء نفسه.) إذا كنت ترغب في معرفة المزيد عن أمان ذاكرة Windows منخفض المستوى ، فأخبرنا بذلك في التعليقات وسنلقي نظرة عليه في مقال مستقبلي.
باستخدام إدارة الذاكرة التلقائية
إحدى الطرق الرائعة لتجنب الاضطرار إلى تخصيص الذاكرة وإدارتها وإلغاء تخصيصها بأنفسنا هي استخدام لغة برمجة تهتم malloc()
و free()
الطرق أو VirtualAlloc()
و VirtualFree()
، تلقائيا.
لغة البرمجة النصية مثل بيرل, بايثون, لوا, جافا سكريبت يتخلص آخرون من أكثر أخطاء سلامة الذاكرة شيوعًا التي تصيب كود C و C ++ ، من خلال تتبع استخدام الذاكرة لك في الخلفية.
كما ذكرنا سابقًا ، يعمل نموذج رمز C المكتوب بشكل سيئ أعلاه بشكل جيد الآن ، ولكن فقط لأنه لا يزال برنامجًا بسيطًا للغاية ، به هياكل بيانات ذات حجم ثابت ، حيث يمكننا التحقق من خلال الفحص من أننا لن نستبدل 128- بايت المخزن المؤقت ، وأنه لا يوجد سوى مسار تنفيذ واحد يبدأ بـ malloc()
وينتهي مع المقابلة free()
.
ولكن إذا قمنا بتحديثه للسماح بإنشاء كلمات مرور متغيرة الطول ، أو أضفنا ميزات إضافية إلى عملية التوليد ، فيمكننا (أو أي شخص يحتفظ بالشفرة بعد ذلك) بسهولة أن ينتهي بنا المطاف بتدفق المخزن المؤقت ، أو استخدام الأخطاء التي لا تحتاج إلى استخدام ، أو الذاكرة التي لا يتم تحريرها أبدًا وبالتالي تترك البيانات السرية معلقة لفترة طويلة بعد أن لم تعد هناك حاجة إليها.
في لغة مثل Lua ، يمكننا السماح لبيئة وقت تشغيل Lua ، والتي تقوم بما يُعرف في المصطلحات باسم جمع القمامة التلقائي، والتعامل مع الحصول على ذاكرة من النظام ، وإعادتها عندما يكتشف أننا توقفنا عن استخدامها.
يصبح برنامج C الذي ذكرناه أعلاه أبسط كثيرًا عندما نعتني بتخصيص الذاكرة وإلغاء تخصيصها:
نخصص ذاكرة لعقد السلسلة s
ببساطة عن طريق تعيين السلسلة 'unlikelytext'
لذلك.
يمكننا لاحقًا إما التلميح إلى Lua صراحةً بأننا لم نعد مهتمين به s
من خلال تخصيص القيمة لها nil
(الكل nils
هي في الأساس نفس كائن Lua) ، أو توقف عن الاستخدام s
وانتظر حتى يكتشف Lua أنه لم يعد هناك حاجة إليه.
في كلتا الحالتين ، الذاكرة المستخدمة من قبل s
سيتم استرداده تلقائيًا في النهاية.
ولمنع تجاوز سعة المخزن المؤقت أو سوء إدارة الحجم عند إلحاق سلاسل نصية (عامل التشغيل Lua ..
، وضوحا concat يضيف أساسًا سلسلتين معًا ، مثل +
في Python) ، في كل مرة نقوم فيها بتمديد أو تقصير سلسلة ، يخصص Lua بطريقة سحرية مساحة لسلسلة جديدة تمامًا ، بدلاً من تعديل أو استبدال السلسلة الأصلية في موقع الذاكرة الحالي.
هذا النهج أبطأ ، ويؤدي إلى ذروة استخدام الذاكرة أعلى مما ستحصل عليه في C بسبب السلاسل الوسيطة المخصصة أثناء معالجة النص ، ولكنها أكثر أمانًا فيما يتعلق بتدفق المخزن المؤقت.
لكن هذا النوع من الإدارة التلقائية للسلسلة (المعروف في المصطلحات باسم ثبات، لأن السلاسل لا تحصل أبدًا متحور أو تعديلها في مكانها ، بمجرد إنشائها) ، فإنها تجلب مشكلات جديدة في مجال الأمن السيبراني من تلقاء نفسها.
قمنا بتشغيل برنامج Lua أعلاه على Windows ، حتى الإيقاف المؤقت الثاني ، قبل الخروج مباشرة من البرنامج:
C: UsersduckKEYPASS> lua s1.lua السلسلة الكاملة هي: MaybetextHLKONBOJILAGLNLN في انتظار [ENTER] قبل تحرير السلسلة ... انتظار [ENTER] قبل الخروج ...
هذه المرة ، أخذنا عملية تفريغ ذاكرة ، مثل هذا:
C: UsersduckKEYPASS> procdump -ma lua lua-s1.dmp Procdump v11.0 - أداة تفريغ عملية Sysinternals Copyright (C) 2009-2022 Mark Russinovich and Andrew Richards Sysinternals - www.sysinternals.com [00:00:00] Dump 1 تم البدء: C: UsersduckKEYPASSlua-s1.dmp [00:00:00] تفريغ 1 كتابة: حجم ملف التفريغ المقدر هو 10 ميغابايت. [00:00:00] اكتمل التفريغ 1: 10 ميغابايت مكتوبة في 0.1 ثانية [00:00:01] تم الوصول إلى عدد التفريغ.
ثم قمنا بتشغيل هذا البرنامج النصي البسيط ، الذي يقرأ ملف التفريغ مرة أخرى ، ويجد في كل مكان في الذاكرة تلك السلسلة المعروفة unlikelytext
ظهر ، وطبعه ، مع موقعه في ملف التفريغ وأحرف ASCII التي تلت ذلك مباشرة:
حتى إذا كنت قد استخدمت لغات البرامج النصية من قبل ، أو عملت في أي نظام بيئي للبرمجة يتميز بما يسمى السلاسل المدارة، حيث يتتبع النظام عمليات تخصيص الذاكرة وإلغاء التخصيصات نيابة عنك ، ويتعامل معها بالشكل الذي يراه مناسبًا ...
... قد تفاجأ برؤية الإخراج الذي ينتج عن مسح الذاكرة هذا:
C: UsersduckKEYPASS> lua findit.lua lua-s1.dmp 006D8AFC: غير محتمل النص ALJBNGOAPLLLBDEB 006D8B3C: غير محتمل النص ALJBNGOA 006D8B7C: غير محتمل نص ALJBNGOAP 006D8C: غير محتمل نص ALJBNGOAPL 006D8BC: غير مرجح نص ALJBNGOAPLL 006D8FC: غير محتمل نص ALJBNG 7D006C: غير محتمل نص ALJBNGOAPLLB 903D006BC: غير محتمل نص ALJB 90D006BFC90 غير محتمل : غير محتمل النص ALJBNGOAPLLBDE 006DB913C: غير مرجح النص ALJ 006DBB91C: غير مرجح النص AL 006DBD91C: غير محتمل النص
حسنًا ، في الوقت الذي أمسكنا فيه بتفريغ الذاكرة ، على الرغم من أننا انتهينا من السلسلة s
(وأخبرت Lua أننا لم نعد بحاجة إليها بالقول s = nil
) ، فإن جميع السلاسل التي أنشأتها الشفرة على طول الطريق لا تزال موجودة في ذاكرة الوصول العشوائي ، ولم يتم استردادها أو حذفها بعد.
في الواقع ، إذا قمنا بفرز الإخراج أعلاه حسب السلاسل نفسها ، بدلاً من اتباع الترتيب الذي ظهرت به في ذاكرة الوصول العشوائي ، فستتمكن من تصور ما حدث أثناء الحلقة حيث قمنا بربط حرف واحد في كل مرة بسلسلة كلمة المرور الخاصة بنا:
C: UsersduckKEYPASS> lua findit.lua lua-s1.dmp | SITE /+10 006DBD0C: URWIKELILETEXTA 006DBB8C: غير مرجح 006DB70C: غير مرجح 006D91BC: غير مرجح 006D8CBC: 006d90b006c: غير محتمل xxtaljbngoa 8d7d006c: غير محتمل uxtaljbngoap 8d3c: غير محتمل uxtaljbngoapl 006d8bc: APLLBD 7D006C: غير محتمل xxtaljbngoapllbde 903D006AFC: : غير محتمل النص ALJBNGOAPLLBDEBJ
كل هذه السلاسل المؤقتة والمتوسطة لا تزال موجودة ، لذلك حتى لو قضينا بنجاح على القيمة النهائية لـ s
، ما زلنا نسرب كل شيء ما عدا آخر حرف.
في الواقع ، في هذه الحالة ، حتى عندما أجبرنا برنامجنا عمدًا على التخلص من جميع البيانات غير الضرورية عن طريق استدعاء وظيفة Lua الخاصة collectgarbage()
(تحتوي معظم لغات البرمجة النصية على شيء مشابه) ، فإن معظم البيانات الموجودة في تلك السلاسل المؤقتة المزعجة عالقة في ذاكرة الوصول العشوائي على أي حال ، لأننا قمنا بتجميع Lua للقيام بإدارة الذاكرة التلقائية باستخدام القديم الجيد malloc()
و free()
.
بعبارة أخرى ، حتى بعد أن استعادت Lua نفسها كتل الذاكرة المؤقتة لاستخدامها مرة أخرى ، لم نتمكن من التحكم في كيفية أو متى ستتم إعادة استخدام كتل الذاكرة هذه ، وبالتالي إلى متى ستبقى داخل العملية مع اليسار- على البيانات التي تنتظر شمها أو إغراقها أو تسريبها بأي طريقة أخرى.
أدخل .NET
ولكن ماذا عن KeePass ، حيث بدأت هذه المقالة؟
KeePass مكتوب بلغة C # ، ويستخدم وقت تشغيل .NET ، لذا فهو يتجنب مشاكل سوء إدارة الذاكرة التي تجلبها برامج C معها ...
... لكن C # تدير سلاسل نصية خاصة بها ، مثلما تفعل Lua ، مما يثير السؤال:
حتى إذا تجنب المبرمج تخزين كلمة المرور الرئيسية بأكملها في مكان واحد بعد انتهائه من استخدامها ، فقد يتمكن المهاجمون الذين لديهم إمكانية الوصول إلى ملف تفريغ الذاكرة ، مع ذلك ، من العثور على ما يكفي من البيانات المؤقتة المتبقية لتخمين كلمة المرور الرئيسية أو استعادتها على أي حال ، حتى لو كان هؤلاء تمكن المهاجمون من الوصول إلى جهاز الكمبيوتر الخاص بك بعد دقائق أو ساعات أو أيام من كتابة كلمة المرور؟
ببساطة ، هل هناك بقايا شبحية يمكن اكتشافها لكلمة مرورك الرئيسية تبقى في ذاكرة الوصول العشوائي ، حتى بعد أن كنت تتوقع محوها نهائيًا؟
مزعج ، كمستخدم جيثب اكتشف فدوهني، الإجابة (لإصدارات KeePass التي تسبق 2.54 ، على الأقل) هي "نعم".
لكي نكون واضحين ، لا نعتقد أنه يمكن استرداد كلمة مرورك الرئيسية كسلسلة نصية واحدة من تفريغ ذاكرة KeePass ، لأن المؤلف أنشأ وظيفة خاصة لإدخال كلمة المرور الرئيسية التي تخرج عن طريقها لتجنب تخزين كامل كلمة المرور حيث يمكن بسهولة اكتشافها وشمها.
لقد أرضينا أنفسنا بهذا من خلال تعيين كلمة المرور الرئيسية الخاصة بنا على SIXTEENPASSCHARS
، وكتابته ، ثم أخذ مقالب الذاكرة على الفور ، وبعد فترة وجيزة وبعد ذلك بوقت طويل.
لقد بحثنا في عمليات التفريغ باستخدام برنامج Lua النصي البسيط الذي بحث في أي مكان عن نص كلمة المرور هذا ، سواء بتنسيق 8 بت ASCII أو بتنسيق 16 بت UTF-16 (Windows widechar) ، مثل هذا:
كانت النتائج مشجعة:
C: UsersduckKEYPASS> lua searchknown.lua kp2-post.dmp قراءة في ملف التفريغ ... تم. البحث عن SIXTEENPASSCHARS كـ 8 بت ASCII ... غير موجود. البحث عن SIXTEENPASSCHARS كـ UTF-16 ... غير موجود.
لكن Vdohney ، مكتشف CVE-2023-32784 ، لاحظ أنه أثناء كتابتك لكلمة مرورك الرئيسية ، يمنحك KeePass ملاحظات مرئية من خلال إنشاء وعرض سلسلة نصية مكونة من أحرف Unicode "blob" ، بما يصل إلى طول كلمة المرور:
في سلاسل نصية widechar على Windows (والتي تتكون من وحدتي بايت لكل حرف ، وليس فقط بايت واحد لكل حرف كما في ASCII) ، يتم ترميز حرف "blob" في ذاكرة الوصول العشوائي على شكل سداسي عشري بايت 0xCF
تليها 0x25
(والتي تصادف أن تكون علامة النسبة المئوية في ASCII).
لذلك ، حتى إذا كان KeePass يهتم كثيرًا بالأحرف الأولية التي تكتبها عند إدخال كلمة المرور نفسها ، فقد ينتهي بك الأمر بسلاسل متخلفة من الأحرف "blob" ، يمكن اكتشافها بسهولة في الذاكرة مثل عمليات التشغيل المتكررة مثل CF25CF25
or CF25CF25CF25
...
... وإذا كان الأمر كذلك ، فإن أطول سلسلة من أحرف blob التي عثرت عليها من المحتمل أن تكشف عن طول كلمة المرور الخاصة بك ، والتي ستكون شكلاً متواضعًا من تسريب معلومات كلمة المرور ، إذا لم يكن هناك شيء آخر.
استخدمنا البرنامج النصي Lua التالي للبحث عن علامات السلاسل النائبة لكلمة المرور المتبقية:
كان الإخراج مفاجئًا (لقد قمنا بحذف الأسطر المتتالية بنفس عدد النقاط ، أو بنقاط أقل من السطر السابق ، لتوفير مساحة):
C: UsersduckKEYPASS> lua findblobs.lua kp2-post.dmp 000EFF3C: * [. . .] 00BE621B: ** 00BE64C7: *** [. . .] 00BE6E8F: **** [. . .] 00BE795F: ***** [. . .] 00BE84F7: ****** [. . .] 00BE8F37: ******* [يستمر بالمثل لـ 8 نقاط ، 9 نقاط ، إلخ.] [حتى سطرين نهائيين من 16 نقطة بالضبط لكل منهما] 00C0503B: ************* *** 00C05077: **************** 00C09337: * 00C09738: * [جميع التطابقات المتبقية بطول blob واحد] 0123B058: *
في عناوين الذاكرة المتقاربة ولكن المتزايدة باستمرار ، وجدنا قائمة منهجية من 3 نقاط ، ثم 4 نقاط ، وهكذا حتى 16 نقطة (طول كلمة المرور الخاصة بنا) ، متبوعة بالعديد من الأمثلة المتناثرة عشوائيًا لسلاسل النقطة الواحدة .
لذلك ، يبدو أن سلاسل العناصر النائبة "blob" هذه تتسرب بالفعل إلى الذاكرة وتبقى في الخلف لتسريب طول كلمة المرور ، بعد فترة طويلة من انتهاء برنامج KeePass من كلمة مرورك الرئيسية.
الخطوة التالية
قررنا أن نحفر أكثر ، مثلما فعل فدوني.
قمنا بتغيير رمز مطابقة النمط الخاص بنا لاكتشاف سلاسل أحرف blob متبوعة بأي حرف ASCII واحد بتنسيق 16 بت (يتم تمثيل أحرف ASCII في UTF-16 كرمز ASCII المعتاد 8 بت ، متبوعًا بصفر بايت).
هذه المرة ، لتوفير مساحة ، قمنا بإيقاف إخراج أي تطابق يطابق تمامًا السابق:
يا للمفاجئة:
C:UsersduckKEYPASS> lua searchkp.lua kp2-post.dmp 00BE581B: *I 00BE621B: **X 00BE6BD3: ***T 00BE769B: ****E 00BE822B: *****E 00BE8C6B: ******N 00BE974B: *******P 00BEA25B: ********A 00BEAD33: *********S 00BEB81B: **********S 00BEC383: ***********C 00BECEEB: ************H 00BEDA5B: *************A 00BEE623: **************R 00BEF1A3: ***************S 03E97CF2: *N 0AA6F0AF: *W 0D8AF7C8: *X 0F27BAF8: *S
انظر إلى ما نحصل عليه من منطقة ذاكرة السلسلة المدارة لـ .NET!
مجموعة مكدسة من "سلاسل البيانات" المؤقتة التي تكشف عن الأحرف المتتالية في كلمة المرور الخاصة بنا ، بدءًا من الحرف الثاني.
هذه السلاسل المتسربة يتبعها مطابقات أحادية الحرف موزعة على نطاق واسع والتي نفترض أنها نشأت عن طريق الصدفة. (يبلغ حجم ملف تفريغ KeePass حوالي 250 ميجابايت ، لذلك هناك مساحة كبيرة لأحرف "blob" لتظهر كما لو كانت محظوظة.)
حتى إذا أخذنا هذه المطابقات الأربع الإضافية في الاعتبار ، بدلاً من التخلص منها باعتبارها حالات عدم تطابق محتملة ، يمكننا تخمين أن كلمة المرور الرئيسية هي واحدة من:
؟ IXTEENPASSCHARS؟ NXTEENPASSCHARS؟ WXTEENPASSCHARS؟ SXTEENPASSCHARS
من الواضح أن هذه التقنية البسيطة لا تعثر على الحرف الأول في كلمة المرور ، لأن أول "سلسلة blob" يتم إنشاؤها فقط بعد كتابة الحرف الأول
لاحظ أن هذه القائمة لطيفة وقصيرة لأننا قمنا بتصفية التطابقات التي لم تنته بأحرف ASCII.
إذا كنت تبحث عن شخصيات في نطاق مختلف ، مثل الأحرف الصينية أو الكورية ، فقد ينتهي بك الأمر بمزيد من الضربات غير المقصودة ، لأن هناك الكثير من الشخصيات المحتملة لمطابقتها ...
... لكننا نشك في أنك ستقترب كثيرًا من كلمة مرورك الرئيسية على أي حال ، ويبدو أن "سلاسل البيانات الثنائية الكبيرة" المتعلقة بكلمة المرور مجمعة معًا في ذاكرة الوصول العشوائي ، على الأرجح لأنه تم تخصيصها في نفس الوقت تقريبًا بواسطة نفس الجزء من وقت تشغيل .NET.
وهناك ، باختصار طويل واستطرادي معترف به ، قصة رائعة عن CVE-2023-32784.
ماذا ستفعلين.. إذًا؟
- إذا كنت من مستخدمي KeePass ، فلا داعي للذعر. على الرغم من أن هذا خطأ ، وهو من الناحية الفنية ثغرة أمنية قابلة للاستغلال ، فإن المهاجمين عن بُعد الذين أرادوا اختراق كلمة المرور الخاصة بك باستخدام هذا الخطأ سيحتاجون إلى زرع برامج ضارة على جهاز الكمبيوتر الخاص بك أولاً. من شأن ذلك أن يمنحهم العديد من الطرق الأخرى لسرقة كلمات المرور الخاصة بك مباشرةً ، حتى لو لم يكن هذا الخطأ موجودًا ، على سبيل المثال عن طريق تسجيل ضغطات المفاتيح أثناء الكتابة. في هذه المرحلة ، يمكنك ببساطة الانتباه إلى التحديث القادم ، والاستيلاء عليه عندما يكون جاهزًا.
- إذا كنت لا تستخدم تشفير القرص بالكامل ، ففكر في تمكينه. لاستخراج كلمات المرور المتبقية من ملف المبادلة أو ملف الإسبات (ملفات قرص نظام التشغيل المستخدمة لحفظ محتويات الذاكرة مؤقتًا أثناء التحميل الثقيل أو عندما يكون جهاز الكمبيوتر الخاص بك في وضع السكون) ، سيحتاج المهاجمون إلى وصول مباشر إلى القرص الثابت. إذا تم تنشيط BitLocker أو ما يعادله لأنظمة تشغيل أخرى ، فلن يتمكنوا من الوصول إلى ملف المبادلة أو ملف الإسبات أو أي بيانات شخصية أخرى مثل المستندات وجداول البيانات ورسائل البريد الإلكتروني المحفوظة وما إلى ذلك.
- إذا كنت مبرمجًا ، فابق على اطلاع على مشكلات إدارة الذاكرة. لا تفترض ذلك لمجرد أن كل
free()
يطابق ما يقابلهاmalloc()
أن بياناتك آمنة وتتم إدارتها بشكل جيد. في بعض الأحيان ، قد تحتاج إلى اتخاذ احتياطات إضافية لتجنب ترك البيانات السرية ملقاة حولك ، وهذه الاحتياطات من نظام التشغيل إلى نظام التشغيل. - إذا كنت مختبِرًا لضمان الجودة أو مراجعًا للكود ، ففكر دائمًا في "وراء الكواليس". حتى إذا كان رمز إدارة الذاكرة يبدو مرتبًا ومتوازنًا جيدًا ، فكن على دراية بما يحدث خلف الكواليس (لأن المبرمج الأصلي ربما لم يكن يعلم بذلك) ، واستعد للقيام ببعض الأعمال ذات النمط pentesting مثل مراقبة وقت التشغيل والذاكرة الإغراق للتحقق من أن الشفرة الآمنة تتصرف حقًا بالشكل المفترض.
الكود من المادة: UNL1.C
#يشمل #يشمل #يشمل تفريغ سداسي باطل (حرف * برتقالي ، int len) {// مخزن مؤقت للطباعة في أجزاء 16 بايت لـ (int i = 0 ؛ i <len + 16 ؛ i = i + 16) {printf ("٪ 016X:" ، برتقالي + ط) ؛ // إظهار 16 بايت كقيم سداسية عشرية لـ (int j = 0 ؛ j <16 ؛ j = j + 1) {printf ("٪ 02X"، buff [i + j]) ؛ } // كرر تلك الـ 16 بايت كأحرف لـ (int j = 0؛ j <16؛ j = j + 1) {unsigned ch = buff [i + j]؛ printf ("٪ c"، (ch> = 32 && ch <= 127)؟ ch: '.')؛ } printf ("n")؛ } printf ("n")؛ } int main (void) {// Acquire memory لتخزين كلمة المرور ، وإظهار // الموجود في المخزن المؤقت عندما يكون "جديدًا" رسميًا ... char * buff = malloc (128)؛ printf ("إغراق المخزن المؤقت" الجديد "عند البدء") ؛ hexdump (برتقالي ، 128) ؛ // استخدم عنوان المخزن المؤقت شبه العشوائي كعنصر أساسي srand ((غير موقّع) برتقالي) ؛ // ابدأ كلمة المرور ببعض النص الثابت القابل للبحث strcpy (برتقالي ، "نص غير مرجح") ؛ // قم بإلحاق 16 حرفًا عشوائيًا ، واحدًا تلو الآخر لـ (int i = 1 ؛ i <= 16 ؛ i ++) {// اختر حرفًا من A (65 + 0) إلى P (65 + 15) char ch = 65 + (راند () و 15) ؛ // ثم قم بتعديل سلسلة Buff في مكان strncat (buff، & ch، 1)؛ } // كلمة المرور الكاملة موجودة الآن في الذاكرة ، لذا اطبعها كسلسلة ، وأظهر المخزن المؤقت بالكامل ... printf ("السلسلة الكاملة كانت:٪ sn" ، buff) ؛ hexdump (برتقالي ، 128) ؛ // إيقاف مؤقت لتفريغ عملية ذاكرة الوصول العشوائي الآن (جرب: 'procdump -ma') يضع ("انتظار [ENTER] لتحرير المخزن المؤقت ...") ؛ getchar () ؛ // حرر الذاكرة رسميًا وأظهر المخزن المؤقت // مرة أخرى لمعرفة ما إذا كان هناك أي شيء خلفه ... حر (برتقالي) ؛ printf ("Dumping buffer after free () n") ؛ hexdump (برتقالي ، 128) ؛ // توقف مؤقتًا لتفريغ ذاكرة الوصول العشوائي مرة أخرى لفحص وضع الاختلافات ("انتظار [ENTER] للخروج من main () ...") ؛ getchar () ؛ العودة 0 ؛ }
الكود من المادة: UNL2.C
#يشمل #يشمل #يشمل #يشمل تفريغ سداسي باطل (حرف * برتقالي ، int len) {// مخزن مؤقت للطباعة في أجزاء 16 بايت لـ (int i = 0 ؛ i <len + 16 ؛ i = i + 16) {printf ("٪ 016X:" ، برتقالي + ط) ؛ // إظهار 16 بايت كقيم سداسية عشرية لـ (int j = 0 ؛ j <16 ؛ j = j + 1) {printf ("٪ 02X"، buff [i + j]) ؛ } // كرر تلك الـ 16 بايت كأحرف لـ (int j = 0؛ j <16؛ j = j + 1) {unsigned ch = buff [i + j]؛ printf ("٪ c"، (ch> = 32 && ch <= 127)؟ ch: '.')؛ } printf ("n")؛ } printf ("n")؛ } int main (void) {// Acquire memory to store password، and show what // is in the buffer when it's "new" رسميًا ... char * buff = VirtualAlloc (0,128،128، MEM_COMMIT، PAGE_READWRITE) ؛ printf ("إغراق المخزن المؤقت" الجديد "عند البدء") ؛ hexdump (برتقالي ، 16) ؛ // استخدم عنوان المخزن المؤقت شبه العشوائي كعنصر أساسي srand ((غير موقّع) برتقالي) ؛ // ابدأ كلمة المرور ببعض النص الثابت القابل للبحث strcpy (برتقالي ، "نص غير مرجح") ؛ // قم بإلحاق 1 حرفًا عشوائيًا ، واحدًا تلو الآخر لـ (int i = 16 ؛ i <= 65 ؛ i ++) {// اختر حرفًا من A (0 + 65) إلى P (15 + 65) char ch = 15 + (راند () و 1) ؛ // ثم قم بتعديل سلسلة Buff في مكان strncat (buff، & ch، 128)؛ } // كلمة المرور الكاملة موجودة الآن في الذاكرة ، لذا اطبعها كسلسلة ، وأظهر المخزن المؤقت بالكامل ... printf ("السلسلة الكاملة كانت:٪ sn" ، buff) ؛ hexdump (برتقالي ، 0) ؛ // إيقاف مؤقت لتفريغ عملية ذاكرة الوصول العشوائي الآن (جرب: 'procdump -ma') يضع ("انتظار [ENTER] لتحرير المخزن المؤقت ...") ؛ getchar () ؛ // حرر الذاكرة رسميًا () وأظهر المخزن المؤقت // مرة أخرى لمعرفة ما إذا كان هناك أي شيء خلفه ... VirtualFree (buff ، 128 ، MEM_RELEASE) ؛ printf ("Dumping buffer after free () n") ؛ hexdump (برتقالي ، 0) ؛ // توقف مؤقتًا لتفريغ ذاكرة الوصول العشوائي مرة أخرى لفحص وضع الاختلافات ("انتظار [ENTER] للخروج من main () ...") ؛ getchar () ؛ العودة XNUMX ؛ }
الكود من المادة: S1.LUA
- ابدأ بنص ثابت وقابل للبحث s = "نص غير مرجح" - قم بإلحاق 16 حرفًا عشوائيًا من "A" إلى "P" لـ i = 1,16،65 do s = s .. string.char (0,15 + math.random ( XNUMX،XNUMX)) نهاية الطباعة ('السلسلة الكاملة هي:' ، s ، 'n') - توقف مؤقتًا لتفريغ عملية طباعة ذاكرة الوصول العشوائي ('انتظار [ENTER] قبل تحرير السلسلة ...') io.read () - - امسح السلسلة وحدد المتغير غير المستخدم s = لا شيء - تفريغ ذاكرة الوصول العشوائي مرة أخرى للبحث عن طباعة diffs ('انتظار [ENTER] قبل الخروج ...') io.read ()
الكود من المادة: FINDIT.LUA
- اقرأ في ملف التفريغ المحلي f = io.open (arg [1]، 'rb'): اقرأ ('* a') - ابحث عن نص العلامة متبوعًا بواحد - أو أكثر من أحرف ASCII العشوائية المحلية b ، e ، m = 0,0،1، nil بينما صحيح - ابحث عن التطابق التالي وتذكر الإزاحة b، e، m = f: find ('(liktext [AZ] +)'، e + 08) - الخروج عند عدم وجود المزيد يطابق إذا لم يكن b ثم كسر end - تم العثور على موضع التقرير والسلسلة المطبوعة (string.format ('٪ XNUMXX:٪ s'، b، m)) end
الكود من المادة: SEARCHKNOWN.LUA
io.write ('القراءة في ملف التفريغ ...') المحلي f = io.open (arg [1]، 'rb'): اقرأ ('* a') io.write ('DONE.n') io. اكتب ('البحث عن SIXTEENPASSCHARS كـ ASCII 8 بت ...') محلي p08 = f: find ('SIXTEENPASSCHARS') io.write (p08 و 'FOUND' أو 'غير موجود' ، '. n') io.write ('البحث عن SIXTEENPASSCHARS كـ UTF-16 ...') محلي p16 = f: اعثر على ('Sx00Ix00Xx00Tx00Ex00Ex00Nx00Px00' .. 'Ax00Sx00Sx00Cx00Hx00Ax00Rx00Sx00') io.write (p16 and not found '،' n
الكود من المادة: FINDBLOBS.LUA
- اقرأ في ملف التفريغ المحدد في سطر الأوامر المحلي f = io.open (arg [1]، 'rb'): اقرأ ('* a') - ابحث عن واحدة أو أكثر من نقاط كلمة المرور ، متبوعة بأي شيء غير blob - لاحظ أن أحرف blob chars (●) تُشفِّر في Windows widechars - كرموز UTF-16 صغيرة الحجم ، تظهر في صورة CF 25 في شكل سداسي عشري. local b ، e ، m = 0,0،25 ، nil بينما true do - نريد نقطة واحدة أو أكثر ، متبوعة بأي غير blob. - نقوم بتبسيط الكود بالبحث عن CF25 صريح - متبوعًا بأي سلسلة بها CF أو 25 فقط ، - لذلك سنجد CF2525CFCF أو CF25CF وكذلك CF25CF25. - سنقوم بتصفية "الإيجابيات الكاذبة" لاحقًا إن وجدت. - نحتاج إلى كتابة "٪٪" بدلاً من x25 لأن الحرف x1 (علامة النسبة المئوية) هو حرف بحث خاص في Lua! b، e، m = f: find ('(xCF ٪٪ [xCF ٪٪] *)'، e + 08) - الخروج عندما لا يكون هناك المزيد من التطابقات إذا لم يكن b ثم فاصل النهاية - CMD.EXE لا يمكنه الطباعة النقط ، لذلك نقوم بتحويلها إلى نجوم. طباعة (تنسيق سلسلة ('٪ XNUMXX:٪ s'، b، m: gsub ('xCF ٪٪'، '*'))) نهاية
الكود من المادة: SEARCHKP.LUA
- اقرأ في ملف التفريغ المحدد في سطر الأوامر المحلي f = io.open (arg [1]، 'rb'): اقرأ ('* a') local b، e، m، p = 0,0،25، nil، nil بينما صحيح - الآن ، نريد واحدة أو أكثر من النقط (CF0) متبوعة بالرمز - لـ A..Z متبوعًا بـ 16 بايت لتحويل ACSCII إلى UTF-00 b ، e ، m = f: find (' (xCF ٪٪ [xCF ٪٪] * [AZ]) x1 '، e + 08) - الخروج عندما لا يكون هناك المزيد من التطابقات إن لم يكن b ثم كسر النهاية - CMD.EXE لا يمكنه طباعة النقاط الكبيرة ، لذلك نقوم بتحويلها إلى النجوم. - لتوفير مساحة ، نمنع التطابقات المتتالية إذا كانت m ~ = p ثم اطبع (string.format ('٪ XNUMXX:٪ s'، b، m: gsub ('xCF ٪٪'، '*'))) p = m نهاية النهاية
- محتوى مدعوم من تحسين محركات البحث وتوزيع العلاقات العامة. تضخيم اليوم.
- أفلاطونايستريم. ذكاء بيانات Web3. تضخيم المعرفة. الوصول هنا.
- سك المستقبل مع أدرين أشلي. الوصول هنا.
- شراء وبيع الأسهم في شركات ما قبل الاكتتاب مع PREIPO®. الوصول هنا.
- المصدر https://nakedsecurity.sophos.com/2023/05/31/serious-security-that-keepass-master-password-crack-and-what-we-can-learn-from-it/
- :لديها
- :يكون
- :ليس
- :أين
- ] [ص
- $ UP
- 1
- 10
- 12
- 15%
- 20
- 200
- 2023
- 24
- 250
- 27
- 31
- 3d
- 49
- 50
- 67
- 70
- 72
- 77
- 8
- 9
- a
- ماهرون
- من نحن
- فوق
- مطلق
- AC
- الوصول
- حسابي
- كسب
- كسب
- نشط
- يقدم
- في الواقع
- وأضاف
- إضافي
- العنوان
- عناوين
- يضيف
- بعد
- بعدئذ
- مرة أخرى
- الكل
- تخصيص
- يخصص
- توزيع
- المخصصات
- السماح
- وحده
- على طول
- سابقا
- أيضا
- تغيير
- بالرغم ان
- دائما
- an
- و
- أندرو
- إجابة
- أي وقت
- اى شى
- أي شيء حرج
- تظهر
- ظهر
- نهج
- من وزارة الصحة
- هي
- حول
- البند
- مقالات
- AS
- At
- المؤلفة
- السيارات
- أوتوماتيك
- تلقائيا
- متاح
- تجنب
- تجنب
- علم
- بعيدا
- الى الخلف
- خلفية
- خلفية الصورة
- BE
- لان
- يصبح
- كان
- قبل
- البداية
- وراء
- خلف الكواليس
- أقل من
- أفضل
- قطعة
- حظر
- Blocks
- الحدود
- على حد سواء
- الملابس السفلية
- العلامة تجارية
- جديدة
- استراحة
- موجز
- جلب
- العازلة
- تجاوز سعة المخزن المؤقت
- علة
- البق
- نساعدك في بناء
- لكن
- by
- C + +
- دعوة
- دعوة
- CAN
- يستطيع الحصول على
- يهمني
- حقيبة
- اشتعلت
- CD
- مركز
- بالتأكيد
- السلاسل
- فرصة
- غير
- حرف
- الأحرف
- تدقيق
- الشيكات
- الصينية
- اختار
- واضح
- بوضوح
- اغلاق
- الكود
- اللون
- COM
- يأتي
- آت
- التعليق
- تعليقات
- مشترك
- إكمال
- مجمع
- الكمبيوتر
- نظر
- كبير
- نظرت
- تتكون
- بناء
- محتوى
- محتويات
- باستمرار
- تواصل
- مراقبة
- تحول
- حقوق الطبع والنشر
- المقابلة
- استطاع
- بهيكل
- صدع
- خلق
- خلق
- الخالق
- حرج
- الأمن السيبراني
- DANGER
- خطير
- البيانات
- تسرب البيانات
- أيام
- صفقة
- قررت
- مخصصة
- وصف
- فعل
- الخلافات
- مختلف
- صعوبة
- DIG
- رقمي
- مباشرة
- الوصول المباشر
- مباشرة
- العرض
- عرض
- التصرف
- do
- وثائق
- هل
- لا
- فعل
- فعل
- لا
- إلى أسفل
- قيادة
- اثنان
- تفريغ
- أثناء
- e
- كل
- في وقت سابق
- بسهولة
- النظام الإيكولوجي
- إما
- آخر
- رسائل البريد الإلكتروني
- تمكين
- مشجع
- التشفير
- النهاية
- ينتهي
- كاف
- ضمان
- ضمان
- أدخل
- الدخول
- كامل
- دخول
- البيئة
- معادل
- خطأ
- أساسيا
- مقدر
- إلخ
- الأثير (ETH)
- حتى
- في النهاية
- يتزايد باستمرار
- كل
- كل شىء
- بالضبط
- مثال
- إلا
- إثارة
- يوجد
- القائمة
- خروج
- الخروج
- توقع
- شرح
- استغلال
- مكشوف
- مد
- احتفل على
- استخراج
- حقيقة
- زائف
- ساحر
- المميزات
- ردود الفعل
- أقل
- قتال
- قم بتقديم
- ملفات
- تصفية
- نهائي
- أخيرا
- العثور على
- ويرى
- نهاية
- الاسم الأول
- ثابت
- تركز
- يتبع
- متابعيك
- في حالة
- النموذج المرفق
- رسميا
- شكل
- قادم، صريح، يظهر
- وجدت
- أربعة
- مجانًا
- تبدأ من
- بالإضافة إلى
- تماما
- وظيفة
- وظائف
- إضافي
- مستقبل
- يولد
- جيل
- دولار فقط واحصل على خصم XNUMX% على جميع
- الحصول على
- GitHub جيثب:
- منح
- معطى
- يعطي
- إعطاء
- Go
- يذهب
- الذهاب
- خير
- حكومة
- انتزاع
- عظيم
- ضمان
- كان
- مقابض
- حدث
- حدث
- يحدث
- الثابت
- يملك
- وجود
- الصداع
- ثقيل
- ارتفاع
- هنا
- HEX
- رفيع المستوى
- أعلى
- المشاهدات
- عقد
- حفرة
- أمل
- ساعات العمل
- تحوم
- كيفية
- كيفية
- HTTPS
- مطاردة
- i
- معرف
- if
- فورا
- أهمية
- in
- يشمل
- بما فيه
- معلومات
- وأبلغ
- بدلًا من ذلك
- يستفد
- متوسط
- Internet
- إلى
- مسائل
- IT
- انها
- نفسها
- رطانة
- يونيو
- م
- واحد فقط
- احتفظ
- القفل
- علم
- معروف
- الكوريّة
- لغة
- اللغات
- كمبيوتر محمول
- اسم العائلة
- الى وقت لاحق
- قيادة
- يؤدي
- تسرب
- التسريبات
- تعلم
- تعلم
- الأقل
- مغادرة
- اليسار
- الطول
- خطاب
- المكتبة
- الحياة
- مثل
- على الأرجح
- محدود
- خط
- خطوط
- قائمة
- المدرج
- ll
- تحميل
- محلي
- موقع
- تسجيل
- طويل
- طويل الأجل
- يعد
- بحث
- يبدو مثل
- بدا
- أبحث
- تبدو
- الكثير
- حظ
- تحتفظ
- جعل
- البرمجيات الخبيثة
- إدارة
- تمكن
- إدارة
- مدير
- يدير
- تلاعب
- كثير
- هامش
- علامة
- علامة
- رئيسي
- مباراة
- مطابقة
- ماكس العرض
- مايو..
- يعني
- مكبر الصوت : يدعم، مع دعم ميكروفون مدمج لمنع الضوضاء
- المذكورة
- مایکروسافت
- ربما
- دقائق
- متواضع
- تم التعديل
- تعديل
- لحظة
- مراقبة
- الأكثر من ذلك
- أكثر
- كثيرا
- متعدد
- أنيق
- حاجة
- بحاجة
- صاف
- أبدا
- مع ذلك
- جديد
- أخبار
- التالي
- رحلة جميلة
- لا
- عادي
- لا شى
- يلاحظ..
- الآن
- عدد
- أرقام
- موضوع
- واضح
- of
- خصم
- رسمي
- رسميا
- عوض
- قديم
- on
- مرة
- ONE
- فقط
- المصدر المفتوح
- تعمل
- نظام التشغيل
- أنظمة التشغيل
- عامل
- خيار
- or
- طلب
- أصلي
- أخرى
- أخرى
- وإلا
- لنا
- أنفسنا
- خارج
- الناتج
- على مدى
- الكلي
- الخاصة
- صفحة
- ذعر
- جزء
- كلمة المرور
- إدارة كلمة المرور
- كلمات السر
- مسار
- نمط
- بول
- وقفة
- فى المائة
- ربما
- فترة
- بشكل دائم
- الشخصية
- البيانات الشخصية
- مادي
- صورة
- قطعة
- المكان
- النائب
- طاعون
- أفلاطون
- الذكاء افلاطون البيانات
- أفلاطون داتا
- وفرة
- البوينت
- نقاط
- الرائج
- ان يرتفع المركز
- ممكن
- المنشورات
- محتمل
- على وجه التحديد
- يقدم
- جميل
- منع
- سابق
- السعر
- طباعة
- مطبوعات
- المحتمل
- مشاكل
- عملية المعالجة
- البرنامج
- مبرمج
- المبرمجين
- برمجة وتطوير
- البرامج
- واضح
- وضع
- بايثون
- سؤال وجواب
- سؤال
- يثير
- رامات
- عشوائية
- نطاق
- بدلا
- الخام
- مسودة بيانات
- RE
- التي تم الوصول إليها
- عرض
- نادي القراءة
- استعداد
- حقيقي
- الحياه الحقيقيه
- في الوقت الحقيقي
- في الحقيقة
- تعرف
- استعادة
- يتعافى
- ذات صلة
- المتبقية
- تذكر
- عن بعد
- إزالة
- كرر
- متكرر
- مرارا وتكرارا
- تقرير
- ممثلة
- احترام
- على التوالي
- REST
- النتائج
- عائد أعلى
- عودة
- كشف
- تخلص من
- حق
- المخاطرة
- المخاطر
- غرفة
- يجري
- تشغيل
- مراقبة وقت التشغيل
- s
- خزنة
- أكثر أمانا
- نفسه
- راض
- حفظ
- قول
- تفحص
- مبعثر
- مشاهد
- بحث
- البحث
- الثاني
- ثواني
- سيكريت
- القسم
- تأمين
- أمن
- انظر تعريف
- بذرة
- رؤية
- بدا
- رأيت
- يرى
- مسلسلات
- جدي
- طقم
- ضبط
- قصير
- قريبا
- ينبغي
- إظهار
- أظهرت
- إشارة
- لوحات
- مماثل
- وبالمثل
- الاشارات
- مبسط
- تبسيط
- ببساطة
- عزباء
- مقاس
- النوم
- صغير
- متستر
- التطفل
- So
- تطبيقات الكمبيوتر
- الصلبة
- بعض
- شيء
- قريبا
- مصدر
- شفرة المصدر
- الفضاء
- تختص
- خصيصا
- محدد
- سرعة
- نجوم
- بداية
- بدأت
- ابتداء
- يبدأ
- بدء التشغيل
- لا يزال
- نهب
- قلة النوم
- توقف
- متجر
- تخزين
- قصتنا
- خيط
- قوي
- دراسة
- بنجاح
- هذه
- كاف
- مفترض
- مفاجأة
- مندهش
- مفاجئ
- البقاء على قيد الحياة
- SVG
- مقايضة
- نظام
- أنظمة
- أخذ
- اتخذت
- يأخذ
- مع الأخذ
- الحديث
- فنيا
- تقنيات
- مؤقت
- تجربه بالعربي
- اختبارات
- من
- أن
- •
- المصدر
- من مشاركة
- منهم
- أنفسهم
- then
- نظرية
- هناك.
- وبالتالي
- هم
- شيء
- اعتقد
- هؤلاء
- على الرغم من؟
- فكر
- الوقت
- عنوان
- إلى
- سويا
- استغرق
- أداة
- تيشرت
- مسار
- تتبع الشحنة
- انتقال
- شفاف
- صحيح
- محاولة
- تحول
- اثنان
- نوع
- عادة
- فهم
- يونيكود
- حتى
- غير المستخدمة
- غير مرغوب فيه
- تحديث
- تحديث
- URL
- us
- الحكومة الأمريكية
- الأستعمال
- USB
- تستخدم
- استخدام خالية بعد
- مستعمل
- مستخدم
- يستخدم
- استخدام
- سهل حياتك
- قيمنا
- القيم
- تشكيلة
- تحقق من
- الإصدار
- جدا
- بواسطة
- الضعف
- W
- انتظر
- انتظار
- تريد
- مطلوب
- وكان
- شاهد
- طريق..
- طرق
- we
- أسابيع
- حسن
- كان
- ابحث عن
- متى
- سواء
- التي
- في حين
- من الذى
- من
- كامل
- لماذا
- سوف
- كسب
- نوافذ
- مسح
- مع
- بدون
- يتساءل
- كلمات
- للعمل
- عمل
- عامل
- أعمال
- قلق
- سوف
- كنت لأعطي
- اكتب
- جاري الكتابة
- مكتوب
- حتى الآن
- لصحتك!
- حل متجر العقارات الشامل الخاص بك في جورجيا
- نفسك
- زفيرنت
- صفر