UPnP IGD profile

The UPnP Internet Gateway Device (IGD) profile is implemented on many routers and broadband cable or ADSL modems. The profile has a few subprofiles. Many of these profiles are nothing more than containers for one or more other subprofiles. When it comes to security there are a few profiles that are interesting:

The LANHostConfigManagement profile allows a program to query and possibly set various configuration parameters for, for example, DNS, DHCP and others. The WANIPConnection and WANPPPConnection profiles allow programs to adapt firewall rules, amongst other things.

LANHostConfigManagement

The LANHostConfigManagement profile enables programs to query and set local settings of a router, such as DNS and DHCP. The profile defines a few methods that are interesting methods for an attacker:

These methods should allow an attacker to completely rewire a router networkwise. Accordig to the standard they are required to implement. However, in practice these methods are either not implemented, return an error when they are invoked or UPnP and DNS/DHCP/routing are not coupled to the UPnP system. It never hurts to check though.

WANIPConnection/WANPPPConnection

Programs such as Live Messenger, Windows remote assistance, X-Box live, various networked consoles and games and quite a few Bittorrent clients use actions that are defined in the IGD subprofiles WANPPPConnection (ADSL modems) and WANIPConnection (IP routers) to make it easier to use the network. With these actions the IGD profile works around a fundamental problem of Network Address Translation (NAT): you can't use a predefined port easily anymore if you use NAT. If more than one program needs that port, unless you use something like a proxy. To give an example, say that Live Messenger would have a fixed port for file transfers. If you are behind NAT with a few people, who all want to transfer files with Live Messenger at the same time you have a problem. This is why many programs dynamically allocate a port to avoid conflicts with other programs.

To achieve this the programs make use of the following actions that are available in the UPnP IGD profile:

These actions are implemented as SOAP requests, as explained elsewhere.

A well behaved program first asks for a portmapping and deletes the portmapping when it is not needed anymore. Many UPnP stacks have only been tested with programs that behave well, so many bugs go unnoticed. The rest of this page explains where and why the software goes wrong.

AddPortMapping

The AddPortMapping SOAP command is the command with which a client on a network can request that the firewall opens a specific port and forwards it to the client. The parameters for the command are:

The NewRemoteHost parameter can be used to restrict the port mapping for just one external host, but in practice is never used. The NewExternalPort parameter is used to specify the TCP or UDP port on the WAN side of the router which should be forwarded. This parameter cannot be left empty, otherwise an error is returned, because the command does not make any sense anymore. The NewProtocol parameter can take two values: UDP or TCP. The NewInternalPort parameter specifies the port on a client machine to which all traffic coming in on NewExternalPort for the protocol specified by NewProtocol should be forwarded to. The NewInternalClient parameter sets the client machine that traffic should be sent to. The NewEnabled parameter tells the router if the portmapping should be enabled. In practice this is always set to True. The NewPortMappingDescription parameter is a human readable string that describes the connection. It is used in sorme web interfaces of routers so the user can see which program is using what port. The last parameter is NewLeaseDuration which tells the router how long the portmapping should be active. Since most programs don't know this in advance, it is often set to 0, which means 'unlimited'.

DeletePortMapping

The DeletePortMapping SOAP command takes three parameters:

The three parameters describe a portmapping that should be deleted. The values of the parameters are the same as for the AddPortMapping command.

Protocol dumbness

The specifications for the IGD profile allow any control point ot use AddPortMapping to forward ports to other machines on the LAN. While it can be convenient, it is really easy this way to open file servers, printers and other machines/devices to the outside world.

A fairly solution would be to not allow a control point to ask for port forwards for another IP address except its own. This will make the device not UPnP IGD compatible (strictly speaking), but I am fairly sure that every application/device that depends on port forwards will not break, since these applications/devices only ask for port forwards to themselves.

Common Errors

In many implementations the error checking has not been properly implemented. The parameters in the AddPortMapping request are often not checked to see if the values in there actually make sense.  To make it extra interesting the program that processes these requests is nearly always running with full system privileges, especially on the Linux based routers. Full system privileges are necessary to modify the firewalling rules that are active on the system. This turns a buggy UPnP implementation (most of them) into a ticking digital time bomb.

Involuntary onion routing/port redirection

Some stacks don't check if the NewInternalClient parameter is actually an IP address on the LAN. Those stacks make it possible to specify a routable IP address instead of a private LAN address. The firewall on the router will perform NAT on the incoming packets for the specified port and protocol and send it to whatever NewInternalClient specified. If this is an external IP address which is not on the LAN the packets will be sent there when someone connects to the router from the WAN. The router is effectively turned into an involuntary onion router, since nearly all devices have remote logging via syslog turned off by default and connections are hard to track this way.

Similarly, if a service, such as a website or mailserver, is deployed on a machine on the LAN, with a UPnP enabled router in front, with a forward directly to that service, it might be possible to first delete that forward and then redirect the port to another server with a fake mailserver or website.

In some devices it is possible to make the internal webserver of the router itself available to the outside world. If the default user and password are still there (which is quite often the case) this gives someone complete remote control of the router itself.

Executing shell commands on Linux based routers

Other stacks do less checks, but simply assume that whatever is specified in NewInternalClient is always an IP address. The value of the parameter is extracted from the SOAP request and simply passed on to scripts that are running on the router. These programs are in case of a Linux based router running with complete root privileges. Sometimes these programs are simple Bourne shell or bash scripts that execute a command, sometimes they are C programs that construct a shell command which is then executed using the system() system call. One stack even goes as far as using a PHP-like website, which constructs shell scripts which are then executed.

Using some simple shell script programming using backticks (an often used technique to assign the output of a program to a variable in normal shell scripts) it is possible to execute commands on the router. Depending on the stack there might be restrictions in place to limit the length of NewInternalClient the maximum length of a string representing an IPv4 address (4 * 3 digits, + 3 * 1 dot = 15 characters). This still leaves enough room for commands to for example reboot a router. Other routers have a limit of 255 characters, or no limit at all.

Solutions

A very simple solution which will fix the above mentioned errors is: check the input. In C there are a few standard functions available that can help to check the validity of the address to prevent bogus, like inet_aton(). Checks to see if the IP address specified in NewInternalClient is a valid LAN address should not be too hard to implement either.

The use of system() in C programs to call iptables to make a port mapping is a bit silly if you realize that:

Of course, all input should be checked, not just  NewInternalClient in AddPortMapping, but all parameters for all SOAP functions.

© 2006-2011, Armijn Hemel/upnp-hacks.org