CVE-2016-8714
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.
R 3.3.0
R 3.3.2
7.5 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
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.
$ 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)
2016-11-17 - Vendor Disclosure
2017-03-09 - Public Release
Discovered by Cory Duplantis of Cisco Talos