Linux IGD & Pseudo ICS daemon

A very popular UPnP stack on Linux based devices is Linux IGD. This stack cound be found on many Linux based devices that do not contain a Broadcom or Texas Instruments CPU, but Realtek or ADMtek devices. There are various incarnations of this stack, with a varying degree of bugs. Early versions were written in C++, and included a check to see if the NewInternalClient parameter in the AddPortMapping SOAP request is an actual IP address, but newer versions (written in C and used on a lot of routers) omitted this check and just passed strings around, meaning you can put basically anything in it, including shell commands which are executed on the router with full root privileges.

Depending in the version of Linux IGD that was used there might be a check for length on the NewInternalClient parameter (15 characters maximum). Even with this check you can still execute a small shell command inside backticks with full root privileges on the router itself. This is enough to reboot the router, or set it back to factory defaults. This is the code that is used on all EdiLinux based devices (EdiLinux is what's running on a lot of devices from Edimax and its resellers).

The faulty code can be found mostly in the files pmlist.c (in the function pmlist_AddPortMapping), pmlist.h and gatedevice.c.

These bugs were fixed Linux IGD in May 2006. These versions use execv() instead of system(), or use libiptc if available.

Other bugs that are present (but I don't know yet if they exist in every version of Linux IGD, or just in devices from a single manufacturer) is that the UPnP port is running on the WAN side and you can use UPnP to make internal ports (such as the webinterface) available on the WAN interface. I have also seen one device where you could actually use a lot more code than 13 characters.

Pseudo ICS daemon

Pseudo ICS daemon is a predecessor of Linux IGD and works only with systems that are based on a Linux 2.2 kernel. It is not used much, but every once in a while a device pops up which has this stack. The Pseudo ICS daemon software was written in 2002, but development has stopped a long time ago. Compared to early versions of Linux IGD there are more checks in place to verify the correctness of parameters.

Linux IGD devices

Linux IGD is one of the most widely used UPnP stacks. A lot of companies use it in their products. These companies often make use of the same ODM companies. There are a lot fewer 'unique' devices out there than you might think.

The GPL sources for a Linux based device are a good indication if they are provided (this is not always the case, please contact if you find a GPL violation). The GPL sources quickly lets you determine if the device is vulnerable or not.

Recognizing Linux IGD

The Linux IGD system can be recognized in a few ways. None of these are totally fool proof and other stacks might use them too. The first one is the TCP port. Normally 49152 is used, but occasionally TCP port 49153 is used as well. It seems that sometimes it uses this port if it gets confused enough (accidental power loss, reboot) and 49152 seems to be locked or busy for some reason (for example, another instance of a UPnP daemon).

Linux IGD quirks

The Linux IGD stack has a few quirk you should keep in mind when trying to exploit it. It doesn't always respond directly to discovery requests, but sends out a NOTIFY every now and then (usually 30 minutes). If your script actively first sends a discovery request (as required by the protocol) and then waits until it gets an answer, it will have to wait a long time. It is easier to hardcode the URLs to send commands to in that case.

Another quirk is that sometimes (but not always) the Linux IGD stack requires its input to follow some rules, otherwise it will reject it. I've seen on one device that NewPortMappingDescription (part of WANIPConnection in IGD) needed to have some value and it needed to be a 'normal' character. A single space for example was rejected, while 'a' was acceptable, even in combination with spaces.

© 2006-2011, Armijn Hemel/