All techniques assume user-controlled HTML is fed into the PDF generator.
1) JavaScript Code Execution (Server-Side XSS)
Test HTML rendering, then JavaScript execution:
<b>bold-test</b>
<script>document.write('XSS-OK')</script>
Leak server file path via window.location:
<script>document.write(window.location)</script>
Outputs often show file:///.../tmp_wkhtmlto_pdf_XXXX.html revealing server paths.
2) Server-Side Request Forgery (SSRF)
Force outbound requests by loading external resources:
<img src="http://<your-oast-domain>/ssrf-img"/>
<link rel="stylesheet" href="http://<your-oast-domain>/ssrf-css">
<iframe src="http://<your-oast-domain>/ssrf-iframe"></iframe>
If iframe responses render in the PDF (non-blind SSRF), you can read internal endpoints:
<iframe src="http://127.0.0.1:8080/api/users" width="800" height="500"></iframe>
3) Local File Inclusion (LFI)
With JavaScript
Without JavaScript
Direct tags (may be blocked):
Redirect-based LFI (if file:// blocked but redirects followed):
Server-side redirector.php:
Payload:
4) Annotations / Attachments
Leverage library-specific features to attach local files.
mPDF (older versions or enabled setting):
Consult documentation for the target library and version (see metadata identification).
Always sanitize and encode when testing in real apps; proof in controlled labs.
Outbound network, file://, and JS execution are all configuration-dependent.
For large/binary file exfil via JS, prefer base64 with line wrapping.
Question 1 (lab walkthrough)
Goal: access an internal web app and exfiltrate the flag via PDF generator.
Add a new note; test HTML injection using <b>test</b>.
Only the Note body renders HTML β injection confirmed.
Enumerate internal ports (Apache) via LFI using JS:
Discover internal app on port 8000.
Interact with internal app (non-blind SSRF via iframe):
Endpoints list shows /users.
Probe /users to find key locations:
admin key path: /users/adminkey.txt.
Exfiltrate key via Server-Side XSS + file:// read:
Answer: {hidden}
Obtain the flag (skills assessment)
Visit root page, note PDF invoice generation and hint about an internal orders app.
Test fields for server-side execution:
Comment sanitized; try title via Burp.
Enumerate internal ports via Apache config (in title field):
SSRF to internal web app (port 8000) using iframe (in title):
The internal app exposes endpoints and an XML-backed / with q GET param.
Exfiltrate flag via XPath injection (iframe in title):
Using contains on substring:
Or position-based selection:
Answer: {hidden}
Last updated