
مرحبًا ، اسمي أندري باتوتين ، وأنا كبير مطوري iOS في DataArt. في
مقال سابق ، تحدثنا عن كيفية التعرف على حركة مرور تطبيق الجوال لدينا باستخدام وكيل HTTPS. سنناقش في هذا كيفية تجاوز تثبيت SSL. تحسبًا لذلك ، أوصي بقراءة المقالة الأولى إذا لم تكن قد قرأتها بعد: ستكون هناك حاجة لفهم النص أدناه.
في الواقع ، يتم استخدام SSL Pinning في الممارسة العملية بحيث لا يمكن الوصول إلى الطريقة الموصوفة لفحص وتعديل حركة مرور تطبيق الهاتف المحمول من قبل الأشرار أو الطهاة الفضوليين.
ما هو تثبيت SSL
في المقالة السابقة ، قمنا بتثبيت شهادة Charles Root على الجهاز المحمول الخاص بنا ، والذي سمح لوكيل Charles Proxy باستقبال وفك تشفير وإظهار حركة المرور وتشفيرها وإرسالها إلى Dropbox.
إذا كنت بصفتي مطورًا لتطبيق جوّال ، فإنني أريد فحص حركة المرور الخاصة بي فقط من خلال الخادم الخاص بي وليس أي شخص آخر ، حتى لو قام هذا الآخر بتثبيت شهادة SSL الخاصة به على الجهاز ، فيمكنني استخدام تثبيت SSL.
يتلخص جوهرها في حقيقة أنه أثناء
تبادل اتصال SSL ، يتحقق العميل من الشهادة التي تم تلقيها من الخادم.
تتناول هذه المقالة أسهل طريقة لتثبيت SSL لتطبيقها باستخدام قائمة مسموح بها من الشهادات السلكية في التطبيق (القائمة البيضاء).
يمكن العثور على المزيد حول أنواع تثبيت SSL
هنا .
تنفيذ تثبيت SSL في FoodSniffer
رمز المشروع الكامل
هنا . أولاً ، نحتاج إلى الحصول على شهادتين بتنسيق DER لمضيفين:
يخزن الخادم الثاني JSON نفسه مع قائمة بمشترياتنا.
للحصول على الشهادات بالتنسيق الصحيح ، استخدمت Mozila Firefox.
افتح موقع dropbox.com في المتصفح.
انقر فوق رمز القفل في شريط العنوان.


انقر فوق مزيد من المعلومات ، وحدد الأمان -> عرض الشهادة.

ثم حدد التفاصيل وابحث عن الشهادة النهائية في التسلسل الهرمي للشهادة.

انقر فوق تصدير وحفظ بتنسيق DER.

كرر نفس الإجراء لـ uc9b17f7c7fce374f5e5efd0a422.dl.dropboxusercontent.com.
ملاحظةيستخدم خادم محتوى Dropbox (* .dl.dropboxusercontent.com) شهادة حرف بدل. لذا ، فإن الشهادة التي استخرجتها لخادم uc9b17f7c7fce374f5e5efd0a422 ستكون مناسبة لأي خوادم Dropbox * .dl.dropboxusercontent.com أخرى.
ونتيجة لذلك ، حصلت على ملفين بشهادات:
dropboxcom.crt ،
dldropboxusercontentcom.crt ،
الذي أضفته إلى مشروع تطبيق FoodSniffer iOS.

ثم أضفت امتدادًا لفئة FoodListAPIConsumer ، حيث أتحقق من الشهادة المستلمة من الخادم. للقيام بذلك ، أبحث عنه في قائمة الشهادات المسموح بها ، ومعالجة مفوض تحدي المصادقة لبروتوكول NSURLSessionDelegate:
extension FoodListAPIConsumer { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { guard let trust = challenge.protectionSpace.serverTrust else { completionHandler(.cancelAuthenticationChallenge, nil) return } let credential = URLCredential(trust: trust) if (validateTrustCertificateList(trust)) { completionHandler(.useCredential, credential) } else { completionHandler(.cancelAuthenticationChallenge, nil) } } func validateTrustCertificateList(_ trust:SecTrust) -> Bool{ for index in 0..<SecTrustGetCertificateCount(trust) { if let certificate = SecTrustGetCertificateAtIndex(trust, index){ let serverCertificateData = SecCertificateCopyData(certificate) as Data if ( certificates.contains(serverCertificateData) ){ return true } } } return false } }
في مصفوفة
الشهادات ، لدي بيانات تمثيل لشهاداتي المسموح بها.
الآن ، عند تشغيل Charles Proxy ، سيتم فصل التطبيق عنها لأنه لم يتم تضمين شهادة Charles في قائمة المسموح بها. سيرى المستخدم الخطأ التالي:

هزم القراصنة!
ولكن الآن هناك مشكلة صغيرة واحدة - كيف يمكنني ، المطور ، مراقبة حركة مرور HTTPS للتطبيق الخاص بي؟
فريدا
أحد الخيارات هو تعطيل تثبيت SSL باستخدام إطار حقن الشفرة الديناميكي لإطار عمل
Frida .
الفكرة هي أن أسلوب
validateTrustCertificateList دائمًا ما يرجع بشكل صحيح أثناء تطوير التطبيق.
يمكن تحقيق ذلك ، بالطبع ، بدون
إدخال رمز ديناميكي ، على سبيل المثال ، باستخدام
شرط #if targetEnvironment (simulator) لتعطيل تثبيت SSL على المحاكي ، ولكنه بسيط للغاية.
باستخدام Frida ، يمكننا كتابة نص جافا سكريبت (بذكاء ، أليس كذلك؟) نستبدل فيه تطبيق validateTrustCertificateList بأخرى تُرجع دائمًا true.
وسيتم حقن هذا البرنامج النصي في التطبيق في مرحلة التنفيذ.
كيف تعمل فريدا على نظام iOS ، يمكنك القراءة
هنا .
تركيب فريدا (مأخوذ من هنا ).
sudo pip تثبيت أدوات فريدانص فريدا
يبدو النص البرمجي المباشر لاستبدال دالة validateTrustCertificateList كما يلي:
// Are we debugging it? DEBUG = true; function main() { // 1 var ValidateTrustCertificateList_prt = Module.findExportByName(null, "_T016FoodSnifferFrida0A15ListAPIConsumerC024validateTrustCertificateD0SbSo03SecG0CF"); if (ValidateTrustCertificateList_prt == null) { console.log("[!] FoodSniffer!validateTrustCertificateList(...) not found!"); return; } // 2 var ValidateTrustCertificateList = new NativeFunction(ValidateTrustCertificateList_prt, "int", ["pointer"]); // 3 Interceptor.replace(ValidateTrustCertificateList_prt, new NativeCallback(function(trust) { if (DEBUG) console.log("[*] ValidateTrustCertificateList(...) hit!"); return 1; }, "int", ["pointer"])); console.log("[*] ValidateTrustCertificateList(...) hooked. SSL pinnig is disabled."); } // Run the script main();
- نجد المؤشر للتحقق من صحة قائمة الشهادات في التطبيق الثنائي من خلال الاسم الكامل للدالة.
- نقوم بلف المؤشر في غلاف NativeFunction ، مشيرًا إلى نوع المعلمة وقيمة الإخراج للدالة.
- استبدل تنفيذ وظيفة validateTrustCertificateList بدالة تُرجع دائمًا 1 (أي صواب).
النص البرمجي بالكامل موجود في
{source_root} /fridascrpts/killCertPinnig.js .
إحدى المشاكل هي كيفية الحصول على الاسم الكامل للدالة
_T016FoodSnifferFrida0A15ListAPIConsumerC024validateTrustCertificateD0SbSo03SecG0CFلهذا ، استخدمت الأسلوب التالي.
- إنشاء هدف FoodSnifferFrida إضافي في التطبيق.
- لقد قمت بتوصيل مكتبة FridaGadget.dylib بها ، والتي أخذتها هنا. يتم وصف إجراء اتصال المكتبة بمزيد من التفاصيل هنا.
- تم إطلاق تطبيق FoodSniffer على جهاز المحاكاة.
- استخدم هذا الأمر للعثور على اسم الوظيفة المؤهلة بالكامل ValidateTrustCertificateList :
frida-trace -R -f re.frida.Gadget -i "* validateTrust *" - حصلت عليه في الشكل:

ثم استخدمه في
killCertPinnig.js .
لماذا وصل هذا الاسم "الغريب" إلى نهايته في النهاية وماذا يمكن أن يُرى
هنا عن كل هذه T016 و 0 A15.
قتل SSL تعلق
الآن ابدأ تشغيل FoodSniffer مع تعطيل SSL Pinnig!
ابدأ تشغيل Charles Proxy.
قم بتشغيل FoodSnifferFrida الهدف في مشروع Xcode في المحاكي. يجب أن نرى شاشة بيضاء فقط. التطبيق ينتظر فريدا للاتصال به.

قم بتشغيل فريدا لتنفيذ البرنامج النصي
killCertPinnig.js :
frida -R -f re.frida.Gadget -l ./fridascrpts/killCertPinnig.jsدعنا ننتظر الاتصال بتطبيق iOS:

تابع التطبيق باستخدام الأمر استئناف استئناف:

الآن يجب أن نرى قائمة الطعام في التطبيق:

و JSON في وكيل Charles:

ربح!
الخلاصة
فريدا هي مثل Wireshark للثنائيات. يعمل على أنظمة تشغيل iOS و Android و Linux و Windows. يسمح لك هذا الإطار بتتبع المكالمات إلى الأساليب والوظائف - كل من النظام والمستخدم. وأيضًا استبدال قيم المعلمات وقيم الإرجاع وتنفيذ الوظائف.
قد يبدو تجاوز تجاوز تثبيت SSL في بيئة تطوير باستخدام Frida
مبالغة قليلاً. يجذبني ذلك لأنني لست بحاجة إلى أن يكون لدي منطق محدد في التطبيق لتصحيح الأخطاء وتطوير التطبيق. هذا المنطق يفسد الشفرة ، وإذا تم تنفيذه بشكل غير صحيح ، يمكن أن يتسرب إلى نسخة إصدار التجميع (وحدات الماكرو ، مرحبًا بك!).
بالإضافة إلى ذلك ، Frida ينطبق على Android. وهو ما يتيح لي الفرصة لتسهيل الحياة على فريقي بأكمله وضمان عملية سلسة لتطوير خط الإنتاج بأكمله.
تضع فريدا نفسها كأداة لحقن كود عملية الصندوق الأسود. مع ذلك ، من الممكن ، دون تغيير الكود المباشر لتطبيق iOS ، إضافة طريقة تسجيل المكالمات إلى وقت التشغيل ، والتي يمكن أن تكون لا غنى عنها عند تصحيح الأخطاء المعقدة والنادرة.