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
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
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:
- AddPortMapping ::
adds a portmapping to your firewall configuration
- DeletePortMapping :: removes an existing portmapping
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.
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
The DeletePortMapping SOAP command
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
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.
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
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.
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:
- using system() means spawning an extra process, and
- there are perfectly valid alternatives such as libiptc that take care of a lot of troubles for you. Talking about libiptc, dear Broadcom, please respect the license of this library.