MD2PDF – CTF Writeup

Platform: TryHackMe
Instructions:
TopTierConversions LTD is proud to announce its latest and greatest product launch: MD2PDF.
This easy-to-use utility converts markdown files to PDF and is totally secure! Right…?
Note: Please allow 3-5 minutes for the VM to boot up fully before attempting the challenge.
Work Space
Opened up and did an nmap scan immediately on the IP address with the following output:
Starting Nmap 7.80 ( https://nmap.org ) at 2025-09-08 18:05 BST
mass_dns: warning: Unable to open /etc/resolv.conf. Try using --system-dns or specify valid servers with --dns-servers
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled. Try using --system-dns or specify valid servers with --dns-servers
Nmap scan report for 10.201.21.30
Host is up (0.000091s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
5000/tcp open upnp
MAC Address: 16:FF:D1:C2:05:2D (Unknown)
Nmap done: 1 IP address (1 host up) scanned in 2.66 seconds
We see that SSH and UPNP are open, however we are assuming that this a web based utility, so as a result foremost visited the IP address
Next, I open to see the following webpage:
Look at the files, that are initially present on the site, nothing seem interesting, we note that the text editor that is being used is CodeMirror, which is a common front end text editing tool (found on websites such as LeetCode!). However that is unlikely the core thing we are looking for.
When we type markdown to convert, we end up with a pdf that has taken our markdown and converted it. Looking at the network tab, we note that an endpoint called convert
is called.
Navigating to this endpoint we are first confronted with
Foremost, I thought it would be wise to see if we could find any other pages at the given IP address. I utilized gobuster
to this end. I started with the common.txt sec list.
SecLists is a collection of security focused wordlists that are used for penetration testing and are useful in CTFs! To look through all of the SecLists (and other wordlists) on the TryHackMe attack box, navigate to /usr/share/wordlists
.
Unfortunately this didn’t result in much, as all we got was /admin which returns a 403 status.
gobuster dir -u http://10.201.21.30 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.201.21.30
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/admin (Status: 403) [Size: 166]
Progress: 4655 / 4656 (99.98%)
===============================================================
Finished
===============================================================
We can’t access the page, however there is the possibility here that we could attempt a SSRF (Server Side Request Forgery). As it seems that the page can only be seen internally!
We know that the code to convert the markdown does not exist on the frontend (that would just be a horrible business practice), so we know it is executed server-side. Likely there is some utility which does this conversion! So lets dig a little deeper into the code:
Inside the HTML we notice that the contents of the CodeMirror text editor is taken for the conversion utilizing the getValue() method, which looking at CodeMirror documentation converts the contents into plain text.
That doesn’t really bring us any closer, so lets take a look at a pdf that is returned! We can use the exiftool
command that is installed on AttackBoxes for this. Or we can use any other pdf metadata parser.
root@ip-10-201-64-131:~/Downloads# exiftool document.pdf
ExifTool Version Number : 11.88
File Name : document.pdf
Directory : .
File Size : 6.7 kB
File Modification Date/Time : 2025:09:08 18:46:53+01:00
File Access Date/Time : 2025:09:08 18:46:53+01:00
File Inode Change Date/Time : 2025:09:08 18:46:53+01:00
File Permissions : rw-r--r--
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.4
Linearized : No
Title :
Creator : wkhtmltopdf 0.12.5
Producer : Qt 4.8.7
Create Date : 2025:09:08 17:46:44Z
Page Count : 1
Note that creator line: wkhtmltopdf
is a tool that converts html into a pdf file! We have our answer, we can attempt to inject some HTML into the markdown text editor to give us access to the /admin endpoint at port 5000.
How this can be accomplished is utilizing an iFrame, which is a method to embed another html document inside of our current webpage. So, if we could have the pdf embed the contents of the /admin page into its output. We can see what is there! We enter the following into our command shell:
<iframe src:"http://localhost:5000/admin"></iframe>
And we get the flag outputted in the pdf!
If I were the company here, I think the solution to avoid an attack like this is somewhat simple: just use a different utility instead of wkhtmltopdf
. By looking at the code earlier, we already know that the getValue() function returns plaintext. So a processor relying on that rather than an html converter would be smarter and safer! Or some sort of input sanitization!