تحلیل آسیب پذیری ZEROLOGON

تحلیل آسیب پذیری ZEROLOGON

در این مقاله به بررسی فنی آسیب پذیری به شناسه CVE-2020-1472 که با عنوان Zerologon شناخته می شود خواهیم پرداخت.

اولین کسی باشید که به این سؤال پاسخ می‌دهید

Zerologon یک آسیب پذیری بحرانی در ویندوز سرور است که CVSS Score 10.0 از مایکروسافت دریافت کرده است. برای حل کردن این آسیب پذیری باید وصله های های امنیتی مایکروسافت که در تاریخ اگوست 2020 منتشر شد، روی تمام کنترل کننده های دامنه (Domain Controller) در اکتیودایرکتوری ها نصب شود.

اگر روی DC این وصله ها نصب نشود به هکرها این اجازه داده می شود که دسترسی ادمین دامنه را در اختیار بگیرند.
تنها چیزی که یک هکر نیاز دارد آن است که یک ارتباط TCP با Domain Controller آسیب پذیر ایجاد کند. کافی است هکرها به شبکه کمترین دسترسی را داشته باشند تا بتوانند بدون داشتن هیچ اطلاعات محرمانه ای، کنترل همه چیز را به دست بگیرند.
وصله ای که آسیب پذیری Zerologon را رفع نموده، برخی مکانیزم های دفاعی بیشتری را نیز پوشش داده است که ماشین هایی که به دامنه ملحق می شوند را مجبور می کند که ویژگی های امنیتی که قبلا در پروتکل Netlogon اختیاری بوده را استفاده کنند.
به روزرسانی که در فوریه 2021 منتشر خواهد شد این محدودیت ها را بیشتر می کند و ممکن است بعضی از دستگاه ها و یا نرم افزارهای Third-party را از کار بیندازد. در نظر داشته باشید که نصب کردن وصله منتشر شده در اگوست 2020 روی همه دامین کنترلرها می تواند جلوی این آسیب پذیری خطرناک را بگیرد.
برای کسب اطمینان از آسیب پذیر نبودن می توانید از ابزار موجود در لینک زیر استفاده کنید:


https://github.com/SecuraBV/CVE-2020-1472

حمله ای که اینجا توضیح داده می شود از رخنه های پروتکل رمزنگاری مربوط به فرآیند احراز هویت استفاده می کند که هویت کامیپوتر متصل شده به دامنه را به DC اثبات می کند. به دلیل استفاده نادرست از یک حالت AES در عملیات احراز هویت، این امکان ایجاد می شود که هویت هر کاربری را جعل کرده و پسورد خالی برای آن کاربر در دامنه تنظیم شود.


جزییات آسیب پذیری
پروتکل Netlogon :

Netlogon Remote Protocol یک اینترفیس RPC در کنترل کننده های دامنه ویندوزی هست و برای احراز هویت کاربران استفاده می شود. این پروتکل عملیات Login کردن کاربران به سرورها را با استفاده از پروتکل NTLM تسهیل می کند. از ویژگی های دیگر این پروتکل می توان به احراز هویت پاسخ های NTP و اجازه دادن به کامپیوترها برای آپدیت پسورد ورودی شان به داخل دامنه اشاره کرد. اینترفیس RPC روی TCP، از طریق یک پورت داینامیک اختصاص داده شده توسط سرویس PortMapper کنترل کننده دامنه یا از طریق یک SMB Pipe روی پورت 445 قابل دسترس هست.
آنچه که در مورد این پروتکل جالب است این است که از روش های احراز هویت مشابه در دیگر RPC ها استفاده نمی کند. به جای آن از پروتکل رمزنگاری سفارشی شده استفاده می کند که به کلاینت (کامپیوتر متصل شده) و سرور ( دامین کنترلر) اجازه می دهد که یکدیگر را از طریق رمز مشترک شناسایی کنند. این رمز مشترک، یک هش از پسورد کلاینت می باشد.
یک Netlogon Session به وسیله کلاینت آغاز می شود، که طی آن کلاینت و سرور، Nonce های 8 بایتی را به صورت تصادفی (که به چالش سرور (Server Challenge) و کلاینت (Client Challenge) معروف است) با همدیگر رد و بدل می کنند. هر دوی آن ها یک Session Key را بااستفاده از ترکیب چالش ها با رمز مشترک و ارسال آن به یک تابع اشتقاق کلید (key derivation function یا به اختصار KDF) به دست می آورند. سپس کلاینت از Session Key برای محاسبه ClientCredential استفاده می کند. سرور نیز مجددا مقدار Credential را به روش یکسانی محاسبه می کند و اگر نتیجه مطابقت کند معلوم میشود که که کلاینت Session Key و در نتیجه پسورد کامپیوتر را دارد.

 تحلیل آسیب پذیری ZEROLOGON

در طول Authentication Handshake هر دو ماشین می توانند مذاکره کنند که آیا می خواهند از روش مهر و موم (seal and sign) برای پیام های متوالی (رمزنگاری و احراز هویت کریپتوگرافیکی) که برای حفاظت در برابر هکرها در سطح شبکه لازم است استفاده کنند یا نه. حتی زمانی که رمزنگاری غیرفعال می شود همه فراخوانی های Netlogon که عملیات مهمی را انجام می دهند باید شامل یک مقدار اعتبارسنجی باشند که با استفاده از Session Key محاسبه می شود.
پیاده سازی پروتکل رمزنگاری حساس است یعنی اینکه : یک اشتباه کوچک می تواند منجر دورخوردن توابع پیاده شده با انواع روش ها گردد (در اینجا احراز هویت کامپیوتر و امنیت انتقال اطلاعات). از آنجایی که من از ممیزی های امنیتی منتشر شده درباره این پروتکل آگاه نیستم، تصمیم گرفتم این آسیب پذیری را عمیق تر بررسی کنم. در ابتدا من حملات Man in the middle را بررسی می کردم که منجر به آسیب پذیری CVE-2019-1424 شد که می توانست باعث افزایش دسترسی هکر به سطح مدیر دامنه در صورت داشتن دسترسی به یک کلاینت شود.
اما در مرحله بعدی زمانی که آزمایش های بیشتری برای Authentication Handshake انجام دادم، یک روش خیلی خطرناک تر برای دور زدن احراز هویت کشف کردم که توسط هر مهاجم که بتواند ارتباط TCPای با کنترل کننده دامنه برقرار کند، قابل استفاده خواهد بود.

هسته آسیب پذیری: استفاده نا امن از AES-CFB8

پایه رمزنگاری (Cryptographic primitive) هم در کلاینت و هم در سرور، مقدار Credential را با استفاده از تابعی به نام ComputeNetlogonCredential مطابق پروتکل ایجاد می نماید . این تابع یک ورودی 8 بایتی دریافت نموده و با استفاده از Session key روی آن تعدادی عملیات انجام داده و یک خروجی با طول ثابت تولید می نماید البته با این پیش فرض که مهاجم Session key را نمی داند و قادر نخواهد بود تا خروجی متناسب را محاسبه کرده یا حدس بزند.
در اینجا دو نسخه از این تابع، یکی بر اساس 2DES و نسخه جدیدتر بر اساس AES وجود دارد. هر کدام مطابق با فلگی که کلاینت هنگام اعتبارسنجی تنظیم کرده است استفاده می شود. هرچند تنظیمات پیش فرض نسخه های جدید ویندوز سرور هر تلاشی برای اعتبار سنجی نوع 2DES را رد کند. بنابراین در اکثر دامنه ها از AES استفاده می شود که دقیقا همین پروتکل جدید است که آسیب پذیری را دارد. نسخه های قدیمی به وسیله این آسیب پذیری قابل نفوذ نیستند. (هرچند 2DES به دلایل دیگری ناامن است).
عملیات پایه رمزنگاری AES به این صورت هست که ورودی 16 بایتی را دریافت می کند و با انجام جانشینی هایی (permutes) در ساختار آن، یک خروجی با سایز 16 بایت ایجاد می کند. برای رمزنگاریِ ورودی های بزرگتر یا کوچکتر از 16 بایت، مُد مناسب برای عملیات باید انتخاب شود. تابع ComputeNetlogonCredential که فقط 8 بایت را تغییر می دهد از مد نسبتا مبهمی به نام CFB8 (8-bit cipher feedback) استفاده می کند. این مد 16 برابر کندتر از مدهای رایج دیگر است و علت عدم استفاده گسترده از این مد نیز احتمالا همین است.
AES-CFB8 هر بایت از فاش نوشته (Plaintext) را با اضافه کردن یک بردار اولیه (Initialization Vector) رندوم 16 بایتی رمزنگاری می کند. سپس AES را به اولین 16 بایت از IV+Plaintext اعمال می کند و اولین بایت از خروجی AES را برمی دارد و با بایت بعدی فاش نوشته عملیات XOR را انجام می دهد که در شکل زیر نشان داده شده است.

 تحلیل آسیب پذیری ZEROLOGON

برای اینکه بتوان بایت های اولیه پیام را رمزنگاری کرد یک بردار اولیه (IV) باید مشخص شود که فرآیند رمزنگاری را راه اندازی کند. این IV باید یکتا باشد و برای هر فاش نوشته که با کلید مشابه رمزنگاری شده اند به صورت تصادفی ایجاد شود. اما تابع ComputeNetlogonCredential همواره IV ثابتی با طول 16 بایت تعریف می کند که همواره مقدار آن صفر است که این مورد امنیت را نقض می کند چرا که فقط زمانی IV امن بود که برای یک کلید خاص، تصادفی باشد.
آیا اینجا مشکل امنیتی به وجود می آید؟ چه مشکلی می تواند با IV ای که همه اش صفر است اتفاق بیافتد؟ به دلیل ابهام CFB8 نتوانستم نوشته ای در این باره بیابم. بنابراین تعدادی حمله فاش نوشته منتخب (chosen plaintext attack) بررسی کردم و به نتایج جالبی رسیدم :
1 حالت از 256 حالت کلید ، موجب آن می شود که اگر تمام ورودی (IV+Plaintext) صفر باشد آنگاه خروجی به مقدار تماما صفر تبدیل شود.

 تحلیل آسیب پذیری ZEROLOGON

در حقیقت این خصوصیتی عمومی است. زمانی که یک IV فقط شامل صفر باشد یک عدد صحیح X  با مقداری بین 0 و 255 وجود خواهد داشت که برای آن فاش نوشته که با n بایت و مقدار X شروع می شود و یک رمزنوشته (Ciphertext) خواهیم داشت که با n بایت با مقدار صفر شروع می شود . X به کلید رمزنگاری بستگی دارد و به صورت تصادفی توزیع شده است.برای حمله Netlogon به ویژگی های کلی تری نیاز نداریم. فقط کافی است بدانیم که یک ورودی تماما-صفر منجر به خروجی تماما-صفر می شود. در ادامه خواهیم دید که چطور از این خصوصیت بهره برداری می شود.

اکسپلویت مرحله اول: جعل Credential کلاینت

بعد از ردوبدل کردن چالش ها با فراخوانی NetrServerReqChallenge، یک کلاینت خودش را با فراخوانی NetrServerAuthenticate3 احراز هویت می کند. این تابع پارامتری به نام ClientCredential دارد و بوسیله ComputeNetlogonCredential روی کلاینت که در مرحله قبلی ارسال شد محاسبه می شود. از آنجایی که چالش می تواند به صورت دلخواه توسط ما انتخاب شود می توانیم 8 تا صفر انتخاب کنیم. بنابراین برای رسیدن به احتمال 1 در 256 کلید، ClientCredential صحیح، همان 8 عدد صفر خواهد بود.

بنابراین چطور متوجه می شویم که Session ما کلیدی را انتخاب خواهد کرد که به خروجی 0 خواهد رسید؟ درواقع ما نمی دانیم. اما هر زمانی که سعی در احراز هویت به این شکل کنیم سرور یک چالش یکتا تولید خواهد کرد که پارامتری از تابع اشتقاق تولید Session Key خواهد بود. بنابراین Session Key برای هر بار احراز هویت، متفاوت خواهد بود. از آنجایی که اکانت کامپیوتر بعد از تلاش ناموفق لاگین بسته نمی شود، ما می توانیم چندین بار تلاش کنیم تا به کلید مورد نظر برسیم و احراز هویت با موفقیت انجام شود. عدد میانگین مقدار تلاش های مورد نیاز 256 می باشد که فقط سه ثانیه به طول می انجامد. با این روش ما می توانیم به هر کامپیوتری در دامین کنترلر لاگین کنیم که می تواند شامل دامین کنترلر بکاپ یا خود دامین کنترلر اصلی باشد.


اکسپلویت مرحله دوم: غیرفعال کردن مهر و موم

در حالی که مرحله اول توانستیم عملیات احراز هویت را دور بزنیم، اما هنوز نمی دانیم که مقدار Session key چه چیزی هست. این مورد به دلیل سازوکار رمزنگاری انتقال Netlogon مشکل زا است که از این کلید با الگویی کاملا متفاوت از تابع آسیب پذیر ComputeNetlogonCredential استفاده می کند.
خوشبختانه مهر و موم کردن این مقدار اختیاری هست و می تواند با مقداردهی نکردن یک فلگ در فراخوانی NetrServerAuthenticate3 غیرفعال شود. کلاینت های مدرن زمانی که این فلگ بوسیله سرور ست نشده باشد از وصل شدن به آن خودداری می کنند، اما سرورها، درخواست کلاینت هایی که رمزنگاری ندارند را رد نمی کنند. از آنجایی که ما در این حمله به عنوان کلاینت عمل می کنیم، می توانیم فلگ را حذف کنیم و ادامه بدهیم.


اکسپلویت مرحله 3: جعل یک فراخوانی

حتی زمانی که رمزنگاری فراخوانی غیرفعال است، هر فراخوانی که کار جالبی انجام می دهد باید شامل یک So-called authenticator باشد. این مقدار با اجرای ComputeNetlogonCredential همراه با مقدار Session key روی ClientStoredCredential + Timestamp محاسبه می شود.
ClientStoredCredential یک مقدار افزایشی هست که بوسیله کلاینت نگه داری می شود. زمانی که Handshake انجام می شود، مقدار اولیه آن برابر ClientCredential می شود. Client Credential فقط شامل مقدار صفر هست، بنابراین مقدار ClientStoredCredential برای اولین فراخوانی انجام شده بعد از احراز هویت صفر خواهد بود.
Timestamp باید شامل زمان فعلی با فرمت Posix باشد و در فراخوانی های کلاینت همراه authenticator وجود دارد. علیرغم این موضوع سرور معمولا روی این بخش محدودیتی نمی گذارد و ما می توانیم به آسانی آن را اول ژانویه 1970 بگذاریم یا همچنین آن را کلا صفر بگذاریم.
اگر ما مرحله 1 را انجام داده باشیم، می دانیم که ComputeNetlogonCredential(0) = 0 می باشد. بنابراین ما می توانیم اولین فراخوانی مان را با authenticator که تمامش صفر است و همچنین با Timestamp تماما- صفر انجام دهیم.


اکسپلویت مرحله 4: تغییر پسورد مربوط به دامنه یک کامپیوتر

حالا که می توانیم به جای هر کامپیوتری درخواست Netlogon را ارسال کنیم، باید چه کنیم؟ تعدادی از فراخوانی های مربوط به کپی پایگاه داده حساب کاربری وجود دارند که بعد از معرفی اکتیودایرکتوری غیرفعال شده اند. بنابراین نمی توانیم Credential را با استفاده از آن ها استخراج کنیم.
فراخوانی جالب دیگری به نام NetrServerPasswordGet وجود دارد که اجازه می دهد هش NTLM از پسورد یک کامپیوتر را داشته باشیم. متاسفانه این هش با Session key و با استفاده از یک الگوریتم متفاوت رمزنگاری شده است و بنابراین قابل استفاده نیست.
آنچه که می توانیم بهره برداری کنیم NetrServerPasswordSet است که برای ایجاد پسورد جدید برای کلاینت استفاده می شود. این پسورد هش شده نیست ولی با Session key رمزنگاری شده است. حتما می پرسید چگونه؟ با استفاده از CFB8 و یک IV تمام صفر.
ساختار پسورد فاش نوشته در پروتکل Netlogon شامل 516 بایت است. آخرین چهار بایت، طول پسورد را به بایت نشان می دهد. همه بایت هایی که در این ساختار بخشی از تابع پسورد نیستند به عنوان padding دیده می شوند و می توانند مقدار دلخواهی داشته باشند.
اگر ما 516 تا صفر داشته باشیم، به 516 تا صفر رمزگشایی می شود، که نمونه ای از آن پسورد با طول صفر است. بنابراین تنظیم پسورد خالی برای یک کامپیوتر در دامنه غیرممکن نیست و می توان برای هر کامپیوتری پسورد خالی گذاشت!(شکل 4)
زمانی که این عمل انجام شد، ما می توانیم یک کانکشن Netlogon جدید به نمایندگی از یک کامپیوتر داشته باشیم. در حالی که اکنون ما پسورد کامپیوتر را می دانیم (پسورد خالی) بنابراین حالا می توانیم به طور نرمال پروتکل را دنبال کنیم و اگر بخواهیم می توانیم پسورد هر سیستمی را به یک پسورد خالی تغییر دهیم.
زمانی که پسورد کامپیوتر را به این شکل تغییر دادیم این تغییرات فقط در AD اعمال شده است. سیستم موردنظر پسورد اصلیش را به صورت محلی نگه می دارد و آن کامپیوتر دیگر نمی تواند در دامنه احراز هویت شود و باید به صورت دستی مجددا همگام سازی شود. بنابراین با این حرکت، نوعی از Denial-Of-Service را پیاده سازی می کنیم که می توانیم هر دستگاهی را در دامنه قفل کنیم. همچنین اگر این کامپیوتر دسترسی های خاصی را در دامنه داشته باشد می توانیم از آن ها سوء استفاده کنیم.

اکسپلویت مرحله پنجم: گرفتن دسترسی مدیر دامنه با تغییر پسورد

یکی از کامپیوترهایی که می توانیم پسوردش را عوض کنیم خود کنترل کننده دامنه است. با انجام این کار موقعیت جالبی ایجاد خواهد شد، به گونه ای که پسورد ذخیره شده برای DC در اکتیودایرکتوری با پسورد ذخیره شده در رجیستری خود HKLM\SECURITY\Policy\Secrets\$machine.ACC) DC) متفاوت خواهد بود.
این موضوع باعث می شود DC رفتارهای غیرقابل پیش بینی انجام دهد. (به عنوان مثال در محیط آزمایشگاهی سرویس DNS متوقف شد!) به عنوان مهاجم، ما تمایل داریم تا از پسورد خود DC برای لاگین استفاده کنیم تا کنترل کامل آن را به دست گیریم.

 تحلیل آسیب پذیری ZEROLOGON

این روش زمانی کار می کند که DC از پسورد ذخیره شده در اکتیودایرکتوری به جای پسورد ذخیره شده به صورت محلی برای اعتبارسنجی استفاده کند. بعد از تعدادی تست متوجه شدیم که اجرای قابلیت Secretsdump از ابزار Impacket با پسورد جدید DC عمل می کند و این اسکریپت هش تمام کاربران دامنه را از طریق Domain Replication Service می تواند استخراج کند. این مقادیر شامل هش ادمین (شامل کلید 'krbtgt'، که می توان با آن Golden Ticket تولید کرد) نیز هست و می تواند برای لاگین به DC استفاده شود و به این طریق می توان پسورد ذخیره شده در رجیستری لوکال DC را آپدیت کرد. حالا DC به صورت طبیعی رفتار می کند و مهاجم، ادمین دامنه شده است.

نتیجه گیری:

با ارسال ساده تعدادی پیغام Netlogon که در آن فیلدهای مختلفی با صفر پر شده اند یک مهاجم می تواند پسورد کامپیوتر کنترل کننده دامنه را که در AD ذخیره شده را تغییر دهد که می تواند منجر به دسترسی به Credential مدیر دامنه شود و نهایتا منجر به بازیابی پسورد اصلی DC شود.
این حمله اثرات زیادی دارد: به هر مهاجمی در شبکه محلی (مانند کارمندان یک شرکت یا افراد غیر مجاز یا کسی که به سادگی دستگاهی را به پورت شبکه داخلی متصل می کند) اجازه می دهد تا کل دامنه ویندوزی را بدون نیاز به احراز هویت تصاحب کند.
وصله منتشر شده در آگوست 2020 این مسئله را با اجبار کردن Secure NRPC (برای مثال مهرو موم Netlogon) برای همه ویندوز سرورها و کلاینت ها در دامنه حل می کند و اکسپلویت مرحله 2 را از بین می برد.علاوه بر این موضوع، طبق آزمایش های ما مرحله یک نیز حتی در صورتی که فلگ مهر و موم هم از بین نرود شکست می خورد. نحوه پیاده سازی این وصله دقیقا مشخص نیست و امکان دارد بوسیله رد کردن فرایندهای احراز هویت در حالتی که فیلد ClientCredential با تعداد زیادی صفر شروع شود انجام شده است و ما موفق به دور زدن این وصله نشدیم. با نصب این وصله، حمله Zerologon با توضیحات بالا دیگر عمل نخواهد کرد.
اگر راه های عملی برای بایپس کردن حفاظت مرحله یک وجود داشت (شاید شامل تعداد زیادی عملیات Brute-Force) این آسیب پذیری می توانست کامپیوترهایی که قابلیت Secure NRPC برای آن ها اجبار نشده است را در خطر قرار دهد و سپس یک مهاجم می توانست با تغییر پسورد مربوط به دامنه در این کامپیوترها، ارتباط آن ها با دامنه را قطع و این کامپیوترها دچار منع سرویس کند. همچنین در این صورت ممکن بود حمله های Man in the Middle مشابه CVE-2019-1424 قابل انجام باشد که مهاجم می تواند دسترسی محلی ادمین به این کامپیوترها داشته باشد.
برای رفع خطرهای باقی مانده، ویندوز رویداد های هشداری (warning) را زمانی که این دستگاه های آسیب پذیر در دامنه وجود داشته باشند را در Event log ذخیره خواهد کرد. گزینه اختیاری دیگری که وجود دارد، فعال کردن Enforcement mode می باشد که قابلیت Secure NRPC را برای همه کامپیوترها در شبکه اجباری می کند که ممکن است باعث از کار افتادن آن ها شود. در فوریه 2021 این گزینه به صورت پیش فرض فعال خواهد شد و لازم است تا ادمین ها کامپیوترهایی که Secure NRPC را پشتیبانی نمی کنند را آپدیت یا Whitelist یا حذف کنند. برای اطلاعات بیشتر به راهنمای ارائه شده مایکروسافت مراجعه نمایید.

با تشکر از آقای عادل پیری که در تهیه این مقاله دپارتمان امنیت سکان را یاری نمودند.

منبع