The Common Unix Printing System (CUPS) is installed on most Linux distros by default. When setting up a new laptop, the author of this post found that port 631 was open on 0.0.0.0 that was associated with this. The cups-browsed subsystem is a system responsible for discovering new printers and adding them to the system. The article is about the journey into madness reading through this.
The service can be connected to by anyone with no restrictions. There is a configuration file that allows this to be restricted but it's not down by default on any systems that they reviewed. Running this through AFL gave them 5 unique crashes. Two of them appeared to be pointers being derefenerenecd before the exit condition was verified. The second one was a denial of service from a lock being held onto for too long.
They didn't even try to exploit these, as they thought lower hanging fruit might be available. They hacked together some Python code to communicate with the service and got back a connection over the Internet Printing Protocol (IPP) to their computer from the box on the Internet. Now, the Linux box thinks that our friend EvilSocket is a printer with many requests being sent via HTTP for information such as the model, vendor and other things.
They found a Python library called
ippserver to interact with the computer properly. Using this, they were able to add a fake printer to the computer without any user interaction. Now, we have a good way to interact with the Linux computer as a fake printer to further go deep.
While reading the logs of the service, they saw references to a PPD or PostScript Printer Description file. This text file is provided by vendors to describe printer capabilities to CUPS and instructs an interface via various commands on how to use it properly via a DSL. Notability, the fake printer is writing this to the users system to describe how to interact with their printer.
After reading the documentation for some time, they came across the cupsFilter2 directive. This will execute binaries located within a particular location on the system and the checks for which binaries are executed is pretty solid. Luckily, there are some of programs to work with, including foomatic-rip. This program accepts an arbitrary command to be executed from bash!
This sounds crazy (and it is) but it's apparently a necessary evil. This issue has been known for a while but it's difficult to fix because of the way existing drivers from older printers use it. They found one doozy that was running a Perl command in it even. This issue was once patched in FoomaticRipCommandLine but was not added when this functionality was ported to CUPS. Sometimes, security can be in direct conflict with backwards compatibility and usability.
This isn't a zero click RCE luckily but is still scary. First, an attacker would add their printer to the machine. Next, they return the malicious directive that gives us arbitrary command execution. Finally, the user must send a print job to the fake printer, which will pop a shell when executed. To get this to run, they needed to find a parsing bypass (which was easy with added a few spaces) to get this to be executed in the cupsFilter. An amazing bug that only took them a weekend to find.
The remediation process seemed quite terrible for them and time consuming. Most of the considerations were is this a real issue that needs to be addressed at all?. When you have arguments like "I am just pointing out that the public Internet attack is limited to servers that are directly connected to the Internet" to try to limit the expected impact, it's hard, especially with 200-300K devices that were likely effected on Shodan alone.
I feel bad for how this was handled, as it was pretty terrible. The people working on CUPS want to add features to make users lives better and security is just a thorn in the side of that goal. They're also volunteers in all likelihood. As a developer, we need to be open to fixing our mistakes and evaluating the impact for what it truly is. Great write up on both the technical and non-technical side!