Exploiting UPnP, Literally Childsplay.

As a kid, I used to love playing Minecraft. I was technically precocious from a fairly young age, and naturally gravitated to attempting to host my own Minecraft server for me and my band of geeky pals to play on. The problem was, I had no idea what port forwarding was, nor how to log into a router. The solution I found was about as novel as it was dumb.

I tried a few different things initially. I firstly tried hosting a Minecraft server on a few different ‘free’ VPS suppliers. Immediately, the lack of RAM was an issue, creating unplayable lag spikes that took the fun out of it. It took me a while to realise that there was no free lunch, and nobody was going to host my ridiculously resource hungry Java based server in a way that would be beneficial to me. Gigabytes of RAM were expensive.

Next, I tried hosting it locally, but kept hitting up against a concept my young brain knew nothing about - which was port forwarding. I knew it required access to the Router, but that was guarded by my father, who was understandably and correctly worried about letting his son mess about in settings that he himself also did not really understand.

A photo of a white Netgear DG834GT router

Netgear DG834GT - The router provisioned to my family

Furious, rushed Googling led me to Hamachi. Hamachi, now owned by LogMeIn is a hosted VPN service. Effectively it puts you and your friends who want to play on a VPN together. This worked a little better than my previous attempts, but still introduced a lot of latency, and as such wasn’t ideal. I stuck with this for a little while, but there had to be a better way.

The only other time I’d ever come across port forwarding was in my use of Bittorrent. Supposedly, without an open port, Bittorrent couldn’t function correctly. How did it function correctly then, I wondered? My client of choice (Transmission) would dutifully tell me whichever port I selected was ‘open’. Were all the ports open? Was my Minecraft server lying to me? After all, Transmission seemed to work perfectly downloading and even seeding things. I regularly used Bittorrent for distributing files between my few PCs and friends at the time, and it seemed to work perfectly.

A screenshot showing the Transmission Bittorrent 'test open port' function

No matter the Listening Port number - Test Port reported open!

It didn’t seem to matter which port I selected, when I pressed that “Test Port” button, somehow it was open! This wasn’t fair! How come the router stazi allowed Transmission to talk to whoever it wanted to, whenever it wished, yet my poor Minecraft server received no such special treatment? Was Big Torrent bribing Netgear? What sort of nepotism was this?!

UPNP meant nothing to me, and I didn’t think to Google it at the time, but it was the technology that allowed Transmission to talk to whoever it wanted.

One day, almost by accident, I found a solution, that was far better than Hamachi. It turned out that if I opened the Minecraft Server first, then entered the port that it was configured to use into the Port box within Transmission, and then hit Test Port, and left Transmission open while me and my friends would waste hours building things I’d eventually accidentally blow up with TNT, it just seemed to work!

What I didn’t realise back then was I was taking advantage of a security flaw within UPNP. Even though I was innocently hijacking the port Transmission opened for use with Minecraft, I was actually exploiting a fairly serious security vulnerability in the protocol. UPNP allows any old software to punch a hole through your routers firewall. It doesn’t verify which software is making use of said port. Any old code running on your computer is able to do this, including most terrifyingly to me at the time I realised what I was doing the hugely popular Adobe Flash.

How UPnP works

UPnP is a complicated standard whose overarching goal is to allow devices on a network to discover each others presence without require configuration from the user. It seems to want to abstract over various network configurations to reduce the mental burden of the user using a product which supports it. A noble goal. Far too much to talk about here! Instead I will focus on one part of UPnP, which is how it allows devices inside your network to punch holes through your routers firewall (port forward).

UPnP makes use of Internet Gateway Device Protocol, which is a protocol for mapping ports where NAT (Network Address Translation) is in use. Effectively it allows devices on a network to communicate their requests for a router to route data hitting a particular port to a the system making the request. IGDP also allows applications to learn the external IP address without having to use an external system, and even see which port mappings already exist. Crazily, there is even provision for the standard to allow applications on your network to request the router get a new public IP address, however I’ve personally never seen this in use.

When an application, for example Transmission, wants to map a port for its use, it makes a request to what the RFC for this refers to as the IGD Control point (in most cases the router).

After this, and if authentication is either not enabled or passes (it is not enabled in most cases!) - the IGD sends a “AddAnyPortMapping()” request through to the Internet Gateway Device - Port Control Protocol Interworking Function, or the IGD-PCP IWF for short. Oh aren’t RFCs fun! The IGD-PCP IWF then makes a Port Control Protocol MAP request to the PCP server.

The PCP Server can then do one of three broad categories of things:

  • It can refuse. It may refuse because the port has already been opened for someone else. It may refuse for other reasons too.
  • It can accept, and return a PCP MAP Response with the assigned external port the UPnP Control Point requested
  • It can accept, and return a PCP MAP Response with another external port that the UPnP Control Point did not request but it can use if it wishes.

The application that triggered this whole flow may then test that the port mapping worked - usually by using some external api to attempt to GET something running on that port on the machine running the software. Voila, the port is open. The software can then request that the mapping it made be deleted. So can anyone else who can make requests to the IGD. The Software then effectively has a lease over this port, and the port will remain open until its lease expires, or the software deletes it manually. The maximum length of a lease is configurable by the IGD, but the max defined in the spec is 4294967296 seconds - a ridiculously high max.

The only other case where the lease will be terminated is when the IP that generated it is no longer around. If the machine shuts down or its DHCP lease over its own IP expires, the spec assumes the port mappings associated with it are lost too. This is not always the case though.

The RFC states that “we assume that the IGD applies the appropriate security policies to determine whether a Control Point has the rights to delete one or a set of mappings”. This is not an unreasonable assumption; after all, routers come in all shapes and sizes, and the authentication mechanisms they rely on come in various shapes and sizes too. It has become obvious with time though that due to the nature of the consumer hardware industry, security is an afterthought, if a thought at all. Indeed, a rather hilarious but sad security exploit reported by Akamai found that around 3.5 million routers scanned responded to UPnP probe packets. This means that external parties can punch holes through the firewall by sending UPnP requests to it. Even worse, around 277,000 of these routers actually don’t verify that the software making the request is port forwarding to itself! In fact, the RFC mandates this. If routers were to ensure that port mappings being requested by a source were to point at that source, they’d not be in compliant with RFC 6970!

This means that previously inaccessible hosts within a network can now be reached by attackers spamming the routers with UPnP port forward requests - effectively opening the machines behind the firewall to the open internet. Terrifying stuff.

It gets worse though. Some of these routers routers don’t do this origin check, and in addition they don’t even check that the port mapping points to a machine that exists on the local network. Essentially this means that any one of these routers can be hacked to become a sort of proxy. How? By asking it to, of course.

This is why I now disable UPNP everywhere I have the power to. It’s one of those convenient yet terrifying technologies I am not sure I can trust. Sometimes free convenience is far more expensive than anybody realizes. Just ask the NSA.

Let me know what you thought! Hit me up on Mastodon at @kn100@fosstodon.org.