Lucene search

K
hackeroneRobboticH1:1704017
HistorySep 18, 2022 - 11:27 p.m.

curl: CVE-2022-32221: POST following PUT confusion

2022-09-1823:27:44
robbotic
hackerone.com
21

0.007 Low

EPSS

Percentile

79.8%

Summary:

The bug I submitted at https://github.com/curl/curl/issues/9507 can have at least a few unintended security issues:

  • Information Disclosure: this bug causes an HTTP PUT to occur when the user intends for an HTTP POST to occur. The user, who intended an HTTP POST, expects the POSTed information to come from CURLOPT_POSTFIELDS. However, as an HTTP PUT is performed instead, the data that is PUT comes from a buffer specified in CURLOPT_READDATA, which may be sensitive information intended for an entirely different host (host1.com below). If CURLOPT_READDATA is not specified, this data could come from stdin!
  • Use after free: using the description above, if the user had already freed the data specified in CURLOPT_READDATA, then the unintended HTTP PUT (which was intended to be an HTTP POST) would attempt to read the freed data specified in CURLOPT_READDATA.

Steps To Reproduce:

The following code is similar to the code I posted at https://github.com/curl/curl/issues/9507, but now highlights the potential security issues (which I did not think wise to disclose on GitHub):

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>

typedef struct
{
    char *buf;
    size_t len;
} put_buffer;

static size_t put_callback(char *ptr, size_t size, size_t nmemb, void *stream)
{
    put_buffer *putdata = (put_buffer *)stream;
    size_t totalsize = size * nmemb;
    size_t tocopy = (putdata->len < totalsize) ? putdata->len : totalsize;
    memcpy(ptr, putdata->buf, tocopy);
    putdata->len -= tocopy;
    putdata->buf += tocopy;
    return tocopy;
}

int main()
{
    CURL *curl = NULL;
    put_buffer pbuf = {};
    char *otherdata = "This is some other data";

    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();

    // PUT
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, put_callback);
    pbuf.buf = strdup("This is highly secret and sensitive data");
    pbuf.len = strlen(pbuf.buf);
    curl_easy_setopt(curl, CURLOPT_READDATA, &pbuf);
    curl_easy_setopt(curl, CURLOPT_INFILESIZE, pbuf.len);
    curl_easy_setopt(curl, CURLOPT_URL, "http://host1.com/putsecretdata");
    curl_easy_perform(curl);

    // Without this line, a PUT instead of a POST will be sent below (this is a bug in libcurl)
    //curl_easy_setopt(curl, CURLOPT_UPLOAD, 0L);

    // Without this line, the POST below will send "This is highly secret and sensitive data"
    //    when instead the user intended to send "This is some other data"
    // With this line, the program will attempt to use freed data, causing a segfault or any number
    //    of potential exploits.
    //free(pbuf.buf);

    // POST (will be a PUT without the line just above)
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, otherdata);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(otherdata));
    curl_easy_setopt(curl, CURLOPT_URL, "http://host2.com/postotherdata");
    curl_easy_perform(curl);

    curl_easy_cleanup(curl);

    curl_global_cleanup();

    return 0;
}

Supporting Material/References:

The bug that leads to these potential security issues is documented at https://github.com/curl/curl/issues/9507

Impact

An attacker could potentially inject data, either from stdin or from an unintended buffer. Further, without even an active attacker, this could lead to segfaults or sensitive information being exposed to an unintended recipient.