CVE-2018-3836
An exploitable command injection vulnerability exists in the gplotMakeOutput function of Leptonica 1.74.4. A specially crafted gplot rootname argument can cause a command injection resulting in arbitrary code execution. An attacker can provide a malicious path as input to an application that passes attacker data to this function to trigger this vulnerability.
Leptonica 1.74.4
7.0 - CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
Leptonica is an open source library mainly used for image processing and analysis. An OS Command Injection vulnerability exists in gplotMakeOutput function. A lack of sanitization of the gplot->cmdname
field could allow an attacker to inject an arbitrary command which is later executed via the system
function.
Let us take a closer look at the vulnerable function:
Line 374 l_int32
Line 375 gplotMakeOutput(GPLOT *gplot)
Line 376 {
Line 377 char buf[L_BUF_SIZE];
Line 378 char *cmdname;
Line 379 l_int32 ignore;
Line 380
Line 381 PROCNAME("gplotMakeOutput");
Line 382
Line 383 if (!gplot)
Line 384 return ERROR_INT("gplot not defined", procName, 1);
Line 385
Line 386 gplotGenCommandFile(gplot);
Line 387 gplotGenDataFiles(gplot);
Line 388 cmdname = genPathname(gplot->cmdname, NULL);
Line 389
Line 390 #ifndef _WIN32
Line 391 snprintf(buf, L_BUF_SIZE, "gnuplot %s", cmdname);
Line 392 #else
Line 393 snprintf(buf, L_BUF_SIZE, "wgnuplot %s", cmdname);
Line 394 #endif /* _WIN32 */
Line 395
Line 396 #ifndef OS_IOS /* iOS 11 does not support system() */
Line 397 ignore = system(buf); /* gnuplot || wgnuplot */
Line 398 #endif /* !OS_IOS */
At line 397
we can see a call to the system
function which takes buf
as parameter. This variable is created based on the gnuplot
application name and the content of the cmdname
field.
The cmdname
field is initialized inside the gplotCreate
function :
Line 137 GPLOT *
Line 138 gplotCreate(const char *rootname,
Line 139 l_int32 outformat,
Line 140 const char *title,
Line 141 const char *xlabel,
Line 142 const char *ylabel)
Line 143 {
Line 144 char *newroot;
Line 145 char buf[L_BUF_SIZE];
Line 146 GPLOT *gplot;
Line 147
Line 148 PROCNAME("gplotCreate");
Line 149
Line 150 if (!rootname)
Line 151 return (GPLOT *)ERROR_PTR("rootname not defined", procName, NULL);
Line 152 if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
Line 153 outformat != GPLOT_EPS && outformat != GPLOT_LATEX)
Line 154 return (GPLOT *)ERROR_PTR("outformat invalid", procName, NULL);
Line 155
Line 156 if ((gplot = (GPLOT *)LEPT_CALLOC(1, sizeof(GPLOT))) == NULL)
Line 157 return (GPLOT *)ERROR_PTR("gplot not made", procName, NULL);
Line 158 gplot->cmddata = sarrayCreate(0);
Line 159 gplot->datanames = sarrayCreate(0);
Line 160 gplot->plotdata = sarrayCreate(0);
Line 161 gplot->plottitles = sarrayCreate(0);
Line 162 gplot->plotstyles = numaCreate(0);
Line 163
Line 164 /* Save title, labels, rootname, outformat, cmdname, outname */
Line 165 newroot = genPathname(rootname, NULL);
Line 166 gplot->rootname = newroot;
Line 167 gplot->outformat = outformat;
Line 168 snprintf(buf, L_BUF_SIZE, "%s.cmd", rootname);
Line 169 gplot->cmdname = stringNew(buf);
At lines 168-169
we see that the argument rootname
is copied to gplot->cmdname
. The variable rootname
should represent the root path name for all plotting operations, but
because this parameter can be dynamically set based on data coming from a user it should be sanitized..
A malicious user can create a path containing one of several special characters [ | , &, ` ` ] which allows for adding additional command and which in consequence can lead to arbitrary code execution.
#include "allheaders.h"
int main()
GPLOT *gplot;
gplot = gplotCreate("/tmp/lept/histo/color & calc ", GPLOT_PNG,
"color histogram with octcube indexing",
"octcube index", "number of pixels in cube");
gplotMakeOutput(gplot);
return 0;
2018-01-22 - Vendor Disclosure
2018-02-01 - Public Release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.