[00:06.060 --> 00:12.780] Hello everyone, welcome to DEF CON Safe Mode. What a special year, glad to see you in this way. [00:13.540 --> 00:18.860] Our talk is Evil Printer, How to Hack Windows Machines with Printing Protocol. [00:22.150 --> 00:28.530] First, a self-introduction. Zhi Peng Huo is a senior security researcher, and he is a member [00:28.530 --> 00:34.550] of the EcoSec team at Dunson Security's Shell Lab. His research focuses on Windows and macOS [00:34.550 --> 00:40.650] platform security. He has found and reported many vulnerabilities to Microsoft and Apple. [00:42.290 --> 00:48.030] Chuanda Ding is a co-author of this presentation. He leads the EcoSec team at Dunson Security's [00:48.030 --> 00:59.980] Shell Lab. This is the agenda of our talk. First, an introduction of printing internals, [00:59.980 --> 01:05.160] components, and interactions. Then, we cover the attack surface of Windows printing. [01:05.880 --> 01:12.360] Finally, a critical bug that we found, a detailed walkthrough of its exploitation, and patch. [01:14.420 --> 01:18.220] We have published a demo video on Twitter about two months ago. [01:19.040 --> 01:22.740] First, the attacker listens for incoming connections. [01:23.660 --> 01:27.700] Next, the victim tries to connect to a attacker-controlled printer. [01:28.780 --> 01:33.100] The attacker immediately gets a reverse shell with system privilege. [01:33.660 --> 01:36.800] This vulnerability is what we call the evil printer. [01:37.540 --> 01:44.160] In this talk, we will show you what it is, how we found and exploit it, and what can it do. [01:48.240 --> 01:51.520] Most of you may have done some printing before, [01:51.520 --> 01:58.180] and many of you may have worked with a network printer. So how does network printing work? [02:00.160 --> 02:04.580] The system where users create the print job on is a print client. [02:05.500 --> 02:10.780] Print server connects to the physical printer and makes the printer available to other systems [02:10.780 --> 02:18.180] on the network. When client wants to print a document, it will go to the server and say, [02:18.180 --> 02:24.180] hey, server, print this document. The server gets the print job, [02:24.180 --> 02:28.400] then it will go to the real printer and say, hey, printer, print this. [02:29.680 --> 02:33.200] The printer would finally print a document for the client. [02:34.580 --> 02:39.000] This is the procedure when you want to print a document on a client. [02:43.280 --> 02:49.260] There are so many different printer products manufactured by different companies. [02:49.480 --> 02:55.760] Printers do not understand application data from print clients. So the application data [02:56.250 --> 02:59.970] needs to be converted to the data format that the printer could understand. [03:00.540 --> 03:06.360] This process is called rendering. In a network printing, there are two different types of [03:06.360 --> 03:12.160] rendering. Client-side and server-side. For client-side rendering, print client [03:12.160 --> 03:18.160] translates the application data to printer-specific data, then sends the data to the printer server. [03:18.720 --> 03:23.580] For server-side rendering, print client sends the unmodified data [03:23.580 --> 03:28.100] directly to the printer server. Then the printer server translates the application data [03:28.100 --> 03:35.740] to the printer-specific data. The rendering jobs are handled by print driver. [03:38.330 --> 03:42.110] Printer driver is an important component of printing. [03:42.830 --> 03:47.070] It is the interface component between the OS and the printers. [03:47.730 --> 03:52.810] Printer drivers include a rendering component and a configuration component. [03:53.370 --> 03:59.070] The rendering component converts application data into the data that printer could use. [03:59.410 --> 04:02.670] And the configuration component contains a user interface [04:02.670 --> 04:05.450] that enables users to control the printers. [04:07.990 --> 04:11.690] In order to support both client-side and server-side rendering, [04:11.690 --> 04:16.490] it is a requirement that the printer drivers are available to both print client and print server. [04:17.410 --> 04:21.250] There are two mechanisms for distributing printer driver. [04:21.250 --> 04:24.950] They are called point-and-print and package point-and-print. [04:25.630 --> 04:31.210] Point-and-print allows a print client to download printer driver directly from a print server. [04:32.190 --> 04:37.690] Package point-and-print allows a print client to download a printer support package. [04:37.830 --> 04:41.130] And the package would include a needed printer driver. [04:43.390 --> 04:49.910] According to Microsoft, the package approach to driver installation provides improved security [04:49.910 --> 04:55.030] for point-and-print by checking driver signing during the establishment of a point-and-print [04:55.030 --> 05:03.710] connection. Print spooler service is the core of Windows printing. Print spooler service [05:03.710 --> 05:09.210] manages print drivers. It is responsible for retrieving a correct print driver [05:09.210 --> 05:16.990] and dynamically loading it. It is an autostart service on Windows OS. It manages the entire [05:16.990 --> 05:21.950] printing process and explores the printing APIs for other printing components and the [05:21.950 --> 05:29.350] user applications to use. It implements both print client and print server roles. [05:30.650 --> 05:36.870] The design of the print spooler is extremely dangerous. For example, it runs at system [05:36.870 --> 05:42.890] privilege level, it has networking tasks, and it can dynamically load third-party binaries. [05:43.970 --> 05:48.570] Client-server printing model is a very common model that shares the printer through the [05:48.570 --> 05:54.570] network to many users. In this model, print server connects to the real printer and shares [05:54.570 --> 06:01.270] itself in the network. The print client connects to the shared print server. When applications [06:01.270 --> 06:07.270] on print client want to start print job, it calls the printing APIs to communicate with [06:07.270 --> 06:13.070] the local print spooler. Then print spooler will send the action to the remote print spooler [06:13.070 --> 06:20.750] on a print server through network protocols, such as SMB. The print spooler on the print [06:20.750 --> 06:25.370] server would communicate with the real printer to finish the printing job. [06:26.310 --> 06:32.070] The Windows printing is ancient. It has existed for more than 25 years. [06:32.110 --> 06:37.500] It's highly integrated with Windows OS, and it is one of the most important services. [06:38.210 --> 06:46.010] The architecture and implementation of it is extremely complex, even confusing. Many parts [06:46.010 --> 06:51.310] of it works at the highest privilege level to make it one of the most valuable targets [06:51.310 --> 07:00.870] for bug hunting. There are two types of attack surfaces of Windows printing. First, the local [07:00.870 --> 07:07.130] attack surface. In order to serve applications and other components running at different [07:07.130 --> 07:12.950] privilege levels, Windows printing made many of its interfaces available to applications [07:12.950 --> 07:20.190] running at lower privilege levels. Abusing them may cause local privilege escalation. [07:21.830 --> 07:27.450] Second, the remote attack surface. In client-server printing model, [07:27.450 --> 07:31.990] both the print server and print client would suffer from the potential attack. [07:32.470 --> 07:38.450] For the print server, it shares the printer to other users and exposes itself to potential [07:38.450 --> 07:44.730] attacks in the network. For a print client, it may be attacked by a malicious print server, [07:44.730 --> 07:52.050] also known as evil printer. What happens behind the scenes when Windows connects to a printer? [07:53.950 --> 07:59.570] If a user wants to do print jobs through a print server, they must actively connect to the print [07:59.570 --> 08:05.930] server. There are many methods for a print client to connect to a print server. If you are familiar [08:05.930 --> 08:10.970] with PowerShell, you could use add-printer command-line to add a new network printer connection [08:10.970 --> 08:16.190] by specifying the name of a print server and a shared printer on that server. [08:16.490 --> 08:21.690] If you want to program, Microsoft provides Win32 print spooler API, [08:21.690 --> 08:26.190] such as add-printer-connection and add-printer-connection-to. [08:27.070 --> 08:34.250] And you could also use the GUI provided by print-ui-im to select a shared printer by name. [08:36.010 --> 08:40.670] Although many methods could be used for connecting to a specified print server, [08:40.670 --> 08:45.370] they could be traced to the one same API add-printer-connection-to. [08:46.050 --> 08:51.570] This API adds a connection to the specified printer for the current user and specified [08:51.570 --> 08:57.910] connection details. The print server and shared printer name are passed in through parameter [08:58.730 --> 09:07.630] pszName. When adding printer connection, if the print client needs to download and install [09:07.630 --> 09:13.510] printer driver from a remote print server, it will show a warning dialog to ask a user to [09:13.510 --> 09:19.620] install the driver or cancel the request. What's the purpose of this warning dialog? [09:20.150 --> 09:26.210] About four years ago, security researchers from Vector AI found a remote code execution [09:26.210 --> 09:32.610] vulnerability in Windows Print Spooler servers. The root cause of this vulnerability is print [09:32.610 --> 09:38.530] client would load and install a malicious printer driver from attacker-controlled print server. [09:39.070 --> 09:45.770] To address this vulnerability, Microsoft simply added a warning dialog before installing untrusted [09:45.770 --> 09:51.970] printer drivers. It does protect the print client from installing printer drivers without [09:51.970 --> 10:00.010] the user concerned. But is this protection sufficient? In order to answer this question, [10:00.010 --> 10:05.870] let's dig into the implementation of add-printer-connection-to first. Any applications or [10:05.870 --> 10:12.370] print client that call add-printer-connection-to API will send an RPC call to print spooler service [10:12.370 --> 10:19.050] on printer client. The remote function called is RPC add-printer-connection-to. [10:20.250 --> 10:25.370] If the print client is trying to add a remote print server, the print spooler on print client [10:25.370 --> 10:31.230] would try to communicate with print spooler on print server and get information from it. [10:32.630 --> 10:37.630] When print server is fully controllable, it is obvious that the data back to the print [10:37.630 --> 10:45.190] spooler on print client is also fully controllable by print server. For print client, it is an input [10:45.190 --> 10:52.050] source that cannot be trusted. If the returned information is not fully verified, it would cause [10:52.050 --> 10:58.590] critical security issues. The information from the print server would be handled by print spooler [10:58.590 --> 11:04.510] on print client. After finishing, it would return to the caller of add-printer-connection-to. [11:06.090 --> 11:10.790] Add-printer-connection-to would get the return value from print spooler on print client [11:10.790 --> 11:18.910] directly. Error code 0xBB9, which is error printer driver download needed, is a special case. [11:18.970 --> 11:24.550] The error, just as the name described, means the print client does not have the required drivers [11:24.550 --> 11:30.150] and needs to be downloaded from the print server. Upon receiving the server, [11:30.730 --> 11:36.430] the add-printer-connection-to will immediately start to download and install the needed driver. [11:37.200 --> 11:40.760] It calls the function downloadAndInstallLegacyDriver. [11:41.390 --> 11:45.170] This function would load a new module, ntprint, [11:45.170 --> 11:49.640] and call the function psetupDownloadAndInstallLegacyDriver. [11:51.190 --> 11:55.610] But before the real download, you would call displayWarning for download driver [11:55.610 --> 12:01.490] to show a warning dialog for user to choose to install the driver or just cancel. [12:02.710 --> 12:07.590] You would call downloadAndInstallLegacyDriver function to finish the installation of remote [12:07.590 --> 12:15.110] printer only if the user confirms to install. This is the most common scenario of adding a [12:15.110 --> 12:21.950] new network printer. But as we have described, Windows printing has two different mechanisms, [12:21.950 --> 12:27.790] point-and-print and package-point-and-print, to download the correct printer drivers. [12:27.790 --> 12:31.550] So which mechanism does it use in a common case? [12:32.610 --> 12:36.670] In order to know the implementation of downloadAndInstallLegacyDriver, [12:36.670 --> 12:40.390] we do not want to do too much reverse engineering works. [12:40.510 --> 12:44.910] Instead, we prefer to observe the behavior of our operations. [12:45.970 --> 12:47.890] And we really recommend you doing this, [12:47.890 --> 12:52.790] especially when you are analyzing a complex application or want to find some logical bugs. [12:53.610 --> 12:58.450] Here we use process monitor to capture the driver download operations. [12:59.330 --> 13:05.930] This screenshot shows the file operation of print spooler on print client after we confirm to [13:05.930 --> 13:12.370] install the driver. We notice the print spooler on print client reads information through RPC [13:12.870 --> 13:18.930] from the print server and then write the print driver files to a temporary directory directly. [13:19.850 --> 13:24.750] This is the whole procedure of downloading printer driver from print server. [13:27.650 --> 13:32.350] After the printer driver is downloaded, it should be installed so the print client could [13:32.350 --> 13:37.490] use it to do client-side rendering. And we could notice from file operations [13:38.010 --> 13:42.670] that the drivers in temporary directory are moved to the system driver directory. [13:44.330 --> 13:47.910] This is the procedure of printer driver installation. [13:48.450 --> 13:52.190] Now the printer driver is successfully downloaded and installed. [13:53.730 --> 13:59.850] So which mechanism is this? We did not see any package here. It seems all printer drivers [13:59.850 --> 14:05.770] are directly downloaded from the print server. So it seems to be point-and-print. [14:06.690 --> 14:11.250] So why does the current print client only use the point-and-print mechanism? [14:11.790 --> 14:16.890] How does the print client and server negotiate which one to use? [14:17.470 --> 14:20.130] How to enable the package point-and-print? [14:22.110 --> 14:28.130] To answer this question, we dig into the RPC addPrinterConnection2 function in print spooler. [14:28.350 --> 14:32.290] The procedure of addPrinterConnection2 is very complex. [14:32.410 --> 14:38.530] We found the adding connection operation of the remote printer is handled by the Win32 SPL module. [14:39.590 --> 14:45.050] You will try to call the createLocalPrinter function to create a local printer. Then it [14:45.050 --> 14:52.770] uses acquireV3Driver and addPrinter function to get printer driver. Before getting the driver, [14:52.770 --> 15:00.120] it needs to determine install type. In this function, it tries to call checkPackagePointAndPrint. [15:01.390 --> 15:06.850] This function name seems to indicate it would determine to use the point-and-print or package [15:06.850 --> 15:13.190] point-and-print mechanism. But how does the function checkPackagePointAndPrint [15:13.190 --> 15:17.430] determines the mechanisms? Let's see the implementation. [15:18.970 --> 15:27.070] Here is its pseudocode. If there is bit 1 at 0x88 offset of an object, the print spooler [15:27.070 --> 15:34.050] would download and import driver packages. But what is this object? Where it comes from? [15:34.090 --> 15:36.610] And can we control it from the print server? [15:38.710 --> 15:44.310] We found the print client gets that object by calling function remoteGetPrinterDriver. [15:44.510 --> 15:47.970] The function, in fact, is just an RPC stub. [15:48.690 --> 15:55.050] The real implementation is RPC asyncGetPrinterDriver in print spooler of print server. [15:56.030 --> 16:03.050] The object is a returned data from a remote print server. So it is fully controllable by print server. [16:04.070 --> 16:09.310] The structure of the returned object is a DriverInfo8. [16:10.350 --> 16:17.450] And we could know that at the 0x88 offset is the DWPrinterDriver attributes. [16:18.190 --> 16:25.190] The object has many other interesting items such as driver path, config path, inf path, and so on. [16:25.850 --> 16:30.150] The definitions of printer driver attributes could be found in the Windows 10 software [16:30.150 --> 16:37.670] development kit. What we care about is just a value 1, which is PrinterDriverPackageAware. [16:38.170 --> 16:42.810] It means the printer driver is part of a driver package. [16:44.550 --> 16:50.310] Now things get clearer. If the printer driver attributes of the print server [16:50.310 --> 16:55.450] is PrinterDriverPackageAware, the print client would use the package point-and-print [16:55.450 --> 16:58.510] mechanisms to download and import package drivers. [17:00.510 --> 17:04.090] The mechanism used to download print drivers are solely determined [17:04.090 --> 17:09.270] by the remote print server. That seems very interesting and may be dangerous. [17:12.210 --> 17:15.890] What is a driver package in package point-and-print? [17:16.790 --> 17:22.430] A driver package is just a collection of files that are needed to successfully load the printer [17:22.430 --> 17:29.550] driver. It may contain a device information file, a catalog file, and odd files copied by [17:29.550 --> 17:36.650] information file. Now we know how to force the print client to use the package point-and-print [17:36.650 --> 17:41.710] mechanism, and we know the print client would try to download the package driver from the print [17:41.710 --> 17:48.350] server. But where does the print client get the package from? Can we control the package content? [17:50.170 --> 17:56.670] After some research, we found that all printer driver packages are stored in a PCC directory, [17:56.670 --> 18:01.170] and the filename of package driver is very interesting. It is the final directory name [18:01.170 --> 18:12.100] of the inf path in print driver info. If the print client knows the print server wants to use [18:12.100 --> 18:17.840] package point-and-print mechanism, it would download and import driver packages. [18:17.840 --> 18:23.920] But before import, the print client would first download the driver package and then extract it. [18:24.100 --> 18:30.320] The print client would use tdriver install internal copy file to copy driver packages [18:30.320 --> 18:37.820] from print server. Then you would use ncabbing library legacy cab unpack to extract the package. [18:38.200 --> 18:42.640] And the most important thing is the download and extract operations [18:42.640 --> 18:49.840] are all happened before showing the warning dialog. It seems this could be abused. [18:51.140 --> 18:58.140] We know that the driver package is a cabinet file. A cabinet file is an archive file format [18:58.140 --> 19:04.420] for Microsoft Windows. It is ancient and has existed for many years. [19:04.920 --> 19:10.460] It has the suffix .cab and acts like a container for other files. [19:11.700 --> 19:17.880] In order to extract the cabinet file, Microsoft provides a lot of file decompression interface [19:17.880 --> 19:27.860] APIs. Here are some examples. First, fdi create is used to create a fdi context for cabinet file [19:27.860 --> 19:36.200] operations. Next, fdi copy is the most important one. It is used to extract files from cabinet. [19:38.020 --> 19:44.340] fdi destroy deletes and opens the fdi context after the cabinet operations. [19:45.040 --> 19:49.880] fdi copy is the primary API for extracting files from the cabinet. [19:49.980 --> 19:55.960] This API is designed to be very flexible. It provides application-defined callback [19:55.960 --> 20:01.580] notification functions to update the application on the status of a decompressor. [20:02.540 --> 20:09.240] So the behavior of cabinet extraction is highly dependent on the implementation of users of the [20:09.240 --> 20:16.460] API. As we have described, the print client would use nCabinLibraryLegacyCabOnPack [20:16.460 --> 20:23.600] to extract files from the downloaded cab files. This function uses fdi copy to extract files [20:23.600 --> 20:29.680] with a notification callback. nCabinLibraryFdicabNotify to control the extraction [20:29.680 --> 20:38.350] operation of files. In the callback notification, it would receive the fdint [20:38.350 --> 20:43.430] copy file notification to handle copy file operation. [20:44.370 --> 20:48.130] This is part of a pseudocode of copy file processing. [20:50.330 --> 20:56.510] The copy file operation would finally call the nCabinLibrary process copy file. [20:57.060 --> 21:03.650] The process copy file first call nCabinLibrary createFullPath to create a directory if the [21:03.650 --> 21:10.850] specified directory does not exist. When creating the full path, it would check if the [21:10.850 --> 21:17.410] path has dot dot backslash. If it has, the function would just return with an error. [21:18.670 --> 21:24.450] But it forgot to check the dot dot slash, which also works on Windows OS and could be used to do [21:24.450 --> 21:31.630] path traversal. After creating the full path, it would then call the open function to open [21:31.630 --> 21:37.470] the file. If the file does not exist, it will create the file via the ocreate flag. [21:38.890 --> 21:44.990] Now it is obvious that there is a path traversal issue when print client extract the downloaded [21:44.990 --> 21:53.090] cabinet file. And the cabinet file is provided by a print server. Let's try to make a malformed [21:53.090 --> 22:01.290] cab file. Windows has provided the command make cab for cabinet file creation. [22:01.810 --> 22:07.390] However, make cab could not create cabinet file with the file name contain slashes. [22:09.190 --> 22:15.570] So we decided to create a simple cab and then change the name of the file with another program. [22:16.990 --> 22:20.850] Here we used make cab to create the test.cab. [22:21.770 --> 22:26.650] After we have a cabinet file, we try to change the file name inside the cabinet file. [22:26.710 --> 22:31.530] We used programs such as 7-zip to try to edit the name of the file. [22:33.290 --> 22:40.590] But the file name is not editable. That's very sad. Are we doomed? [22:42.430 --> 22:47.590] No, that could not stop us. We could still modify the file names directly in binary. [22:48.730 --> 22:52.050] Let's edit the file name with an hex editor. [22:53.210 --> 22:58.550] Here we use a small trick using ones and twos in file names as placeholders. [22:59.450 --> 23:04.490] We just modify all ones in file name to dot and twos to slash. [23:06.510 --> 23:11.790] After the modification, we use lzip program to open the cabinet file again. [23:12.070 --> 23:14.990] It can be successfully opened and the file name contains [23:14.990 --> 23:21.790] dot dot slash that could be used to do path traversal. We now have a malformed cabinet. [23:23.950 --> 23:29.510] Replace the cabinet file in the print server with this malformed cab to make it an evil printer. [23:32.250 --> 23:38.410] Let's make an evil printer. First, we should have a fully controllable print server. [23:39.030 --> 23:47.290] To prepare a print server, we prefer to use a virtual PDF printer to simulate the printer instead of getting a real physical printer. [23:48.150 --> 23:55.030] There are many virtual printer products available. Here we randomly choose one, the Qt PDF Writer. [23:55.390 --> 23:58.110] Or other virtual printers should also work. [23:59.370 --> 24:03.030] To prepare a workable print server is very easy. [24:03.250 --> 24:09.490] Just install the printer and then share this printer so that any user on your network can print to it. [24:10.010 --> 24:13.450] Here we just share the printer with the share name test. [24:15.390 --> 24:21.830] Now we have got a fully controllable print server. We will wait for a print client to connect to it. [24:23.210 --> 24:30.550] Because the print server is fully controllable, we have many ways to change the return data before it sends to the print client. [24:31.050 --> 24:36.490] The easiest way is to change the real printer driver info of the shared printer. [24:37.670 --> 24:43.130] We found the print server stores all the definitions of printer driver information in the registry. [24:44.350 --> 24:51.810] As shown in this screenshot, we could know the default print driver attribute of Qt PDF Writer is 0. [24:54.360 --> 24:58.540] Now, let's make a package point-and-print print server. [24:59.420 --> 25:09.460] 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. [25:10.760 --> 25:15.300] Next, we need to configure the driver package that would be downloaded. [25:16.260 --> 25:21.880] As we have described, the package name comes from the directory name of the nth pass. [25:22.840 --> 25:32.120] Here, we configure it to ccolumn backslash test backslash test.int, and make sure the int file exists. [25:32.660 --> 25:38.000] The package name that will be downloaded should be test.cap. [25:39.340 --> 25:45.190] We just needed to place a prepared test.cap to the PCC directory. [25:46.320 --> 25:49.590] Now we finally have a workable Evo printer. [25:50.690 --> 26:01.610] 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. [26:01.810 --> 26:06.650] What would happen if a print client tries to connect to this Evo printer? [26:07.350 --> 26:16.710] We could see the print spooler in print client download the test.cap file from the print server and then extract the cabinet file. [26:17.670 --> 26:29.930] Because of the path traversal bug, ccolumn backslash windows backslash system32 backslash diagnostic services backslash userenvironment.do is created. [26:30.630 --> 26:35.190] Because the print spooler service is running with system privilege, [26:35.750 --> 26:41.010] the Evo printer could write arbitrary file to print client with system privilege. [26:41.010 --> 26:43.970] It is a logical bug and works very stably. [26:44.610 --> 26:48.870] Okay, now we have covered the remote code execution part of the Evo printer. [26:49.670 --> 26:54.690] This attack only needs the print client to make a connection attempt to the Evo printer. [26:55.230 --> 26:58.230] But can this vulnerability do more? [26:59.530 --> 27:05.130] Three years ago, James Horshow did an excellent job on COM internals and Microsoft Edge Sandbox. [27:05.930 --> 27:12.450] During his talk, he demoed a scan of COM servers reachable from inside the Microsoft Edge Sandbox. [27:14.510 --> 27:20.670] He must be hinting something by highlighting that specific COM server during his talk. [27:22.370 --> 27:28.190] Sandbox is an essential security mechanism in modern security architectures. [27:28.370 --> 27:32.550] Sandbox escapes are important security research target. [27:32.550 --> 27:36.210] So how does Evo printer affect sandboxes? [27:37.590 --> 27:43.630] Microsoft Edge vendor process is the most restricted app container sandbox on Windows. [27:43.970 --> 27:49.550] Microsoft has kept reduced attack surfaces of it for many years. [27:49.910 --> 27:55.350] The interfaces that could be accessed from inside the sandbox is fewer and fewer. [27:55.570 --> 27:59.410] But the printing service has always been one of them. [28:00.350 --> 28:04.710] Until now, the process token of render process still has the capability [28:04.710 --> 28:10.990] LPAC printing. It means the render process could access the printing service. [28:11.910 --> 28:19.270] Using oleview.net, we found the COM service CPrintTicketWW services can be launched and [28:19.270 --> 28:27.290] accessed with capability LPAC printing. So it could be called by the Microsoft Edge render process. [28:29.570 --> 28:38.150] The CPrintTicket server provides an interface bind. This is used to bind to a specific printer. [28:38.650 --> 28:43.110] If we bind to an Evo printer, it will also trigger the vulnerability so we could use it [28:43.110 --> 28:52.130] to escape from the sandbox. App container processes are not allowed to create files. [28:52.430 --> 28:56.570] But we could use this vulnerability to create arbitrary files. [28:57.850 --> 29:02.730] The app container process can launch and access CPrintTicket.com server. [29:03.090 --> 29:08.270] The server is implemented in print ticket services module and launched by deal host [29:08.270 --> 29:15.770] with medium integrity level. The bind interface would call CPrintTicket service base bind. [29:16.630 --> 29:22.570] In this function, it would open a remote print server and get the print driver from print server. [29:23.190 --> 29:28.050] This would also trigger the bug if it's connecting to the Evo printer. [29:29.170 --> 29:35.750] So we could escape the Edge render sandbox and execute arbitrary code with system privilege. [29:39.470 --> 29:47.630] Next, let's do a real demo. In this demo, we have two computers, the victim and the attacker. [29:48.090 --> 29:52.950] The victim is a print client and the attacker is the Evo printer. [29:53.970 --> 30:00.690] First, let's see the Evo printer. We have modified the driver info of a shared printer. [30:01.630 --> 30:07.710] We modify the printer driver attributes to one and set the info path item to c [30:07.710 --> 30:16.430] column backslash test backslash test.inf. And we have placed the test.cap at the PCC directory. [30:18.170 --> 30:21.810] Next, let's go to the victim's computer. [30:22.230 --> 30:27.210] You can see there's no user environment.deal in diagnostic services directory. [30:28.490 --> 30:33.990] Now, we try to connect to the Evo printer from Microsoft Edge render sandbox. [30:35.750 --> 30:41.170] Here, we simulate a code execution inside the sandbox by injecting our exploit deal [30:41.170 --> 30:50.390] into the render process. We could see the warning dialog and we could find a user [30:50.390 --> 30:56.950] environment.deal present in the diagnostic services directory. In fact, the Evo printer [30:56.950 --> 31:08.590] could write arbitrary file with system privilege. The patch of the vulnerability is extremely simple. [31:09.210 --> 31:14.030] We have known the root cause of the vulnerability is because the Win32 SPL [31:14.030 --> 31:20.010] uncapping library process copy file does not properly handle the dot dot slash. [31:20.010 --> 31:27.410] So the patch just check both slashes before process copy file to prevent past traversal issues. [31:29.550 --> 31:34.550] Finally, we want to talk about the possible attack scenarios of this vulnerability. [31:35.870 --> 31:42.090] For lateral movement, the attacker can modify a printer trusted by the victim to Evo printer. [31:42.890 --> 31:48.890] For remote code execution, the attacker could convince the victim to connect to a Evo printer. [31:49.810 --> 31:54.750] For privileged escalation, the attacker could make a connection attempt to an Evo printer [31:54.750 --> 31:58.790] either as an unprivileged user or from inside the sandbox. [32:00.410 --> 32:04.990] For all the above scenarios, the attacker immediately gets code execution as system [32:04.990 --> 32:08.350] with complete control of the victim's computer. [32:10.110 --> 32:16.810] This vulnerability has been reported and fixed. The CVE ID is CVE-2020-1300. [32:17.710 --> 32:21.330] This is Microsoft's description about this vulnerability. [32:22.150 --> 32:28.150] Although it's technically correct about the final exploitation vector, it's kind of misleading. [32:28.390 --> 32:36.610] First, this is not a cabinet API vulnerability. The cabinet API is sophisticated and flexible. [32:37.050 --> 32:41.930] But it is too flexible, many parts of the decompression were handled by user-supplied [32:41.930 --> 32:48.590] callbacks. If they don't handle edge cases properly, it could lead to security issues. [32:49.290 --> 32:54.690] In this case, it is the Windows printing which did not implement the decompression callbacks [32:54.690 --> 33:01.990] correctly. Second, this vulnerability does not need a user confirmation to install the [33:01.990 --> 33:08.570] printer driver. Just as we described and demoed, this entire attack finishes before the warning [33:08.570 --> 33:15.050] dialogue. In fact, the attacker could also configure the print server to prevent the [33:15.050 --> 33:20.330] print client from showing the warning dialogue to make the attack completely unnoticeable. [33:21.830 --> 33:28.690] However, there's no need to be panicked about cabinet files. The cabinet API is old, but its [33:28.690 --> 33:35.830] design is okay. If the users of cabinet API handled callbacks with care, there's no security [33:35.830 --> 33:43.150] issues to be worried about. For example, don't be afraid to open the malformed cabinet we created [33:43.150 --> 33:51.670] in Explorer. The cabview module in Explorer.exe correctly handles special characters in cabinet [33:51.670 --> 33:58.530] API callbacks, so it is safe to open a cabinet file in Explorer and copy files. [34:00.920 --> 34:04.910] In this presentation, we talked about the implementation of Windows printing. [34:04.910 --> 34:09.740] It is complex and privileged and can be one of the best targets for attackers. [34:11.120 --> 34:16.220] And we walked you through a bug we found in Windows printing. It could be exploited both [34:16.220 --> 34:22.280] locally and remotely. It could be used to execute arbitrary code with system privilege and escape [34:22.280 --> 34:30.520] sandboxes. For developers, don't be panicked about the cabinet files, but you should be careful when [34:30.520 --> 34:39.000] writing the cabinet API callbacks. Logical bugs like this are always found to be harmful. We think [34:39.000 --> 34:45.880] you will love it just as we do. We would like to thank James Forshaw for his excellent tools and [34:45.880 --> 34:53.720] hints. Big draw AI for their previous works and shares. And thank you for listening.