WEBVTT

00:06.060 --> 00:09.420
Hello everyone, welcome to DEF CON Safe Mode.

00:09.620 --> 00:12.780
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:24.610
First, a self-introduction.

00:24.850 --> 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.

00:31.950 --> 00:36.210
His research focuses on Windows and macOS platform security.

00:36.410 --> 00:40.650
He has found and reported many vulnerabilities to Microsoft and Apple.

00:42.290 --> 00:45.330
Chuanda Ding is a co-author of this presentation.

00:45.510 --> 00:49.170
He leads the EcoSec team at Dunson Security's Shell Lab.

00:54.360 --> 00:57.080
This is the agenda of our talk.

00:57.080 --> 01:01.840
First, an introduction of printing internals, components, and interactions.

01:02.180 --> 01:05.160
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:55.200
Most of you may have done some printing before, and many of you may have worked with a network printer.

01:55.700 --> 01:58.180
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:12.000
Print server connects to the physical printer and makes the printer available to other systems on the network.

02:12.880 --> 02:20.520
When client wants to print a document, it will go to the server and say, hey, server, print this document.

02:21.640 --> 02:28.400
The server gets the print job, 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:53.920
Printers do not understand application data from print clients.

02:54.120 --> 02:59.970
So the application data needs to be converted to the data format that the printer could understand.

03:00.540 --> 03:03.000
This process is called rendering.

03:03.340 --> 03:07.240
In a network printing, there are two different types of rendering.

03:07.240 --> 03:09.440
Client-side and server-side.

03:09.580 --> 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.

03:18.720 --> 03:25.580
For server-side rendering, print client sends the unmodified data directly to the printer server.

03:25.640 --> 03:30.660
Then the printer server translates the application data to the printer-specific data.

03:32.040 --> 03:35.740
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:05.450
And the configuration component contains a user interface that enables users to control the printers.

04:07.990 --> 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.

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: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.

04:58.650 --> 05:02.150
Print spooler service is the core of Windows printing.

05:02.510 --> 05:05.890
Print spooler service manages print drivers.

05:06.330 --> 05:11.750
It is responsible for retrieving a correct print driver and dynamically loading it.

05:12.430 --> 05:15.770
It is an autostart service on Windows OS.

05:15.890 --> 05:23.990
It manages the entire printing process and explores the printing APIs for other printing components and the user applications to use.

05:25.190 --> 05:29.350
It implements both print client and print server roles.

05:30.650 --> 05:34.670
The design of the print spooler is extremely dangerous.

05:34.970 --> 05:42.890
For example, it runs at system privilege level, it has networking tasks, and it can dynamically load third-party binaries.

05:43.970 --> 05:50.330
Client-server printing model is a very common model that shares the printer through the network to many users.

05:50.770 --> 05:56.190
In this model, print server connects to the real printer and shares itself in the network.

05:56.490 --> 05:59.870
The print client connects to the shared print server.

06:00.370 --> 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.

06:09.470 --> 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.

06:18.850 --> 06:25.370
The print spooler on the print server would communicate with the real printer to finish the printing job.

06:26.310 --> 06:29.090
The Windows printing is ancient.

06:29.090 --> 06:32.070
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:44.630
The architecture and implementation of it is extremely complex, even confusing.

06:45.150 --> 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.

06:54.530 --> 06:58.810
There are two types of attack surfaces of Windows printing.

06:59.270 --> 07:02.490
First, the local attack surface.

07:02.970 --> 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.

07:16.510 --> 07:20.190
Abusing them may cause local privilege escalation.

07:21.830 --> 07:25.170
Second, the remote attack surface.

07:25.470 --> 07:31.990
In client-server printing model, both the print server and print client would suffer from the potential attack.

07:32.470 --> 07:40.070
For the print server, it shares the printer to other users and exposes itself to potential attacks in the network.

07:40.470 --> 07:46.950
For a print client, it may be attacked by a malicious print server, also known as evil printer.

07:48.390 --> 07:52.050
What happens behind the scenes when Windows connects to a printer?

07:53.950 --> 08:00.470
If a user wants to do print jobs through a print server, they must actively connect to the print server.

08:00.750 --> 08:04.710
There are many methods for a print client to connect to a print server.

08:05.010 --> 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.

08:16.490 --> 08:26.190
If you want to program, Microsoft provides Win32 print spooler API, 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: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.

08:46.050 --> 08:53.250
This API adds a connection to the specified printer for the current user and specified connection details.

08:53.870 --> 08:59.970
The print server and shared printer name are passed in through parameter pszName.

09:03.190 --> 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.

09:17.550 --> 09:19.620
What's the purpose of this warning dialog?

09:20.150 --> 09:29.370
About four years ago, security researchers from Vector AI found a remote code execution vulnerability in Windows Print Spooler servers.

09:29.610 --> 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.

09:39.070 --> 09:47.390
To address this vulnerability, Microsoft simply added a warning dialog before installing untrusted printer drivers.

09:47.390 --> 09:53.670
It does protect the print client from installing printer drivers without the user concerned.

09:53.890 --> 09:57.010
But is this protection sufficient?

09:57.630 --> 10:04.270
In order to answer this question, let's dig into the implementation of add-printer-connection-to first.

10:04.450 --> 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.

10:14.770 --> 10:19.050
The remote function called is RPC add-printer-connection-to.

10:20.250 --> 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.

10:32.630 --> 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.

10:42.570 --> 10:47.210
For print client, it is an input source that cannot be trusted.

10:48.190 --> 10:54.070
If the returned information is not fully verified, it would cause critical security issues.

10:55.210 --> 10:59.830
The information from the print server would be handled by print spooler on print client.

11:00.030 --> 11:04.510
After finishing, it would return to the caller of add-printer-connection-to.

11:06.090 --> 11:12.090
Add-printer-connection-to would get the return value from print spooler on print client directly.

11:13.010 --> 11:18.910
Error code 0xBB9, which is error printer driver download needed, is a special case.

11:18.970 --> 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.

11:28.650 --> 11:36.430
Upon receiving the server, 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:49.640
This function would load a new module, ntprint, and call the function psetupDownloadAndInstallLegacyDriver.

11:51.190 --> 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.

12:02.710 --> 12:11.130
You would call downloadAndInstallLegacyDriver function to finish the installation of remote printer only if the user confirms to install.

12:11.710 --> 12:16.550
This is the most common scenario of adding a new network printer.

12:17.250 --> 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.

12:27.790 --> 12:31.550
So which mechanism does it use in a common case?

12:32.610 --> 12:40.390
In order to know the implementation of downloadAndInstallLegacyDriver, 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:52.790
And we really recommend you doing this, 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:07.330
This screenshot shows the file operation of print spooler on print client after we confirm to install the driver.

13:07.790 --> 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.

13:19.850 --> 13:24.750
This is the whole procedure of downloading printer driver from print server.

13:27.650 --> 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.

13:35.170 --> 13:42.670
And we could notice from file operations 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:56.290
So which mechanism is this?

13:56.290 --> 13:58.390
We did not see any package here.

13:58.390 --> 14:02.730
It seems all printer drivers are directly downloaded from the print server.

14:02.830 --> 14:05.770
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:44.610
You will try to call the createLocalPrinter function to create a local printer.

14:44.730 --> 14:50.290
Then it uses acquireV3Driver and addPrinter function to get printer driver.

14:50.890 --> 14:55.270
Before getting the driver, it needs to determine install type.

14:55.770 --> 15:00.120
In this function, it tries to call checkPackagePointAndPrint.

15:01.390 --> 15:08.610
This function name seems to indicate it would determine to use the point-and-print or package point-and-print mechanism.

15:09.990 --> 15:15.170
But how does the function checkPackagePointAndPrint determines the mechanisms?

15:15.670 --> 15:17.430
Let's see the implementation.

15:18.970 --> 15:21.330
Here is its pseudocode.

15:21.910 --> 15:29.530
If there is bit 1 at 0x88 offset of an object, the print spooler would download and import driver packages.

15:30.090 --> 15:32.350
But what is this object?

15:32.470 --> 15:34.050
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 --> 15:59.950
The object is a returned data from a remote print server.

15:59.950 --> 16:03.050
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:31.630
The definitions of printer driver attributes could be found in the Windows 10 software development kit.

16:31.750 --> 16:37.670
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:46.830
Now things get clearer.

16:47.010 --> 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.

17:00.510 --> 17:06.550
The mechanism used to download print drivers are solely determined by the remote print server.

17:06.710 --> 17:09.270
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:23.430
A driver package is just a collection of files that are needed to successfully load the printer driver.

17:24.010 --> 17:31.070
It may contain a device information file, a catalog file, and odd files copied by information file.

17:32.510 --> 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.

17:42.770 --> 17:46.230
But where does the print client get the package from?

17:46.230 --> 17:48.350
Can we control the package content?

17:50.170 --> 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.

17:59.730 --> 18:05.010
It is the final directory name of the inf path in print driver info.

18:09.220 --> 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.

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:32.000
The print client would use tdriver install internal copy file to copy driver packages from print server.

18:32.040 --> 18:37.820
Then you would use ncabbing library legacy cab unpack to extract the package.

18:38.200 --> 18:46.720
And the most important thing is the download and extract operations are all happened before showing the warning dialog.

18:47.420 --> 18:49.840
It seems this could be abused.

18:51.140 --> 18:55.200
We know that the driver package is a cabinet file.

18:55.480 --> 18:59.960
A cabinet file is an archive file format for Microsoft Windows.

19:00.320 --> 19:04.420
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:19.120
In order to extract the cabinet file, Microsoft provides a lot of file decompression interface APIs.

19:19.240 --> 19:21.460
Here are some examples.

19:21.900 --> 19:29.260
First, fdi create is used to create a fdi context for cabinet file operations.

19:29.700 --> 19:33.340
Next, fdi copy is the most important one.

19:33.340 --> 19:36.200
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:53.840
This API is designed to be very flexible.

19:53.840 --> 20:01.580
It provides application-defined callback notification functions to update the application on the status of a decompressor.

20:02.540 --> 20:10.360
So the behavior of cabinet extraction is highly dependent on the implementation of users of the API.

20:10.540 --> 20:20.100
As we have described, the print client would use nCabinLibraryLegacyCabOnPack to extract files from the downloaded cab files.

20:20.120 --> 20:25.980
This function uses fdi copy to extract files with a notification callback.

20:27.600 --> 20:31.520
nCabinLibraryFdicabNotify to control the extraction operation of files.

20:34.610 --> 20:43.430
In the callback notification, it would receive the fdint 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:06.370
The process copy file first call nCabinLibrary createFullPath to create a directory if the specified directory does not exist.

21:07.610 --> 21:13.570
When creating the full path, it would check if the path has dot dot backslash.

21:13.950 --> 21:17.410
If it has, the function would just return with an error.

21:18.670 --> 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.

21:27.050 --> 21:32.570
After creating the full path, it would then call the open function to open the file.

21:32.750 --> 21:37.470
If the file does not exist, it will create the file via the ocreate flag.

21:38.890 --> 21:46.470
Now it is obvious that there is a path traversal issue when print client extract the downloaded cabinet file.

21:47.150 --> 21:50.590
And the cabinet file is provided by a print server.

21:51.490 --> 21:54.490
Let's try to make a malformed cab file.

21:55.910 --> 22:01.290
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:36.190
But the file name is not editable.

22:37.070 --> 22:38.970
That's very sad.

22:39.290 --> 22:40.590
Are we doomed?

22:42.430 --> 22:44.550
No, that could not stop us.

22:44.550 --> 22:47.590
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:18.950
It can be successfully opened and the file name contains dot dot slash that could be used to do path traversal.

23:19.170 --> 23:21.790
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:34.530
Let's make an evil printer.

23:34.710 --> 23:38.410
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:51.370
There are many virtual printer products available.

23:51.490 --> 23:55.030
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:18.870
Now we have got a fully controllable print server.

24:18.870 --> 24:21.830
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: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.

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:06.830
Until now, the process token of render process still has the capability LPAC printing.

28:06.830 --> 28:10.990
It means the render process could access the printing service.

28:11.910 --> 28:22.430
Using oleview.net, we found the COM service CPrintTicketWW services can be launched and accessed with capability LPAC printing.

28:22.430 --> 28:27.290
So it could be called by the Microsoft Edge render process.

28:29.570 --> 28:33.870
The CPrintTicket server provides an interface bind.

28:33.870 --> 28:38.150
This is used to bind to a specific printer.

28:38.650 --> 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.

28:48.150 --> 28:52.130
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:10.490
The server is implemented in print ticket services module and launched by deal host with medium integrity level.

29:11.350 --> 29:15.770
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:41.950
Next, let's do a real demo.

29:42.430 --> 29:47.630
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 --> 29:56.890
First, let's see the Evo printer.

29:57.290 --> 30:00.690
We have modified the driver info of a shared printer.

30:01.630 --> 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.

30:12.510 --> 30:16.430
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:43.370
Here, we simulate a code execution inside the sandbox by injecting our exploit deal into the render process.

30:46.830 --> 30:54.390
We could see the warning dialog and we could find a user environment.deal present in the diagnostic services directory.

30:55.390 --> 31:00.290
In fact, the Evo printer could write arbitrary file with system privilege.

31:04.370 --> 31:08.590
The patch of the vulnerability is extremely simple.

31:09.210 --> 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.

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: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.

32:00.410 --> 32:08.350
For all the above scenarios, the attacker immediately gets code execution as system with complete control of the victim's computer.

32:10.110 --> 32:12.850
This vulnerability has been reported and fixed.

32:12.850 --> 32:16.810
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:32.510
First, this is not a cabinet API vulnerability.

32:32.910 --> 32:36.610
The cabinet API is sophisticated and flexible.

32:37.050 --> 32:43.150
But it is too flexible, many parts of the decompression were handled by user-supplied callbacks.

32:43.350 --> 32:48.590
If they don't handle edge cases properly, it could lead to security issues.

32:49.290 --> 32:55.910
In this case, it is the Windows printing which did not implement the decompression callbacks correctly.

32:57.230 --> 33:03.250
Second, this vulnerability does not need a user confirmation to install the printer driver.

33:03.250 --> 33:09.590
Just as we described and demoed, this entire attack finishes before the warning dialogue.

33:10.390 --> 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.

33:21.830 --> 33:25.950
However, there's no need to be panicked about cabinet files.

33:26.390 --> 33:30.290
The cabinet API is old, but its design is okay.

33:31.190 --> 33:37.870
If the users of cabinet API handled callbacks with care, there's no security issues to be worried about.

33:38.690 --> 33:44.610
For example, don't be afraid to open the malformed cabinet we created in Explorer.

33:45.770 --> 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.

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:14.760
And we walked you through a bug we found in Windows printing.

34:14.760 --> 34:17.900
It could be exploited both locally and remotely.

34:18.220 --> 34:23.720
It could be used to execute arbitrary code with system privilege and escape sandboxes.

34:25.000 --> 34:32.800
For developers, don't be panicked about the cabinet files, but you should be careful when writing the cabinet API callbacks.

34:34.880 --> 34:38.340
Logical bugs like this are always found to be harmful.

34:38.480 --> 34:41.140
We think you will love it just as we do.

34:42.260 --> 34:46.760
We would like to thank James Forshaw for his excellent tools and hints.

34:47.580 --> 34:50.760
Big draw AI for their previous works and shares.

34:51.140 --> 34:53.720
And thank you for listening.

