DNSSEC حقیقتی فراموش شده (قسمت اول: تاریخچه)

مدتی بود که تقریبا در اکثر مقالاتی که میخوندم چشمم به اصطلاحی می افتاد به اسم DNSSEC. از اونجایی که چندان میونه ی خوبی با امنیت ندارم (امنیت هم با من میونه ی خوبی نداره 🙂 ) با خودم میگفتم خب DNS که تکلیفش معلومه چیه، SEC هم که یعنی Security، پس احتمالا باید مربوط باشه به یک توسعه ی امنیتی برای DNS. اما هرچی بیشتر زمان می گذشت تاکید بر این واژه بیشتر و بیشتر می شد. همین عامل باعث شد که من بالاخره بخوام پا در دنیای امنیت (البته صرفا برای مدتی کوتاه و برای یک بخش خیلی کوچیک از این دنیا 🙂 ) بذارم و به دنبال شناخت DNSSEC برم.

قبل از هرچیزی دوست دارم شما هم مثل من با تاریخچه ی شکل گیری و ظهور DNSSEC آشنا بشید چون نظرم این هست که دونستن تاریخچه‌ی هر چیزی ما رو در یافتن نیازها و ایده ی اصلی که منجر به ایجاد اون مفهوم شده و هم چنین درک درست عملکردش کمک میکنه.

***

زمانی که مفهوم اینترنت به گستردگی حال حاضر نبود، سیستم ها برای برقراری ارتباط با یکدیگر، مستقیما از IP بهره می گرفتند. پس از چندی تصمیم بر آن شد که سیستم ها با نام همدیگر را فرابخوانند. به همین جهت باید از مکانیزمی استفاده می شد که برای سیستم مشخص می گردید که IP متناظر با هر نام چیست. این مکانیزم استفاده از فایلی با نام host بود که در آن IP متناظر با هر نام درج می گردید و باید به هر سیستمی که قصد ارتباط با سایر سیستم ها با نام را داشت منتقل می شد. اما با گسترده تر شدن دنیای اینترنت و اضافه شدن میلیون ها Host به این ساختار، استفاده از فایل host و انتقال آن به هر سیستم عملا غیرممکن شد.

همین عامل سبب معرفی سرویسی با نام Domain Name Service (DNS) گردید. این سرویس طی دو RFC با شماره های 882 (بررسی مشکلاتی که سبب ایجاد این سرویس گردید) و 883 (بررسی مشخصات و ویژگی های عملکردی DNS) در سال 1983 معرفی شد.

نحوه ی عملکرد DNS در حالت نرمال:

DNS یک دیتابیس توزیع شده، سلسه مراتبی و داینامیک است که وظیفه ی آن نگاشت اطلاعاتی چون hostname، آدرس IP، رکوردهای text، اطلاعات تبادل mail (یا همان رکورد MX)، اطلاعات name server ها (NS record) و هم چنین اطلاعات کلید امنیتی به یکدیگر می باشد که هر کدام از این اطلاعات توسط یک Resource Record یا اصطلاحا RR مشخص می شوند.

اطلاعات مشخص شده در RR ها در zone های مختلف گروهبندی شده و داخل یک DNS server محلی نگهداری می شوند. این DNS سرور محلی می تواند از طریق معماری توزیع شده ی DNS، به صورت جهانی نیز در دسترس قرار گیرد. DNS هم میتواند از UDP برای انتقال اطلاعات خود بهره گیرد و هم TCP و به صورت پیش فرض از destination port 53 استفاده میکند.

آدرس های DNS از چندین label ساخته شده اند که هر label مشخص کننده ی سلسله مراتبی است که به ترتیب باید به سراغ آن ها رفت. این label ها از راست به چپ بررسی می شوند. به عنوان مثال آدرس .www.example.com دارای چهار label می باشد: www که در این سلسله مراتب leaf محسوب می شود؛ example” که یک دامنه است؛ com که یک TLD یا Top Level Domain می باشد و نهایتا “.” که نشان دهنده ی Root Server است.

زمانی که در مرورگر خود آدرس www.example.com را وارد می کنید، در اولین گام سیستم عامل Cache خود را بررسی می کند تا شاید آدرس IP متناظر با آن را بیابد. در صورتی که هیچ رکوردی پیدا نکرد، recursive query ای را به سمت Recursive Resolver ارسال می کند.

در DNS از دو نوع query استفاده می شود: recursive و iterative. تفاوت این دو query در آن است که:

  • recursive query حتما باید با ارسال یک response پاسخ داده شود
  • iterative query نیازی به دریافت response یا پاسخ ندارد.

منظور از Recursive resolver می تواند به عنوان مثال DNS سروری که ISP برای شما فراهم کرده باشد و یا هر name server دیگری. Recursive Resolver در واقع از سایر DNS سرورهایی که می توانند به سوال آن در رابطه با IP آدرس www.example.com پاسخ دهند، آگاهی دارد. Recursive Resolver ابتدا با بررسی Cache خود اطمینان حاصل می کند که از آدرس IP آن Host اطلاع دارد یا نه. اگر نداشته باشد با بررسی label های آدرس .www.example.com از چپ به راست (اولین برچسب . می باشد) متوجه می شود که اولین مکانی که برای پیدا کردن آدرس IP مربوطه باید به سراغ آن برود Root Server است.

در حال حاضر سیزده Root Server در سراسر دنیا وجود دارد که در بردارنده ی اطلاعات DNS مربوط به Top Level Domain ها  (TLD) می باشند. (لازم به ذکر است که ایران نیز یکی از میزبانان K.root-servers.net می باشد)  TLD ها در واقع دامنه هایی چون .com، .org و … هستند. بنابراین Recursive Resolver با ارسال یک iterative query از Root Server در رابطه به com. سوال می پرسد و Root Server نیز در پاسخ، برای آن آدرس IP مربوط به TLD .com را ارسال می کند.

در گام بعد Recursive Resolver یک iterative request برای TLD ای که آدرس IP آن را از Root Server دریافت نمود، ارسال کرده و در رابطه با example.com می پرسد. TLD ها، DNS Server هایی هستن که اطلاعات DNS مربوط به زیردامنه های خود را نگهداری می کنند (در اینجا example). زمانی که TLD درخواست را دریافت می کند آدرس IP مربوط به example.com را برای Recursive Resolver مربوطه ارسال می نماید.

در مرحله ی بعد Recursive Resolver با ارسال یک iterative query برای example.com آدرس IP متعلق به رکورد www.example.com را خواستار می شود. example.com نیز با ارسال آدرس IP مربوط به رکورد www.example.com به این query پاسخ میدهد. نهایتا Recursive Resolver که اکنون آدرس IP مربوط به www.example.com را یافته آن را برای سیستم شما ارسال کرده و صفحه ی مربوط به این آدرس در مرورگر شما باز می شود (البته با چشم پوشی از چند مرحله ی دیگر که بعد از این مراحل رخ می دهند و ارتباطی با DNS ندارند). تمام این اتفاقات در کم تر از چند ثانیه رخ می دهند. تصویر زیر نمایانگر مراحلی است که شرح داده شد:

حقایق تلخ DNS:

در ابتدای معرفی DNS هیچ تصوری از ایجاد مشکلات امنیتی برای این سرویس محبوب نبود. البته این موضوع در رابطه با تمام سرویس ها و پروتکل هایی که در اوایل دهه ی 1980 معرفی می گردیدند، صدق می کرد. همین موضوع باعث شد تا آسیب های امنیتی جدی برای DNS ایجاد شود.

مسائل امنیتی DNS به طور کلی در دسته های زیر قرار می گیرند:

  • استفاده از reverse DNS به منظور جعل هویت کاربران
  • خطاهای نرم افزاری (مثل سرریز بافر و …)
  • رمزنگاری بد (مثل توالی های قابل پیش بینی و …)
  • نشت اطلاعات (مثل داده های نامعتبر یا افشای محتویات cache)
  • قرار دادن داده های نامناسب در Cache یا اصطلاحا Cache poisoning

اولین مشکل امنیتی که در DNS کشف شد، Cache Poisoning بود که از آن با نام DNS Spoofing نیز یاد می شود. DNS Cache Poisoning زمانی اتفاق می افتد که DNS سرور پایین دست (Recursive Resolver) داده ها یا IP نادرستی را ارسال کند. علت رخ دادن این موضوع نیز به این جهت می باشد که attacker با اصطلاحا سمی کردن Cache سرور DNS پایین دست، سبب می شود که این DNS سرور در مقابل درخواست هایی که دریافت کند، پاسخ های اشتباه و مورد دلخواه مهاجم را ارسال نماید.

برای درک بهتر این حمله ابتدا باید با فیلدهای داده های DNS که در گذشته استفاده می گردید، آشنا شد. در تصویر زیر قالب پیامی حاوی داده های DNS نشان داده شده که فیلدهای مهم مورد استفاده در حمله ی Cache Poisoning در آن با رنگ زرد متمایز گردیده است.

پایه و اساس این حمله بر دو موضوع استوار بود: اول آن که در آن زمان، DNS سرورها به ازای هر Query که تولید می کردند در فیلد Query ID (QID) یا Transaction ID (که از آن به منظور رهگیری query ها و response های آن ها بهره گرفته می شود) مقداری عددی قرار می دادند که به ازای هر پیام جدید، این مقدار یک واحد اضافه می گشت. به عبارت دیگر، شماره QID ها یک رشته از اعداد متوالی بودند و بنابراین با به دست آوردن یک QID، QID پیام بعدی به راحتی قابل حدس زدن بود. مورد دوم آن بود که DNS از UDP استفاده می کرد به این صورت که در زمان ارسال یک پیام Query بر روی یک پورت UDP، منتظر دریافت پاسخ مربوط به آن، از روی همان پورت می ماند و به محض دریافت اولین پاسخ درست آن را پذیرفته و سایر پیام ها رد می شدند چرا که دیگر Query در حالت pending (انتظار) قرار نداشت.

مهاجم ابتدا برای به دست آوردن QID و شماره پورت، به سمت Recursive Resolver یک Query که در آن Host ای در DNS Server ای که خود ایجاد کرده بود، درخواست شده بود ارسال می کرد. از آن جایی که در آن زمان DNS سرورها یک بار از سیستم عامل یک شماره پورت UDP تصادفی و خالی را می گرفتند و سپس برای تمام پیام های بعدی که قرار بر ارسال آن ها بود از همین شماره پورت به عنوان شماره پورت مبدا در هدر UDP آن پیام استفاده می کردند و از آن جایی که شماره QID ها هم به طور متوالی افزایش پیدا می کرد، مهاجم فقط کافی بود تا با شنود ترافیک DNS ای که به سمت سرور آن جریان یافته بود، به راحتی به این دو مورد دست یابد.

در مرحله ی بعد نوبت به اصطلاحا سمی کردن رکورد مربوط به Host مورد حمله در DNS سرور Recursive Resolver می رسید. ابتدا مهاجم با ارسال Query از Recursive Resolver آدرس IP مربوط به Host مورد نظر را پرس و جو می کند. Recursive Resolver نیز به دنبال پیدا کردن آدرس آن Host (البته در صورتی که آن را در Cache خود ذخیره نداشته باشد) به سراغ Root Server می رود. همزمان با این که Recursive Resolver پیام Query را برای یافتن آدرس IP، هاست مورد نظر برای Root Server ارسال می کند، مهاجم نیز شروع به ارسال پی در پی response هایی با آدرس IP جعلی و QID هایی در رنج QID ای که به دست آورده می کند.

اولین QID که با QID مربوط به Query ارسال شده مطابقت یابد، Recursive Server همان را به عنوان جواب درست پذیرفته و در Cache خود ذخیره می کند و حتی اگر سرور اصلی مربوط به آن Host نیز، بعد از آن جواب درست را ارسال کند آن جواب دیگر پذیرفته نخواهد شد. تصویر زیر بیانگر اتفاقاتی است که شرح داده شد:

شاید این حمله به گفتار ساده باشد اما در حقیقت دارای پیچیدگی های زیادی هم بود. اول آن که Host مورد حمله نباید در Cache سرور Recursive موجود باشد چرا که در غیر این صورت اصلا مراحل بالا صورت نمی گیرد و بلافاصله در همان مرحله ی اول دریافت Query از جانب سیستم مهاجم، Recursive Resolver آدرس IP ای که در Cache خود ذخیره دارد برای آن ارسال می کند. دوم آن که مهاجم باید توانایی حدس زدن QID را داشته باشد و نهایتا، مورد سوم آن که سیستم مهاجم باید خیلی سریعتر از ارتباط بین Recursive Resolver و Root Server عمل نماید تا بتواند پاسخی با QID مورد انتظار در Recursive Resolver را سریعتر از Name Server اصلی ارسال نماید.

این مشکل نخستین بار توسط Computer Science Research Group(CSRG) در دانشگاه Berkeley در سال 1989 کشف گردید و نهایتا در داکیومنتی توسط  Steve Bellovin در سال 1993 تشریح شد.

این مشکل از آن جایی دارای اهمیت بود که دو برنامه ی مشهور UNIX ای در آن زمان (rsh و rlogin) از DNS برای احراز هویت کاربرانی که قصد ریموت زدن به آن ها را داشتند، استفاده می کردند. این دو برنامه با نگاهی بر IP آدرس، hostname را به دست می آوردند و بدون هیچ پرسش اضافه تری که آیا این کاربر معتبر است یا نه، آن را می پذیرفتند. بنابراین یک مهاجم به راحتی می توانست با یک کاربر جعلی به این برنامه ها دسترسی یابد. CSRG برای حل این مشکل این پیشنهاد را ارائه نمود که علاوه بر A Record که حاوی آدرس IP است، رکورد PTR که حاوی نام است نیز query شود. اما این روش نیز توسط DNS cache poisoning قابل دور زدن بود.

نگرانی ها در مورد Cache Poisoning زمانی جدی شد که مقاله هایی عمومی در رابطه با این حمله به انتشار رسید و بدتر از آن این که، Bellovin یک نسخه از مقاله ی خود را در رابطه با تشریح این مشکل، در FTP سرور یک محکوم جرایم رایانه ای یافت! همین امر موجب گردید که دیگر جایی برای سرپوش گذاشتن بر این ضعف امنیتی DNS نباشد و Bellovin در سال 1995 مقاله ی خود را برای سمپوزیوم Usenix Security ارسال کند و در پی آن راه حل هایی از جمله استفاده از Transaction ID های تصادفی برای BIND ارایه گردد.

راه حل های پیشنهادی برای امن سازی DNS چندان هم خوب به نظر نمی رسیدند و نیاز به پیدا کردن یک راه حل بهتر، هم چنان احساس می شد. در سال 1997 نهاد IETF نخستین RFC (2065) را در رابطه با راه حلی بهتر برای امن سازی DNS ارایه نمود. این راه حل Domain Name System Security Extensions (DNSSEC) نام داشت اما این راه حل جز برای محققانی که به خوبی بر مشکلات عدیده ی DNS آگاهی داشتند، مورد استقبال قرار نگرفت و یا بنا به هر دلیلی، جدی قلمداد نشد.

باگ Kaminsky :

در سال 2008، محققی به نام Dan Kaminsky اعلام نمود که به شیوه ی تازه ای از حملات Cache Poisoning پی برده که بسیار بدتر از انواع قبلی است.

همانطور که در بالا شرح داده شد، در حمله ی Cache Poisoning مهاجم قادر بود تا با سمی کردن رکورد مربوط به Host مورد حمله در Cache سرور Recursive، کاری کند که درخواست کلاینت ها برای دسترسی به آن Host، به سمت سرور جعلی او منتقل شوند. اما آن چه Kaminsky کشف نمود این بود که مهاجم می توانست یک گام فراتر نهد و به جای سمی کردن تنها رکورد مربوط به یک Host، کاری کند که تمام درخواست هایی که مربوط به یک دامنه ی خاص هستند، سمی شوند. برای نمونه فرض کنید در تصویر بالا تمام درخواست هایی که مربوط به دامنه ی example.com هستند (www.example.com، www.example2.com و …) به سمت سرور جعلی مهاجم منتقل شوند.

مکانیزم این حمله به این صورت بود که مهاجم در این حالت به جای هدف قرار دادن A record در پیام DNS، به سراغ Authority رکوردها می رود و این گونه ادعا میکند که name server مورد درخواست نیست اما از آن اطلاع دارد و میتواند پاسخ درخواست های مربوط به این name server را بدهد. به این ترتیب هر درخواستی که به دست Recursive Resolver برسد که مربوط به دامنه ی هدف باشد، به سمت مهاجم ارسال می‌شود.

پیدا شدن این باگ دوباره لرزه‌ای را بر اندام جامعه‌ی اینترنت انداخت و آن ها را مجاب به یافتن راهی برای حل این مشکل نمود. راه حل پیشنهادی برای حل این مشکل آن بود که علاوه بر استفاده از QID های تصادفی، افزایش سایز QID از 16 بیت به 32 بیت صورت گیرد و هم چنین از شماره پورت های تصادفی برای هر پیام DNS به جای یک پورت UDP یکسان برای همه ی پیام ها، استفاده گردد. این راه حل ها گرچه سبب سختتر شدن کار مهاجمان برای انجام این حمله می شدند اما این حمله را به یک امر غیرممکن مبدل نمی‌ ساختند. بنابراین باز هم نیاز به روشی برای امن تر کردن DNS هم چنان احساس می شد.

درخشش DNSSEC

عملی که DNSSEC انجام می دهد آن است که با حفاظت از رکوردهای موجود در پیام DNS، برای Resolver این امکان را فراهم آورد که بتواند داده های DNS دریافتی را احراز هویت نماید. در واقع هدف DNSSEC فراهم کردن روشی است که از طریق آن اعتبار رکوردهای DNS توسط هرکسی که آن ها را دریافت می کند، سنجیده شود.

برای مطالعه ی بیشتر در رابطه با تاریخچه ی DNSSEC می توانید به این لینک مراجعه نمایید.

در قسمت بعد به سراغ DNSSEC و عملکرد آن می رویم تا بیشتر با این توسعه ی امنیتی و نه چندان جدید و فراموش شده ی DNS آشنا شویم.

 

نویسنده: مینا رضائی

محقق و همیشه در حال یادگیری، عاشق نقاشی، گاهی هم نویسندگی یا تألیف کتابای بزرگ :) (مسئولیت و صحت و سقم کلیه ی مطالب منتشر شده از جانب من تنها بر عهده ی خودم می باشد)

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.