Talos Vulnerability Report

TALOS-2016-0227

R PDF LoadEncoding Code Execution Vulnerability

March 9, 2017
CVE Number

CVE-2016-8714

Summary

An exploitable buffer overflow vulnerability exists in the LoadEncoding functionality of the R programming language version 3.3.0. A specially crafted R script can cause a buffer overflow resulting in a memory corruption. An attacker can send a malicious R script to trigger this vulnerability.

Tested Versions

R 3.3.0
R 3.3.2

Product URLs

https://www.r-project.org/

CVSSv3 Score

7.5 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H

Details

The R programming language is commonly used in statistical computing and supported by the R Foundation for Statistical Computing. R is praised for having a large variety of statistical and graphical features.

During the creation of a PDF document, the file containing the encoding array can be specified by the user. The following command can specify the encoding file for a pdf.

 pdf(encoding="/path/to/some/file")

While loading this file, each of the specific elements in the file is copied into the cname element for each item in the encnames array [0].

 src/library/grDevices/src/devPS.c:493

LoadEncoding(const char *encpath, char *encname,
            char *encconvname, CNAME *encnames,
            char *enccode, Rboolean isPDF)
 {
 ...
     for(i = 0; i < 256; i++) {
         if (GetNextItem(fp, buf, i, &state)) {
             fclose(fp); return 0;
         }

         strcpy(encnames[i].cname, buf+1); // [0]

         strcat(enccode, " /"); strcat(enccode, encnames[i].cname);
         if(i%8 == 7) strcat(enccode, "\n");
     }
 ...

The encnames array is a part of a EncodingInfo structure.

 /*
 * Information about a font encoding
 */
 typedef struct EncInfo {
     char encpath[PATH_MAX];
     char name[100]; /* Name written to PostScript/PDF file */
     char convname[50]; /* Name used in mbcsToSbcs() with iconv() */
     CNAME encnames[256];
     char enccode[5000];
 } EncodingInfo, *encodinginfo;

The encnames array is of structure type CNAME with a cname attribute that is a buffer of length 40 [1].

 src/library/grDevices/src/devPS.c:281

 /* The longest named Adobe glyph is 39  chars:
    whitediamondcontainingblacksmalldiamond
 */

 typedef struct {
    char cname[40]; // [1]
 } CNAME;

By providing an element in the encoding file of longer than length 40, the cname buffer is overflown. This could be leveraged to potentially gain remote code execution later in the program.

Crash Information

$ R -d valgrind -f poc.r
...
==21442== Invalid write of size 1
==21442==    at 0x4C34140: __stpcpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21442==    by 0xA0D4D89: ??? (in /usr/lib/R/library/grDevices/libs/grDevices.so)
==21442==    by 0xA0D6A5B: ??? (in /usr/lib/R/library/grDevices/libs/grDevices.so)
==21442==    by 0xA0E226D: PDFDeviceDriver (in /usr/lib/R/library/grDevices/libs/grDevices.so)
==21442==    by 0xA0E3DE9: PDF (in /usr/lib/R/library/grDevices/libs/grDevices.so)
==21442==    by 0x4F08F80: ??? (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F34BFC: ??? (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F40F2F: Rf_eval (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F4296D: Rf_applyClosure (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F410CC: Rf_eval (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F68891: Rf_ReplIteration (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F68C10: ??? (in /usr/lib/R/lib/libR.so)
==21442==  Address 0x79f5eee is 0 bytes after a block of size 19,486 alloc'd
==21442==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21442==    by 0xA0D6A28: ??? (in /usr/lib/R/library/grDevices/libs/grDevices.so)
==21442==    by 0xA0E226D: PDFDeviceDriver (in /usr/lib/R/library/grDevices/libs/grDevices.so)
==21442==    by 0xA0E3DE9: PDF (in /usr/lib/R/library/grDevices/libs/grDevices.so)
==21442==    by 0x4F08F80: ??? (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F34BFC: ??? (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F40F2F: Rf_eval (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F4296D: Rf_applyClosure (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F410CC: Rf_eval (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F68891: Rf_ReplIteration (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F68C10: ??? (in /usr/lib/R/lib/libR.so)
==21442==    by 0x4F68CC3: run_Rmainloop (in /usr/lib/R/lib/libR.so)

Timeline

2016-11-17 - Vendor Disclosure
2017-03-09 - Public Release

Credit

Discovered by Cory Duplantis of Cisco Talos