start	end	text
6060	12780	Hello everyone, welcome to DEF CON Safe Mode. What a special year, glad to see you in this way.
13540	18860	Our talk is Evil Printer, How to Hack Windows Machines with Printing Protocol.
22150	28530	First, a self-introduction. Zhi Peng Huo is a senior security researcher, and he is a member
28530	34550	of the EcoSec team at Dunson Security's Shell Lab. His research focuses on Windows and macOS
34550	40650	platform security. He has found and reported many vulnerabilities to Microsoft and Apple.
42290	48030	Chuanda Ding is a co-author of this presentation. He leads the EcoSec team at Dunson Security's
48030	59980	Shell Lab. This is the agenda of our talk. First, an introduction of printing internals,
59980	65160	components, and interactions. Then, we cover the attack surface of Windows printing.
65880	72360	Finally, a critical bug that we found, a detailed walkthrough of its exploitation, and patch.
74420	78220	We have published a demo video on Twitter about two months ago.
79040	82740	First, the attacker listens for incoming connections.
83660	87700	Next, the victim tries to connect to a attacker-controlled printer.
88780	93100	The attacker immediately gets a reverse shell with system privilege.
93660	96800	This vulnerability is what we call the evil printer.
97540	104160	In this talk, we will show you what it is, how we found and exploit it, and what can it do.
108240	111520	Most of you may have done some printing before,
111520	118180	and many of you may have worked with a network printer. So how does network printing work?
120160	124580	The system where users create the print job on is a print client.
125500	130780	Print server connects to the physical printer and makes the printer available to other systems
130780	138180	on the network. When client wants to print a document, it will go to the server and say,
138180	144180	hey, server, print this document. The server gets the print job,
144180	148400	then it will go to the real printer and say, hey, printer, print this.
149680	153200	The printer would finally print a document for the client.
154580	159000	This is the procedure when you want to print a document on a client.
163280	169260	There are so many different printer products manufactured by different companies.
169480	175760	Printers do not understand application data from print clients. So the application data
176250	179970	needs to be converted to the data format that the printer could understand.
180540	186360	This process is called rendering. In a network printing, there are two different types of
186360	192160	rendering. Client-side and server-side. For client-side rendering, print client
192160	198160	translates the application data to printer-specific data, then sends the data to the printer server.
198720	203580	For server-side rendering, print client sends the unmodified data
203580	208100	directly to the printer server. Then the printer server translates the application data
208100	215740	to the printer-specific data. The rendering jobs are handled by print driver.
218330	222110	Printer driver is an important component of printing.
222830	227070	It is the interface component between the OS and the printers.
227730	232810	Printer drivers include a rendering component and a configuration component.
233370	239070	The rendering component converts application data into the data that printer could use.
239410	242670	And the configuration component contains a user interface
242670	245450	that enables users to control the printers.
247990	251690	In order to support both client-side and server-side rendering,
251690	256490	it is a requirement that the printer drivers are available to both print client and print server.
257410	261250	There are two mechanisms for distributing printer driver.
261250	264950	They are called point-and-print and package point-and-print.
265630	271210	Point-and-print allows a print client to download printer driver directly from a print server.
272190	277690	Package point-and-print allows a print client to download a printer support package.
277830	281130	And the package would include a needed printer driver.
283390	289910	According to Microsoft, the package approach to driver installation provides improved security
289910	295030	for point-and-print by checking driver signing during the establishment of a point-and-print
295030	303710	connection. Print spooler service is the core of Windows printing. Print spooler service
303710	309210	manages print drivers. It is responsible for retrieving a correct print driver
309210	316990	and dynamically loading it. It is an autostart service on Windows OS. It manages the entire
316990	321950	printing process and explores the printing APIs for other printing components and the
321950	329350	user applications to use. It implements both print client and print server roles.
330650	336870	The design of the print spooler is extremely dangerous. For example, it runs at system
336870	342890	privilege level, it has networking tasks, and it can dynamically load third-party binaries.
343970	348570	Client-server printing model is a very common model that shares the printer through the
348570	354570	network to many users. In this model, print server connects to the real printer and shares
354570	361270	itself in the network. The print client connects to the shared print server. When applications
361270	367270	on print client want to start print job, it calls the printing APIs to communicate with
367270	373070	the local print spooler. Then print spooler will send the action to the remote print spooler
373070	380750	on a print server through network protocols, such as SMB. The print spooler on the print
380750	385370	server would communicate with the real printer to finish the printing job.
386310	392070	The Windows printing is ancient. It has existed for more than 25 years.
392110	397500	It's highly integrated with Windows OS, and it is one of the most important services.
398210	406010	The architecture and implementation of it is extremely complex, even confusing. Many parts
406010	411310	of it works at the highest privilege level to make it one of the most valuable targets
411310	420870	for bug hunting. There are two types of attack surfaces of Windows printing. First, the local
420870	427130	attack surface. In order to serve applications and other components running at different
427130	432950	privilege levels, Windows printing made many of its interfaces available to applications
432950	440190	running at lower privilege levels. Abusing them may cause local privilege escalation.
441830	447450	Second, the remote attack surface. In client-server printing model,
447450	451990	both the print server and print client would suffer from the potential attack.
452470	458450	For the print server, it shares the printer to other users and exposes itself to potential
458450	464730	attacks in the network. For a print client, it may be attacked by a malicious print server,
464730	472050	also known as evil printer. What happens behind the scenes when Windows connects to a printer?
473950	479570	If a user wants to do print jobs through a print server, they must actively connect to the print
479570	485930	server. There are many methods for a print client to connect to a print server. If you are familiar
485930	490970	with PowerShell, you could use add-printer command-line to add a new network printer connection
490970	496190	by specifying the name of a print server and a shared printer on that server.
496490	501690	If you want to program, Microsoft provides Win32 print spooler API,
501690	506190	such as add-printer-connection and add-printer-connection-to.
507070	514250	And you could also use the GUI provided by print-ui-im to select a shared printer by name.
516010	520670	Although many methods could be used for connecting to a specified print server,
520670	525370	they could be traced to the one same API add-printer-connection-to.
526050	531570	This API adds a connection to the specified printer for the current user and specified
531570	537910	connection details. The print server and shared printer name are passed in through parameter
538730	547630	pszName. When adding printer connection, if the print client needs to download and install
547630	553510	printer driver from a remote print server, it will show a warning dialog to ask a user to
553510	559620	install the driver or cancel the request. What's the purpose of this warning dialog?
560150	566210	About four years ago, security researchers from Vector AI found a remote code execution
566210	572610	vulnerability in Windows Print Spooler servers. The root cause of this vulnerability is print
572610	578530	client would load and install a malicious printer driver from attacker-controlled print server.
579070	585770	To address this vulnerability, Microsoft simply added a warning dialog before installing untrusted
585770	591970	printer drivers. It does protect the print client from installing printer drivers without
591970	600010	the user concerned. But is this protection sufficient? In order to answer this question,
600010	605870	let's dig into the implementation of add-printer-connection-to first. Any applications or
605870	612370	print client that call add-printer-connection-to API will send an RPC call to print spooler service
612370	619050	on printer client. The remote function called is RPC add-printer-connection-to.
620250	625370	If the print client is trying to add a remote print server, the print spooler on print client
625370	631230	would try to communicate with print spooler on print server and get information from it.
632630	637630	When print server is fully controllable, it is obvious that the data back to the print
637630	645190	spooler on print client is also fully controllable by print server. For print client, it is an input
645190	652050	source that cannot be trusted. If the returned information is not fully verified, it would cause
652050	658590	critical security issues. The information from the print server would be handled by print spooler
658590	664510	on print client. After finishing, it would return to the caller of add-printer-connection-to.
666090	670790	Add-printer-connection-to would get the return value from print spooler on print client
670790	678910	directly. Error code 0xBB9, which is error printer driver download needed, is a special case.
678970	684550	The error, just as the name described, means the print client does not have the required drivers
684550	690150	and needs to be downloaded from the print server. Upon receiving the server,
690730	696430	the add-printer-connection-to will immediately start to download and install the needed driver.
697200	700760	It calls the function downloadAndInstallLegacyDriver.
701390	705170	This function would load a new module, ntprint,
705170	709640	and call the function psetupDownloadAndInstallLegacyDriver.
711190	715610	But before the real download, you would call displayWarning for download driver
715610	721490	to show a warning dialog for user to choose to install the driver or just cancel.
722710	727590	You would call downloadAndInstallLegacyDriver function to finish the installation of remote
727590	735110	printer only if the user confirms to install. This is the most common scenario of adding a
735110	741950	new network printer. But as we have described, Windows printing has two different mechanisms,
741950	747790	point-and-print and package-point-and-print, to download the correct printer drivers.
747790	751550	So which mechanism does it use in a common case?
752610	756670	In order to know the implementation of downloadAndInstallLegacyDriver,
756670	760390	we do not want to do too much reverse engineering works.
760510	764910	Instead, we prefer to observe the behavior of our operations.
765970	767890	And we really recommend you doing this,
767890	772790	especially when you are analyzing a complex application or want to find some logical bugs.
773610	778450	Here we use process monitor to capture the driver download operations.
779330	785930	This screenshot shows the file operation of print spooler on print client after we confirm to
785930	792370	install the driver. We notice the print spooler on print client reads information through RPC
792870	798930	from the print server and then write the print driver files to a temporary directory directly.
799850	804750	This is the whole procedure of downloading printer driver from print server.
807650	812350	After the printer driver is downloaded, it should be installed so the print client could
812350	817490	use it to do client-side rendering. And we could notice from file operations
818010	822670	that the drivers in temporary directory are moved to the system driver directory.
824330	827910	This is the procedure of printer driver installation.
828450	832190	Now the printer driver is successfully downloaded and installed.
833730	839850	So which mechanism is this? We did not see any package here. It seems all printer drivers
839850	845770	are directly downloaded from the print server. So it seems to be point-and-print.
846690	851250	So why does the current print client only use the point-and-print mechanism?
851790	856890	How does the print client and server negotiate which one to use?
857470	860130	How to enable the package point-and-print?
862110	868130	To answer this question, we dig into the RPC addPrinterConnection2 function in print spooler.
868350	872290	The procedure of addPrinterConnection2 is very complex.
872410	878530	We found the adding connection operation of the remote printer is handled by the Win32 SPL module.
879590	885050	You will try to call the createLocalPrinter function to create a local printer. Then it
885050	892770	uses acquireV3Driver and addPrinter function to get printer driver. Before getting the driver,
892770	900120	it needs to determine install type. In this function, it tries to call checkPackagePointAndPrint.
901390	906850	This function name seems to indicate it would determine to use the point-and-print or package
906850	913190	point-and-print mechanism. But how does the function checkPackagePointAndPrint
913190	917430	determines the mechanisms? Let's see the implementation.
918970	927070	Here is its pseudocode. If there is bit 1 at 0x88 offset of an object, the print spooler
927070	934050	would download and import driver packages. But what is this object? Where it comes from?
934090	936610	And can we control it from the print server?
938710	944310	We found the print client gets that object by calling function remoteGetPrinterDriver.
944510	947970	The function, in fact, is just an RPC stub.
948690	955050	The real implementation is RPC asyncGetPrinterDriver in print spooler of print server.
956030	963050	The object is a returned data from a remote print server. So it is fully controllable by print server.
964070	969310	The structure of the returned object is a DriverInfo8.
970350	977450	And we could know that at the 0x88 offset is the DWPrinterDriver attributes.
978190	985190	The object has many other interesting items such as driver path, config path, inf path, and so on.
985850	990150	The definitions of printer driver attributes could be found in the Windows 10 software
990150	997670	development kit. What we care about is just a value 1, which is PrinterDriverPackageAware.
998170	1002810	It means the printer driver is part of a driver package.
1004550	1010310	Now things get clearer. If the printer driver attributes of the print server
1010310	1015450	is PrinterDriverPackageAware, the print client would use the package point-and-print
1015450	1018510	mechanisms to download and import package drivers.
1020510	1024090	The mechanism used to download print drivers are solely determined
1024090	1029270	by the remote print server. That seems very interesting and may be dangerous.
1032210	1035890	What is a driver package in package point-and-print?
1036790	1042430	A driver package is just a collection of files that are needed to successfully load the printer
1042430	1049550	driver. It may contain a device information file, a catalog file, and odd files copied by
1049550	1056650	information file. Now we know how to force the print client to use the package point-and-print
1056650	1061710	mechanism, and we know the print client would try to download the package driver from the print
1061710	1068350	server. But where does the print client get the package from? Can we control the package content?
1070170	1076670	After some research, we found that all printer driver packages are stored in a PCC directory,
1076670	1081170	and the filename of package driver is very interesting. It is the final directory name
1081170	1092100	of the inf path in print driver info. If the print client knows the print server wants to use
1092100	1097840	package point-and-print mechanism, it would download and import driver packages.
1097840	1103920	But before import, the print client would first download the driver package and then extract it.
1104100	1110320	The print client would use tdriver install internal copy file to copy driver packages
1110320	1117820	from print server. Then you would use ncabbing library legacy cab unpack to extract the package.
1118200	1122640	And the most important thing is the download and extract operations
1122640	1129840	are all happened before showing the warning dialog. It seems this could be abused.
1131140	1138140	We know that the driver package is a cabinet file. A cabinet file is an archive file format
1138140	1144420	for Microsoft Windows. It is ancient and has existed for many years.
1144920	1150460	It has the suffix .cab and acts like a container for other files.
1151700	1157880	In order to extract the cabinet file, Microsoft provides a lot of file decompression interface
1157880	1167860	APIs. Here are some examples. First, fdi create is used to create a fdi context for cabinet file
1167860	1176200	operations. Next, fdi copy is the most important one. It is used to extract files from cabinet.
1178020	1184340	fdi destroy deletes and opens the fdi context after the cabinet operations.
1185040	1189880	fdi copy is the primary API for extracting files from the cabinet.
1189980	1195960	This API is designed to be very flexible. It provides application-defined callback
1195960	1201580	notification functions to update the application on the status of a decompressor.
1202540	1209240	So the behavior of cabinet extraction is highly dependent on the implementation of users of the
1209240	1216460	API. As we have described, the print client would use nCabinLibraryLegacyCabOnPack
1216460	1223600	to extract files from the downloaded cab files. This function uses fdi copy to extract files
1223600	1229680	with a notification callback. nCabinLibraryFdicabNotify to control the extraction
1229680	1238350	operation of files. In the callback notification, it would receive the fdint
1238350	1243430	copy file notification to handle copy file operation.
1244370	1248130	This is part of a pseudocode of copy file processing.
1250330	1256510	The copy file operation would finally call the nCabinLibrary process copy file.
1257060	1263650	The process copy file first call nCabinLibrary createFullPath to create a directory if the
1263650	1270850	specified directory does not exist. When creating the full path, it would check if the
1270850	1277410	path has dot dot backslash. If it has, the function would just return with an error.
1278670	1284450	But it forgot to check the dot dot slash, which also works on Windows OS and could be used to do
1284450	1291630	path traversal. After creating the full path, it would then call the open function to open
1291630	1297470	the file. If the file does not exist, it will create the file via the ocreate flag.
1298890	1304990	Now it is obvious that there is a path traversal issue when print client extract the downloaded
1304990	1313090	cabinet file. And the cabinet file is provided by a print server. Let's try to make a malformed
1313090	1321290	cab file. Windows has provided the command make cab for cabinet file creation.
1321810	1327390	However, make cab could not create cabinet file with the file name contain slashes.
1329190	1335570	So we decided to create a simple cab and then change the name of the file with another program.
1336990	1340850	Here we used make cab to create the test.cab.
1341770	1346650	After we have a cabinet file, we try to change the file name inside the cabinet file.
1346710	1351530	We used programs such as 7-zip to try to edit the name of the file.
1353290	1360590	But the file name is not editable. That's very sad. Are we doomed?
1362430	1367590	No, that could not stop us. We could still modify the file names directly in binary.
1368730	1372050	Let's edit the file name with an hex editor.
1373210	1378550	Here we use a small trick using ones and twos in file names as placeholders.
1379450	1384490	We just modify all ones in file name to dot and twos to slash.
1386510	1391790	After the modification, we use lzip program to open the cabinet file again.
1392070	1394990	It can be successfully opened and the file name contains
1394990	1401790	dot dot slash that could be used to do path traversal. We now have a malformed cabinet.
1403950	1409510	Replace the cabinet file in the print server with this malformed cab to make it an evil printer.
1412250	1418410	Let's make an evil printer. First, we should have a fully controllable print server.
1419030	1427290	To prepare a print server, we prefer to use a virtual PDF printer to simulate the printer instead of getting a real physical printer.
1428150	1435030	There are many virtual printer products available. Here we randomly choose one, the Qt PDF Writer.
1435390	1438110	Or other virtual printers should also work.
1439370	1443030	To prepare a workable print server is very easy.
1443250	1449490	Just install the printer and then share this printer so that any user on your network can print to it.
1450010	1453450	Here we just share the printer with the share name test.
1455390	1461830	Now we have got a fully controllable print server. We will wait for a print client to connect to it.
1463210	1470550	Because the print server is fully controllable, we have many ways to change the return data before it sends to the print client.
1471050	1476490	The easiest way is to change the real printer driver info of the shared printer.
1477670	1483130	We found the print server stores all the definitions of printer driver information in the registry.
1484350	1491810	As shown in this screenshot, we could know the default print driver attribute of Qt PDF Writer is 0.
1494360	1498540	Now, let's make a package point-and-print print server.
1499420	1509460	First, we need to make sure the printer driver attributes of the shared printer is 1, so that print client would use the package point-and-print mechanism.
1510760	1515300	Next, we need to configure the driver package that would be downloaded.
1516260	1521880	As we have described, the package name comes from the directory name of the nth pass.
1522840	1532120	Here, we configure it to ccolumn backslash test backslash test.int, and make sure the int file exists.
1532660	1538000	The package name that will be downloaded should be test.cap.
1539340	1545190	We just needed to place a prepared test.cap to the PCC directory.
1546320	1549590	Now we finally have a workable Evo printer.
1550690	1561610	This screenshot shows how to configure the prepared Qt PDF Writer printer to use the package point-and-print mechanism and convert it to Evo printer.
1561810	1566650	What would happen if a print client tries to connect to this Evo printer?
1567350	1576710	We could see the print spooler in print client download the test.cap file from the print server and then extract the cabinet file.
1577670	1589930	Because of the path traversal bug, ccolumn backslash windows backslash system32 backslash diagnostic services backslash userenvironment.do is created.
1590630	1595190	Because the print spooler service is running with system privilege,
1595750	1601010	the Evo printer could write arbitrary file to print client with system privilege.
1601010	1603970	It is a logical bug and works very stably.
1604610	1608870	Okay, now we have covered the remote code execution part of the Evo printer.
1609670	1614690	This attack only needs the print client to make a connection attempt to the Evo printer.
1615230	1618230	But can this vulnerability do more?
1619530	1625130	Three years ago, James Horshow did an excellent job on COM internals and Microsoft Edge Sandbox.
1625930	1632450	During his talk, he demoed a scan of COM servers reachable from inside the Microsoft Edge Sandbox.
1634510	1640670	He must be hinting something by highlighting that specific COM server during his talk.
1642370	1648190	Sandbox is an essential security mechanism in modern security architectures.
1648370	1652550	Sandbox escapes are important security research target.
1652550	1656210	So how does Evo printer affect sandboxes?
1657590	1663630	Microsoft Edge vendor process is the most restricted app container sandbox on Windows.
1663970	1669550	Microsoft has kept reduced attack surfaces of it for many years.
1669910	1675350	The interfaces that could be accessed from inside the sandbox is fewer and fewer.
1675570	1679410	But the printing service has always been one of them.
1680350	1684710	Until now, the process token of render process still has the capability
1684710	1690990	LPAC printing. It means the render process could access the printing service.
1691910	1699270	Using oleview.net, we found the COM service CPrintTicketWW services can be launched and
1699270	1707290	accessed with capability LPAC printing. So it could be called by the Microsoft Edge render process.
1709570	1718150	The CPrintTicket server provides an interface bind. This is used to bind to a specific printer.
1718650	1723110	If we bind to an Evo printer, it will also trigger the vulnerability so we could use it
1723110	1732130	to escape from the sandbox. App container processes are not allowed to create files.
1732430	1736570	But we could use this vulnerability to create arbitrary files.
1737850	1742730	The app container process can launch and access CPrintTicket.com server.
1743090	1748270	The server is implemented in print ticket services module and launched by deal host
1748270	1755770	with medium integrity level. The bind interface would call CPrintTicket service base bind.
1756630	1762570	In this function, it would open a remote print server and get the print driver from print server.
1763190	1768050	This would also trigger the bug if it's connecting to the Evo printer.
1769170	1775750	So we could escape the Edge render sandbox and execute arbitrary code with system privilege.
1779470	1787630	Next, let's do a real demo. In this demo, we have two computers, the victim and the attacker.
1788090	1792950	The victim is a print client and the attacker is the Evo printer.
1793970	1800690	First, let's see the Evo printer. We have modified the driver info of a shared printer.
1801630	1807710	We modify the printer driver attributes to one and set the info path item to c
1807710	1816430	column backslash test backslash test.inf. And we have placed the test.cap at the PCC directory.
1818170	1821810	Next, let's go to the victim's computer.
1822230	1827210	You can see there's no user environment.deal in diagnostic services directory.
1828490	1833990	Now, we try to connect to the Evo printer from Microsoft Edge render sandbox.
1835750	1841170	Here, we simulate a code execution inside the sandbox by injecting our exploit deal
1841170	1850390	into the render process. We could see the warning dialog and we could find a user
1850390	1856950	environment.deal present in the diagnostic services directory. In fact, the Evo printer
1856950	1868590	could write arbitrary file with system privilege. The patch of the vulnerability is extremely simple.
1869210	1874030	We have known the root cause of the vulnerability is because the Win32 SPL
1874030	1880010	uncapping library process copy file does not properly handle the dot dot slash.
1880010	1887410	So the patch just check both slashes before process copy file to prevent past traversal issues.
1889550	1894550	Finally, we want to talk about the possible attack scenarios of this vulnerability.
1895870	1902090	For lateral movement, the attacker can modify a printer trusted by the victim to Evo printer.
1902890	1908890	For remote code execution, the attacker could convince the victim to connect to a Evo printer.
1909810	1914750	For privileged escalation, the attacker could make a connection attempt to an Evo printer
1914750	1918790	either as an unprivileged user or from inside the sandbox.
1920410	1924990	For all the above scenarios, the attacker immediately gets code execution as system
1924990	1928350	with complete control of the victim's computer.
1930110	1936810	This vulnerability has been reported and fixed. The CVE ID is CVE-2020-1300.
1937710	1941330	This is Microsoft's description about this vulnerability.
1942150	1948150	Although it's technically correct about the final exploitation vector, it's kind of misleading.
1948390	1956610	First, this is not a cabinet API vulnerability. The cabinet API is sophisticated and flexible.
1957050	1961930	But it is too flexible, many parts of the decompression were handled by user-supplied
1961930	1968590	callbacks. If they don't handle edge cases properly, it could lead to security issues.
1969290	1974690	In this case, it is the Windows printing which did not implement the decompression callbacks
1974690	1981990	correctly. Second, this vulnerability does not need a user confirmation to install the
1981990	1988570	printer driver. Just as we described and demoed, this entire attack finishes before the warning
1988570	1995050	dialogue. In fact, the attacker could also configure the print server to prevent the
1995050	2000330	print client from showing the warning dialogue to make the attack completely unnoticeable.
2001830	2008690	However, there's no need to be panicked about cabinet files. The cabinet API is old, but its
2008690	2015830	design is okay. If the users of cabinet API handled callbacks with care, there's no security
2015830	2023150	issues to be worried about. For example, don't be afraid to open the malformed cabinet we created
2023150	2031670	in Explorer. The cabview module in Explorer.exe correctly handles special characters in cabinet
2031670	2038530	API callbacks, so it is safe to open a cabinet file in Explorer and copy files.
2040920	2044910	In this presentation, we talked about the implementation of Windows printing.
2044910	2049740	It is complex and privileged and can be one of the best targets for attackers.
2051120	2056220	And we walked you through a bug we found in Windows printing. It could be exploited both
2056220	2062280	locally and remotely. It could be used to execute arbitrary code with system privilege and escape
2062280	2070520	sandboxes. For developers, don't be panicked about the cabinet files, but you should be careful when
2070520	2079000	writing the cabinet API callbacks. Logical bugs like this are always found to be harmful. We think
2079000	2085880	you will love it just as we do. We would like to thank James Forshaw for his excellent tools and
2085880	2093720	hints. Big draw AI for their previous works and shares. And thank you for listening.
