Within this post I’ll be doing a write up of the BlinkerFluids challenge from the HackTheBox Cyber Apocalypse 2022 CTF competition (14/05/2022). This write up will be written according to my thought process whilst I was trying to complete the challenge.
Reconnaissance
First look
After downloading the file attached to the challenge from the CTF platform, I decided to take a look through it. The first file which caught my eye was the ‘package.json’ file, I figured from the presence of this file the challenge was a node js application and this file listed the dependencies. The contents were as follows:
|
|
I found this file interesting, but none of these dependencies were immediately sticking out to me as a vulnerability yet, so I decided to move on.
Webpage
Looking at the main page of the application, it appeared that its purpose was for generating invoices in PDF format. Clicking the ‘create an invoice’ button resulted in the following:
So it seemed that the application was converting the markdown to a PDF format somehow? I decided to take a closer look.
Further investigation
Eventually, I found an ‘index.js’ file within the ‘routes’ directory of the downloaded archive. After opening this file, these lines in particular were of interest to me:
|
|
It appeared that MDHelper was being used to parse submitted user input and create an entry in the database. But where there’s user input, there’s risk. Looking back to the top of the file, I found a reference to a file, MDHelper.js. The contents of the file were as follows:
|
|
It appeared that the file was an implementation of the ‘md-to-pdf’ library which converted markdown files to pdf files. Considering this was the main functionality of the application, I thought I should check if it has any vulnerabilities.
Exploitation
Trial and error
Aha! I managed to find a post on GitHub detailing a vulnerability (or feature) in a dependency for ‘md-to-pdf which can lead to code execution, with the example payload being as follows:
|
|
All I had to do was create a new PDF, with the payload as the content to exploit it. This payload injects another javascript object into node js and executes the command ‘id > /tmp/RCE.txt’ synchronously (meaning, in the same thread). I decided to tweak this payload slightly to fit my needs:
|
|
Here I modified the payload to get the contents of the flag, which was 1 directory up from the application’s directory and then send it to my machine using netcat. I decided to test my exploit locally by building the docker image myself and deploying it so I could see the ‘stdout’ and ‘stderr’ from the application.
After capturing a request to add a pdf using burpsuite and replacing the contents with my payload, the application threw an error regarding the speech marks I was using in the payload, so I replaced them with single quotes instead. After doing this and resubmitting the payload, I saw the following error in the application:
Refining the payload
Okay, so it looked like my command was being executed, however netcat wasn’t installed on the target system! It looked like I was going to have to get creative with my exploit in order to get the flag. The idea of using curl occurred to me as it’s on almost every unix systems, however I wasn’t quite sure how I was going to get it to send the data in a post request. I came across this post on stackoverflow which taught me that the ‘@-’ argument can be used to read from the pipe. So I ended up with the following exploit.
|
|
However, the standard python http server unfortunately did not accept HTTP POST requests, nor log their data, so I had to use this script in order to view the submitted flag. Firstly, I did a test run with the payload locally.
Great, next I fired up ngrok:
|
|
And attempted to exploit the vulnerability:
Excellent! What an interesting challenge, I’ve never had to use curl to exfiltrate data before.
Mitigations
md-to-pdf
A patch was applied to later versions of md-to-pdf which prevented the gray-matter engine from executing javascript objects in the markdown input. The version of the md-to-pdf dependency should be updated.