1 00:00:06,060 --> 00:00:09,420 Hello everyone, welcome to DEF CON Safe Mode. 2 00:00:09,620 --> 00:00:12,780 What a special year, glad to see you in this way. 3 00:00:13,540 --> 00:00:18,860 Our talk is Evil Printer, How to Hack Windows Machines with Printing Protocol. 4 00:00:22,150 --> 00:00:24,610 First, a self-introduction. 5 00:00:24,850 --> 00:00:31,730 Zhi Peng Huo is a senior security researcher, and he is a member of the EcoSec team at Dunson Security's Shell Lab. 6 00:00:31,950 --> 00:00:36,210 His research focuses on Windows and macOS platform security. 7 00:00:36,410 --> 00:00:40,650 He has found and reported many vulnerabilities to Microsoft and Apple. 8 00:00:42,290 --> 00:00:45,330 Chuanda Ding is a co-author of this presentation. 9 00:00:45,510 --> 00:00:49,170 He leads the EcoSec team at Dunson Security's Shell Lab. 10 00:00:54,360 --> 00:00:57,080 This is the agenda of our talk. 11 00:00:57,080 --> 00:01:01,840 First, an introduction of printing internals, components, and interactions. 12 00:01:02,180 --> 00:01:05,160 Then, we cover the attack surface of Windows printing. 13 00:01:05,880 --> 00:01:12,360 Finally, a critical bug that we found, a detailed walkthrough of its exploitation, and patch. 14 00:01:14,420 --> 00:01:18,220 We have published a demo video on Twitter about two months ago. 15 00:01:19,040 --> 00:01:22,740 First, the attacker listens for incoming connections. 16 00:01:23,660 --> 00:01:27,700 Next, the victim tries to connect to a attacker-controlled printer. 17 00:01:28,780 --> 00:01:33,100 The attacker immediately gets a reverse shell with system privilege. 18 00:01:33,660 --> 00:01:36,800 This vulnerability is what we call the evil printer. 19 00:01:37,540 --> 00:01:44,160 In this talk, we will show you what it is, how we found and exploit it, and what can it do. 20 00:01:48,240 --> 00:01:55,200 Most of you may have done some printing before, and many of you may have worked with a network printer. 21 00:01:55,700 --> 00:01:58,180 So how does network printing work? 22 00:02:00,160 --> 00:02:04,580 The system where users create the print job on is a print client. 23 00:02:05,500 --> 00:02:12,000 Print server connects to the physical printer and makes the printer available to other systems on the network. 24 00:02:12,880 --> 00:02:20,520 When client wants to print a document, it will go to the server and say, hey, server, print this document. 25 00:02:21,640 --> 00:02:28,400 The server gets the print job, then it will go to the real printer and say, hey, printer, print this. 26 00:02:29,680 --> 00:02:33,200 The printer would finally print a document for the client. 27 00:02:34,580 --> 00:02:39,000 This is the procedure when you want to print a document on a client. 28 00:02:43,280 --> 00:02:49,260 There are so many different printer products manufactured by different companies. 29 00:02:49,480 --> 00:02:53,920 Printers do not understand application data from print clients. 30 00:02:54,120 --> 00:02:59,970 So the application data needs to be converted to the data format that the printer could understand. 31 00:03:00,540 --> 00:03:03,000 This process is called rendering. 32 00:03:03,340 --> 00:03:07,240 In a network printing, there are two different types of rendering. 33 00:03:07,240 --> 00:03:09,440 Client-side and server-side. 34 00:03:09,580 --> 00:03:18,160 For client-side rendering, print client translates the application data to printer-specific data, then sends the data to the printer server. 35 00:03:18,720 --> 00:03:25,580 For server-side rendering, print client sends the unmodified data directly to the printer server. 36 00:03:25,640 --> 00:03:30,660 Then the printer server translates the application data to the printer-specific data. 37 00:03:32,040 --> 00:03:35,740 The rendering jobs are handled by print driver. 38 00:03:38,330 --> 00:03:42,110 Printer driver is an important component of printing. 39 00:03:42,830 --> 00:03:47,070 It is the interface component between the OS and the printers. 40 00:03:47,730 --> 00:03:52,810 Printer drivers include a rendering component and a configuration component. 41 00:03:53,370 --> 00:03:59,070 The rendering component converts application data into the data that printer could use. 42 00:03:59,410 --> 00:04:05,450 And the configuration component contains a user interface that enables users to control the printers. 43 00:04:07,990 --> 00:04:16,490 In order to support both client-side and server-side rendering, it is a requirement that the printer drivers are available to both print client and print server. 44 00:04:17,410 --> 00:04:21,250 There are two mechanisms for distributing printer driver. 45 00:04:21,250 --> 00:04:24,950 They are called point-and-print and package point-and-print. 46 00:04:25,630 --> 00:04:31,210 Point-and-print allows a print client to download printer driver directly from a print server. 47 00:04:32,190 --> 00:04:37,690 Package point-and-print allows a print client to download a printer support package. 48 00:04:37,830 --> 00:04:41,130 And the package would include a needed printer driver. 49 00:04:43,390 --> 00:04:56,290 According to Microsoft, the package approach to driver installation provides improved security for point-and-print by checking driver signing during the establishment of a point-and-print connection. 50 00:04:58,650 --> 00:05:02,150 Print spooler service is the core of Windows printing. 51 00:05:02,510 --> 00:05:05,890 Print spooler service manages print drivers. 52 00:05:06,330 --> 00:05:11,750 It is responsible for retrieving a correct print driver and dynamically loading it. 53 00:05:12,430 --> 00:05:15,770 It is an autostart service on Windows OS. 54 00:05:15,890 --> 00:05:23,990 It manages the entire printing process and explores the printing APIs for other printing components and the user applications to use. 55 00:05:25,190 --> 00:05:29,350 It implements both print client and print server roles. 56 00:05:30,650 --> 00:05:34,670 The design of the print spooler is extremely dangerous. 57 00:05:34,970 --> 00:05:42,890 For example, it runs at system privilege level, it has networking tasks, and it can dynamically load third-party binaries. 58 00:05:43,970 --> 00:05:50,330 Client-server printing model is a very common model that shares the printer through the network to many users. 59 00:05:50,770 --> 00:05:56,190 In this model, print server connects to the real printer and shares itself in the network. 60 00:05:56,490 --> 00:05:59,870 The print client connects to the shared print server. 61 00:06:00,370 --> 00:06:08,990 When applications on print client want to start print job, it calls the printing APIs to communicate with the local print spooler. 62 00:06:09,470 --> 00:06:18,130 Then print spooler will send the action to the remote print spooler on a print server through network protocols, such as SMB. 63 00:06:18,850 --> 00:06:25,370 The print spooler on the print server would communicate with the real printer to finish the printing job. 64 00:06:26,310 --> 00:06:29,090 The Windows printing is ancient. 65 00:06:29,090 --> 00:06:32,070 It has existed for more than 25 years. 66 00:06:32,110 --> 00:06:37,500 It's highly integrated with Windows OS, and it is one of the most important services. 67 00:06:38,210 --> 00:06:44,630 The architecture and implementation of it is extremely complex, even confusing. 68 00:06:45,150 --> 00:06:52,870 Many parts of it works at the highest privilege level to make it one of the most valuable targets for bug hunting. 69 00:06:54,530 --> 00:06:58,810 There are two types of attack surfaces of Windows printing. 70 00:06:59,270 --> 00:07:02,490 First, the local attack surface. 71 00:07:02,970 --> 00:07:15,730 In order to serve applications and other components running at different privilege levels, Windows printing made many of its interfaces available to applications running at lower privilege levels. 72 00:07:16,510 --> 00:07:20,190 Abusing them may cause local privilege escalation. 73 00:07:21,830 --> 00:07:25,170 Second, the remote attack surface. 74 00:07:25,470 --> 00:07:31,990 In client-server printing model, both the print server and print client would suffer from the potential attack. 75 00:07:32,470 --> 00:07:40,070 For the print server, it shares the printer to other users and exposes itself to potential attacks in the network. 76 00:07:40,470 --> 00:07:46,950 For a print client, it may be attacked by a malicious print server, also known as evil printer. 77 00:07:48,390 --> 00:07:52,050 What happens behind the scenes when Windows connects to a printer? 78 00:07:53,950 --> 00:08:00,470 If a user wants to do print jobs through a print server, they must actively connect to the print server. 79 00:08:00,750 --> 00:08:04,710 There are many methods for a print client to connect to a print server. 80 00:08:05,010 --> 00:08:16,190 If you are familiar with PowerShell, you could use add-printer command-line to add a new network printer connection by specifying the name of a print server and a shared printer on that server. 81 00:08:16,490 --> 00:08:26,190 If you want to program, Microsoft provides Win32 print spooler API, such as add-printer-connection and add-printer-connection-to. 82 00:08:27,070 --> 00:08:34,250 And you could also use the GUI provided by print-ui-im to select a shared printer by name. 83 00:08:36,010 --> 00:08:45,370 Although many methods could be used for connecting to a specified print server, they could be traced to the one same API add-printer-connection-to. 84 00:08:46,050 --> 00:08:53,250 This API adds a connection to the specified printer for the current user and specified connection details. 85 00:08:53,870 --> 00:08:59,970 The print server and shared printer name are passed in through parameter pszName. 86 00:09:03,190 --> 00:09:16,250 When adding printer connection, if the print client needs to download and install printer driver from a remote print server, it will show a warning dialog to ask a user to install the driver or cancel the request. 87 00:09:17,550 --> 00:09:19,620 What's the purpose of this warning dialog? 88 00:09:20,150 --> 00:09:29,370 About four years ago, security researchers from Vector AI found a remote code execution vulnerability in Windows Print Spooler servers. 89 00:09:29,610 --> 00:09:38,530 The root cause of this vulnerability is print client would load and install a malicious printer driver from attacker-controlled print server. 90 00:09:39,070 --> 00:09:47,390 To address this vulnerability, Microsoft simply added a warning dialog before installing untrusted printer drivers. 91 00:09:47,390 --> 00:09:53,670 It does protect the print client from installing printer drivers without the user concerned. 92 00:09:53,890 --> 00:09:57,010 But is this protection sufficient? 93 00:09:57,630 --> 00:10:04,270 In order to answer this question, let's dig into the implementation of add-printer-connection-to first. 94 00:10:04,450 --> 00:10:14,170 Any applications or print client that call add-printer-connection-to API will send an RPC call to print spooler service on printer client. 95 00:10:14,770 --> 00:10:19,050 The remote function called is RPC add-printer-connection-to. 96 00:10:20,250 --> 00:10:31,230 If the print client is trying to add a remote print server, the print spooler on print client would try to communicate with print spooler on print server and get information from it. 97 00:10:32,630 --> 00:10:41,590 When print server is fully controllable, it is obvious that the data back to the print spooler on print client is also fully controllable by print server. 98 00:10:42,570 --> 00:10:47,210 For print client, it is an input source that cannot be trusted. 99 00:10:48,190 --> 00:10:54,070 If the returned information is not fully verified, it would cause critical security issues. 100 00:10:55,210 --> 00:10:59,830 The information from the print server would be handled by print spooler on print client. 101 00:11:00,030 --> 00:11:04,510 After finishing, it would return to the caller of add-printer-connection-to. 102 00:11:06,090 --> 00:11:12,090 Add-printer-connection-to would get the return value from print spooler on print client directly. 103 00:11:13,010 --> 00:11:18,910 Error code 0xBB9, which is error printer driver download needed, is a special case. 104 00:11:18,970 --> 00:11:27,530 The error, just as the name described, means the print client does not have the required drivers and needs to be downloaded from the print server. 105 00:11:28,650 --> 00:11:36,430 Upon receiving the server, the add-printer-connection-to will immediately start to download and install the needed driver. 106 00:11:37,200 --> 00:11:40,760 It calls the function downloadAndInstallLegacyDriver. 107 00:11:41,390 --> 00:11:49,640 This function would load a new module, ntprint, and call the function psetupDownloadAndInstallLegacyDriver. 108 00:11:51,190 --> 00:12:01,490 But before the real download, you would call displayWarning for download driver to show a warning dialog for user to choose to install the driver or just cancel. 109 00:12:02,710 --> 00:12:11,130 You would call downloadAndInstallLegacyDriver function to finish the installation of remote printer only if the user confirms to install. 110 00:12:11,710 --> 00:12:16,550 This is the most common scenario of adding a new network printer. 111 00:12:17,250 --> 00:12:27,790 But as we have described, Windows printing has two different mechanisms, point -and-print and package-point-and-print, to download the correct printer drivers. 112 00:12:27,790 --> 00:12:31,550 So which mechanism does it use in a common case? 113 00:12:32,610 --> 00:12:40,390 In order to know the implementation of downloadAndInstallLegacyDriver, we do not want to do too much reverse engineering works. 114 00:12:40,510 --> 00:12:44,910 Instead, we prefer to observe the behavior of our operations. 115 00:12:45,970 --> 00:12:52,790 And we really recommend you doing this, especially when you are analyzing a complex application or want to find some logical bugs. 116 00:12:53,610 --> 00:12:58,450 Here we use process monitor to capture the driver download operations. 117 00:12:59,330 --> 00:13:07,330 This screenshot shows the file operation of print spooler on print client after we confirm to install the driver. 118 00:13:07,790 --> 00:13:18,930 We notice the print spooler on print client reads information through RPC from the print server and then write the print driver files to a temporary directory directly. 119 00:13:19,850 --> 00:13:24,750 This is the whole procedure of downloading printer driver from print server. 120 00:13:27,650 --> 00:13:34,610 After the printer driver is downloaded, it should be installed so the print client could use it to do client-side rendering. 121 00:13:35,170 --> 00:13:42,670 And we could notice from file operations that the drivers in temporary directory are moved to the system driver directory. 122 00:13:44,330 --> 00:13:47,910 This is the procedure of printer driver installation. 123 00:13:48,450 --> 00:13:52,190 Now the printer driver is successfully downloaded and installed. 124 00:13:53,730 --> 00:13:56,290 So which mechanism is this? 125 00:13:56,290 --> 00:13:58,390 We did not see any package here. 126 00:13:58,390 --> 00:14:02,730 It seems all printer drivers are directly downloaded from the print server. 127 00:14:02,830 --> 00:14:05,770 So it seems to be point-and-print. 128 00:14:06,690 --> 00:14:11,250 So why does the current print client only use the point-and-print mechanism? 129 00:14:11,790 --> 00:14:16,890 How does the print client and server negotiate which one to use? 130 00:14:17,470 --> 00:14:20,130 How to enable the package point-and-print? 131 00:14:22,110 --> 00:14:28,130 To answer this question, we dig into the RPC addPrinterConnection2 function in print spooler. 132 00:14:28,350 --> 00:14:32,290 The procedure of addPrinterConnection2 is very complex. 133 00:14:32,410 --> 00:14:38,530 We found the adding connection operation of the remote printer is handled by the Win32 SPL module. 134 00:14:39,590 --> 00:14:44,610 You will try to call the createLocalPrinter function to create a local printer. 135 00:14:44,730 --> 00:14:50,290 Then it uses acquireV3Driver and addPrinter function to get printer driver. 136 00:14:50,890 --> 00:14:55,270 Before getting the driver, it needs to determine install type. 137 00:14:55,770 --> 00:15:00,120 In this function, it tries to call checkPackagePointAndPrint. 138 00:15:01,390 --> 00:15:08,610 This function name seems to indicate it would determine to use the point-and-print or package point-and-print mechanism. 139 00:15:09,990 --> 00:15:15,170 But how does the function checkPackagePointAndPrint determines the mechanisms? 140 00:15:15,670 --> 00:15:17,430 Let's see the implementation. 141 00:15:18,970 --> 00:15:21,330 Here is its pseudocode. 142 00:15:21,910 --> 00:15:29,530 If there is bit 1 at 0x88 offset of an object, the print spooler would download and import driver packages. 143 00:15:30,090 --> 00:15:32,350 But what is this object? 144 00:15:32,470 --> 00:15:34,050 Where it comes from? 145 00:15:34,090 --> 00:15:36,610 And can we control it from the print server? 146 00:15:38,710 --> 00:15:44,310 We found the print client gets that object by calling function remoteGetPrinterDriver. 147 00:15:44,510 --> 00:15:47,970 The function, in fact, is just an RPC stub. 148 00:15:48,690 --> 00:15:55,050 The real implementation is RPC asyncGetPrinterDriver in print spooler of print server. 149 00:15:56,030 --> 00:15:59,950 The object is a returned data from a remote print server. 150 00:15:59,950 --> 00:16:03,050 So it is fully controllable by print server. 151 00:16:04,070 --> 00:16:09,310 The structure of the returned object is a DriverInfo8. 152 00:16:10,350 --> 00:16:17,450 And we could know that at the 0x88 offset is the DWPrinterDriver attributes. 153 00:16:18,190 --> 00:16:25,190 The object has many other interesting items such as driver path, config path, inf path, and so on. 154 00:16:25,850 --> 00:16:31,630 The definitions of printer driver attributes could be found in the Windows 10 software development kit. 155 00:16:31,750 --> 00:16:37,670 What we care about is just a value 1, which is PrinterDriverPackageAware. 156 00:16:38,170 --> 00:16:42,810 It means the printer driver is part of a driver package. 157 00:16:44,550 --> 00:16:46,830 Now things get clearer. 158 00:16:47,010 --> 00:16:58,510 If the printer driver attributes of the print server is PrinterDriverPackageAware, the print client would use the package point-and-print mechanisms to download and import package drivers. 159 00:17:00,510 --> 00:17:06,550 The mechanism used to download print drivers are solely determined by the remote print server. 160 00:17:06,710 --> 00:17:09,270 That seems very interesting and may be dangerous. 161 00:17:12,210 --> 00:17:15,890 What is a driver package in package point-and-print? 162 00:17:16,790 --> 00:17:23,430 A driver package is just a collection of files that are needed to successfully load the printer driver. 163 00:17:24,010 --> 00:17:31,070 It may contain a device information file, a catalog file, and odd files copied by information file. 164 00:17:32,510 --> 00:17:42,710 Now we know how to force the print client to use the package point-and-print mechanism, and we know the print client would try to download the package driver from the print server. 165 00:17:42,770 --> 00:17:46,230 But where does the print client get the package from? 166 00:17:46,230 --> 00:17:48,350 Can we control the package content? 167 00:17:50,170 --> 00:17:59,730 After some research, we found that all printer driver packages are stored in a PCC directory, and the filename of package driver is very interesting. 168 00:17:59,730 --> 00:18:05,010 It is the final directory name of the inf path in print driver info. 169 00:18:09,220 --> 00:18:17,840 If the print client knows the print server wants to use package point-and-print mechanism, it would download and import driver packages. 170 00:18:17,840 --> 00:18:23,920 But before import, the print client would first download the driver package and then extract it. 171 00:18:24,100 --> 00:18:32,000 The print client would use tdriver install internal copy file to copy driver packages from print server. 172 00:18:32,040 --> 00:18:37,820 Then you would use ncabbing library legacy cab unpack to extract the package. 173 00:18:38,200 --> 00:18:46,720 And the most important thing is the download and extract operations are all happened before showing the warning dialog. 174 00:18:47,420 --> 00:18:49,840 It seems this could be abused. 175 00:18:51,140 --> 00:18:55,200 We know that the driver package is a cabinet file. 176 00:18:55,480 --> 00:18:59,960 A cabinet file is an archive file format for Microsoft Windows. 177 00:19:00,320 --> 00:19:04,420 It is ancient and has existed for many years. 178 00:19:04,920 --> 00:19:10,460 It has the suffix .cab and acts like a container for other files. 179 00:19:11,700 --> 00:19:19,120 In order to extract the cabinet file, Microsoft provides a lot of file decompression interface APIs. 180 00:19:19,240 --> 00:19:21,460 Here are some examples. 181 00:19:21,900 --> 00:19:29,260 First, fdi create is used to create a fdi context for cabinet file operations. 182 00:19:29,700 --> 00:19:33,340 Next, fdi copy is the most important one. 183 00:19:33,340 --> 00:19:36,200 It is used to extract files from cabinet. 184 00:19:38,020 --> 00:19:44,340 fdi destroy deletes and opens the fdi context after the cabinet operations. 185 00:19:45,040 --> 00:19:49,880 fdi copy is the primary API for extracting files from the cabinet. 186 00:19:49,980 --> 00:19:53,840 This API is designed to be very flexible. 187 00:19:53,840 --> 00:20:01,580 It provides application-defined callback notification functions to update the application on the status of a decompressor. 188 00:20:02,540 --> 00:20:10,360 So the behavior of cabinet extraction is highly dependent on the implementation of users of the API. 189 00:20:10,540 --> 00:20:20,100 As we have described, the print client would use nCabinLibraryLegacyCabOnPack to extract files from the downloaded cab files. 190 00:20:20,120 --> 00:20:25,980 This function uses fdi copy to extract files with a notification callback. 191 00:20:27,600 --> 00:20:31,520 nCabinLibraryFdicabNotify to control the extraction operation of files. 192 00:20:34,610 --> 00:20:43,430 In the callback notification, it would receive the fdint copy file notification to handle copy file operation. 193 00:20:44,370 --> 00:20:48,130 This is part of a pseudocode of copy file processing. 194 00:20:50,330 --> 00:20:56,510 The copy file operation would finally call the nCabinLibrary process copy file. 195 00:20:57,060 --> 00:21:06,370 The process copy file first call nCabinLibrary createFullPath to create a directory if the specified directory does not exist. 196 00:21:07,610 --> 00:21:13,570 When creating the full path, it would check if the path has dot dot backslash. 197 00:21:13,950 --> 00:21:17,410 If it has, the function would just return with an error. 198 00:21:18,670 --> 00:21:26,050 But it forgot to check the dot dot slash, which also works on Windows OS and could be used to do path traversal. 199 00:21:27,050 --> 00:21:32,570 After creating the full path, it would then call the open function to open the file. 200 00:21:32,750 --> 00:21:37,470 If the file does not exist, it will create the file via the ocreate flag. 201 00:21:38,890 --> 00:21:46,470 Now it is obvious that there is a path traversal issue when print client extract the downloaded cabinet file. 202 00:21:47,150 --> 00:21:50,590 And the cabinet file is provided by a print server. 203 00:21:51,490 --> 00:21:54,490 Let's try to make a malformed cab file. 204 00:21:55,910 --> 00:22:01,290 Windows has provided the command make cab for cabinet file creation. 205 00:22:01,810 --> 00:22:07,390 However, make cab could not create cabinet file with the file name contain slashes. 206 00:22:09,190 --> 00:22:15,570 So we decided to create a simple cab and then change the name of the file with another program. 207 00:22:16,990 --> 00:22:20,850 Here we used make cab to create the test.cab. 208 00:22:21,770 --> 00:22:26,650 After we have a cabinet file, we try to change the file name inside the cabinet file. 209 00:22:26,710 --> 00:22:31,530 We used programs such as 7-zip to try to edit the name of the file. 210 00:22:33,290 --> 00:22:36,190 But the file name is not editable. 211 00:22:37,070 --> 00:22:38,970 That's very sad. 212 00:22:39,290 --> 00:22:40,590 Are we doomed? 213 00:22:42,430 --> 00:22:44,550 No, that could not stop us. 214 00:22:44,550 --> 00:22:47,590 We could still modify the file names directly in binary. 215 00:22:48,730 --> 00:22:52,050 Let's edit the file name with an hex editor. 216 00:22:53,210 --> 00:22:58,550 Here we use a small trick using ones and twos in file names as placeholders. 217 00:22:59,450 --> 00:23:04,490 We just modify all ones in file name to dot and twos to slash. 218 00:23:06,510 --> 00:23:11,790 After the modification, we use lzip program to open the cabinet file again. 219 00:23:12,070 --> 00:23:18,950 It can be successfully opened and the file name contains dot dot slash that could be used to do path traversal. 220 00:23:19,170 --> 00:23:21,790 We now have a malformed cabinet. 221 00:23:23,950 --> 00:23:29,510 Replace the cabinet file in the print server with this malformed cab to make it an evil printer. 222 00:23:32,250 --> 00:23:34,530 Let's make an evil printer. 223 00:23:34,710 --> 00:23:38,410 First, we should have a fully controllable print server. 224 00:23:39,030 --> 00: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. 225 00:23:48,150 --> 00:23:51,370 There are many virtual printer products available. 226 00:23:51,490 --> 00:23:55,030 Here we randomly choose one, the Qt PDF Writer. 227 00:23:55,390 --> 00:23:58,110 Or other virtual printers should also work. 228 00:23:59,370 --> 00:24:03,030 To prepare a workable print server is very easy. 229 00:24:03,250 --> 00:24:09,490 Just install the printer and then share this printer so that any user on your network can print to it. 230 00:24:10,010 --> 00:24:13,450 Here we just share the printer with the share name test. 231 00:24:15,390 --> 00:24:18,870 Now we have got a fully controllable print server. 232 00:24:18,870 --> 00:24:21,830 We will wait for a print client to connect to it. 233 00:24:23,210 --> 00: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. 234 00:24:31,050 --> 00:24:36,490 The easiest way is to change the real printer driver info of the shared printer. 235 00:24:37,670 --> 00:24:43,130 We found the print server stores all the definitions of printer driver information in the registry. 236 00:24:44,350 --> 00:24:51,810 As shown in this screenshot, we could know the default print driver attribute of Qt PDF Writer is 0. 237 00:24:54,360 --> 00:24:58,540 Now, let's make a package point-and-print print server. 238 00:24:59,420 --> 00: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. 239 00:25:10,760 --> 00:25:15,300 Next, we need to configure the driver package that would be downloaded. 240 00:25:16,260 --> 00:25:21,880 As we have described, the package name comes from the directory name of the nth pass. 241 00:25:22,840 --> 00:25:32,120 Here, we configure it to ccolumn backslash test backslash test.int, and make sure the int file exists. 242 00:25:32,660 --> 00:25:38,000 The package name that will be downloaded should be test.cap. 243 00:25:39,340 --> 00:25:45,190 We just needed to place a prepared test.cap to the PCC directory. 244 00:25:46,320 --> 00:25:49,590 Now we finally have a workable Evo printer. 245 00:25:50,690 --> 00: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. 246 00:26:01,810 --> 00:26:06,650 What would happen if a print client tries to connect to this Evo printer? 247 00:26:07,350 --> 00: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. 248 00:26:17,670 --> 00:26:29,930 Because of the path traversal bug, ccolumn backslash windows backslash system32 backslash diagnostic services backslash userenvironment.do is created. 249 00:26:30,630 --> 00:26:41,010 Because the print spooler service is running with system privilege, the Evo printer could write arbitrary file to print client with system privilege. 250 00:26:41,010 --> 00:26:43,970 It is a logical bug and works very stably. 251 00:26:44,610 --> 00:26:48,870 Okay, now we have covered the remote code execution part of the Evo printer. 252 00:26:49,670 --> 00:26:54,690 This attack only needs the print client to make a connection attempt to the Evo printer. 253 00:26:55,230 --> 00:26:58,230 But can this vulnerability do more? 254 00:26:59,530 --> 00:27:05,130 Three years ago, James Horshow did an excellent job on COM internals and Microsoft Edge Sandbox. 255 00:27:05,930 --> 00:27:12,450 During his talk, he demoed a scan of COM servers reachable from inside the Microsoft Edge Sandbox. 256 00:27:14,510 --> 00:27:20,670 He must be hinting something by highlighting that specific COM server during his talk. 257 00:27:22,370 --> 00:27:28,190 Sandbox is an essential security mechanism in modern security architectures. 258 00:27:28,370 --> 00:27:32,550 Sandbox escapes are important security research target. 259 00:27:32,550 --> 00:27:36,210 So how does Evo printer affect sandboxes? 260 00:27:37,590 --> 00:27:43,630 Microsoft Edge vendor process is the most restricted app container sandbox on Windows. 261 00:27:43,970 --> 00:27:49,550 Microsoft has kept reduced attack surfaces of it for many years. 262 00:27:49,910 --> 00:27:55,350 The interfaces that could be accessed from inside the sandbox is fewer and fewer. 263 00:27:55,570 --> 00:27:59,410 But the printing service has always been one of them. 264 00:28:00,350 --> 00:28:06,830 Until now, the process token of render process still has the capability LPAC printing. 265 00:28:06,830 --> 00:28:10,990 It means the render process could access the printing service. 266 00:28:11,910 --> 00:28:22,430 Using oleview.net, we found the COM service CPrintTicketWW services can be launched and accessed with capability LPAC printing. 267 00:28:22,430 --> 00:28:27,290 So it could be called by the Microsoft Edge render process. 268 00:28:29,570 --> 00:28:33,870 The CPrintTicket server provides an interface bind. 269 00:28:33,870 --> 00:28:38,150 This is used to bind to a specific printer. 270 00:28:38,650 --> 00:28:45,350 If we bind to an Evo printer, it will also trigger the vulnerability so we could use it to escape from the sandbox. 271 00:28:48,150 --> 00:28:52,130 App container processes are not allowed to create files. 272 00:28:52,430 --> 00:28:56,570 But we could use this vulnerability to create arbitrary files. 273 00:28:57,850 --> 00:29:02,730 The app container process can launch and access CPrintTicket.com server. 274 00:29:03,090 --> 00:29:10,490 The server is implemented in print ticket services module and launched by deal host with medium integrity level. 275 00:29:11,350 --> 00:29:15,770 The bind interface would call CPrintTicket service base bind. 276 00:29:16,630 --> 00:29:22,570 In this function, it would open a remote print server and get the print driver from print server. 277 00:29:23,190 --> 00:29:28,050 This would also trigger the bug if it's connecting to the Evo printer. 278 00:29:29,170 --> 00:29:35,750 So we could escape the Edge render sandbox and execute arbitrary code with system privilege. 279 00:29:39,470 --> 00:29:41,950 Next, let's do a real demo. 280 00:29:42,430 --> 00:29:47,630 In this demo, we have two computers, the victim and the attacker. 281 00:29:48,090 --> 00:29:52,950 The victim is a print client and the attacker is the Evo printer. 282 00:29:53,970 --> 00:29:56,890 First, let's see the Evo printer. 283 00:29:57,290 --> 00:30:00,690 We have modified the driver info of a shared printer. 284 00:30:01,630 --> 00:30:12,030 We modify the printer driver attributes to one and set the info path item to c column backslash test backslash test.inf. 285 00:30:12,510 --> 00:30:16,430 And we have placed the test.cap at the PCC directory. 286 00:30:18,170 --> 00:30:21,810 Next, let's go to the victim's computer. 287 00:30:22,230 --> 00:30:27,210 You can see there's no user environment.deal in diagnostic services directory. 288 00:30:28,490 --> 00:30:33,990 Now, we try to connect to the Evo printer from Microsoft Edge render sandbox. 289 00:30:35,750 --> 00:30:43,370 Here, we simulate a code execution inside the sandbox by injecting our exploit deal into the render process. 290 00:30:46,830 --> 00:30:54,390 We could see the warning dialog and we could find a user environment.deal present in the diagnostic services directory. 291 00:30:55,390 --> 00:31:00,290 In fact, the Evo printer could write arbitrary file with system privilege. 292 00:31:04,370 --> 00:31:08,590 The patch of the vulnerability is extremely simple. 293 00:31:09,210 --> 00:31:20,010 We have known the root cause of the vulnerability is because the Win32 SPL uncapping library process copy file does not properly handle the dot dot slash. 294 00:31:20,010 --> 00:31:27,410 So the patch just check both slashes before process copy file to prevent past traversal issues. 295 00:31:29,550 --> 00:31:34,550 Finally, we want to talk about the possible attack scenarios of this vulnerability. 296 00:31:35,870 --> 00:31:42,090 For lateral movement, the attacker can modify a printer trusted by the victim to Evo printer. 297 00:31:42,890 --> 00:31:48,890 For remote code execution, the attacker could convince the victim to connect to a Evo printer. 298 00:31:49,810 --> 00:31:58,790 For privileged escalation, the attacker could make a connection attempt to an Evo printer either as an unprivileged user or from inside the sandbox. 299 00:32:00,410 --> 00:32:08,350 For all the above scenarios, the attacker immediately gets code execution as system with complete control of the victim's computer. 300 00:32:10,110 --> 00:32:12,850 This vulnerability has been reported and fixed. 301 00:32:12,850 --> 00:32:16,810 The CVE ID is CVE-2020-1300. 302 00:32:17,710 --> 00:32:21,330 This is Microsoft's description about this vulnerability. 303 00:32:22,150 --> 00:32:28,150 Although it's technically correct about the final exploitation vector, it's kind of misleading. 304 00:32:28,390 --> 00:32:32,510 First, this is not a cabinet API vulnerability. 305 00:32:32,910 --> 00:32:36,610 The cabinet API is sophisticated and flexible. 306 00:32:37,050 --> 00:32:43,150 But it is too flexible, many parts of the decompression were handled by user-supplied callbacks. 307 00:32:43,350 --> 00:32:48,590 If they don't handle edge cases properly, it could lead to security issues. 308 00:32:49,290 --> 00:32:55,910 In this case, it is the Windows printing which did not implement the decompression callbacks correctly. 309 00:32:57,230 --> 00:33:03,250 Second, this vulnerability does not need a user confirmation to install the printer driver. 310 00:33:03,250 --> 00:33:09,590 Just as we described and demoed, this entire attack finishes before the warning dialogue. 311 00:33:10,390 --> 00:33:20,330 In fact, the attacker could also configure the print server to prevent the print client from showing the warning dialogue to make the attack completely unnoticeable. 312 00:33:21,830 --> 00:33:25,950 However, there's no need to be panicked about cabinet files. 313 00:33:26,390 --> 00:33:30,290 The cabinet API is old, but its design is okay. 314 00:33:31,190 --> 00:33:37,870 If the users of cabinet API handled callbacks with care, there's no security issues to be worried about. 315 00:33:38,690 --> 00:33:44,610 For example, don't be afraid to open the malformed cabinet we created in Explorer. 316 00:33:45,770 --> 00:33:58,530 The cabview module in Explorer.exe correctly handles special characters in cabinet API callbacks, so it is safe to open a cabinet file in Explorer and copy files. 317 00:34:00,920 --> 00:34:04,910 In this presentation, we talked about the implementation of Windows printing. 318 00:34:04,910 --> 00:34:09,740 It is complex and privileged and can be one of the best targets for attackers. 319 00:34:11,120 --> 00:34:14,760 And we walked you through a bug we found in Windows printing. 320 00:34:14,760 --> 00:34:17,900 It could be exploited both locally and remotely. 321 00:34:18,220 --> 00:34:23,720 It could be used to execute arbitrary code with system privilege and escape sandboxes. 322 00:34:25,000 --> 00:34:32,800 For developers, don't be panicked about the cabinet files, but you should be careful when writing the cabinet API callbacks. 323 00:34:34,880 --> 00:34:38,340 Logical bugs like this are always found to be harmful. 324 00:34:38,480 --> 00:34:41,140 We think you will love it just as we do. 325 00:34:42,260 --> 00:34:46,760 We would like to thank James Forshaw for his excellent tools and hints. 326 00:34:47,580 --> 00:34:50,760 Big draw AI for their previous works and shares. 327 00:34:51,140 --> 00:34:53,720 And thank you for listening.