В первой части мы начнем рассматривать тему, связанную со cтеганографией и созданием скрытых каналов на базе стека протоколов TCP/IP.
Автор: John Torakis
В первой части мы начнем рассматривать тему, связанную со стеганографией и созданием скрытых каналов на базе стека протоколов TCP/IP.
Я знаю, что материал этой статьи не является чем-то новым. Просто загуглите фразу «Covert TCP». Все, что найдется, уже давно покрытой пылью времен, и даже реализован рабочий код. Однако по каким-то причинам я не часто встречаю использование этих техник в проектах, связанных с пентестами. Возможно из-за сероватого оттенка данных методов и отсутствия универсальной и практической реализации.
Однако простота идеи очень привлекает. Суть заключается в том, мы можем раздобыть большое количество (конфиденциальной) информации при помощи утечки через не строго определенные поля, используемые в заголовках сетевых протоколов (в частности IP и TCP). Далее будут показаны рабочие инструменты, а Эндрю Танетбаум уже написал пятое издание книги Computer Networks.
Поле Identification в протоколе IP
На рисунке ниже показан заголовок протокола IPv4:
Рисунок 1: Заголовок протокола IPv4
Вот что говорит нам RFC по поводу поля Identification:
Рисунок 2: Выдержка из RFC относительно поля Identification
Из документации следует, что поле Identification размером 16 бит и назначается отправителем с целью содействия в сборке фрагментов датаграммы.
Получается, что значение из этого поля полезно только в случае фрагментирования пакетов. В случае отсутствия фрагментирования это поле бесполезно. Абзац, описывающий поле Identification, мог бы закончиться так: «Только не используйте одинаковых значений».
Во всех реализациях протокола IP используется прибавление единицы. То есть каждый новый исходящий пакет будет иметь идентификатор, равный идентификатору предыдущего пакета + 1.
На базе этой концепции работала функция TCP Idle Scan в сканере nmap, предназначенная для сканирования портов, которое было очень сложно отследить. Как подобное могло произойти – отельная история. Очень напоминает дьявольскую идею от отъявленного сетевого мастера.
После появления подобных разработок в поле Identification стали использоваться случайные значения. И это наш шанс.
Случайные значения как точка отсчета!
Если мы знаем, что ожидаются случайные значения в определенном поле, то не можем выполнить никаких проверок, поскольку дозволены любые значения.
Например: в поле Identification пакета могут быть байты «FU» или «GG» или 2 нулевых байта (\x00). Мы не можем влиять на процесс формирования этого значения. И здесь начинается наша стартовая точка отсчета.
(На самом деле существует подводный камень под названием «энтропия». Жизнь не так проста, как кажется на первый взгляд. Поговорим о решении этой проблемы во второй части)
В наших экспериментах мы будем пользоваться утилитой Scapy и Python. Пристегните ремни:
Рисунок 3: Передача полезной нагрузки через IP-пакеты
На рисунке выше показана передача полезной нагрузки «Hello!» (6 байт) от отправителя получателю при помощи инкапсуляции в поле Identification в три IP-пакета (по 2 байта каждом).
Получатель собирает заново поля Identification из пакетов и воссоздает строку.
Эта простая схема выглядит очень впечатляющей. Кроме того, пакеты имеют специфический шестнадцатеричный формат, из-за чего передача таким способом довольно незаметна.
Рисунок 4: Шестнадцатеричное представление IP-пакета
Если присмотреться к рисунку выше, то можно обнаружить отдельные части полезной нагрузки «Hello!» в каждом пакете, которые передаются в формате с порядком следования байтов, начиная от старшего (Big Endian). С одной стороны, кажется, что такую схему легко обнаружить, но с другой – никто не будет анализировать заголовки пакетов на предмет информационной утечки. Эти пакеты могут быть поддельными HTTP-запросами, что еще больше запутает аналитика.
Проблема
Рисунок 5: Параметры файла /etc/shadow
Файл /etc/shadow вполне подходит для утечки, но если использовать только поле Identification, потребуется 978 пакетов.
Поиск альтернативы
Если посмотреть другие поля, которые нечетко определены или предназначены для передачи случайных данных, то подходящим кандидатом является поле ISN, используемым в протоколе TCP.
Рисунок 6: Формат пакета в протоколе TCP
Начальный номер последовательности (Initial Sequence Number) не является строго случайным, но меняется в широких пределах при каждом новом соединении (см. RFC 793, страницу 27).
Если коротко, то поле, содержащее номер последовательности, считает, сколько байт было передано во время соединения из точки A в B. Однако если бы все соединения начинались с номера последовательности равной 0 (поскольку еще не передано ни одного байта), это значение могло быть легко подобрано злоумышленником, что дает возможность инжектировать пакеты, передаваемые при соединении из точки A в B. Например, можно изменить .exe файл, загружаемый с FTP-сервера или веб-страницы.
С целью затруднения подбора ISN предусмотрен специальный синхронизирующий алгоритм, который делает содержимое поля ISN почти случайным. И тут наша игра только начинается.
Еще 4 байта?
В некотором смысле… Но здесь нужно быть аккуратным, поскольку при TCP-соединении номера последовательности не являются случайными, а хранят количество байт, передаваемых во время соединения. Случайность присутствует при формировании первоначального номера последовательности. Таким образом, в нашем распоряжении еще 4 байта «полосы» при попытке соединения. И только первый пакет каждого потенциального соединения. Успешного или неудачного. Эти пакеты мы будем доставлять под видом сканирования портов.
Таким образом, мы будем использовать скомпрометированную систему в качестве сканера портов. На первый взгляд, данная схема неидеальна, поскольку происходит выход во внешнюю среду, но давайте сначала взглянем на следующую строчку кода:
Рисунок 7: Получение списка наиболее популярных портов
На рисунке выше показан код для получения списка наиболее популярных портов из файла из файла nmap-services, где указана частота использования портов. Этот файл применяется в связке с параметром –top-ports.
Мы собираемся сделать имитацию сканирования портов.
Рисунок 8: Передача информации через симулятор сканера портов
В итоге мы получили хеш пароля, и весь процесс уместился в 17 пакетов.
.pcap файл со всеми пакетами, доступный для обработки в Wireshark и других приложениях, можно скачать отсюда. Можете провести анализ и сделать модификацию под ваш конкретный случай.
Примечание: приятно видеть, что в утилите scapy в качестве стандартного установлен порт источника 20/ftp-data, который, согласно информации с курса SANS504, наиболее популярен при сканировании. Очень разумно.
Удаленное выполнение команд
Продолжаем разговор. Чтобы работать с утилитой scapy, вначале необходимо получить права суперпользователя. Либо для создания пакетов, либо для 2-уровневого сниффинга. Если мы уже получили права суперпользователя, нужно выжимать по максимуму из этой возможности. А получение конфиденциальной информации лишь малая доля того, что можно сделать.
Далее мы попробуем организовать нестандартный скрытый шелл для удаленного выполнения команд.
Преимущества
Отсутствие соединения и, следовательно, тотальная незаметность в операционной системе с 4-уровневой системой сокетов.
Недостатки
Концепция
Мы хотим незаметно доставить и запустить команду, предназначенную для создания пользователя с паролем на удаленной машине:
Рисунок 9: Команда для создания имени пользователя и пароля в системе жертвы
Команду на рисунке выше следует разбить на несколько частей для доставки при помощи серии пакетов. Кроме того, в последнем пакете нужно предусмотреть переключатель для информирования слушателя на другом конце провода о завершении передачи, поскольку команды имеют различные длины.
Здесь также уместна идея дополнения (padding). Если после деления длины команды на 5 (новый канал одиночного пакета) присутствует остаток, значит, в последний пакет нужно добавить дополнительные байты. Впоследствии эти байты нужно либо удалять, либо игнорировать.
Слушатель команд
Рисунок 10: Код слушателя команд
На русском языке алгоритм выглядит так:
Внутри бесконечного цикла мы получаем первый пакет и собираем строку посредством соединения содержимого полей ID и Sequence Number. Полученную строку добавляем к полезной нагрузке. Если обнаруживается байт \xff, процесс продолжается (эта строка была добавлена для последующего расширения функциональности).
Если обнаруживается байт \xdd, значит, мы получили последний пакет, имеющий отношение к текущей команде. Затем происходит запуск команды при помощи функции system().
Далее выводится сообщение о том, какого рода задача выполняется на данный момент (в отладочных целях).
В конце обнуляем строку с полезной нагрузкой, ожидаем следующую команду и переходим в начало выполнения.
Отправитель команд
Рисунок 11: Код отправителя команд
Как видно на рисунке выше, код работает только для localhost и имеет множество ограничений, поскольку здесь реализован базовый вариант скрытого шелла. Расширенная версия будет продемонстрирована во второй части.
Демонстрация работоспособности скрытого шелла
Рисунок 12: Демонстрация удаленного выполнения команд (отправитель - слева, слушатель - справа вверху, пример выполнения команды – справа внизу)
Анализ передаваемых пакетов
Рисунок 13: Измерение энтропии у полей передаваемых пакетов
Во время анализа трафика выясняется, что поля ID и Sequence number не являются случайными, по крайней мере, у пакетов, отправляем с данного хоста. Интересно, почему?
Продолжение следует.
Наш канал — питательная среда для вашего интеллекта