 Hello, DefCon. Welcome to my talk, Bring Your Own Print Driver Vulnerability. In this talk, I'll discuss how standard low privilege user can install print drivers of their choosing by design on window systems. And I'll show how a local attacker can escalate to system using a handful of different print drivers. Now I want to say up front that I won't be talking about print nightmare. Print nightmare at this point is supposed to be a patch vulnerability. Whereas what I'm going to talk about in this presentation is likely a built-in feature that will be difficult to patch. I also had to record this shortly after print nightmare's release, so even if I wanted to incorporate it, there really just wasn't enough time. Now this talk is roughly broken down into four parts. To start, I'll discuss some research that influenced this talk. Then, we'll explore how a standard user can install a print driver. Next, we'll discuss actual exploitation and I'll introduce a tool I wrote. Finally, I'll touch on detecting the sort of attack in the wild and mitigations that may prevent it. I'll also give a quick rundown of the vulnerability disclosure timelines associated with this talk. Now in my opinion, the slides are just an educational tool. While it's all well and good for me to present them, it's also important for the viewer to read them at their own pace. Click links, read background material, and try out code snippets. There are also exploits associated with this talk. And because of all that, the code and slides are available at the following GitHub repository. The name of the repo will make a little bit more sense later on in the talk. Finally, before we get too far into it, I'd like to introduce myself. My name is Jake Baines and I'm a vulnerability researcher. I like to use the handle albino lobster, which is why you'll see this little lobster almost everywhere I'm active online. My most well known work is probably my micro tick work, although it isn't well known at all. But I have had the good fortune to be able to present at a few conferences, including DEF CON 27. I'm currently employed by Dregos. However, all the work I'm discussing today was done while I was employed by Dark Wolf Solutions in fall 2020. Dark Wolf very kindly gave me permission to share this work for which I am truly grateful. So thank you very much to them. Now, there are some researchers that cut their own path and break new ground, but I'm just not one of those people. To learn the printer subsystem and arrive at the conclusions I did, I had to stand on the shoulders of many more talented researchers that came before me. I think it's important and useful to understand the work that influenced my final outcome. So let's quickly discuss some previous printer vulnerabilities. The first issue I want to familiarize you with is CVE 2019-19363. This is a vulnerability in a third-party print driver. The driver was developed by RICO and it allows for privileged escalation to system by overriding a DLL. PenaGrid handled the disclosure and published a nice proof of concept while Shelby Pace of Rapid 7 developed the Metasploit module. It's a good vulnerability, but the driver has to be installed on the system in order to exploit it. So it is sort of limited in that capacity. This is a good one to remember for later in the talk as we will reference it again. Of course there is CVE 2010-48, which is better known as PrintDemon. Now it got a lengthy and a bit of a meandering right up on the Windows Internals blog. But if you spend some time with it, that blog provides really good exposure to some of the important WinAPI function calls associated with printers. The vulnerability itself allows a local attacker to print to arbitrary files as system after restarting the spooler, resulting in privileged escalation. The image here is actually from the VoidSec blog that talks about the vulnerability. And what you see is the UI rejecting the attack due to insufficient permissions. However, a similar call via the WinAPI was allowed resulting in the vulnerability. And of course there was the patch bypass for PrintDemon. A variety of people are actually credited with this CVE, but VoidSec did the best write up in my opinion. This is a really simple attack where after the file permission checks have been done, the attacker just swaps the file port with a junction and then they just execute the normal PrintDemon attack. Really just that easy. I like Rapid7's attacker KB because it's an easy way to get other attacker's thoughts on vulnerabilities. As you can see, CVE 2021-37, still just a local privilege escalation, is rated as very high. Finally, CVE 2020-1300 or Evil Printer was presented at DEF CON28 last year. Again, this is a local privilege escalation using the printer subsystem, but this time with a cab file delivered by a remote printer. ZDI wrote up some technical details about the cab file, but other than Steven Sealy's tweet in November, I haven't seen anyone publish a full exploit for this one. Now I loved the DEF CON28 presentation and it served as the jumping off point for my own research. And because Evil Printer was so important to me and my thought process, I want to spend a few minutes just walking through the attack in its entirety. The attack setup requires two things, a standard user account on a Windows machine and an Evil Printer to serve up a malicious cab file. The standard user simply uses the add printer interface to connect to the Evil Printer, which triggers the cab download and unpackaging. The cab file contains a file path with a directory traversal that gets unpacked anywhere on the system the attacker would like, essentially allowing the attacker to plant a DLL or overwrite an executable to escalate the system. As Steven Sealy's tweet suggested, generation of a malicious cab is actually quite easy. Here I generate a cab file containing a file called UALAPI.DLL that, due to the path traversal, will get written to the system32 directory. Of course, UALAPI.DLL is a known missing DLL that an attacker can plant in order to escalate the system on reboot. And of course, if you're interested in recreating the cab yourself, here's the source of the DLL I generated. Anyone familiar with PanicRidge RecoExploit will know I basically stole the snippet from them. But either way, if you go to the link repository, you'll find a project file that will compile the DLL. Obviously, this is nothing special or exciting. I just want to point out that this DLL executes who am I and writes the output to cresult.txt. We will refer back to this throughout the talk. The more complicated part of the Evil Printer attack is setting up the Evil Printer. And as I've suggested, this method is lifted entirely from last year's DEF CON presentation. Now for whatever reason, QtPDF Rider has implemented delivery of a cab file to remote clients via package point and print. So we can rely on the QtPDF Rider to do all of our heavy lifting. If you prepare a Windows box in your control with the steps in the slide, you'll be ready to serve up malicious cab files. The next step is the actual exploitation. As a standard low privilege user, using the AdPrinter UI connects to the Evil Printer you just configured. When the attacker connects to the printer, the cab file is downloaded and unpackaged, which means our malicious DLL gets dropped into System32. We also see this pop-up regarding installation of a driver, which requires administrator approval. However, at this point our attack has already been successful. So we can just hit cancel. After rebooting the system, the UALAPI.DLL we dropped in System32 is loaded into a system process and executed. As you see, the result.txt created by the DLL contains the result of Who Am I, which, when the DLL was executed, was System. A successful privilege escalation and a really great attack in my opinion. It's only complicated by the requirement of an Evil Printer, but in most attack scenarios that shouldn't be a deal breaker. Like I said, there wasn't a public exploit for this, at least the I was aware of, so I've published my own. It's wrapped up into a tool that we'll talk about later, so I won't explain the silly name or how to use the exploit. We'll get there later. Just know a public exploit exists now and it's in the repository I mentioned earlier. So last fall, after this had been patched, I was exploring this attack surface and I was thinking about this installed driver prompt. I was interested if driver installation always required administrative rights or if I could bypass that somehow. So I decided to spend some time learning how a standard, low privilege user can install a print driver on their system. But first we need to pick a driver that we would actually want to install. As an attacker, I'd love to install this vulnerable RICO driver that we talked about earlier. As a reminder, the vulnerability in this driver is a race condition to overriding a DLL during the ad printer call. If timed correctly, a standard user can escalate to a system. Now one of the requirements to ad printer is of course the driver name the new printer will be using, which is all well and good when the driver is available like in this screenshot. The ad printer call would be successful on this target. But when the driver isn't present, ad printer will obviously fail. So it should be fairly obvious why I'm interested in finding ways to install the driver without needing administrator privileges. If I can trick the system to loading the driver somehow, then I can install the driver as a standard low privilege user and exploit the driver's vulnerability and attack that like to call bring your own print driver vulnerability. So how can a standard user try to install the vulnerable print driver? There are actually a surprising amount of legitimate options. I listed a bunch here and we're going to quickly look at what happens when they're invoked by a standard user. First of all, thank you to Penigrid for leaving links to the RICO installer in their blog. That did prove very helpful to me. The RICO installer for the vulnerable driver isn't so much an installer but just right clicking on an M file to invoke the MF installer which just so happens to require administrative rights. So that's not really all that useful for the standard user. Pointing the printer user interface at the M file yields similar results. So that's another no-go for the standard user. PowerShell fails with a very ugly and sort of useless error message. However, looking up the command in MS documentation, we find this useful tidbit. The M file should exist in the driver's door. Well, what is that? Well, just hold on. We'll circle back to that. Invoking printui.dll yields the exact same result as just using the UI. Kind of what you'd expect. So yet another failure for the standard user. And yet again, another failure when trying to use pure end driver.vbs. And while there are too many MS API functions for printers, printdemons specifically use install printer driver from package because a standard user could invoke it. If, as highlighted here, the driver is in the driver's door. So it seems like getting the print driver into the driver's door would be really useful. How do we go about doing that? Well, let's talk about it. In this section, we'll finally see how to get the RICO driver onto the system as a standard user. A good place to start is, what is the driver's door? The answer is that it's a trusted location on the system where signed and verified driver packages are stored. Adding a driver to the driver's door is referred to as staging, likely so it isn't confused with installation. Staging a driver in the driver's door is not the same as installing it. Only administrators can stage drivers. Probably the best tool for enumerating, adding and removing drivers is the plug and play util tool. In this screenshot, the administrator adds the vulnerable RICO driver to the driver's door. And once the vulnerable RICO driver is in the driver's door, a standard low privilege user can install it while adding a new printer. Now, obviously this talk is about a standard low privilege user adding a driver to the driver's door and not an administrator like in the previous slide. But I want to highlight how owning the driver's door is all we need to be able to then exploit the RICO driver. So finally coming full circle, we sought to discover if a low privilege user can introduce arbitrary drivers to the system. We tested multiple methods of installing the vulnerable RICO driver and we checked out how the driver's door works. Is there any way to stage a print driver as a standard low privilege user? And the answer, of course, is yes. A standard low privilege user can stage drivers into the driver's door by connecting to a printer that uses package point and print just like Evil Printer. The package or the cab file, if signed, will be stored, will be staged in the driver's door. So an attacker that controls an Evil Printer and a standard Windows account can stage drivers of their choosing. The client need only invoke the get Printer driver MSAPI function. The printer responds with the driver and the system verifies the driver's integrity before finally dropping it into the driver's door. It's really just that easy. So let's try it ourselves. We need to create a cab file for our vulnerable RICO driver. As we talked about earlier, the RICO installer just sort of left us this exploded directory. Well, we can roll all that up into a cab file using make cab. Obviously, the cab file we generate isn't signed. But fortunately for us, Windows doesn't care about that. When unpackaging the cab, the system will hunt out the security catalog that I've highlighted. The security catalog itself is signed by Microsoft Windows Hardware Compatibility Publisher. And the catalog contains hashes of each file that the driver needs. Now, if you have sharp eyes, you might ask, does it matter if the valid to date has expired? And the answer is no. The system doesn't care at all about that. So we've created a RICO cab that is cryptographically acceptable to the Windows printer subsystem. Now we just need to configure the Evil Printer just as we did earlier in the talk. I'll leave that as an exercise for home. Since it's the exact same setup we discussed before, and I'll share a tool in a bit that automates all of that. Now, once the Evil Printer is all set up, we can connect to it as a standard low privilege user via the Ad Printer UI. If successful, we should see a new entry in the driver's door. Here, we've established our connection to the Evil Printer and I've highlighted our RICO driver staged in the driver's door. The only downside here is that we've triggered Windows Update. Later, we'll discuss how to avoid triggering the update and really the UI altogether. We can now see that our RICO driver is staged via the print UI. So a low privilege user can now use it to add a printer and most importantly, exploit it to achieve system. That's the whole thing, using a remote printer to stage drivers and exploiting the stage driver. Literally, bring your own print driver vulnerability. Is this a vulnerability in Windows? Yes, I think so. As I just said, we clearly crossed the security boundary by adding a driver into the driver's door. And the result of crossing that security boundary is that we're able to escalate to system. But is this actually a vulnerability in Windows? No, it's a feature that's working as designed. This is exactly how printers are supposed to work. The system is supposed to automatically download and stage the package so that the user can add a new printer. And, as we all know, features aren't vulnerabilities. We can dislike the feature and believe it's flawed, but at the end of the day, a feature really just isn't a vulnerability. But really, is this a vulnerability in Windows? I'd say honestly, I'm not sure and I'm not sure I really care all that much. Well, I think both arguments are true. At the end of the day, I can escalate to system. You can call the bug. You can call the feature. The result is the same either way. Escalation of system. Is this useful? Of course this is useful. As long as you can establish a remote connection to an evil printer in your control, you can escalate to system. What's more, is that I'm not sure it's a patchable issue. It's working as designed and it works for Windows versions back to at least Windows 7. Maybe Vista, I actually didn't get a chance to try. What's more, though, is it makes old or unlikely to be seen in the wild. Print drivers like Rico, really valuable. Since now we can just pop them on the box at will and exploit them. So that's the entire concept. Standard user can add a print driver of their choosing and exploit it to obtain system privileges. But of course, no one wants to do that manually. So I've developed a tool that automates the process. The tool is called concealed position. So here's an early screenshot of the GitHub repo and a link. As of August 7th, this should be open to everyone. Now concealed position is developed in C++ and has three major components. The first is the server for configuring the evil printer. The second is the client for staging the driver and executing the privilege escalation. And finally, the DLL that gets executed with system privileges. Concealed position currently has four exploits you can choose from. Slashing damage and poison damage are the two we've already spoken about. That's CVE-2020-1300 and poison damage is the Rico driver. But it also has two more vulnerable drivers that I found that two more vulnerable drivers that I found. And while recording this, I'm still in the middle of disclosing to the vendors, which we will talk about at the end of this talk. The first one is asset damage, which is a vulnerability in Lexmark's universal print driver. And the second is radiant damage, which is vulnerability in Canyon's TR-150 print driver. Concealed position can also be executed in a local only mode when the drivers already exist in the driver's store. Now here's a simple screenshot of the server. And as you can see, it's simple to invoke. You just select the exploit you want to use. And the client is similar, except you need to either specify local exploitation or provide the evil printer address and the name of the evil printer you're going to connect to. And here's the tool after executing an attack using asset damage. Again, we see the DLL used just echoes whom I to the result.txt file you see pictured here. And one of the previous slides, we saw that connecting to the evil printer using the add printer UI triggered windows update, which is obviously a no go during a real attack. By using the win API calls listed in the slide, the client is able to avoid windows update and the UI altogether. In the first stage, which is the connection to the remote printer, the attacker utilizes get printer driver. In the second phase, the driver is installed from the driver store using install printer driver from package. Exploitation typically then occurs during the add printer call. Now there's a lot of love for PowerShell out there, and I think it's the obvious tool for a lot of people. So some might wonder why didn't develop concealed position in PowerShell. Well, first of all, I just happen to love C++ and it's really sort of the language that I think in first. But I think it's also good to know if you do want to use PowerShell. The add printer using connection name will stage the driver into the driver store, but it also triggers windows update as well. But if you like PowerShell, that's probably easy enough to work around. If you want to develop your own tooling, you should definitely pursue that. Alright, so we've talked about the attack and I've showed off my tools. So let's talk about the new driver vulnerabilities that I found. The first one is acid damage. And like I said earlier, it's an issue with Lexmark's universal print driver affecting versions 2.15.1.0 and below. This has been assigned CVE 2021 35449. The issue is that during add printer, a world writable file is parsed for DLLs. An attacker can just insert a path traversal to a DLL in their control, resulting in escalation to system. Very, very simple. Now, obviously, the exploit has an implementation in concealed position, but I've also developed a metasploit module for this as well. Now, the module doesn't use an evil printer, it's just a local only attack. However, one of the challenges with recording this so far in the past, like I said, I'm recording this in mid July, July 13. So the challenge here is that I can't really show an open pull request until August 7. So I can't link it here, but trust me, when the morning of August 7 throws around, I will open that pull request. Now, remember to use this attack with the evil printer, we need to generate a cap file. Now we can cheat and just download version 10 2.10.0.5 from the Windows update catalog. So that works fine. So why not? The cap file downloaded from Windows catalog is also signed by Microsoft. So that's kind of a neat thing we can't recreate just by using MakeCab. But if you want to use the latest version, we can do that too. First, we just have to grab the Lexmark installer and it will dump the required files off of C Lexmark. We can use the same technique as before using DER to generate our files list. Except MakeCab doesn't respect directories unless you tell it to. So you have to modify the files.txt file to let MakeCab know that the driver needs the director's structure to be respected. But that's really it. Pass the modified files.txt to MakeCab and we have a cap file to use with concealed position. Again, our generated cap file isn't signed, but it contains a valid security catalog. The next vulnerable driver, RadiantDamage, is an issue I discovered in the driver for Canon's PIXMA TR-150 mobile wireless printer. The TR-150 driver 3.71.2.10 and blow is affected. And again, this is a local privilege escalation during the ad printer process. This issue has not been assigned to CVE yet time of recording. So I guess we'll discuss that in a bit. Similar to the Ricoh vulnerability, this is a race condition to overwrite a DLL and program data. If you can time it correctly, the overwritten DLL will get picked up by print isolation hosts and executed a system. Again, very simple. I found that this is a bit difficult to time a little bit harder than the NASA damages, but it usually takes no more than a couple of minutes to finally hit. Again, we need a cap file to work with concealed position server. And again, you can actually download the TR-150 driver from the update catalog. So we can simply download it and we have assigned, well formed, most current version of a totally exploitable driver to use. Now, of course, it might be useful to know how to generate our own still. The Canon installer will download the following files into a directory and app data. Note the flat file structure. Because of the flat file structure, it's trivial to package up using MakeCab. We just do exactly what we did for the Ricoh cab. And just like that, we generated our own correctly formed TR-150 cab. Again, you can find the implementation of radiant damage at the following link. And again, there is a metasploit module. I just couldn't include the link because I recorded so far in the past. So that's all for the exploitation sections. And I hope you find it interesting. But I now want to touch on detection and mitigation for those of us that have to defend against this sort of thing in the real world. Now, my full-time job is not defending. So these are best effort. Forgive me if I have overlooked anything obvious. So the first detection is from the event log. Event ID 600 is great for catching CVE-2020-1300 or what I call slashing damage, or what is known as the aversional evil printer. This is the path traversal presented last year at DEF CON. And you can even see in the description that the failure is that mentions that the failure can occur due to a bad or missing signature, which is exactly what the aversional evil printer serves up. Event 215 catches all the other issues, at least as I've coded them up. Here you can see the exploitation caused the print driver to fail to install correctly during the ad printer process. You can also investigate the setup api.deb file and see windows slash int. Now, this could be quite tedious as it's very verbose and quite long, but it's actually great documentation for any driver that has been introduced to the system or even a driver that has been attempted to be introduced to the system. And of course, you can detect the attack over the wire as long as SMB encryption isn't enabled. The challenge here, of course, is that this attack uses totally legitimate behavior, although depending on your environment and where the evil printer is located, this might be a good way to detect the attack. For instance, it's probably a bad thing if one of your systems is reaching out to a printer over the internet. I've also embedded a unique string into concealed positions client. I chose the client because that's typically the victim system. So if you're using YARA or any other signature based system, you should be able to identify use of CP client based on the string. Naturally, smart attackers are going to review the code I've written and remove this line. But there are a lot of dumb attackers out there too. So hopefully, if this ever does get used in the wild, this will help stop that. Now, one of the challenges with mitigations is I doubt this will ever see any real patch. You know, installing a printer is meant to use these mechanisms. So I think the best you can do is just ensure that the affected drivers aren't on your systems already and then enable the package point and print approved servers in GPO. Now, of course, that will make it very difficult for your end users to add printers. That's sort of the entire issue, isn't it? And printers can't be trusted. And finally, I'd like to discuss the disclosures of the vulnerabilities and suggest some future work. So after getting my DEF CON acceptance and talking to Darkwolf, I sent similar disclosures to Lexmark, Canon, and Microsoft. All were provided descriptions and exploit code. All very similar disclosures, really. And they were all informed of the August 7th disclosure date. Excuse me. Lexmark was awesome. And this is exactly how you want disclosure to go. They acknowledged receipt immediately. I sent the disclosure on a Friday because I'm a monster, and they confirmed the issue on a Monday. And it only took a little more than a week to send me a beta patch, which is really impressive. You can see at the end here that Lexmark intends to release a patch shortly after I record this talk. So by the end of the week of July 12th. And Lexmark has been a great communicator overall. They even went as far as wishing me good luck on my DEF CON talk, which I never actually told them about. So I thought that was pretty clever. So shout out to Graydon if you're listening. Now, the only real problem with this disclosure is it took MITRE two weeks to assign a CVE, which is really frustrating from a researcher's point of view that they can't move faster than that. They literally have two jobs, assigning and publishing CVE that other people write. So, you know, how hard is that? Otherwise, you know, great disclosure. Lexmark is awesome. So Canon and Lexmark were sent a very similar content to the point that I accidentally left the word Lexmark in a spot in my Canon disclosure. And disclosure with Canon started off very well. They asked clarifying questions on the affected component, but then nothing. By July 9th, they had the vulnerability for three weeks and they hadn't confirmed the issue. They haven't denied the issue. They didn't indicate if they tried the POC or if they'd even looked at the POC, even though I keep asking. Now, they did release a security patch on July 4th, but after looking at it, it doesn't affect the vulnerability I reported. And they, for some reason, didn't mention it to me until eight days later. But basically, I'm not sure where the confusion lies with Canon. They aren't giving me any type of feedback so that I can help them. And I think at some point I'll probably have to loop in cert-cc so that this gets CVE, hopefully, by August 7th. The Microsoft disclosure has been reasonable. As you can see from the timeline, from the timeline, there was a fair amount of back and forth about recreating the issue. But eventually, I guess the proof-of-concept video got there, which probably just means my written instructions weren't very good. Now, while they did acknowledge the issue on July 12th, I actually don't expect any type of CVE here or security bulletin. Really, I just wanted Microsoft to be aware that this is a thing they designed into their system and that I'm going to talk about it on August 7th. So mission accomplished. But I'm honestly, I'm not sure how they can address this without breaking normal printer workflows. I think it is very funny how these three different disclosures, they were all very similar content, but they all had very different results. So one turned out good, one turned out bad, and one spent a lot of time and can't reproduce. So last slide, future work. Like I said, any print driver that is compatible with the driver store is fair game, new or old. Really, very old is even up for grabs here. So there are many drivers that could be analyzed and added to concealed position. There's also nothing special about QPDF. It's only there because I couldn't get sandwiched to what I wanted and didn't have the time to write my own implementation of delivering a package point and print cab file. Now hopefully in the future, I or someone else will code that up so that others can use an evil printer as they as they choose. Once that is done, this would be this attack would be great paired with a USB attack. And finally, concealed position could use polishing. Like most exploits, it was written only to prove that the attack was possible. So it's a little messy at the moment and some of the mechanisms around dropping DLL and customizing payloads could be extended. Otherwise, that's it. Thank you all so much for listening. Thank you very much to Darkbull for letting me share and thank you again Defcon for both the support and allowing me to present again. Thank you all.