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:
- LANHostConfigManagement
- WANIPConnection/WANPPPConnection
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:
- SetDNSServer
- DeleteDNSServer
- SetIPRouter
- DeleteIPRouter
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:
- 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.
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:
- NewRemoteHost
- NewExternalPort
- NewProtocol
- NewInternalPort
- NewInternalClient
- NewEnabled
- NewPortMappingDescription
- NewLeaseDuration
DeletePortMapping
The DeletePortMapping SOAP command
takes three
parameters:
- NewRemoteHost
- NewExternalPort
- NewProtocol
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:
- 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.