Прошло чуть более года с момента публикации предыдущих статей (1, 2), и только недавно обстоятельства сложились так, что у меня появился повод для проведения новой атаки.
В этот раз физического доступа к сетевой инфраструктуре нет. Есть лишь ноутбук с доступом в интернет по Wi-Fi. Жертва – сосед по общежитию — подключена к другой точке доступа (DIR-320) по Ethernet, но пароль для подключения к точке известен почти всем, т.к. её хозяин предпочитает использовать в качестве средства разграничения доступа фильтрацию по MAC-адресам, добавляя и удаляя адреса из базы по мере необходимости. Моего MAC-адреса в списке разрешенных нет.
Ок, подключаемся, делаем несколько тестов, и видим, что фильтрация MAC-адресов происходит только на сетевом уровне, то есть точка доступа не отказывается:
- пересылать мои фреймы в Ethernet сегмент, и доставлять ответы
- отвечать на ARP-запросы и принимать ARP-ответы
Единственное что точка доступа отказывается делать, так это взаимодействовать с чужаком на сетевом уровне, то есть IP-адрес она мне через DHCP не выдаёт, пропинговать её нельзя и в интернет через неё тоже не выйти.
ARP-Spoofing
Для тех кто не знает что такое ARP и ARP-Spoofing – небольшой ликбез. Сетевой уровень, на котором используются IP-адреса, используется поверх канального уровня (на нём используются MAC-адреса, задающиеся производителями сетевой карты). Отправляя IP-пакет, компьютер должен обернуть его в Ethernet-фрейм, указав MAC-адрес получателя (или шлюза). Чтобы узнать MAC-адрес получателя, компьютер делает широковещательный ARP-запрос вида «Компьютер с ip a.b.c.d, отзовись!». Компьютер a.b.c.d отвечает ARP-ответом вида «a.b.c.d – это я, мой MAC-адрес следующий: 00:11:22:33:44:55». Причем ответ можно посылать даже если не было запроса и он будет обработан. Все компьютеры поддерживают кэш соответствий IP → MAC и при каждом удобном случае (получен ARP-запрос/ответ) его обновляют.
Никакой аутентификации на уровне ARP нет, на чем и основана атака ARP-spoofing. Достаточно представиться (отправить ARP-ответ) роутеру жертвой, а жертве роутером, чтобы проксировать через себя их трафик.
Но, раз в интернет точка доступа меня не пускает, то классический вариант ARP-спуфинга – встать между жертвой и роутером – не пройдёт. Раз так, можно встать не между жертвой и роутером, а вместо роутера. Идём на рынок, покупаем USB-WiFi адаптер, подключаемся встроенным адаптером (отключив на нём IP-протокол) к целевой сети, а вторым – к своей, чтобы иметь канал в интернет. Создаём в VirtualBox виртуальную машину с двумя адаптерами, первый соединяем мостом с целевой сетью, на втором делаем NAT. Настраиваем NAT внутри виртуальной машины-роутера, запускаем на ней же arpspoof с целью убедить компьютер жертвы, что MAC-адрес роутера сменился на наш.
В результате жертва будет отправлять пакеты не настоящему роутеру, а нашему, который сможет маршрутизировать их в интернет, просматривая и модифицируя. Практически стандартная схема ARP-спуфинга. Лишь с одним небольшим недостатком – она не работает. Точнее работает, но с такими перебоями, что жертва не может не заметить проблем с сетью.
Посмотрев на трафик в сети, можно понять почему. Да, мы уведомляем раз в секунду роутер жертвы о том что адрес 192.168.0.105 принадлежит нам, и жертву о том, что ip адрес 192.168.0.1 принадлежит нам. Однако в сети есть и другая ARP-активность. Например роутер периодически вещает в сеть «192.168.0.109, где ты?», причем такого адреса в сети нет. Причины этой активности не очень ясны – возможно на роутере прокинут порт с внешнего ip на этот адрес. Но ни к чему хорошему такая общительность со стороны роутера не приводит. Компьютер жертвы видит этот широковещательный запрос, и, хоть запрос и не относится к нему, обновляет у себя в кэше информацию о MAC-адресе роутера. В итоге получается race condition, и жертва отправляет исходящие пакеты то на наш адрес, то на адрес настоящего роутера.
Что же делать? Раз роутер так волнуется из-за несуществующих ip-адресов, нужно его утихомирить, например, сказав ему что эти адреса принадлежат нам. Итак:
- Раз в пару секунд посылать широковещательный запрос ARP request всем адресам сегмента, чтобы выяснить, кто же есть в сети
- Раз в десять секунд для каждого IP-адреса, который мы давно не видели в сети, отправлять ARP reply роутеру, сообщая, что этот адрес принадлежит нам
После добавления такой функциональности в виде скрипта на python, парсящего вывод tcpdump arp и рассылающего ARP-запросы и ответы, сбоев связи стало гораздо меньше. Когда какой-либо компьютер подключается к сети, он обычно начинает свою деятельность с ARP запроса своего IP и IP роутера, вследствие чего мы видим что он появился и перестаем выдавать себя за него. Когда компьютер отключается, мы видим что он отключился и занимаем его место. В итоге у роутера теперь нет поводов посылать широковещательные ARP-запросы и сбивать компьютер жертвы с толку.
Получение контроля над машиной
Прослушивание http-трафика, или использование sslstrip, с целью прослушать трафик ssl-enabled сайтов нас сейчас не интересует – во-первых это старо, во-вторых в трафике ничего интересного мы не найдём. Хочется получить полный контроль над целевой машиной.
Бэкдор
Для максимальных привилегий наша программа-бэкдор должна запускаться от имени LocalSystem. Для этого пишем Windows Service (на C# это пара десятков строк, которые к тому же генерирует IDE). Для управления будем использовать протокол Jabber (agsXMPP). Сервис будет при запуске коннектиться к Jabber-серверу, и ожидать команд. Управлять им можно будет с помощью любого Jabber-клиента, посылая команды через чат. Что касается команд – cmd.exe почему-то с точки зрения Windows считается программой с UI, а системным службам взаимодействовать с пользователем нельзя. Запустить cmd.exe из службы так и не удалось. В итоге было решено вместо команд оболочки cmd передавать боту код на C#, который он будет интепретировать и возвращать результат, получается достаточно универсальный «шелл».
Инсталлятор
Инсталлятор хранит в себе исполняемый файл и библиотеки сервиса и при запуске делает следующее:
- Сохранить файлы сервиса в какое-нибудь укромное место в директории %WINDOWS%
- Инсталлировать сервис
- Сделать HTTP GET на http://google.com/success (зачем это нужно – станет понятно позже)
Установка
Теперь нужно как-то заставить клиента запустить наш инсталлятор.
Посмотрим на автоматические обновления, может быть удастся подменить их. По HTTP-заголовкам выясняем, что на машине в качестве браузера стоит Opera, но, как оказалось, её обновления идут по https, так что нам они не по зубам. Обновления от Microsoft идут по plain-http, но там, наверняка, каждый файл обновления имеет цифровую подпись, которая проверяется перед запуском, всё-таки в MS не школьники работают.
Ок, с автоматическими обновлениями ничего поделать не удается, остаётся надеяться на невнимательность пользователя. Попробуем внедрить инсталлятор в первый попавшийся скачиваемый исполняемый файл.
Для этого пишем прозрачный прокси (на Twisted это чуть более сотни строк), который помимо своих обычных обязанностей выполняет следующие действия:
- Если URL запроса равен google.com/serviceinstaller, то в качестве ответа отдаём созданный ранее бинарник инсталлятора
- Если URL запроса равен google.com/success, то доложить мне об успехе и перейти в режим обычного честного прокси
- Если код ответа сервера равен 200, Content-Type принадлежит списку ['application/octet-stream', 'application/x-msdownload', 'application/exe', 'application/x-exe', 'application/dos-exe', 'vms/exe', 'application/x-winexe', 'application/msdos-windows', 'application/x-msdos-program', 'application/binary'], и Content-Length не превышает 20 мегабайт, то:
- Скачать файл
- Отправить файл POST-запросом на основную машину (т.к. там Windows) для дальнейшего анализа
- Ответ на POST-запрос отправить клиенту (соответственно подправив заголовки Content-Length и Content-MD5)
Запускаем этот прокси-сервер на роутере-виртуалке и перенаправляем с помощью iptables весь HTTP трафик на него.
Теперь пишем на C# проект-обертку, главная программа которого в качестве ресурса включает в себя в качестве ресурса исполняемый файл original.exe (пока что создадим просто пустой файл с таким именем). Прописываем в манифесте обертки, что она должна запускаться с правами администратора. Код обертки крайне прост:
- Скачать по адресу google.com/serviceinstaller и запустить инсталлятор нашего сервиса
- Сохранить встроенный ресурс original.exe во временный файл и запустить его
После этого пишем вспомогательный веб-сервер, который для каждого полученного запроса выполняет следующие действия:
- Сохранить полученные данные в файл original.exe
- Если original.exe является исполняемым файлом и не имеет цифровой подписи, то запустить перестроение проекта-обертки, и вернуть результат компиляции. Иначе вернуть исходный файл без изменений.
На этом с кодингом покончено. Теперь запускаем все компоненты, и смотрим, как оно должно работать:
- Пользователь идёт скачать какой-нибудь инсталлятор игры или ещё чего-то (неподписанных инсталляторов в интернете сейчас хватает, тот же Notepad++, который является весьма удобной и популярной программой)
- Прокси-сервер получает HTTP-запрос, пересылает его серверу, получает от сервера заголовки ответа, видит по заголовкам что скачиваемый файл — потенциальный кандидат на то, чтобы внедрить в него наш инсталлятор
- Прокси-сервер скачивает файл до конца, и посылает его серверу инъекций
- Сервер инъекций проверяет, что это действительно исполняемый файл (а то мало ли что в application/octet-stream могло передаваться), проверяет что файл без подписи, значит модифицировать его можно без опасности разоблачения (контрольные суммы инсталлятора всё равно никто не смотрит, даже если на сайте они выложены)
- Сервер инъекций компилирует бинарник-обертку, встраивая в него оригинальный исполняемый файл и возвращает результат прокси-серверу
- Прокси отдает файл клиенту (клиент ничего не заподозрит, так как исходный файл был не больше 20 мегабайт, а, значит, предыдущие три пункта задержали старт закачки всего на несколько секунд)
- Клиент запускает скачанный файл, получает запрос UAC (точно такой же, какой был бы от оригинального файла), акцептует его
- Скачивается и запускается наш инсталлятор, делает своё черное дело, сообщает об успехе нам
- Запускается оригинальный инсталлятор
Запустив всё, ждём. И, спустя пару дней, видим в логах сервера инъекций:
и в логах прокси-сервера:
Теперь можно идти к соседу и порадовать его, показав фокусы, которые мы можем делать с его компом (перезагрузить, выдать страшные звуки из аудиосистемы и т.п).
Выводы
- Фильтрация по MAC-адресу. Не полагайтесь на неё. От взломщика это не спасет. От студента, который хочет попользоваться интернетом за ваш счёт – тоже, он просто сменит MAC-адрес на любой из подслушанных.
- ARP-spoofing. От него можно защититься даже на SOHO роутере. Например для популярного девайса Dlink DIR-300/320 можно включить Guest Zone, которая изолирует клиентов друг от друга.
- MITM. Не пользуйтесь незащищёнными средствами связи (
например ICQ передает пароль открытым текстом, vk.com тоже, кажется, до сих пор так делает. UPD: ICQ и vk уже используют SSL для аутентификации). Если нужно скачать инсталлятор, качайте его по https. Если он раздается только по http, то проверьте после скачивания цифровую подпись файла. Если цифровой подписи нет, то сверьте контрольные суммы с указанными на сайте (желательно контрольные суммы на сайте смотреть по другому интернет-каналу). - Антивирус. Не полагайтесь на него, человек всегда будет умнее программы. Не знаю, как бы тут поступил другой антивирус, но Microsoft Security Essentials, стоящий на компьютере жертвы, на все вышеописанные манипуляции никак не отреагировал.
- Мораль. Повторю совет из первой части: не будьте «плохим парнем», может быть ваш сосед как раз ищет себе жертву.
______________________