воскресенье, 22 ноября 2015 г.

Разбор уязвимости DNS Каминского

Оригинал: Understanding Kaminsky's DNS Bug
Автор: Кори Райт (Cory Wright)

За последние дни всплыли подробности о природе уязвимости DNS, о которой Дэн Камински объявил две недели назад. Да, она настолько крупная и страшная, как и сообщалось.

Как вам, может быть, известно, Каминский согласовал объявление со многими крупными разработчиками программного обеспечения и обещал не раскрывать способ эксплуатации уязвимости до 6 августа, когда состоится ежегодная конференция специалистов по компьютерной безопасности Black Hat (чёрная шляпа) в Лас-Вегасе. У провайдеров было 30 дней, чтобы исправить их системы и защитить своих пользователей. Каминский также попросил членов сообщества по компьютерной безопасности воздержаться от публикации подробностей проблемы, пока не будет опубликовано официальное заявление. Возможно он попросил слишком многого, потому что уже через 13 дней проблема стала достоянием общественности.

Теперь стали известны подробности, а сам Каминский предоставил комментарии. Давайте изучим проблему и попытаемся понять, насколько она серьёзная.

Основы DNS

Для начала, нам нужно понять основы обмена данными DNS. Обычно имеется три действующих стороны:
  • ваш компьютер,
  • рекурсивные серверы DNS вашего провайдера, и
  • авторитативные DNS-серверы веб-сайта.
Авторитативные серверы DNS публикуют IP-адреса доменных имён. Рекурсивные серверы DNS общаются с авторитативными серверами DNS, чтобы найти адреса опубликованных ими доменных имён. Ваш компьютер общается только с рекурсивными серверами DNS, которые ищут для вас адрес доменного имени. Ваш компьютер и рекурсивные серверы DNS вашего провайдера представляют собой две разновидности клиентов, которые запрашивают информацию извне. Конечно, это упрощённое представление процесса, но для наших целей этого достаточно.

Давайте рассмотрим типичные DNS-запрос и ответ. Для этого мы воспользуемся доменным именем example.com и парой выдуманных серверов DNS. (Ненужные фрагменты вывода dig вырезаны).
$ dig @ns1.example.com www.example.com
;; ANSWER SECTION/РАЗДЕЛ ОТВЕТА/:
www.example.com. 120 IN A 192.168.1.10
;; AUTHORITY SECTION/АВТОРИТЕТНЫЙ РАЗДЕЛ/:
example.com. 86400 IN NS ns1.example.com.
example.com. 86400 IN NS ns2.example.com.
;; ADDITIONAL SECTION/ДОПОЛНИТЕЛЬНЫЙ РАЗДЕЛ/:
ns1.example.com. 604800 IN A 192.168.2.20
ns2.example.com. 604800 IN A 192.168.3.30
Здесь мы обратились к авторитетному серверу DNS, ns1.example.com, и спросили у него адрес www.example.com. Как можно видеть, ответ содержит IP-адрес www.example.com наряду с двумя другими наборами записей - авторитетными и дополнительными. Авторитетный раздел содержит список авторитативных серверов DNS для домена из запроса. Дополнительный раздел содержит IP-адреса этих серверов. То, что вся эта информация возвращается в одном ответе, имеет непосредственное отношение к недавней уязвимости.

Проверка зоны ответственности

Рассмотрим следующую аналогию. Предположим, что мы с вами путешествуем по скоростной автомагистрали и наша машина ломается. Я спрашиваю у вас телефонный номер ближайшей мастерской, а вы отвечаете: "Я не знаю их номер телефона. Вам нужно позвонить им, чтобы его найти." Но как узнать номер мастерской, если её номер ещё не известен?

Теперь представим ту же ситуацию применительно к DNS. Мы хотим найти адрес www.example.com, поэтому мы просим у корневого сервера DNS список DNS-серверов для .com. Корневой сервер DNS даёт нам список DNS-серверов .com, из которого мы берём один и спрашиваем у него список DNS-серверов для example.com. Если серверы .com просто ответят, что это ns1.example.com и ns2.example.com, мы окажемся в тупике. Мы хотели найти информацию об example.com, но по дороге узнали, что должны обратиться за ответом к DNS-серверам example.com. Чтобы решить проблему курицы и яйца, в дополнительном разделе предоставляются две записи "A", которые являются недостающим звеном. Они называются связующими записями.

Связующие записи - это обычные записи типа "A", которые предоставляются вместе с ответом. В ответе выше вполне могли оказаться посторонние записи:
$ dig @ns1.example.com www.example.com
;; ANSWER SECTION/РАЗДЕЛ ОТВЕТА/:
www.example.com. 120 IN A 192.168.1.10
;; AUTHORITY SECTION/АВТОРИТЕТНЫЙ РАЗДЕЛ/:
example.com. 86400 IN NS ns1.example.com.
example.com. 86400 IN NS ns2.example.com.
;; ADDITIONAL SECTION/ДОПОЛНИТЕЛЬНЫЙ РАЗДЕЛ/:
ns1.example.com. 604800 IN A 192.168.2.20
ns2.example.com. 604800 IN A 192.168.3.30
www.linuxjournal.com. 43200 IN A 66.240.243.113
Заметили дополнительную строку в конце? Мы запросили информацию о чём-то в домене example.com, но подлый сервер добавил в ответ информацию о www.linuxjournal.com. Этот сервер действительно имеет право отвечать на DNS-запросы к linuxjournal.com? Чтобы определить, принимать или не принимать эти дополнительные записи, клиенты используют приём, который называется проверкой зоны ответственности. Это просто означает, что игнорируются любые записи не из этого же домена. Если мы попросили информацию о ftp.example.com, то из дополнительного раздела мы примем информацию только об example.com.

Начиная с 1997 года, почти все современные клиенты DNS используют проверку зоны ответственности, чтобы защититься от этой разновидности атаки заражения кэша.

UDP и идентификаторы запросов

Большая часть трафика DNS отправляется поверх UDP, который является протоколом без установки соединения. Это означает, что клиент (ваш компьютер или рекурсивный сервер DNS) отправляет запрос и просто ждёт, когда кто-нибудь ответит. Обычно несколько запросов DNS выполняются одновременно, поэтому клиенту нужен способ сопоставить отправленные запросы с полученными ответами. Для этого каждый запрос снабжается числом от 0 до 65536, которое называется идентификатором запроса. Сервер всегда отправляет ответ с тем же идентификатором запроса, какой он получил в запросе.

Существовали эксплойты, угадывающие идентификатор запроса. Раньше клиенты просто увеличивали идентификатор запроса, поэтому угадать его было предельно просто. После появления эксплойтов, большинство DNS-клиентов начали использовать в качестве идентификаторов запросов псевдослучайные числа. Поскольку идентификатор запроса - это 16-битное число, чисел для выбора не так уж много (всего 65536). Исследователи в области компьютерной безопасности продемонстрировали методы предсказания этих случайных чисел.

Эксплойт

После того, как мы разобрались с основами, перейдём к эксплойту Каминского.

Представим, что клиент запрашивает IP-адрес doesnotexist.example.com. Атакующий отправляет ответ, который выглядит следующим образом:
$ dig doesnotexist.example.com
;; ANSWER SECTION/РАЗДЕЛ ОТВЕТА/:
doesnotexist.example.com. 120 IN A 10.10.10.10
;; AUTHORITY SECTION/АВТОРИТЕТНЫЙ РАЗДЕЛ/:
example.com. 86400 IN NS www.example.com.
;; ADDITIONAL SECTION/ДОПОЛНИТЕЛЬНЫЙ РАЗДЕЛ/:
www.example.com. 604800 IN A 10.10.10.20
Атакующий пытается обмануть клиента, заставив его поверить, что www.example.com теперь находится за 10.10.10.20 и это нужно запомнить на 604800 секунд (7 дней). Проверка зоны ответственности проходит успешно, поскольку домены в авторитетном и дополнительном разделах являются доменами из запроса. Однако вспомним, что клиент примет ответ только с тем идентификатором, который был отправлен в запросе. Поскольку в большинстве случаев трафик передаётся через UDP, ничто не мешает атакующим наводнить ответами клиента. Но отправка ответов на несуществующие запросы бессмысленна. Поэтому нужно чтобы ответ атакующего был получен до настоящего ответа.

Но атакующий не может просто угадать отправленные запросы. Чтобы не угадывать запросы, атакующий может настроить веб-страницу с большим количеством картинок, указывающих на различные домены. Вот так:
<img src="http://aaaa.example.com/image.jpg"/>
<img src="http://aaab.example.com/image.jpg"/>
<img src="http://aaac.example.com/image.jpg"/>
Когда браузер попытается отобразить эту страницу, он попросит клиента DNS найти адреса aaaa.example.com, aaab.example.com и так далее, пока пока не будут найдены адреса для всех 1000 картинок. По ходу поиска он будет отправлять запросы с разными идентификаторами запросов, от 1 до 65535. Если атакующий будет постоянно отправлять ответы с одним и тем же идентификатором запроса, например - 12345, в конечном итоге этот идентификатор совпадёт с идентификатором из одного из настоящих запросов и будет принят. (Для наглядности можно представить, что атакующий отправляет обратно одновременно 65536 ответов с разными идентификаторами запросов, и тогда уж точно один из ответов будет принят.)

А как же проверка зоны ответственности? Вспомним, что атакующий не контролирует example.com, он просто отправляет свои собственные ответы клиенту DNS, чтобы поддельные ответы прошли проверку зоны ответственности. Ответы могут выглядеть следующим образом:
;; ANSWER SECTION/РАЗДЕЛ ЗАПРОСА/:
aaaa.example.com. 120 IN A 10.10.10.10
;; AUTHORITY SECTION/АВТОРИТЕТНЫЙ РАЗДЕЛ/:
example.com. 86400 IN NS www.example.com.
;; ADDITIONAL SECTION/ДОПОЛНИТЕЛЬНЫЙ РАЗДЕЛ/:
www.example.com. 604800 IN A 10.10.10.20
Атакующий отправил ответ вашему клиенту DNS и указал ему на 7 дней сохранить 10.10.10.20 в качестве IP-адреса www.example.com. Все последующие DNS-запросы будут отправляться по этому адресу, потому что запись NS тоже попадёт в кэш.

Для эксплойта не имеет значения, каким был запрос, потому что авторитетный и дополнительный разделы всегда будут одними и теми же. Важно лишь, чтобы ответ прибыл до реального ответа на любой из этих запросов. Наводняя клиента ответами, атакующий увеличивает вероятность того, что один из ответов будет принят, а какой именно - не важно. Каминский обнаружил способ соединить слабость идентификаторов запросов с прохождением проверки зоны ответственности для заражения кэша.

До выпуска недавних исправлений уязвимости все клиенты провайдера (Comcast, AT&T, Verizon и т.п.) оказались бы уязвимыми, если один из них посетил бы веб-страницу атакующего. Рекурсивные DNS-серверы провайдера могли бы слать весь трафик www.bankofamerica.com на IP-адрес, который управляется кем-то, обладающим сомнительной репутацией.

Реальность эксплойта

Да, эксплойт реален и серьёзен. Крикет Ли, признанный эксперт и автор широкой известной книги "DNS и BIND" издательства O'Reilly, предположил, что это может быть самой значительной проблемой безопасности DNS в истории Интернета, а большинство других экспертов с ним согласились. Дэн Камински упомянул, что обмануть систему можно менее чем за 10 секунд. Это означает, что Дэн мог в считанные секунды заполучить контроль над вашим банковским счётом, электронной почтой, учётной записью на ebay или чем угодно, чем вы активно пользуетесь. И вы ничего не смогли бы с этим поделать. Каждый из тысяч или сотен тысяч пользователей вашего провайдера мог поставить под угрозу всех остальных клиентов, включая вас. Вот почему было так важно, чтобы эти системы были вовремя исправлены.

Перейдите на веб-сайт Дэна Камински, DoxPara Research, и щёлкните по кнопке "Check my DNS" ("Проверить мой DNS") справа, чтобы проверить, безопасен ли ваш провайдер. Если он всё ещё уязвим, вам стоит подумать о временном использовании OpenDNS.

воскресенье, 8 ноября 2015 г.

Переводы страниц руководства на manpages.stupin.su

Ранее, в заметке Легкий перевод страниц руководства с помощью po4a, я уже упоминал о своём проекте переводов страниц руководства manpages.ylsoftware.com. Теперь этот проект переехал на адрес manpages.stupin.su.

На старом сайте проекта практически все переводы соответствуют версиям страниц руководства, поставляемых в Debian Lenny. Долгое время я пытался обновить переводы, но каждый раз не успевал закончить обновление до выхода очередного релиза. К добавлению были готовы переводы из новых пакетов, которые я собирался представить одновременно с обновлением остальных переводов. И вот наконец я успел выполнить обновление до выхода очередного релиза Debian. В значительной мере этот релиз состоялся благодаря Вячеславу Чертову, который выполнил перевод страниц руководства из пакета traceroute, а также сконвертировал имеющийся в сети перевод страницы руководства screen и обновил его.

К обновлению приурочены несколько нововведений. Во-первых, сайт сменил адрес. Во-вторых, с него убраны устаревшие разделы, в том числе раздел с переводами из Dragonfly BSD. В-третьих, репозиторий теперь генерируется при помощи очень удобного инструмента - aptly. И, наконец, вишенка на торте - на сайте появился favicon :)

Подробнее о релизе можно прочитать в новости на сайте: manpages.stupin.su.

воскресенье, 1 ноября 2015 г.

IPSec между Debian и MikroTik

Коллеги с прошлой работы обратились за помощью. В одном удалённом офисе начались проблемы со связью, исправить которые провайдер не смог. В результате этот офис подключили к другому провайдеру. С предыдущим провайдером использовался DSL-модем, а компьютеры удалённого офиса подключались к центральному офису через индивидуальные подключения PPTP. Новый провайдер предоставляет услуги по Ethernet и поэтому DSL-модем нужно было заменить на что-то другое. В качестве замены они выбрали маршрутизатор MikroTik RB951G-2HnD, планируя заменить PPTP-подключения от каждого компьютера на общий туннель IPSec.



Не вдаваясь в детали, скажу что в центральном офисе установлен сервер под управлением Debian Squeeze, с которым и нужно было объединить MikroTik туннелем IPSec. На самом деле офис этот тоже не совсем центральный и имеется большой набор ресурсов, который доступен через каналы в вышестоящие локальные сети. Список используемых удалённым офисом ресурсов непостоянен, а потому стандартная настройка IPSec с шифрованием трафика между заранее известными сетями нам не подойдёт. В данном случае нужно считать, что за центральным офисом как бы находится сеть 0.0.0.0/0. В удалённом же офисе используется сеть 192.168.81.240/28.

Если изобразить это схематично, то получится такая схема:
[0.0.0.0/0] --- 192.168.81.1 debian 11.11.11.11 ==== 22.22.22.22 mikrotik 192.168.81.241 --- [192.168.81.240/28]
1. Хождение по мукам

Этот раздел можно безболезненно пропустить. Здесь я просто дал волю своей графомании и описал, какой ценой мне достался этот рецепт. Можете считать меня неудачником :)

Как ни странно, но сходу настроить даже тестовую конфигурацию мне не удалось. Туннель упорно не хотел подниматься и трафик не шёл. Стало понятно, что взять эту задачу нахрапом не получится. Маршрутизатор отдали мне на растерзание домой. Дома у меня есть коммутатор с поддержкой VLAN и компьютер, на котором я думал настроить необходимое количество виртуальных машин и соединить всё это между собой, собрав этакий виртуальный стенд.

В первый выходной я потратил на всё это безобразие около 9 часов и всё-таки поднял туннель, соединив внешний интерфейс маршрутизатора с внешним интерфейсом виртуальной машины под управлением Debian:
debian 11.11.11.11 === 11.11.11.12 mikrotik
Я, правда, так и не понял, чем настроенная конфигурация отличалась от той, которую я пытался настраивать первоначально. И так много времени ушло в этот раз скорее не на саму настройку, а на подготовительные работы - проброс VLAN, поиск нормально работающей системы для запуска виртуальных машин (воспользовался VirtualBox), её правильную настройку (нужно было собрать дополнительные модули для ядра Linux), скачивание и установку в виртуальную машину Debian Squeeze. Дополнительное время ушло на тупление с мостовым интерфейсом, который я настроить-настроил, а поднять забыл.

Ещё некоторое время было потрачено из-за моей невнимательности, когда IPSec стал требовать вдруг шифрования трафика и на локальном интерфейсе, в результате чего я потерял управление и мне пришлось сбрасывать MikroTik и настраивать его снова. Зато я узнал о существовании "безопасного режима" в RouterOS.

Наконец, после установки первоначального туннеля я потратил ещё некоторое время на шлифование конфигурации.

Во второй выходной я уже попытался воссоздать будущие условия работы маршрутизатора более точно. Сначала настроил такую схему, с дополнительной виртуалкой, которая изображала сеть провайдера и маршрутизировала трафик между Debian и MikroTik'ом:
debian 11.11.11.11 ==(провайдер)== 22.22.22.22 mikrotik
Далее я настроил ещё две виртуальные машины, каждая из которых изображала компьютер в офисе. Одна виртуальная машина изображала компьютер в центральном офисе, а вторая - в удалённом офисе. Получилась уже такая схема:
[192.168.80.113/24] --- 192.168.81.1 debian 11.11.11.11 ==(провайдер)== 22.22.22.22 mikrotik 192.168.81.241 --- [192.168.81.242/28]
Далее я потратил ещё некоторое время на тестирование настроек при включенном NAT на Debian. Дело в том, что NAT изменяет адрес отправителя (что ожидаемо - для этого он и предназначен). Из-за этого пакет с изменившимися IP-адресами отправителя и получателя может не попасть под правила IPSec и уйти не в удалённый офис через туннель IPSec, а уйти прямо в сеть провайдера безо всякого шифрования. Этот момент тоже нужно учитывать, чем я и занялся.

В результате получилась отлаженная конфигурация. Я настроил реальный сервер Debian и передал настроенный маршрутизатор своим бывшим коллегам. Были, правда, некоторые сомнения в том, что я всё учёл. Но, как это ни странно, когда маршрутизатор установили на место, всё сразу заработало как нужно. Полученный рецепт привожу ниже.

2. Настройка Debian

Для настройки туннеля я выбрал алгоритм шифрования blowfish, алгоритм хэширования sha1 и группу Дифи-Хеллмана, исходя из желания достичь наибольшей защищённости, поддерживаемой программным обеспечением с обеих сторон туннеля.

Перед настройкой укажу на особенность настраиваемого IPSec-туннеля. У этого туннеля нет IP-адресов конечных точек внутри туннеля. Фактически, IPSec хватает пакеты перед выходом из сетевого интерфейса, выполняет шифрование пакета и кладёт в IP-пакет, в котором указаны "белые" IP-адреса обеих сторон туннеля. Чтобы этот процесс не зациклился и пакеты не продолжали шифроваться и вкладываться снова и снова, IPSec'у чётко указываются правила, пакеты с какими IP-адресами необходимо подвергать обработке. Из-за такой особенности кажется весьма необычным, что пакеты с локальными IP-адресами маршрутизируются прямо через провайдерскую сеть. Очень важно понимать эту особенность, т.к. в противном случае при настройке IPSec можно натурально сойти с ума :)

Устанавливаем необходимые пакеты:
# apt-get install ipsec-tools racoon
Прописываем настройки racoon в файле /etc/racoon/racoon.conf:
remote 22.22.22.22 {
        nat_traversal off;
        exchange_mode main;
        proposal {
                encryption_algorithm blowfish;
                hash_algorithm sha1;
                authentication_method pre_shared_key;
                dh_group modp6144;
        }
}

sainfo anonymous {
      pfs_group modp6144;
      lifetime time 1 hour;
      encryption_algorithm blowfish;
      authentication_algorithm hmac_sha1;
      compression_algorithm deflate;
}
При помощи утилиты pwgen из одноимённого пакета генерируем случайный будущий общий ключ:
$ pwgen 32
Помещаем ключ в файл /etc/racoon/psk.txt:
22.22.22.22 generated_psk_sequence
Настроим ipsec, отредактировав файл /etc/ipsec-tools.conf
flush;
spdflush;

spdadd 192.168.81.240/28 192.168.81.240/28 any -P out none;

spdadd 0.0.0.0/0 192.168.81.240/28 any -P out ipsec
        esp/tunnel/11.11.11.11-22.22.22.22/require;

spdadd 192.168.81.240/28 192.168.81.240/28 any -P in none;

spdadd 192.168.81.240/28 0.0.0.0/0 any -P in ipsec
        esp/tunnel/22.22.22.22-11.11.11.11/require;
Запустим настроенные демоны:
# /etc/init.d/setkey start
# /etc/init.d/racoon start
Добавляем маршруты в удалённую локальную сеть через внешний интерфейс:
# ip route add to 192.168.81.240/28 via 11.11.11.11 src 11.11.11.11
Добавляем правила в пакетный фильтр для прохождения трафика IPSec:
# iptables -A INPUT -i eth0 -m udp -p udp -s 22.22.22.22 --dport 500 -j ACCEPT
# iptables -A INPUT -i eth0 -p ah -s 22.22.22.22 -j ACCEPT
# iptables -A INPUT -i eth0 -p esp -s 22.22.22.22 -j ACCEPT
Добавляем правила в пакетный фильтр для трафика из сети удалённого офиса к серверу Debian:
# iptables -A INPUT -i eth0 -s 192.168.81.240/28 -p tcp -m multiport --dport 25,53,80,110,143,3128 -j ACCEPT
# iptables -A INPUT -i eth0 -s 192.168.81.240/28 -p udp -m udp --dport 53 -j ACCEPT
Если на внешнем интерфейсе осуществляется трансляция адресов, то сеть, доступную через туннель IPSec, нужно исключить из обработки. Ниже приведены два правила - первое исключает сеть из обработки, второе осуществляет трансляцию адресов остального трафика:
# iptables -t nat -I POSTROUTING -o eth0 -d 192.168.81.240/28 -j ACCEPT
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 11.11.11.11
3. Настройка MikroTik

Внимание! Указанные ниже команды приведены для примера. Будьте внимательны и не копируйте их прямо в командную строку. Прежде чем выполнять любые примеры команд remove для начала проверьте при помощи команды print, что вы собрались удалить. Внимательно проверяйте IP-адреса и вообще - делайте что-то только если вы чётко представляете, зачем вы это делаете.

Добавляем новый адрес на локальном интерфейсе:
/ip address add interface=ether2-master-local address=192.168.81.241/28
Удаляем старый адрес 192.168.88.1, который был настроен на мостовом интерфейсе в конфигурации по умолчанию:
/ip address remove numbers=0
Переподключаемся на новый адрес, удаляем мостовой интерфейс:
/interface bridge remove numbers=0
Удаляем настройки DHCP-клиента на внешнем интерфейсе:
/ip dhcp-client remove numbers=0
Настраиваем новый внешний адрес:
/ip address add interface=ether1-gateway address=22.22.22.22/25
Настраиваем маршрут по умолчанию:
/ip route add gateway=22.22.22.1
Удаляем настройки NAT:
/ip firewal nat remove numbers=0
Удаляем правила пакетного фильтра:
/ip firewall filter remove numbers=0,1,2,3,4,5
Отключаем доступ к устройству по всем протоколам, кроме ssh:
/ip service disable numbers=0,1,2,5,6,7
Отключаем MAC-telnet (телнет с подключением по MAC-адресу, а не по IP-адресу):
/tool mac-server disable numbers=1,2,3,4,5,6
Теперь переходим к собственно настройке IPSec.

Настраиваем предпочитаемые алгоритмы аутентификации, шифрования и обмена ключами:
/ip ipsec proposal

set default auth-algorithms=sha1 \
enc-algorithms=blowfish \
lifetime=1h \
pfs-group=modp6144
Настраиваем политику, какой трафик шифровать:
/ip ipsec policy

add src-address=192.168.81.240/28 dst-address=192.168.81.240/28 \
sa-src-address=22.22.22.22 sa-dst-address=11.11.11.11 \
tunnel=no action=none

add src-address=192.168.81.240/28 dst-address=0.0.0.0/0 \
sa-src-address=22.22.22.22 sa-dst-address=11.11.11.11 \
tunnel=yes action=encrypt proposal=default
Настраиваем, с кем нужно установить соединение IPSec:
/ip ipsec peer

add address=11.11.11.11/32 local-address=22.22.22.22 port=500 \
auth-method=pre-shared-key secret="generated_psk_sequence" dh-group=modp6144 \
enc-algorithm=blowfish hash-algorithm=sha1 \
lifetime=1h nat-traversal=no
4. Использованные материалы