في هذه المقالة ، أريد أن أخبركم كيف قمت باختراق عدة أجزاء من بروتوكول WhatsApp VoIP باستخدام جهاز iOS مكسور الحماية ومجموعة من برامج التحليل المختلفة.
في الآونة الأخيرة ، تلقى Whatsapp الكثير من الاهتمام بسبب نقاط الضعف وفرص المتسللين.
من وجهة النظر هذه ، من المهم جدًا إجراء بحث حول سلامته.
كل من يهتم بهذا أيضًا ، مرحبًا به تحت القط.
على الرغم من أن الصفحات الرسمية لـ Whatsapp تحتوي على وصف لتشفيرها ، في الواقع ، لا توجد معلومات مفصلة في أي مكان حول كيفية عملها وكيفية تنفيذها في البروتوكول.
وبالتالي ، لا يوجد أساس لتحليلات أمنية مفصلة على Whatsapp نفسه.
وكان بحثي يقوم على ثلاثة أمور:
1. تحليل حركة مرور شبكة الاتصال
2. ثنائيات
تحليلات تحليلات السلوك 3. تطبيق في أوضاع مختلفة
أدوات
لتحليل العميل Wahtsapp لدائرة الرقابة الداخلية، واستخدمت الأدوات التالية:
- ثنائي اصف - bfdecrypt
المجمع ثنائي ملف - - هوبر مفكك وradare2
- تحليل حركة مرور الشبكة - Wireshark
- تحليلات إجراءات التطبيق - Frida
إن كيفية إعداد كسر الحماية على iOS خارج نطاق هذه المقالة.
تحليل حركة مرور الشبكة
في هذا الجزء ، سنقوم بتحليل حركة مرور الشبكة لعميل Whatsapp أثناء المكالمة ، والتي سنقوم بتسجيلها باستخدام Wireshark.
لتسجيل حركة المرور هذه ، قمت بإنشاء واجهة شبكة افتراضية بعيدة.
يبدو الأمر الخاص بـ
Makos كما يلي : rvictl -s هنا يحتاج UUID للجهاز إلى استبدال UUID الخاص بالجهاز مع عميل watsap.
يكتشف Wireshark استخدام أدوات اجتياز الجلسة لـ NAT (STUN).
STUN هو بروتوكول إشارات مطلوب لإنشاء اتصالات من نظير إلى نظير بين العملاء.
هنا يستخدم عميل WhatsApp حزم TCP للتواصل مع خوادم Watzap المختلفة.
في نفس الوقت ، يتم استخدام حزم UDP للتبادل بين العملاء.
تمر مئات حزم UDP في دقيقة واحدة.
يستخدم Vatsap بروتوكول الوقت الحقيقي الآمن (SRTP) ومن الواضح أن حزم UDP هذه تحتوي على بيانات SRTP حول المكالمة.
يوفر بروتوكول SRTP التشفير والمصادقة والحماية من هجمات إعادة التشغيل على حركة مرور RTP.
دعونا نلقي نظرة فاحصة على حزم SRTP المتبادلة بين الجانبين A و B.
للقيام بذلك ، قم بتحويلها إلى نظام سداسي عشري:
يمكن ملاحظة أن الحقول تحتوي على رؤوس RTP خاصة بـ SRTP.
أول أربعة بايت (مظللة باللون الأحمر) هي 7 حقول رأس RTP.
دعونا نفكر فيها بمزيد من التفصيل:
0x8078001e = 0b10_0_0_0000_0_111100_00000000000011110 = V = 10 | P = 0 | X = 0 | CC = 0000 | M = 0 | PT = 111100 | SEQ = 00000000000011110
أول 2 بت تحتوي على رقم الإصدار (V) ، في حالتنا هو الإصدار الثاني.
البتة الثالثة هي حقل للمعلومات الاختيارية ، وهي فارغة في حالتنا.
البتة الرابعة - يشير حقل الامتداد (X) إلى أنه في هذه الحالة لا توجد رؤوس أخرى بعد رأس حزمة RTP.
البتات من 5 إلى 8 - تحتوي على عدد معرفات CSRC التي تلي الرأس الدائم.
CSRC (المصدر المساهم) هو مصدر تدفق حزم RTP الذي يساهم في إجمالي التدفق الناتج عن خالط RTP. يقوم الخلاط بإدراج قائمة بمعرفات SSRC التي تحدد المصادر الجزئية في رأس حزم RTP. هذه القائمة تسمى قائمة CSRC. على سبيل المثال - مؤتمر صوتي حيث يقوم الخلاط بتمييز جميع السماعات التي يصدر صوتها حزمًا صادرة. يسمح هذا للجانب المستلم بتحديد المتحدث ، على الرغم من أن جميع الحزم لها نفس معرف SSRC.
8 بت هو علامة بت (M). تستخدم على مستوى التطبيق ويحددها ملف التعريف. إذا تم تعيين هذا الحقل ، فإن بيانات الحزمة لها معنى خاص للتطبيق.
6 بتات التالية هي رموز نوع بيانات إضافية. لم يتم تعريف هذه البيانات في معايير RTP و SRTP. من المرجح أن يكون معنى هذه البتات مخصصًا اختاره Whatsapp.
تشير آخر 17 بت إلى مصدر الساعة. يتم زيادة الرقم بمقدار 1 بالترتيب عند إرسال حزمة بيانات RTP التالية ، ويمكن للمستقبل استخدام هذا الرمز لتسجيل خسائر الحزمة واستعادة الترتيب الحقيقي للأجزاء المرسلة. وفقًا للمعيار ، تكون القيمة الأولية للرمز عشوائية ، ولكن لا يتم تنفيذ هذه التوصية بواسطة watsap ، لأنه كما يمكننا أن نرى من بيانات Wireshark ، فإن القيمة الأولية لـ watsap هي دائمًا 0.
البايتات الأربعة التالية (المميزة باللون الأزرق) هي الطابع الزمني للحزمة.
4 بايت بعد ذلك (أخضر) - حقل SSRC. يحدد مصدر التزامن. يتم اختيار هذا المعرف عشوائيًا بحيث لا يوجد رمزان متساويان لـ SSRC في جلسة RTP واحدة. يجب أن تكون جميع التطبيقات قادرة على الكشف عن تساوي SSRC. إذا قام المرسل بتغيير عنوان النقل الخاص به ، فيجب عليه أيضًا تغيير معرف SSRC.
لذلك ، اكتشفنا أن Whatsapp يستخدم SRTP لحماية المكالمات.
تم تأكيد ذلك من خلال بنية حزم UDP المتبادلة بين عملاء Watcap.
أيضًا ، يستخدم Watzap بروتوكول TCP لتبادل البيانات بين العميل والخادم.
أدناه سوف نرى كيف يتم استخدام بروتوكول Noise Pipes لتشفير هذا الجزء التحليلات الثنائية
يحتوي عميل WhatsApp لنظام iOS على ثنائيين رئيسيين - تطبيق WhatsApp الثنائي وإطار عمل WhatsApp الأساسي.
في هذا الجزء ، سوف نلقي نظرة فاحصة عليها باستخدام أداة تفكيك النطاط والرادار 2.
يتم تشفير هذه الثنائيات عند تنزيلها من Appstore.
هنا خدعنا Apple في كسر حماية جهاز iOS والوصول إلى هذه الملفات.
أضف أيضًا أنه تم فك تشفير ثنائيات Whatsapp هذه باستخدام bfdecrypt.
بعد ذلك ، سأوضح لك كيف جمعت معلومات حول أساسيات البروتوكول والخوارزميات والمكتبات مفتوحة المصدر التي يستخدمها Whatsapp.
المكتبات مفتوحة المصدر مثيرة للاهتمام بشكل خاص لأنه يمكن تحليلها بسهولة.
libsignal- البروتوكول- ج
يستخدم Watsap libsignal-protocol-c - مكتبة مفتوحة المصدر - والتي طبقها في بروتوكول الإشارة.
يعتمد البروتوكول على خوارزمية السقاطة المزدوجة ، والتي تقوم بتشفير رسائل الواتساب.
تم العثور على هذه المكتبة في ثنائيات Whatsapp للميزات البارزة التالية:
r2 WhatsAppCore
[0x0082b517]> / _signal_
البحث عن 8 بايت في نتائج [0x0-0x654000]
: 33
0x00837a7b hit2_0 .il_key_data_from_signal_keydispatch_.
0x0083df33 hit2_1 ._torlice_signal_protocol_paramet.
0x008407c0 hit2_2 .d_fac_3key_signal_message_big.
0x00840d50 hit2_3 .mmetric_signal_protocol_paramet.
0x00840e70 hit2_4 .ob_signal_protocol_paramet.
0x00841492 hit2_5 .pre_key_signal_messagesigna.
0x008de24b hit2_6 .agc_reset_alice_signal_protocol_paramet.
0x008de274 hit2_7 .rs_create_alice_signal_protocol_paramet.
0x008de440 hit2_8 .bitno_MRDTX_bob_signal_protocol_paramet.
0x008de467 hit2_9 .ters_create_bob_signal_protocol_paramet.
0x008e311c hit2_10 .pre_big_pre_key_signal_message_copy_pr.
0x008e3139 hit2_11 .ge_copy_pre_key_signal_message_create_.
0x008e3158 hit2_12 ._create_pre_key_signal_message_deserial.
0x008e317c hit2_13 .rialize_pre_key_signal_message_destroy.libsrtp
libsrtp
Watsap أيضًا يستخدم libsrtp لتنفيذ بروتوكول الوقت الحقيقي الآمن.
تمت إزالة أسماء الرموز من ثنائيات Whatsapp ، ولكن على الرغم من ذلك ، تحتوي الثنائيات على سطور تشير مباشرة إلى ارتباطها بـ libsrtp:
r2 WhatsApp
[0x1001ada34]> / libsrtp
0x100ee5546 hit1_0 .rc٪ 08X خطأ libsrtp غير معروف٪ duns.
0x100ee57eb hit1_1 .d لتهيئة libsrtp:٪ s فشل في r.
0x100ee580a hit1_2 .led لتسجيل libsrtp deinit. فشل.
0x100ee5831 hit1_3. لإلغاء تفعيل libsrtp:٪ sAES_CM_128_.
0x100ee5883 Hit1_4 .ck crypto Init libsrtp. إنشاء تجمع ..
0x100f07b80 hit1_5. الحزمة:٪ slibsrtpstat اختبار٪ s: c.
علاوة على ذلك ، تحتوي ثنائيات watsap على سلاسل يتم استخدامها في كود libsrtp الخام ، على سبيل المثال "دفق الاستنساخ (SSRC: 0x٪ 08x)":
r2 WhatsApp
[0x1013ddb4f]> / cloning stream
البحث عن 14 بايت في [0x100000000-0x100fb4000]
النتائج: 1
0x100f07823 hit7_0 .sent! Srtp٪ s: استنساخ الدفق (SSRC: 0x٪ 08x).
PJSIP
أيضًا ، يستخدم watsap PJSIP ، الذي ينفذ اتصالات الوسائط المتعددة ، والإشارات ، وترميز بيانات الصوت والفيديو.
يتم أيضًا تنفيذ STUN هناك ، والذي يظهر بوضوح عند التحليل باستخدام Wireshark.
تم تحديد المكتبة بواسطة PJSIP بواسطة سلاسل في ثنائيات watcap بسبب معلومات التصحيح في PJSIP:
r2 WhatsApp
[0x1013ddb4f]> / pjmedia
البحث عن 7 بايت في نتائج [0x100000000-0x100fb4000]
: 180
0x100edd55f hit9_0.
0x100edd591 hit9_1 .r %d, stream %ppjmedia_audio_piggyback.
0x100edd5d4 hit9_2 .d, tx_packet %dpjmedia_audio_piggyback.
0x100edd601 hit9_3 .ideo_enabled %dpjmedia_audio_piggyback.
0x100eddcf3 hit9_4 .ibyuv converterpjmedia_converter_creat.
0x100eddd21 hit9_5 .rter count = %dpjmedia_converter_creat.
0x100ede3e3 hit9_6 .rame, status=%dpjmedia_delay_buf_get_s.
0x100ede46e hit9_7 .%sec_delay_bufpjmedia_echo_create2: %.
0x100ede64d hit9_8 .eUnknown pjmedia-videodev error.
0x100ede90c hit9_9 .o errorUnknown pjmedia-audiodev error.
0x100edebba hit9_10 .ATENCY)Unknown pjmedia error %dUnspec.
0x100ee027e hit9_11 .queue.format.cpjmedia_format_get_vide.
معلومات 0x100ee02ca hit9_12 .mat لـ٪ dpjmedia_format_get_vide.
0x100ee1446 hit9_13 .c_buf قصير جدًاpjmedia_h26x_packetize.
mbed TLS
أيضًا ، يستخدم Watzap بروتوكول TLS مفتوح المصدر لتنفيذ بروتوكول TLS الخاص به.
تم تحديد هذه المكتبة في كود Watzap بأسماء الوظائف التالية:
r2 WhatsAppCore
[0x0082b517]> / mbedtls
البحث عن 7 بايت في نتائج [0x814000-0x934000]
: 41
0x008e299b hit5_0 .TLSErrorDomain_mbedtls_aes_crypt_cbc
0x008e29b2 hit5_1 ._aes_crypt_cbc_mbedtls_aes_crypt_cfb12.
0x008e29cc hit5_2 .s_crypt_cfb128_mbedtls_aes_crypt_cfb8.
0x008e29e4 hit5_3 .aes_crypt_cfb8_mbedtls_aes_crypt_ctr_.
0x008e29fb hit5_4 ._aes_crypt_ctr_mbedtls_aes_crypt_ecb_.
0x008e2a12 hit5_5 ._aes_crypt_ecb_mbedtls_aes_decrypt_mb.
0x008e2a27 hit5_6 .ls_aes_decrypt_mbedtls_aes_encrypt_mb.
0x008e2a3c hit5_7 .ls_aes_encrypt_mbedtls_aes_free_mbedt.
0x008e2a4e hit5_8 .edtls_aes_free_mbedtls_aes_init_mbedt.
0x008e2a60 hit5_9 .edtls_aes_init_mbedtls_aes_setkey_dec.
0x008e2a78 hit5_10 .aes_setkey_dec_mbedtls_aes_setkey_enc.
0x008e2a90 hit5_11 .aes_setkey_enc_mbedtls_cipher_auth_dec.
0x008e2aad hit5_12 .r_auth_decrypt_mbedtls_cipher_auth_enc.
0x008e2aca hit5_13 .r_auth_encrypt_mbedtls_cipher_check_ta.
... يستخدم
XMPP
Watzap أيضًا بروتوكول المراسلة والتواجد المفتوح (XMPP) لتبادل الرسائل غير المتزامنة بين العملاء.
تم اكتشاف ذلك من خلال أسماء الفئات في كود watsap المستخدم في XMPP:
r2 WhatsApp
[0x1013ddb4f]> / XMPP
البحث عن 4 بايت في نتائج [0x1013ac000-0x1014b4000]
: 150
البحث عن 4 بايت في [0x100fb4000-0x1013ac000]
مرات: 150
البحث في 4 بايت في [0x100000000-0x100fb4000]
يضرب: 396
0x1013d05b5 hit12_0. @ _ OBJC_CLASS _ $ _ XMPPAckStanza @ _.
0x1013d05d6 hit12_1. @ _ OBJC_CLASS _ $ _ XMPPBinaryCoder.
0x1013d05fa hit12_2. @ _ OBJC_CLASS _ $ _ XMPPCallStanza.
0x1013d0624 hit12_3. @ _ OBJC_CLASS _ $ _ XMPPChatStateStanza.
0x1013d064b hit12_4. @ _ OBJC_CLASS _ $ _ XMPPConnection.
0x1013d0679 hit12_5. @ _ OBJC_CLASS _ $ _ XMPPError.
0x1013d069e hit12_6. @ _ OBJC_CLASS _ $ _ XMPPGDPRDeleteReport.
0x1013d06cd hit12_7. @ _ OBJC_CLASS _ $ _ XMPPGDPRGetReportSta.
0x1013d0707 hit12_8. @ _ OBJC_CLASS _ $ _ XMPPGDPRRequestRepor.
0x1013d0736 hit12_9. @ _ OBJC_CLASS _ $ _ XMPPIQStanza.
0x1013d0762 hit12_10. @ _ OBJC_CLASS _ $ _ XMPPMessageStanza.
0x1013d0787 hit12_11. @ _ OBJC_CLASS _ $ _ XMPPMessageStatusCha.
0x1013d07b9 hit12_12. @ _ OBJC_CLASS _ $ _ XMPPMultiReceipt.
0x1013d07dc hit12_13. @ _ OBJC_CLASS _ $ _ XMPPNotificationStan.
...
إطار بروتوكول الضوضاء
وفقًا للتقارير الرسمية ، يستخدم Watzap إطار بروتوكول الضوضاء للتواصل بشكل آمن بين العملاء والخوادم.
تم تصميم إطار عمل بروتوكول الضوضاء لإنشاء بروتوكولات تشفير سهلة الاستخدام باستخدام مجموعة من الكتل المنفصلة.
ولكن بالمعنى الدقيق للكلمة ، يستخدم Watzap فقط بروتوكول أنابيب الضوضاء ، والذي تم أخذه من إطار بروتوكول الضوضاء الأكثر اكتمالا.
تم العثور على هذه الخطوط في ثنائيات Watzap:
“Noise_XX_25519_AESGCM_SHA256” ،
• “Noise_IK_25519_AESGCM_SHA256” ،
• “Noise_XXfallback_25519_AESGCM_SHA256”.
تحتوي هذه الأسطر على أنماط المصافحة المطبقة في عملاء watsap.
السطر الأول ينتمي إلى فئة WANoiseFullHandshake.
والثاني هو WANoiseResumeHandshake والأخير لـ WANoiseFallbackHandshak.
لن نفكر بالتفصيل في كيفية عمل هذا البروتوكول في إطار هذه المقالة.
تحليل وقت التشغيل
في هذا الجزء ، سوف نستكشف سلوك عميل watsap باستخدام Frida.
Frida هي ما يسمى بـ Dinamic Instrumentation Toolkit ، وهي عبارة عن مجموعة من الأدوات التي تسمح لك بحقن الكود الخاص بك في تطبيقات أخرى أثناء التنقل.
سنتصل بعملية ما في التطبيق ونغير سلوكها باستخدام وحدة تحكم JS تفاعلية.
مفتاح النقل
في هذا الجزء ، سوف نستكشف الآليات الرئيسية لعمل بروتوكول watcap.
وفقًا للوصف الرسمي من Whatsapp الذي يصف تشفير مكالمة VOIP - يقوم بادئ المكالمة بإنشاء سر رئيسي لـ SRTP 32 بايت.
ثم يتم إرسال الرسالة المشفرة إلى الجانب B مع محتوى سر SRTP الرئيسي.
تُستخدم هذه المعلومات بعد ذلك لإعادة بناء الجانب B.
أولاً ، قمت بالتتبع باستخدام كلمة "سر":
frida-trace -U WhatsApp -m "* [* * Secret *]" -m "* [* * secret *]"
بعد بدء استدعاء طريقة vatsap deriveSecretsFromInputKeyMaterial باستخدام فئة WAHKDF:
+ [WAHKDF
deriveSecretsFromInputKeyMaterial: 0x121e08a20
salt: 0x0
the info : 0x121e07840
outputLength: 0x2e
withMessageVersion: 0x3
]
تشير قيمتا الإدخال 0x121e08a20 و 0x121e07840 إلى كائنات Objective-C.
يتيح لك Frida إنشاء كائنات وكيل Objective-C لجافا سكريبت.
يتم استخدام خطاف deriveSecretsFromInputKeyMaterial لطباعة وصف الكائنات:
{
onEnter: function (log، args، state) {
log ("+ [WAHKDF deriveSecretsFromInputKeyMaterial:" +
ObjC.Object (args [2]) .toString () + "\ n" +
"salt:" + ObjC.Object (args [3]) .toString () + "\ n" +
"info:" + ObjC. الكائن (args [4]) .toString () + "\ n" +
"بايت:" + args [5] .toInt32 () + "\ n" +
"withMessageVersion:" + args [6] .toInt32 () + "\ ن]")؛
}
}
وبعد النصي:
+ [WAHKDF deriveSecretsFromInputKeyMaterial: <09a38e76 fe90e4f1 26ed66d0 5a6783ba d48776b6 1daaf7c9 39c005ea 2d8ccdf6>
الملح: لا شيء
من المعلومات: <34393135 39303537 37313632 3040732e 77686174 73617070 2e6e6574>
بايت: 46
withMessageVersion: 3
]
المعلمات الأول والثالث مثل الكائنات NSData والتي تحتوي على مخزن بايت ثابت.
يبلغ طول المعلمة الأولى 32 بايت ، كما هو موضح في المستند التعريفي التمهيدي لتطبيق WhatsApp.
المعلمة الثالثة هي سلسلة ASCII تحتوي على JID الخاص بالمستدعي.
سنرى لاحقًا أنه ، في الواقع ، هو السطر الأول الذي يحتوي على السر الرئيسي.
تشفير السر الرئيسي
وفقًا لورقة WhatsApp البيضاء ، يعد السر الرئيسي جزءًا ضروريًا لتأمين جلسة مكالمة.
لذلك ، يجب تسليمها بأمان إلى الجانب "ب"
. للتحقيق في كيفية حدوث هذا التسليم ، قمت بتتبع يحتوي على كلمات رئيسية ذات صلة بعملية التشفير:
frida-trace -U WhatsApp -m "* [* * crypt *]" "* crypt *"
بعد بدء المكالمة ، قم باستدعاء وظيفة signal_encrypt من مكتبة libsignal-protocol-c.
رأس Signal_encrypt:
نص عادي يمكن قراءته باستخدام خطاف فريدا:
تُستخدم أول 4 بايت في إجراء تسلسل للسر الرئيسي باستخدام مخازن بروتوكول Google المؤقتة.
(التسلسل هو عملية ترجمة بعض هياكل البيانات إلى سلسلة من البتات).
البايتات التالية هي السر الرئيسي نفسه.
آخر 13 بايت عبارة عن حشوة تشفير.
يتم تشفير النص العادي باستخدام AES-256 في وضع CBC.
يتم الحصول على مفاتيح التشفير باستخدام خوارزمية السقاطة المزدوجة ، والتي تعد جزءًا من بروتوكول الإشارة.
لم يتم تناول Libsignal-protocol-c و Signal Protocol في هذه المقالة. نتيجة
Signal_encrypt:
تحتوي النتيجة على المزيد من وحدات البايت لأنه تمت إضافة علامة مصادقة إلى الرسالة التي تستخدم HMAC-SHA256.
لقد قمنا بتغطية الجزء الأول من بروتوكول WhatsApp VoIP.
للتلخيص ، يتم تسلسل السر الرئيسي وتشفيره باستخدام مفتاح 256 بت AES في وضع CBC.
تم الحصول على مفتاح التشفير ومفتاح المصادقة باستخدام مكتبة libsignal-protocol-c مفتوحة المصدر.
تحليل السر الرئيسي
دعونا نرى كيف يتم تشفير السر الرئيسي.
نقوم بالتتبع باستخدام الكلمة الأساسية للإشارة:
frida-trace -U WhatsApp -i “* signal *”
Frida توضح أن وظيفة textecure__signal_message__pack تشارك في تشفير السر الرئيسي.
تنشئ الوظيفة رسالة Signal تحتوي على السر الرئيسي المشفر والمعلمات الأخرى المطلوبة: يتم استخدام
وحدات البايت المميزة باللون الأخضر للتسلسل.
بايت أزرق - مفتاح إرسال (يستخدم للتشفير من طرف إلى طرف).
عداد الرسائل برتقالي بايت.
أخيرًا ، يتم تمييز وحدات بايت السر الرئيسي باللون الأخضر.
عند تتبع XMPP ، يمكننا أن نرى أن طريقة writeNoiseFrameToSocketWithPayload من فئة XMPPStream تسمى.
ترسل هذه الطريقة رسائل XMPP مشفرة بواسطة بروتوكول Noise Pipes باستخدام بروتوكول TCP إلى خادم watchap.
فتحت هنا المحتوى في الحمولة:
هذه رسالة XMPP ثنائية تحتوي على رسالة التشوير التي تم إنشاؤها أعلاه.
من أجل التفكيك ، نقوم بإنشاء أثر لفئة XMPPBinaryCoder.
تحتوي هذه الفئة على طريقة تسلسل تنشئ تمثيلًا ثنائيًا لسلاسل XMPP.
عند عرض هذه المعلمات ، يمكنك رؤية أزواج مفاتيح متنوعة ملحقة برسالة XMPP:
- [تسلسل XMPPBinaryCoder:
[call from='49************@s.whatsapp.net '
id =' 1555415586-10 '
to='49**********@s.whatsapp.net '
[offer call-id ='
45D7827C624353A70084AED9B8C509D3'call-creator='49**********@s.whatsapp .net '
[معدل الصوت =' 8000 'enc =' opus ']
[معدل الصوت =' 16000 'enc =' opus ']
[net medium =' 3 ']
[قدرة ver =' 1 '{5b}]
[encopt keygen = '2']
[enc v = '2' type = 'pkmsg' {201b}]
]
]
مضغوط: 0x0]
تمكنت من عمل إشعار وهمي حول مكالمة فائتة من A إلى B ، على الرغم من أن مالوري قد بدأ بالفعل المكالمة ...
أصبح هذا ممكنًا بعد إعادة كتابة منشئ المكالمة ومن المعلمات في JID على الجانب A. على
الرغم من أن اسم Mallory يظهر في الإشعار.
عندما يبدأ الطرف "ب" في الرد على مثل هذه الرسالة ، يتم استدعاء الطرف "أ" بدلاً من مالوري.
سيكون هذا السلوك أكثر إثارة للاهتمام لتحليله لاحقًا.
دعونا نلخص النتائج الوسيطة - في watsap ، يتم تعبئة السر الرئيسي المشفر في رسالة إشارة ، والتي تتم إضافتها إلى سلاسل XMPP.
تحتوي سلاسل XMPP أيضًا على ID و JID لكلا الجانبين.
تمرير السر الرئيسي للطرف الآخر
وفقًا للوصف الرسمي من عملاء Watsup ، استخدم بروتوكول Noise Pipes مع Curve25519 و AESGCM و SHA256 من إطار بروتوكول الضوضاء.
إذا كنت تستخدم التتبع الذي يحتوي على الكلمات الأساسية المتعلقة بـ Noise Protocol Framework ، فيمكنك أن ترى أن فئة WANoiseStreamCipher تُستخدم لتشفير المكالمات إلى خوادم Vatsap.
يستخدم الفصل طريقة encryptPlaintext.
بعد بدء المكالمة ، تكون قيمة النص العادي هي رسالة XMPP الموضحة أعلاه.
ثم يتم تشفير الرسالة مرة أخرى باستخدام mbedtls_gcm_crypt_and_tag لمكتبة mbed TLS.
يبلغ حجم mbedtls_gcm_setkey 256 بت ، مما يعني استخدام AES-256-GCM.
يتم استخدام مفتاح التشفير من بروتوكول Noise Pipes ، والذي لم يتم تناوله في هذه المقالة.
ثم ينتقل النص العادي المشفر عبر TCP إلى خادم watsap (يمكن رؤية ذلك باستخدام Wireshark).
سيقوم الخادم بعد ذلك بإعادة توجيه هذه الرسالة إلى الطرف المتصل به لبدء المكالمة.
تشكيل المفتاح
في هذا الجزء ، سننظر في كيفية عمل وظيفة تشكيل المفتاح (KDF) /
تم الحصول على النتائج باستخدام Frida أثناء تتبع فئة WAHKDF ومكتبة libcommonCrypto.
تم استخدام فئة WAHKDF لاستخراج المفاتيح والملح وأكواد المرة الواحدة عند تهيئة تدفقات SRTP.
يتم استدعاء طريقة deriveSecretsFromInputKeyMaterial 10 مرات قبل بدء المكالمة:
+[WAHKDF deriveSecretsFromInputKeyMaterial: <09a38e76 fe90e4f1 26ed66d0 5a6783ba d48776b6 1daaf7c9 39c005ea 2d8ccdf6>, salt: nil, info: <34393135 39303537 37313632 3040732e 77686174 73617070 2e6e6574>, bytes: 46, withMessageVersion: 3] => result: <4633c47f 94d5ed59 93a6dba8 514d5fb8 5092ba90 4256f8d3 4d56e72e 665bcd4c 5b6c418b db811e7f 84a70c83 f401>+[WAHKDF deriveSecretsFromInputKeyMaterial: <09a38e76 fe90e4f1 26ed66d0 5a6783ba d48776b6 1daaf7c9 39c005ea 2d8ccdf6>, salt: nil, info: <34393137 ******** ******** ******** ******** 6170702e 6e6574>, bytes: 46, withMessageVersion: 3] => result: <a174670a e25d8138 4de0ed3b f4ce7f76 c62c1d00 9ece6573 2ecb497b 1f6ed09c 18c444b9 c180fbd3 51713739 761c>+[WAHKDF deriveSecretsFromInputKeyMaterial: <34354437 38323743 36323433 35334137 30303834 41454439 42384335 30394433>, salt: <00000000>, info: <34393135 39303537 37313632 3040732e 77686174 73617070 2e6e6574>, bytes: 4, withMessageVersion: 3] => result: <0ec654fd>+[WAHKDF deriveSecretsFromInputKeyMaterial: <34354437 38323743 36323433 35334137 30303834 41454439 42384335 30394433>, salt: <01000000>, info: <34393135 39303537 37313632 3040732e 77686174 73617070 2e6e6574>, bytes: 4, withMessageVersion: 3] => result: +[WAHKDF deriveSecretsFromInputKeyMaterial: <34354437 38323743 36323433 35334137 30303834 41454439 42384335 30394433>, salt: <04000000>, info: <34393135 39303537 37313632 3040732e 77686174 73617070 2e6e6574>, bytes: 4, withMessageVersion: 3] => result: +[WAHKDF deriveSecretsFromInputKeyMaterial: <34354437 38323743 36323433 35334137 30303834 41454439 42384335 30394433>, salt: <00000000>, info: <34393137 ******** ******** ******** ******** 6170702e 6e6574>, bytes: 4, withMessageVersion: 3] => result: +[WAHKDF deriveSecretsFromInputKeyMaterial: <34354437 38323743 36323433 35334137 30303834 41454439 42384335 30394433>, salt: <01000000>, info: <34393137 ******** ******** ******** ******** 6170702e 6e6574>, bytes: 4, withMessageVersion: 3] => result: +[WAHKDF deriveSecretsFromInputKeyMaterial: <34354437 38323743 36323433 35334137 30303834 41454439 42384335 30394433>, salt: <04000000>, info: <34393137 ******** ******** ******** ******** 6170702e 6e6574>, bytes: 4, withMessageVersion: 3] => result:
, JID .
6 SRTP , 3 .
JavaScript:
const crypto = require(«crypto»);
// master secret
const keyMaterial = new Buffer(
«09a38e76fe90e4f126ed66d05a6783bad48776b61daaf7c939c005ea2d8ccdf6»,
«hex»
);
// JID param: 4915905771620@s.whatsapp.net
const info = «3439313539303537373136323040732e77686174736170702e6e6574»;
const salt = new Buffer(
«0000000000000000000000000000000000000000000000000000000000000000»,
«hex»
);
const initialKey = crypto.createHmac(«sha256», salt)
.update(keyMaterial)
.digest();
const temp1 = crypto.createHmac(«sha256», initialKey)
.update(new Buffer(info + «01», «hex»))
.digest();
const temp2 = new Buffer(temp1.toString(«hex») + info + «02», «hex»);
const temp3 = crypto.createHmac(«sha256», initialKey)
.update(temp2)
.digest();
const result = Buffer.concat([temp1, temp3.slice(0, 14)]);
console.log(result.toString(«hex»));
// 4633c47f94d5ed5993a6dba8514d5fb85092ba904256f8d34d56e72e665bcd4c5b6c418bdb811e7f84a70
SRTP .
Frida.
KDF libcommonCrypto .
3 HMAC-SHA256.
KDF RFC 5869.
SRTP, libsrtp, VOIP .
, libsrtp .
.
libsrtp .
libsrtp , .
.
, libsrtp.
, .
libsrtp 12 .
Frida .
Frida.
srtp_aes_icm_context_init libsrtp.
SRTP AES-ICM.
, , .
srtp_aes_icm_context_init, 2 :
debug_print(srtp_mod_aes_icm, «key: %s»,
srtp_octet_string_hex_string(key, base_key_len));
debug_print(srtp_mod_aes_icm, «offset: %s», v128_hex_string(&c→offset));
debug_print .
, .
Hopper Disassembler:
int sub_100bbda00(int arg0, int arg1) {
r31 = r31 — 0x60;
var_30 = r24;
stack[-56] = r23;
var_20 = r22;
stack[-40] = r21;
var_10 = r20;
stack[-24] = r19;
saved_fp = r29;
stack[-8] = r30;
r19 = arg0;
sub_100bbf094(arg0, arg1 + 0x10);
r20 = r19 + 0x10;
sub_100bbf094(r20, arg1 + 0x10);
*(int16_t *)(r19 + 0x1e) = 0x0;
*(int16_t *)(r19 + 0xe) = 0x0;
if (*(int32_t *)dword_1012b5760 != 0x0) {
sub_100bbf048(&var_40);
sub_100bc085c(0x7, "%s: key: %s\n");
if (*(int32_t *)0x1012b5760 != 0x0) {
sub_100bbf048(r20);
sub_100bc085c(0x7, "%s: offset: %s\n");
}
}
sub_100bbbffc(&var_40, r19 + 0x30);
*(int32_t *)(r19 + 0xe0) = 0x0;
return 0x0;
}
19 22 .
, .
iOS Address Space Layout Randomization (ASLR) .
.
srtp_aes_icm_context_init :
const apiResolver = new ApiResolver(«objc»);
const resolvedMatches = apiResolver.enumerateMatches(
"+[NSURL URLWithUnicodeString:]"
);
const SCAN_SIZE = 100000;
const scanStart = resolvedMatches[0].address;
const scanResults = Memory.scanSync(
ptr(scanStart),
SCAN_SIZE,
// first bytes of the hexadecimal representation of srtp_aes_icm_context_init
«FF 83 01 D1 F8 5F 02 A9 F6 57 03 A9»
);
// srtp_err_status_t srtp_aes_icm_context_init(void *cv, const uint8_t *key)
const targetPointer = ptr(scanResults[0].address);
const targetFunction = new NativeFunction(targetPointer, «int», [
«pointer»,
«pointer»
]);
console.log(«scan start: » + scanStart);
console.log(«srtp_aes_icm_context_init: » + scanResults[0].address);
Interceptor.attach(targetFunction, {
onEnter: function(args) {
/*
static srtp_err_status_t srtp_aes_icm_context_init(void *cv, const uint8_t *key)
typedef struct {
v128_t counter; holds the counter value
v128_t offset; initial offset value
v128_t keystream_buffer; buffers bytes of keystream
srtp_aes_expanded_key_t expanded_key; the cipher key
int bytes_in_buffer; number of unused bytes in buffer
int key_size; AES key size + 14 byte SALT
} srtp_aes_icm_ctx_t;
*/
console.log(«srtp_aes_icm_context_init » + args[0] + " key:");
console.log(
hexdump(args[1], {
offset: 0,
length: 16
})
);
},
onLeave: function(args) {}
});
ApiResolver Frida .
ApiResolver .
Frida.
URLWithUnicodeString, 3 .
, linear search .
SCAN_SIZE .
12 12 .
, NativeFunction, 17 Frida ( ).
2 — encryption context (cv) encryption key (key).
srtp_aes_icm_context_init 6 6 SRTP .
key.
AES-ICM.
srtp_aes_icm_alloc, “allocating cipher with key length %d”.
key length , 16 .
AES-128-ICM SRTP .
46 key derivation function, 30 .
16 2 .
16 !
srtp_aes_icm_encrypt, libsrtp .
SRTP AES-128-ICM.
“block index: %d” .
SRTP srtp_aes_icm_encrypt:
12 , , .
SRTP payload.
4 ( ) – authentication tag.
6 , SRTP payload .
Call Integrity
SRTP .
libsrtp srtp_hmac_compute.
authentication tag SRTP .
srtp_hmac_compute Frida,
“intermediate state: %s” .
srtp_hmac_compute :
static srtp_err_status_t srtp_hmac_compute(void *statev,
const uint8_t *message,
int msg_octets,
int tag_len,
uint8_t *result)
srtp_hmac_compute HMAC-SHA1 .
Frida , tag_len SRTP .
tag_len message srtp_hmac_compute :
Attaching…
search srtp_hmac_compute in memory from: 0x1016380ac
found srtp_hmac_compute at: 0x10163b5f4
tag_len: 10
message: 81 ca 00 07 fe 67 2e 32 56 14 89 75 c5 c0 39 4a d3 a0 cd 48 8c 4b 61 8a 78 32 a7 89 1e b7 71 26 80 00 00 01tag_len: 4
message: 00 00 00 00tag_len: 10
message: 81 d0 00 02 fe 67 2e 32 b5 6f 93 8e 80 00 00 02tag_len: 4
message: 00 00 00 00tag_len: 4
message: 00 00 00 00tag_len: 4
message: 00 00 00 00tag_len: 4
message: 00 00 00 00tag_len: 10
message: 81 ca 00 07 83 42 f3 44 81 78 9f f5 39 b1 23 50 48 19 e0 f1 61 5b b5 32 dc b3 10 08 e7 47 a8 4b 80 00 00 01tag_len: 10
message: 81 d0 00 02 83 42 f3 44 94 60 21 fe 80 00 00 02tag_len: 4
message: 00 00 00 00tag_len: 4
message: 00 00 00 00tag_len: 10
message: 81 c8 00 12 fe 67 2e 32 87 b7 69 f8 5a 27 4c 76 b4 29 f6 5d 59 26 de af bd e9 4c 8b f3 ff 48 e3 a9 7e 62 cf db 9c 8a 3d 34 50 48 f8 fc 0e 88 7a 17 eb 17 94 9f 3d 91 27 89 d5 cc bd 21 ea 01 39 27 e1 05 07 66 69 1f 68 08 53 1a 18 02 9e bc 50 ed 8e 40 3e 8a 7b d3 b6 19 e8 54 6f 6b 58 ac 4e e3 25 f5 c2 e8 1c 97 bb 46 f9 38 45 80 00 00 03...
2 :
1. SRTP 4 .
Message SRTP .
4 authentication tag.
, , .
- .
2. 10 .
, VOIP .
SRTP , 10 :
const scanStart = new ApiResolver(«objc»).enumerateMatches(
"+[NSURL URLWithUnicodeString:]"
)[0].address;
console.log(«search srtp_hmac_compute in memory from: » + scanStart);
const size = 100000;
const matches = Memory.scanSync(
ptr(scanStart),
size,
// first bytes of the hexadecimal representation of srtp_hmac_compute
«E0 03 16 AA 4C 00 00 94 D5 02 01 91»
);
const targetPtr = ptr(matches[0].address);
console.log(«found srtp_hmac_compute at: » + matches[0].address);
const targetFunction = new NativeFunction(targetPtr, «int», [
«pointer»,
«pointer»,
«int»,
«int»,
«pointer»
]);
const MANIPULATABLE_TAG_SIZE = 10;
const manipulatedTag = Memory.alloc(MANIPULATABLE_TAG_SIZE);
manipulatedTag.writeByteArray([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
Interceptor.attach(ptr(targetFunction), {
onEnter: function(args) {
/*
static srtp_err_status_t srtp_hmac_compute(void *statev,
const uint8_t *message,
int msg_octets,
int tag_len,
uint8_t *result)
*/
console.log(«srtp_hmac_compute tag (» + args[3].toInt32() + "):");
const tag_len = args[3].toInt32();
if (tag_len === MANIPULATABLE_TAG_SIZE) {
console.log(
hexdump(args[1], {
length: args[2].toInt32()
})
);
args[3] = 0;
args[4].writePointer(manipulatedTag);
}
}
});
Frida, VOIP .
, SRTP .
, , .
WhatsApp VoIP …
, .
:
— libsignal-protocol-c, libsrtp, PJSIP mbed TLS VOIP .
— “master secret” 2 SRTP , AES-128-ICM.
key derivation function (HKDF), , nonces SRTP.
— Noise Pipes Protocol, Signal Protocol XMPP .
Signal Protocol, XMPP , Noise Pipes Protocol .
.
— VOIP – SRTP .
, , SRTP .
— SRTP , VOIP .
— .
, .
.
:
github.com/schirrmacher/files/blob/master/WhatsApp%20VoIP%20Protocol.pdf
github.com/schirrmacher/files/blob/master/WhatsApp
github.com/schirrmacher/files/blob/master/WhatsAppCore
– , , .
Frida .
.
.
علاوة على ذلك ، يجب على المطورين أيضًا إزالة ثوابت السلسلة التي تحتوي على معلومات مهمة أو قد تكون مفيدة في تحديد الوظائف.