Why I finally disabled UPnP
Universal Plug and Play, UPnP for short, doesn’t have a great reputation.
To shamelessly quote Wikipedia:
Universal Plug and Play (UPnP) is a set of networking protocols that permits networked devices, such as personal computers, printers, Internet gateways, Wi-Fi access points and mobile devices to seamlessly discover each other’s presence on the network and establish functional network services for data sharing, communications, and entertainment. UPnP is intended primarily for residential networks without enterprise-class devices.
I can easily the recall the moment in which I initially fell in love with UPnP. It must have been around 2010-2011 and I was sitting in my living room playing around with a new Android phone I had recently acquired. I was watching Netflix to get a sense for the display quality when I saw a symbol in the corner of my screen I didn’t recognize. I tapped it, waited a few moments, and then watched in shock as my Xbox 360 came to life, opened Netflix, and resumed the video on my TV.
In that moment, I felt like Tony Stark automating his home around him with Jarvis and his glass tablet. I was taken aback by how invasive this tool would be if used improperly..
The good
UPnP is designed to make networking easier, and it does! When your phone is able to discover and list your Chromecast for casting Netflix, or you’re able to stream TV shows from your home Plex media server while half way across the world, we have UPnP to thank.
The use cases for UPnP are pretty vast, and it’s easy to see how a push towards zero-configuration networking would be advantageous as the IoT field expands and users are deploying more and more internet-connected devices on their home networks.
Relying on UPnP for service discovery on a home network, for example, allows users’ devices to talk to each other without explicitly needing to configure any hostnames or IPs.
UPnP also allows for remote access to devices otherwise hidden behind a NAT, which has loads of use cases for gaming and media streaming, and eliminates the need to delve into a router to configure port forwarding.
This is also know as ‘hole-punching’, and we’ll quickly see why many take issue with this practice.
The bad
As enabling as UPnP is for use cases like this, the online opinion on the protocol remains rather sour.
For one, the protocol is very dependent on multi-cast traffic, making it suboptimal for larger, enterprise networks as opposed to home networks.
The problematic component, however, seems to be the aforementioned ‘hole-punching’ component.
While allowing devices to configure themselves for remote access and create port mappings is quite convenient, this essentially allows any device to create its own backdoor into your local network. This generally places a lot of trust on your local devices, and with the rise in shoddy IoT products and botnets on the prowl, this is something to be taken seriously.
This is a lesson that I discovered first-hand, although the root cause was rather unexpected, and the potential impact was far greater.
The ugly
Earlier this year, I had setup and exposed a local device on my network to act as a reverse proxy on ports 80 and 443 for serving HTTP and HTTPS traffic. Understanding that this was going to generate quite a lot of malicious chatter, I kept a pretty close eye on my reverse proxy and router logs to ensure that nothing awry was happening that I wasn’t prepared for.
In hindsight, this was a smart move, as I quickly detected some pretty worrying behavior, although it wasn’t actually at all related to the reverse proxy I had setup.
Looking at my logs, I was seeing a mass of remote access logs from entirely unknown IP addresses to my local laptop I was using! From the logs, I could see that it wasn’t even any particular port that was being forwarded, but an array of unknown ports.
I checked lots of the source IPs against AbuseIPDB and was concerned to find that they were essentially all flagged as malicious. Scary!
Thankfully, I have a firewall running on my laptop and wasn’t hosting anything anyway, so these port scans wouldn’t return much. But geez though! What if I was?!
Somehow my router had seemingly made the executive decision to forward virtually all traffic towards my laptop. Why would that be happening?
Looking further into the logs, I was able to see the culprit:
For whatever reason, something triggering UPnP events on my router that seemed to be enabling this behavior. The port map deletion and subsequent remapping struck me as odd as well as the external IP address mapping.
I decided to analyze my network’s traffic with Wireshark to see if it might be the origin of these events, and sure enough, it was!
Doing a bit of work to properly interpret this, we can see my laptop sending a port map request to my router using Simple Service Disccovery Protocol (SSDP) and Port Control Protocol (PCP). Unsure as to why it would be doing so, I checked out the RFC for PCP to explore this further.
One thing that struck me as odd compared to what I was seeing was the Internal Port field:
Internal Port: Internal port for the mapping. The value 0 indicates ‘all ports’, and is legal when the lifetime is zero (a delete request), if the protocol does not use 16-bit port numbers, or the client is requesting ‘all ports’. If the protocol is zero (meaning ‘all protocols’), then internal port MUST be zero on transmission and MUST be ignored on reception.
This seemed to indicate what might be happening with me, although the specified port was 9, not 0, in my case. Unsure as to what port 9 would be used for, I found an old Internet-Draft outline PCP various flows. It provided me the answer I was looking for:
So, this shortlived mapping and request for external IP address seemed to align with the UPnP events I was seeing in the logs. The questions now were:
- What was triggering this UPnP packet on my laptop?
- Why was my router forwarding all traffic in addition to retrieving the external IP address?
The source
So where was this packet even coming from in the first place?
Using some tools like netstat
, I was ultimately able to determine the mDNSResponder was the source of these messages.
This is funcionality built-in to mDNSResponder, so seeing this packet isn’t entirely unexpected, but it does raise the question as to what was triggering mDNSResponder to request this external IP.
Interestingly enough, I was ultimately able to determine that this occurred every time I connected to my employer’s VPN, so my guess is that something else on the VPN was using mDNS to somehow trigger this on my laptop, although I wasn’t able to track this down, and I also couldn’t tell if this behavior would be malicious at all.
The side effects
With the source determined, I was curious as to why a relatively innocent PCP packet was triggering such dangerous behavior on my router. As it turns out, others have seen this before.
Ultimately, it seems as though there is an issue with my router’s PCP implementation. In the above Internet-Draft screenshot, you can see that the ‘Internal Port’ and ‘Suggested External Port’ fields are typically both set to 9, whereas the Suggested External Port is set to 0 in my case. I’m unclear as to whether or not this erroneous from the sender, but my guess is that a potential bug in my router is first handling the External IP Address and then erroneously acting in response to 0 value, forwarding all port as is outlined in this flow:
Given that the message doesn’t seem malicious in itself, I’m going to assume that there are some well-meaning request being handled that are inadvertantly triggering this scary behavior on my router.
I attempted to reach out to the vendor of my router to file a bug, but it appears as though they no longer accept bug reports for that class of device. Lovely.
So, with a better understanding as to what was happening, the fact remained that connecting to the VPN continued to trigger this behavior, which I really found quite sketchy. The cynic in me still suspects this could somehow be something cleverly malicous, targeting routers with pooly implemented UPnP. Also, understanding aside, I had no means of actually stopping this, and I’d really rather not leave my laptop open for constant port scanning.
That being said, I decided to disable UPnP on my router, in part as an immediate remedy to this issue, but also because the possibility of events like this occurring is pretty worrying to me.
For the most part, I haven’t really noticed any change. I had to explicitly set up port forwarding for a Plex server, and video games and software occassionally list my NAT as restricted, but I haven’t really noticed any major change! And I can always forward ports myself if need be.
It’s also worth noting that my local devices can still use UPnP to talk to each other, so I can still cast any media just fine.
All in all, a rather small price to pay!