Вразливість BIND дозволяє «упустити» будь-сервер: як і чому це працює



Майже місяць тому, 11 січня 2017 року, розробники найбільш популярного DNS-сервер з відкритим вихідним кодом BIND випустили виправлення для чотирьох нових вразливостей, які дозволяють віддаленого атакуючому аварійно завершити роботу DNS сервера. У числі вразливостей присутній CVE-2016-9147, про яку далі піде мова. Атака не вимагає спеціальних умов крім необхідності зловмиснику бачити виходить від уразливого сервера трафік.

Ми задалися метою створити правила (NAD) для виявлення експлуатації даних вразливостей по мережі — щоб це зробити, нам довелося глибше розібратися з кодом BIND та написати власні експлоїти. Наш розбір допоможе зрозуміти, як все влаштовано всередині такого популярного DNS-сервера, а також дізнатися про прорахунках, допущених розробниками проекту, і можливі рішення цих проблем.

У чому проблема
Під найбільшим ризиком знаходяться рекурсивні сервери з підтримкою DNSSEC, тому далі ми розглянемо саме випадок рекурсивного запиту.

В описі патча стверджується, що певне поєднання DNSSEC записів у відповіді на рекурсивний запит може викликати відмову в обслуговуванні сервера або, по-простому, креш. Крім того, розробники доповнюють, що таке поєднання полів не зустрічається в нормальному DNS-трафік.

Для подальшого розуміння проблеми необхідно вивчити публічно доступний патч для цієї CVE. Патч виправляє усього кілька рядків коду в одному з модулів, відповідальних за обробку DNS відповідей.

--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -6984,15 +6984,19 @@ answer_response(fetchctx_t *fctx) {
* a CNAME or DNAME).
*/
INSIST(!external);
- if ((rdataset->type !=
- dns_rdatatype_cname) ||
- !found_dname ||
- (aflag ==
- DNS_RDATASETATTR_ANSWER))
+ /*
+ * Don't use found_cname here
+ * as we have just set it
+ * above.
+ */
+ if (cname == NULL &&
+ !found_dname &&
+ aflag ==
+ DNS_RDATASETATTR_ANSWER)
{
have_answer = ISC_TRUE;
- if (rdataset->type ==
- dns_rdatatype_cname)
+ if (found_cname &&
+ cname == NULL)
cname = name;
name->attributes |=
DNS_NAMEATTR_ANSWER;

Як ми можемо бачити, патч виправляє логічну помилку в умові

if ((rdataset->type != dns_rdatatype_cname) || !found_dname || (aflag == DNS_RDATASETATTR_ANSWER))
на 
if (cname == NULL && !found_dname && aflag == DNS_RDATASETATTR_ANSWER)

Виконання всіх трьох виразів стало обов'язковим для зміни змінної
have_answer
true. Це необходимо для визначення того, містив пакет-відповідь на наш запит:



Таким чином, стає очевидно, що експлуатація уразливості відбувається через неповне виконання умови з патча. Спробуємо зрозуміти, яке поєднання записів в пакеті необхідно для експлуатації.

Пишемо експлоїти
Потрапити в гілку з вразливим кодом можна через наступне короткий умова

6968 if (found) {

Змінна
found
встановлюється в п'яти блоках коду з цієї ж функції, які обробляють різні варіації відповідей, такі, як перенаправлення імен записами
CNAME
або
DNAME
, відповідь на запит з типом
ANY
і т. д.:


6891 if (rdataset->type == type && !found_cname) {
6892 /*
6893 * we've found an ordinary answer.
6894 */



6899 } else if (type == dns_rdatatype_any) {
6900 /*
6901 * we've found an answer matching
6902 * an ANY query. There may be
6903 * more.
6904 */



6907 } else if (rdataset->type == dns_rdatatype_rrsig
6908 && rdataset->covers == type
6909 && !found_cname) {
6910 /*
6911 * we've found that a signature
6912 * covers the type we're looking for.
6913 */



6917 } else if (rdataset->type ==
6918 dns_rdatatype_cname
6919 && !found_type) {
6920 /*
6921 * we're looking for something else,
6922 * but we found a CNAME.
6923 *



6955 } else if (rdataset->type == dns_rdatatype_rrsig
6956 && rdataset->covers ==
6957 dns_rdatatype_cname
6958 && !found_type) {
6959 /*
6960 * we're looking for something else,
6961 * but we found a SIG CNAME.
6962 */



Згадаймо невелику підказку в описі патча:

“Named mishandled some responses where covering RRSIG records are returned without the requested data resulting in a assertion failure. (CVE-2016-9147)"

Яка говорить, що одна із записів повинна бути записом
RRSIG
.
RRSIG
— це один з механізмів
DNSSEC
, що забезпечує цілісність даних DNS у відповіді. Для будь-якого типу (A, AAAA, NS, DNAME, CNAME і т. д.) у відповіді передається відповідна їм запис
RRSIG
, яка містить цифровий підпис. Для того, щоб зрозуміти, для якого типу
RRSIG
містить підпис,
RRSIG
є поле
Type Covered
.



Всього 2 з 5 умов пов'язані з виявленням RRSIG в DNS відповіді:

6907 } else if (rdataset->type == dns_rdatatype_rrsig
6908 && rdataset->covers == type
6909 && !found_cname) {
6910 /*
6911 * we've found that a signature
6912 * covers the type we're looking for.
6913 */
6914 found = ISC_TRUE;
6915 found_type = ISC_TRUE;
6916 aflag = DNS_RDATASETATTR_ANSWERSIG;

Дана перевірка спрацьовує, якщо ми виявили RRSIG з підписом для запису, що ми шукаємо (для якої посилали запит).

6955 } else if (rdataset->type == dns_rdatatype_rrsig
6956 && rdataset->covers ==
6957 dns_rdatatype_cname
6958 && !found_type) {
6959 /*
6960 * we're looking for something else,
6961 * but we found a SIG CNAME.
6962 */
6963 found = ISC_TRUE;
6964 found_cname = ISC_TRUE;
6965 aflag = DNS_RDATASETATTR_ANSWERSIG;
6966 }

А це умова подібно до першого, тільки запис RRSIG повинна покрити тип CNAME.

Ми впритул підійшли до висновку, що для експлуатації цієї помилки потрібна одна єдина запис RRSIG
ANSWER_SECTION
. І дійсно, така ситуація не повинна зустрічатися в звичайному DNS трафік, т. к. RRSIG не може бути не прив'язана до іншого запису.

Спробуємо відтворити топологію з рекурсивным DNS сервером і на рекурсивний запит надіслати відповідь з однієї RRSIG запису, яка покриває або CNAME або тип DNS запиту.



Як і передбачалося, ми бачимо аварійне завершення роботи Named демона:



у підсумку
Розглянута уразливість досить проста і небезпечна ще й тим, що для її експлуатації не потрібно складних умов. Розробники BIND постійно виправляють серйозні уразливості DNS сервери, які дозволяють порушити його роботу.

Експерти Positive Technologies уважно вивчили всі усунені розробниками уразливості, відтворили їх у реальних умовах і розробили IDS сигнатури для виявлення експлуатації.

@ISCdotORG #BIND remote #DoS
CVE-2016-9147
Affected: 9.9.9-P4, 9.9.9-S6, 9.10.4-P4, and 9.11.0-P1#Suricata rule:https://t.co/D4RujnkE9k  Attack Detection (@AttackDetection) February 7, 2017


Автор: Кирило Шипулін, спеціаліст групи з дослідження методів виявлення атак
Positive Technologies
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.