Several years ago, everyone on the Internet was talking about a security bug in Windows' Universal Plug and Play (UPnP) component. This news scared many users to the extent that they never installed or enabled UPnP on their Windows platforms, let alone purchased UPnP devices. But Microsoft fixed the bug long ago, and now many (if not most) networked devices such as media players and broadband routers are UPnP enabled, letting systems administrators remotely manage them. What you might not realize is that other people and applications might be compromising your network's security by modifying devices such as your UPnP broadband router.
Understanding the Threat
Broadband routers are a type of Internet Gateway Device (IGD)—that is, a device that lets you access the Internet. Most people know IGDs by their more common names: router, wireless router, broadband router, cable modem, Network Address Translation (NAT) device, and wireless Access Point (AP). Typically, you can configure IGDs through a Web page hosted on the device. However, some vendors provide configuration utilities that locate and configure the device without user intervention. Such automatic device integration is commonly achieved through UPnP.
If configuration happens automatically, why should you care about UPnP? Consider this: Your broadband router sits directly on the Internet, which means hackers can try to compromise the device by using every possible means of attack. If the attack is successful, you can be sure the hacker will try to reconfigure your IGD's settings in an attempt to gain access to machines on your private network. An attacker might be able to gain such access by modifying your IGD's port map, which tells the device where to direct incoming TCP or UDP packets. For example, if you have aWeb server on your private network, you've probably configured your IGD to map (or forward) all incoming port 80 TCP traffic to port 80 on your internal Web server. But an attacker could change the mapping to forward traffic elsewhere.
In addition, applications running on your PC might use UPnP to communicate with your IGD to temporarily map ports. For example, when you use Windows Media Player (WMP) to stream movies or music across the Internet, WMP might temporarily map incoming UDP ports so that it can stream content by using the Microsoft Media Server (MMS) protocol or Real Time Streaming Protocol (RTSP). Other software such as Orb Networks' Orb application, which lets you access your media files from anywhere on the Internet, might instruct the IGD to map ports so that you can access the application from outside your home network.
With these possibilities for programmatically manipulating IGD port maps, you can imagine how useful it would be to occasionally examine the port mappings that are active on your IGDs. You could even go a step further, as I have, and write a Perl script that periodically queries an IGD to lists its port mappings and other information.
The QueryPortMap.pl script queries your network for all IGDs and displays statistics and the port map for each device it finds. This script uses Satoshi Konno's Net::UPnP Perl package and related packages, such as Net::UPnP ::ControlPoint. I wrote the script using Net::UPnP 1.1.3, which is available on CPAN at http://search.cpan.org/~skonno/Net-UPnP-1.1.3. You can also install the package by using Perl Package Manager (PPM), a utility that comes with ActiveState's version of Perl. PPM downloads and installs all available packages and extensions. (For examples of how to use PPM, see http://www.roth.net/perl/packages/#PPM.)
The script requires no commandline parameters. To run it, simply type
To understand how the script works, you'll find it useful to first understand how UPnP works. The Web-exclusive sidebar "Universal Plug and Play" (http://www.windowsitpro.com/windowsscripting, InstantDoc ID 50097) will get you started. And a Google search will return many sites that explain the fundamentals of UPnP. Before you do any UPnP programming, be sure to read up on the technology.
Walking Through the Script
The first thing that QueryPortMap.pl does, as callout A in Listing 1 shows, is define two global hashes: %UPNP and %UPNP_SERVICE_ PROPERTIES. The former hash stores miscellaneous UPnP-related values used throughout the script. The latter hash contains a list of properties associated with a hash key that represents a UPnP service. For each service listed in the hash, the script queries the associated properties. This hash approach lets you easily add and remove properties from the list to query.
At callout B, the script attempts to create a UPnP control-point object. Such objects are the base objects you uses to control UPnP devices. The script use this object to search the network for UPnP IGDs by passing to the object's search() method the UPnP device type (the "urn:schemas-upnp -org:device:InternetGatewayDevice:1" string) from the %UPNP hash at callout A. The search lasts for the number of seconds specified in the second parameter you pass to the method.
The search() method returns a list of UPnP device objects that it finds on the network. For each device the search returns, the code at callout C prints information such as the device's manufacturer and model number. UPnP devices usually host multiple services, and the code at callout D queries all the available services on the device. For each service the query returns, the script queries statistics for the service and stores the service object for later use.
Next, the script calls the DumpStats() subroutine to display the aggregate statistics that it gathered for the device and calls the GetStats() subroutine to query and display all port mappings. The code at callout E shows how the GetStats() subroutine works. If the service object passed to the subroutine isn't a UPnP service object, the subroutine goes to the next object. When the service object is a valid object, the subroutine determines the service by calling its getservicetype() method.
The code then calls the Call() subroutine for each property listed in the %UPNP_SERVICE_PROPERTIES hash for the appropriate service type. The code at callout F shows how the Call() subroutine works. UPnP lets an application call a function on the remote device, passing parameters and receiving result values. The Call() subroutine tells a specific service on the remote device to call the function that the $Name variable specifies. The subroutine passes the $Args hash reference, which specifies parameters to pass to the function. The script performs this work by calling the service's postcontrol() method. The result of calling this method is an object ($Result) that represents the information that the remote device's service returned to the application.
After calling postcontrol(), the script queries the $Result object to determine whether the function call was successful. UPnP uses the HTTP protocol to submit the request and receive the result. When a call to getstatuscontrol() returns a value of 200 (HTTP's success result code), the function call was successful. A successful request is followed by a call to the $Result object's getargumentlist() method, which returns XML code that identifies a list of items that the device service's function call returned. The script parses out any items in the XML list and stores them in the $ResultList hash reference.
The code at callout G shows how the GetList() subroutine works. GetList() calls a specified function in a device service for a specified number of times or until the call fails. The script uses this subroutine to collect a list of all mapped ports and displays the list for your review.
It's a good security practice to periodically check that hackers haven't broken into your network and taken control of it. This is especially true for networks that use UPnP devices, which can be programmatically configured to let hackers and spyware through the front door.
Sometimes such holes are acceptable, such as when you're streaming music or videos. However, if you don't recognize a port mapping, you should log on to your IGD and reconfigure it to close the security hole. QueryPortMap.pl helps you interrogate your routers and firewalls to see what holes have been opened. You can easily modify the script to send email alerts if it finds suspicious port mappings.
With the programmatic-configuration convenience of UPnP comes an added burden of monitoring who or what might be changing IGD settings and why. Using Perl is a great way to monitor such events and tighten your network's security.