В мае мы поделились статистикой по самым популярным атакам с отражением. Тогда средний размер атаки SSDP был в районе 12 Гбит/с, а крупнейшая атака SSDP с отражением была такой:

  • 30 Мп/с (миллионов пакетов в секунду)
  • 80 Гбит/с (миллиардов бит в секунду)
  • 940 тыс. IP-адресов для отражения

Всё изменилось пару дней назад, когда мы заметили необычно крупное умножение пакетов SSDP. Это достойно более тщательного расследования, поскольку атака преодолела символический рубеж в 100 Гбит/с.

График пакетов в секунду:



Использование полосы:



Пакетный флуд продолжался 38 минут. Судя по выборке потока данных, использовались 930 тыс. отражающих серверов. По нашей оценке, каждый рефлектор отправил 120 тыс. пакетов на Cloudflare.

Отражающие сервера располагались по в��ему миру, больше всего в Аргентине, России и Китае. Вот уникальные IP-адреса по странам:

$ cat ips-nf-ct.txt|uniq|cut -f 2|sort|uniq -c|sort -nr|head
439126 CN
135783 RU
74825 AR
51222 US
41353 TW
32850 CA
19558 MY
18962 CO
14234 BR
10824 KR
10334 UA
9103 IT
...


Распределение IP-адресов по ASN вполне типично. Оно во многом соотносится с крупнейшими в мире домашними интернет-провайдерами:

$ cat ips-nf-asn.txt |uniq|cut -f 2|sort|uniq -c|sort -nr|head
318405 4837 # CN China Unicom
84781 4134 # CN China Telecom
72301 22927 # AR Telefonica de Argentina
23823 3462 # TW Chunghwa Telecom
19518 6327 # CA Shaw Communications Inc.
19464 4788 # MY TM Net
18809 3816 # CO Colombia Telecomunicaciones
11328 28573 # BR Claro SA
7070 10796 # US Time Warner Cable Internet
6840 8402 # RU OJSC "Vimpelcom"
6604 3269 # IT Telecom Italia
6377 12768 # RU JSC "ER-Telecom Holding"
...


Впрочем, что такое SSDP?


Данная атака состоит из UDP-пакетов с порта 1900. Этот порт используется протоколами SSDP и UPnP. UPnP — один из протоколов Zeroconf (Zero Configuration Networking), которые создают IP-сеть без конфигурации или специальных серверов. Скорее всего, ваши домашние устройства поддерживают его, чтобы их легче было найти с компьютера или телефона. Когда присоединяется новое устройство (вроде вашего ноутбука), оно может опросить локальную сеть на предмет наличия конкретных устройств, таких как интернет-шлюзы, аудиосистемы, телевизоры или принтеры. Подробнее см. сравнение UPnP и Bonjour.

UPnP плохо стандартизирован, но вот выдержка из спецификаций о фрейме M-SEARCH — основном методе обнаружения:

Когда в сеть добавляется контрольная точка, протокол обнаружения UPnP позволяет этой контрольной точке поиск интересующих устройств в сети. Он делает это с помощью мультивещания поискового сообщения на зарезервированный адрес и порт (239.255.255.250:1900) с шаблоном, или целью, соответствующей типу идентификатора для устройства или сервиса.

Ответы во фрейм M-SEARCH:

Чтобы быть найденным поисковым запросом, устройство должно отправить одноадресный ответ UDP на IP-адрес источника и порт, который прислал сообщение с помощью мультивещания. Ответ требуется, если в поле заголовка ST в запросе M-SEARCH указано “ssdp:all”, “upnp:rootdevice”, “uuid:”, а далее следует UUID, который в точности соответствует UUID устройства, или если запрос M-SEARCH соответствует типу устройства или типу сервиса, поддерживаемому устройством.

Так оно и работает на практике. Например, мой браузер Chrome регулярно опрашивает Smart TV, насколько я понимаю:

$ sudo tcpdump -ni eth0 udp and port 1900 -A
IP 192.168.1.124.53044 > 239.255.255.250.1900: UDP, length 175
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:dial-multiscreen-org:service:dial:1
USER-AGENT: Google Chrome/58.0.3029.110 Windows


Этот фрейм отправляется на IP-адрес для мультивещания. Другие устройства, которые слушают этот адрес и поддерживают специфический многоэкранный тип ST (search-target), должны ответить.

Кроме запросов специфических типов устройств, существует два «общих» типа запросов ST:

  • upnp:rootdevice: поиск корневых устройств
  • ssdp:all: поиск всех устройств и сервисов UPnP

Для имитации этих запросов вы можете запустить такой скрипт Python (основанный на этой работе):

#!/usr/bin/env python2
import socket  
import sys

dst = "239.255.255.250"  
if len(sys.argv) > 1:  
    dst = sys.argv[1]
st = "upnp:rootdevice"  
if len(sys.argv) > 2:  
    st = sys.argv[2]

msg = [  
    'M-SEARCH * HTTP/1.1',
    'Host:239.255.255.250:1900',
    'ST:%s' % (st,),
    'Man:"ssdp:discover"',
    'MX:1',
    '']

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)  
s.settimeout(10)  
s.sendto('\r\n'.join(msg), (dst, 1900) )

while True:  
    try:
        data, addr = s.recvfrom(32*1024)
    except socket.timeout:
        break
    print "[+] %s\n%s" % (addr, data)

В моей домашней сети отзываются два устройства:

$ python ssdp-query.py
[+] ('192.168.1.71', 1026)
HTTP/1.1 200 OK  
CACHE-CONTROL: max-age = 60  
EXT:  
LOCATION: http://192.168.1.71:5200/Printer.xml  
SERVER: Network Printer Server UPnP/1.0 OS 1.29.00.44 06-17-2009  
ST: upnp:rootdevice  
USN: uuid:Samsung-Printer-1_0-mrgutenberg::upnp:rootdevice

[+] ('192.168.1.70', 36319)
HTTP/1.1 200 OK  
Location: http://192.168.1.70:49154/MediaRenderer/desc.xml  
Cache-Control: max-age=1800  
Content-Length: 0  
Server: Linux/3.2 UPnP/1.0 Network_Module/1.0 (RX-S601D)  
EXT:  
ST: upnp:rootdevice  
USN: uuid:9ab0c000-f668-11de-9976-000adedd7411::upnp:rootdevice 

Файрвол


Теперь, когда мы понимаем основы SSDP, будет легко понять суть атаки с отражением. На самом деле есть два способа доставки фрейма M-SEARCH:

  • который мы показали, через адрес для мультивещания
  • напрямую хосту UPnP/SSDP на обычном адресе (одноадресная передача)

Второй метод тоже работает. Мы можем конкретно указать IP-адрес моего принтера:

$ python ssdp-query.py 192.168.1.71
[+] ('192.168.1.71', 1026)
HTTP/1.1 200 OK  
CACHE-CONTROL: max-age = 60  
EXT:  
LOCATION: http://192.168.1.71:5200/Printer.xml  
SERVER: Network Printer Server UPnP/1.0 OS 1.29.00.44 06-17-2009  
ST: upnp:rootdevice  
USN: uuid:Samsung-Printer-1_0-mrgutenberg::upnp:rootdevice  

Теперь проблема легко понятна: протокол SSDP не проверяет, находится ли отправитель сообщения в той же сети, что и устройство. Оно с радостью ответит на запрос M-SEARCH, который пришёл из интернета. Требуется только чуть неправильная настройка файрвола, когда порт 1900 открыт внешнему миру — и вот идеальная мишень для умножения флуда UDP.

Если дать нашему скрипту такую мишень с неправильной конфигурацией файрвола, то он отлично сработает через интернет:

$ python ssdp-query.py 100.42.x.x
[+] ('100.42.x.x', 1900)
HTTP/1.1 200 OK  
CACHE-CONTROL: max-age=120  
ST: upnp:rootdevice  
USN: uuid:3e55ade9-c344-4baa-841b-826bda77dcb2::upnp:rootdevice  
EXT:  
SERVER: TBS/R2 UPnP/1.0 MiniUPnPd/1.2  
LOCATION: http://192.168.2.1:40464/rootDesc.xml

Умножение пакетов


Впрочем, самый реальный вред наносит тип ssdp:all ST. Его ответы намного больше по размеру:

$ python ssdp-query.py 100.42.x.x ssdp:all
[+] ('100.42.x.x', 1900)
HTTP/1.1 200 OK  
CACHE-CONTROL: max-age=120  
ST: upnp:rootdevice  
USN: uuid:3e55ade9-c344-4baa-841b-826bda77dcb2::upnp:rootdevice  
EXT:  
SERVER: TBS/R2 UPnP/1.0 MiniUPnPd/1.2  
LOCATION: http://192.168.2.1:40464/rootDesc.xml

[+] ('100.42.x.x', 1900)
HTTP/1.1 200 OK  
CACHE-CONTROL: max-age=120  
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1  
USN: uuid:3e55ade9-c344-4baa-841b-826bda77dcb2::urn:schemas-upnp-org:device:InternetGatewayDevice:1  
EXT:  
SERVER: TBS/R2 UPnP/1.0 MiniUPnPd/1.2  
LOCATION: http://192.168.2.1:40464/rootDesc.xml

... и ещё 6 ответных пакетов....

В этом конкретном случае единственный пакет SSDP M-SEARCH вызвал 8 пакетов в ответ. Просмотр в tcpdump:

$ sudo tcpdump -ni en7 host 100.42.x.x -ttttt
00:00:00.000000 IP 192.168.1.200.61794 > 100.42.x.x.1900: UDP, length 88
00:00:00.197481 IP 100.42.x.x.1900 > 192.168.1.200.61794: UDP, length 227
00:00:00.199634 IP 100.42.x.x.1900 > 192.168.1.200.61794: UDP, length 299
00:00:00.202938 IP 100.42.x.x.1900 > 192.168.1.200.61794: UDP, length 295
00:00:00.208425 IP 100.42.x.x.1900 > 192.168.1.200.61794: UDP, length 275
00:00:00.209496 IP 100.42.x.x.1900 > 192.168.1.200.61794: UDP, length 307
00:00:00.212795 IP 100.42.x.x.1900 > 192.168.1.200.61794: UDP, length 289
00:00:00.215522 IP 100.42.x.x.1900 > 192.168.1.200.61794: UDP, length 291
00:00:00.219190 IP 100.42.x.x.1900 > 192.168.1.200.61794: UDP, length 291


Мишень совершила восьмикратное умножение пакетов и 26-кратное умножение трафика. К сожалению, это типичный случай SSDP.

Спуфинг IP


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

Мы опросили IP-адреса рефлекторов, которые использовались в вышеупомянутой атаке на 100 Гбит/с. Оказалось, что из 920 тыс. адресов только 350 тыс. (35%) по прежнему отвечают ��а пробные запросы SSDP.

Ответившим на пробные запросы мы отправляли, в среднем, 7 пакетов:

$ cat results-first-run.txt|cut -f 1|sort|uniq -c|sed -s 's#^ \+##g'|cut -d " " -f 1| ~/mmhistogram -t "Response packets per IP" -p
Response packets per IP min:1.00 avg:6.99 med=8.00 max:186.00 dev:4.44 count:350337
Response packets per IP:
value |-------------------------------------------------- count
0 | ****************************** 23.29%
1 | **** 3.30%
2 | ** 2.29%
4 |************************************************** 38.73%
8 | ************************************** 29.51%
16 | *** 2.88%
32 | 0.01%
64 | 0.00%
128 | 0.00%


Пакеты с запросами имели размер 110 байт. Пакеты с ответами — в среднем, 321 байт (± 29 байт).

Согласно нашим измерениям, используя тип ssdp:all M-SEARCH, злоумышленник может получить:

  • 7-кратное умножение количества пакетов
  • 20-кратное умножение трафика

Можно подсчитать, что атака на 43 млн пакетов в секунду и 112 Гбит/с была инициирована с помощью:

  • 6,1 млн пакетов в секунду
  • канала 5,6 Гбит/с

Другими словами, один хорошо подключенный сервер на 10 Гбит/с, способный на подделку IP, может сгенерировать значительную атаку SSDP.

Подробнее о серверах SSDP


Поскольку мы опросили уязвимые серверы SSDP, мы можем показать самые популярные значения заголовка Server:

104833 Linux/2.4.22-1.2115.nptl UPnP/1.0 miniupnpd/1.0
77329 System/1.0 UPnP/1.0 IGD/1.0
66639 TBS/R2 UPnP/1.0 MiniUPnPd/1.2
12863 Ubuntu/7.10 UPnP/1.0 miniupnpd/1.0
11544 ASUSTeK UPnP/1.0 MiniUPnPd/1.4
10827 miniupnpd/1.0 UPnP/1.0
8070 Linux UPnP/1.0 Huawei-ATP-IGD
7941 TBS/R2 UPnP/1.0 MiniUPnPd/1.4
7546 Net-OS 5.xx UPnP/1.0
6043 LINUX-2.6 UPnP/1.0 MiniUPnPd/1.5
5482 Ubuntu/lucid UPnP/1.0 MiniUPnPd/1.4
4720 AirTies/ASP 1.0 UPnP/1.0 miniupnpd/1.0
4667 Linux/2.6.30.9, UPnP/1.0, Portable SDK for UPnP devices/1.6.6
3334 Fedora/10 UPnP/1.0 MiniUPnPd/1.4
2814 1.0
2044 miniupnpd/1.5 UPnP/1.0
1330 1
1325 Linux/2.6.21.5, UPnP/1.0, Portable SDK for UPnP devices/1.6.6
843 Allegro-Software-RomUpnp/4.07 UPnP/1.0 IGD/1.00
776 Upnp/1.0 UPnP/1.0 IGD/1.00
675 Unspecified, UPnP/1.0, Unspecified
648 WNR2000v5 UPnP/1.0 miniupnpd/1.0
562 MIPS LINUX/2.4 UPnP/1.0 miniupnpd/1.0
518 Fedora/8 UPnP/1.0 miniupnpd/1.0
372 Tenda UPnP/1.0 miniupnpd/1.0
346 Ubuntu/10.10 UPnP/1.0 miniupnpd/1.0
330 MF60/1.0 UPnP/1.0 miniupnpd/1.0
...


Самые популярные значения заголовка ST:

298497 upnp:rootdevice
158442 urn:schemas-upnp-org:device:InternetGatewayDevice:1
151642 urn:schemas-upnp-org:device:WANDevice:1
148593 urn:schemas-upnp-org:device:WANConnectionDevice:1
147461 urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
146970 urn:schemas-upnp-org:service:WANIPConnection:1
145602 urn:schemas-upnp-org:service:Layer3Forwarding:1
113453 urn:schemas-upnp-org:service:WANPPPConnection:1
100961 urn:schemas-upnp-org:device:InternetGatewayDevice:
100180 urn:schemas-upnp-org:device:WANDevice:
99017 urn:schemas-upnp-org:service:WANCommonInterfaceConfig:
98112 urn:schemas-upnp-org:device:WANConnectionDevice:
97246 urn:schemas-upnp-org:service:WANPPPConnection:
96259 urn:schemas-upnp-org:service:WANIPConnection:
93987 urn:schemas-upnp-org:service:Layer3Forwarding:
91108 urn:schemas-wifialliance-org:device:WFADevice:
90818 urn:schemas-wifialliance-org:service:WFAWLANConfig:
35511 uuid:IGD{8c80f73f-4ba0-45fa-835d-042505d052be}000000000000
9822 urn:schemas-upnp-org:service:WANEthernetLinkConfig:1
7737 uuid:WAN{84807575-251b-4c02-954b-e8e2ba7216a9}000000000000
6063 urn:schemas-microsoft-com:service:OSInfo:1
...


Уязвимые IP-адреса как будто принадлежат, в основном, домашним маршрутизаторам.

Открытый SSDP — это уязвимость


Само собой понятно, что разрешить входящий трафик 1900/UDP из интернета на ваш домашний принтер или другое устройство — не самая лучшая идея. Эта проблема известна по крайней мере с января 2013 года:


Авторы SSDP явно не думали о потенциале UDP как умножителя пакетов. Есть некоторые очевидные рекомендации об использовании SSDP в будущем:

  • Авторы SSDP должны ответить, существует ли в реальном мире хоть какая-то возможность использования одноадресных запросов M-SEARCH. Насколько я понимаю, M-SEARCH имеет практический смысл только как многоадресный запрос в локальной сети.
  • Поддержку одноадресных запросов M-SEARCH нужно либо отменить, либо ограничить по скорости, как действует ограничение DNS Response Rate Limit.
  • Ответы M-SEARCH должны отправляться только получателям в локальной сети. Ответы за пределы локальной сети имеют мало смысла и открывают возможность использования описанной уязвимости.

В то же время мы рекомендуем:

  • Сетевые администраторы должны убедиться, что входящий порт 1900/UDP заблокирован на файрволе.
  • Интернет-провайдеры никогда не должны разрешать IP-спуфинг в своей сети. Подделка IP-адресов — вот истинная корневая причина проблемы. См. пресловутый BCP38.
  • Интернет-провайдеры должны разрешить своим пользователям использовать BGP flowspec для ограничения входящего трафика 1900/UDP, чтобы рассредоточить скопление трафика при крупных атаках SSDP.
  • Интернет-провайдеры должны собирать образцы netflow. Это нужно для определения истинного источника атаки. С netflow будет просто ответить на вопросы типа: «Кто из моих клиентов отправлял 6,4 млн пакетов в секунду на порт 1900?» Для соблюдения конфиденциальности мы рекомендуем собирать образцы траф��ка с максимальным промежутком выборки: 1 из 64 000 пакетов. Этого достаточно для выявления DDoS-атак, и в то же время сохраняется достаточная конфиденциальность отдельных пользовательских сессий.
  • Разработчикам не следует выкатывать свои собственные протоколы UDP, не приняв в расчёт проблемы умножения пакетов. UPnP нужно нормально стандартизировать и изучить.
  • Конечным пользователям рекомендуется запустить скрипт для сканирования своих сетей на предмет устройств с функцией UPnP и подумать, стоит ли разрешать им выход в интернет.

Более того, мы сделали веб-сайт для онлайновой проверки. Зайдите на него, если хотите узнать, есть ли на вашем публичном IP-адресе уязвимые сервисы SSDP:


К сожалению, большинство незащищённых маршрутизаторов, которые использовались в этой атаке, находятся в Китае, России и Аргентине — местах, которые исторически не славятся расторопностью интернет-провайдеров.

Итог


Клиенты Cloudflare полностью защищены от атак SSDP и других атак с умножением класса L3. Эти атаки хорошо отражаются инфраструктурой Cloudflare и не требуют дополнительных действий. Однако увеличение размера SSDP может стать серьёзной проблемой для других пользователей интернета. Мы должны призвать своих интернет-провайдеров запретить IP-спуфинг в своих сетях, включить поддержку BGP flowspec и настроить сбор потока данных в сети (netflow).

Статью подготовили совместно Марек Майковски и Бен Картрайт-Кокс.