Stupidly Simple DDoS Protocol (SSDP) generates 100 Gbps DDoS
Last month we shared statistics on some popular reflection attacks. Back then the average SSDP attack size was ~12 Gbps and largest SSDP reflection we recorded was:
- 30 Mpps (millions of packets per second)
- 80 Gbps (billions of bits per second)
- using 940k reflector IPs
This changed a couple of days ago when we noticed an unusually large SSDP amplification. It’s worth deeper investigation since it crossed the symbolic threshold of 100 Gbps.
The packets per second chart during the attack looked like this:
The bandwidth usage:
This packet flood lasted 38 minutes. According to our sampled netflow data it utilized 930k reflector servers. We estimate that the during 38 minutes of the attack each reflector sent 112k packets to Cloudflare.
The reflector servers are across the globe, with a large presence in Argentina, Russia and China. Here are the unique IPs per country:
$ cat ips-nf-ct.txt|uniq|cut -f 2|sort|uniq -c|sort -n|tail
...
9103 IT
10334 UA
10824 KR
14234 BR
18962 CO
19558 MY
32850 CA
41353 TW
51222 US
74825 AR
135783 RU
439126 CN
The reflector IP distribution across ASNs is typical. It pretty much follows the world’s largest residential ISPs:
$ cat ips-nf-asn.txt |uniq|cut -f 2|sort|uniq -c|sort -n|tail
...
6377 12768 # RU JSC "ER-Telecom Holding"
6604 3269 # IT Telecom Italia
6840 8402 # RU OJSC "Vimpelcom"
7070 10796 # US Time Warner Cable Internet
11328 28573 # BR Claro SA
18809 3816 # CO Colombia Telecomunicaciones
19464 4788 # MY TM Net
19518 6327 # CA Shaw Communications Inc.
23823 3462 # TW Chunghwa Telecom
72301 22927 # AR Telefonica de Argentina
84781 4134 # CN China Telecom
318405 4837 # CN China Unicom
What’s SSDP anyway?
The attack was composed of UDP packets with source port 1900. This port is used by the SSDP and is used by the UPnP protocols. UPnP is one of the zero-configuration networking protocols. Most likely your home devices support it, allowing them to be easily discovered by your computer or phone. When a new device (like your laptop) joins the network, it can query the local network for specific devices, like internet gateways, audio systems, TVs, or printers. Read more on how UPnP compares to Bonjour.
UPnP is poorly standardised, but here’s a snippet from the spec about the M-SEARCH
frame – the main method for discovery:
When a control point is added to the network, the UPnP discovery protocol allows that control point to search for devices of interest on the network. It does this by multicasting on the reserved address and port (239.255.255.250:1900) a search message with a pattern, or target, equal to a type or identifier for a device or service.
Responses to M-SEARCH
frame:
To be found by a network search, a device shall send a unicast UDP response to the source IP address and port that sent the request to the multicast address. Devices respond if the ST header field of the M-SEARCH
request is “ssdp:all”, “upnp:rootdevice”, “uuid:” followed by a UUID that exactly matches the one advertised by the device, or if the M-SEARCH
request matches a device type or service type supported by the device.
This works in practice. For example, my Chrome browser regularly asks for a Smart TV I guess:
$ 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
This frame is sent to a multicast IP address. Other devices listening on that address and supporting this specific ST
(search-target) multiscreen type are supposed to answer.
Apart from queries for specific device types, there are two “generic” ST
query types:
upnp:rootdevice
: search for root devicesssdp:all
: search for all UPnP devices and services
To emulate these queries you can run this python script (based on this work):
#!/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('rn'.join(msg), (dst, 1900) )
while True:
try:
data, addr = s.recvfrom(32*1024)
except socket.timeout:
break
print "[+] %sn%s" % (addr, data)
On my home network two devices show up:
$ 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
The firewall
Now that we understand the basics of SSDP, understanding the reflection attack should be easy. You see, there are in fact two ways of delivering the M-SEARCH
frame:
- what we presented, over the multicast address
- directly to a UPnP/SSDP enabled host on a normal unicast address
The latter method works. We can specifically target my printer IP address:
$ 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
Now the problem is easily seen: the SSDP protocol does not check whether the querying party is in the same network as the device. It will happily respond to an M-SEARCH
delivered over the public Internet. All it takes is a tiny misconfiguration in a firewall – port 1900 UDP open to the world – and a perfect target for UDP amplification will be available.
Given a misconfigured target our script will happily work over the internet:
$ 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
The amplification
The real damage is done by the ssdp:all
ST
type though. These responses are much larger:
$ 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 more response packets....
In this particular case, a single SSDP M-SEARCH
packet triggered 8 response packets. tcpdump view:
$ 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
That target exposes 8x packet count amplification and 26x bandwidth amplification. Sadly, this is typical for SSDP.
IP Spoofing
The final step for the attack is to fool the vulnerable servers to flood the target IP – not the attacker. For that the attacker needs to spoof the source IP address on their queries.
We probed the reflector IPs used in the shown 100 Gbps+ attack. We found that out of the 920k reflector IPs, only 350k (38%) still respond to SSDP probes.
Out of the reflectors that responded, each sent on average 7 packets:
$ 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%
The response packets had 321 bytes (+/- 29 bytes) on average. Our request packets had 110 bytes.
According to our measurements with the ssdp:all
M-SEARCH
attacker would be able to achieve:
- 7x packet number amplification
- 20x bandwidth amplification
We can estimate the 43 Mpps/112 Gbps attack was generated with roughly:
- 6.1 Mpps of spoofing capacity
- 5.6 Gbps of spoofed bandwidth
In other words: a single well connected 10 Gbps server able to perform IP spoofing can deliver a significant SSDP attack.
More on the SSDP servers
Since we probed the vulnerable SSDP servers, here are the most common Server
header values we received:
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
...
The most common ST
header values we saw:
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
...
The vulnerable IPs are seem to be mostly unprotected home routers.
Open SSDP is a vulnerability
It’s not a novelty that allowing UDP port 1900 traffic from the Internet to your home printer or such is not a good idea. This problem has been known since at least January 2013:
Authors of SSDP clearly didn’t give any thought to UDP amplification potential. There are a number of obvious recommendations about future use of SSDP protocol:
-
The authors of SSDP should answer if there is any real world use of unicast
M-SEARCH
queries. From what I understandM-SEARCH
only makes practical sense as a multicast query in local area network. -
Unicast
M-SEARCH
support should be either deprecated or at least rate limited, in similar way to DNS Response Rate Limit techniques. -
M-SEARCH
responses should be only delivered to local network. Responses routed over the network make little sense and open described vulnerability.
In the meantime we recommend:
-
Network administrators should ensure inbound UDP port 1900 is blocked on firewall.
-
Internet service providers should never allow IP spoofing to be performed on their network. IP spoofing is the true root cause of the issue. See the infamous BCP38.
-
Internet service providers should allow their customers to use BGP flowspec to rate limit inbound UDP source port 1900 traffic, to relieve congestion during large SSDP attacks.
-
Internet providers should internally collect netflow protocol samples. The netflow is needed to identify the true source of the attack. With netflow it’s trivial to answer questions like: “Which of my customers sent 6.4Mpps of traffic to port 1900?”. Due to privacy concerns we recommend collecting netflow samples with largest possible sampling value: 1 in 64k packets. This will be sufficient to track DDoS attacks while preserving decent privacy of single customer connections.
-
Developers should not roll out their own UDP protocols without careful consideration of UDP amplification problems. UPnP should be properly standardized and scrutinized.
-
End users are encouraged to use the script scan their network for UPnP enabled devices. Consider if these devices should be allowed to access to the internet.
Furthermore, we prepared on online checking website. Click if you want to know if your public IP address has a vulnerable SSDP service:
Sadly, the most unprotected routers we saw in the described attack were from China, Russia and Argentina, places not historically known for the most agile internet service providers.
Summary
Cloudflare customers are fully protected from SSDP and other L3 amplification attacks. These attacks are nicely deflected by Cloudflare anycast infrastructure and require no special action. Unfortunately the raising of SSDP attack sizes might be a tough problem for other Internet citizens. We should encourage our ISPs to stop IP spoofing within their network, support BGP flowspec and configure in netflow collection.
This article is a joint work of Marek Majkowski and Ben Cartwright-Cox.
Dealing with large attacks sounds like fun? Join our world famous DDoS team in London, Austin, San Francisco and our elite office in Warsaw, Poland.
No comments yet.