JFrog: CVE-2020-27304 – RCE via Directory Traversal in CivetWeb HTTP server

0

Background

JFrog recently revealed a directory traversal issue in CivetWeb, a very popular embeddable web / library server that can be used as a stand-alone web server or included as a library to add web server functionality to an existing application. The issue has been attributed to CVE-2020-27304.

This directory traversal problem is highly exploitable and can lead to remote code execution, especially if the web server is running as root – due to the attacker’s ability to add or overwrite files. files which are then executed.

Who is really impacted?

This issue affects CivetWeb versions 1.8 through 1.14 (included) and was recently resolved with version 1.15.

This issue only affects CivetWeb-based web applications that use the built-in file upload form manager.
In technical terms, a CivetWeb-based web application is vulnerable if:

  1. The application handles HTTP form data by calling CivetWeb handle_form_request and provides user-defined field_found (required) callback function

  2. Field_found callback function returns MG_FORM_FIELD_STORAGE_STORE to indicate a file download operation

  3. The field_found callback function provides the output argument of the path (required), where the path relies on the input argument of the filename (which comes directly from the data of the HTTP form)

Note that this scenario is the standard way to use CivetWeb’s file upload functionality and is provided as a complete working example in the “embedded_c” example in the CivetWeb sources.

CivetWeb’s built-in file upload functionality

Web servers that allow HTTP clients to upload files to the server often choose to implement this functionality using Form-Based File Upload (RFC 1867), which typically looks like this on the client side (web browser ):

The CivetWeb server contains built-in support for this type of file download, via the mg_handle_form_request API.

A developer who wants file upload support in their web service can simply call this API with a callback function that returns the MG_FORM_FIELD_STORAGE_STORE constant:

struct mg_form_data_handler fdh = {field_found_callback, field_get_callback, field_stored_callback, 0};
...
mg_handle_form_request(conn, &fdh);

Example callback function snippet:

int
field_found_callback (const char *key,
             const char *filename,
             char *path,
             size_t pathlen,
             void *user_data)
{
    ...
    snprintf(path, pathlen, "/tmp/%s", filename);
    return MG_FORM_FIELD_STORAGE_STORE;
    ...
}

The problem of crossing the path

The root cause of the path traversal issue is actually a missing validation for Linux versions of CivetWeb.

The relevant source code in CivetWeb’s mg_handle_form_request which supports the HTTP request is as follows:

int mg_handle_form_request(struct mg_connection *conn, struct mg_form_data_handler *fdh) { 
    ... 
    if (field_storage == MG_FORM_FIELD_STORAGE_STORE) { 
        if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) { 
            fstore.access.fp = NULL; 
        } 
        file_size = 0; 
        if (fstore.access.fp != NULL) { 
            size_t n = (size_t)fwrite(val, 1, (size_t)vallen, fstore.access.fp); 
    ... 
}

The mg_fopen function, which is responsible for creating the downloaded file, tries to prevent path traversal attacks by calling the mg_path_suspicious function, but this function only checks the path separator for Windows builds:

/* Reject files with special characters */
static int
mg_path_suspicious(const struct mg_connection *conn, const char *path)
{
    const uint8_t *c = (const uint8_t *)path;
    ...
    while (*c) {
        if ((*c == '>') || (*c == '<') || (*c == '|')) {
          /* stdin/stdout redirection character */
                 return 0;
                  }
#if defined(_WIN32)
                 if (*c == '') {
                     /* Windows backslash */
                    return 0;
              }
#else
              if (*c == "https://www.marketscreener.com/") {
                  /* Linux ampersand */
                  return 0;
              }
         ...

Therefore, when CivetWeb is compiled for Linux or OSX, there is no path cleanup at all for the downloaded filenames.

Because the sample “embedded_c” web service provided in the source repository is susceptible to this issue, this vulnerability is likely to be exploitable in CivetWeb instances that support file downloads.

Resolution of problem

CivetWeb officials solved this problem in two distinct ways:

  1. The form handling code will now canonicalize the filename (before it is given to the user field_found callback) by removing dot segments, as defined in RFC 3986

  2. The “embedded_c” example has been updated to show how path separator (/ or platform dependent) characters should be filtered out, as defined in RFC 7578

We commend the officials at CivetWeb for resolving the issue in the most professional manner – closely following the RFCs for HTTP Forms and URIs. This is generally best practice, and as can be seen here, it makes the implementation much more resistant to traversal attacks. We recommend that other OSS implementers adhere to all existing relevant RFCs or use an external library that conforms to these RFCs.


Automated detection of affected artifacts

Automated vulnerability scanning can be used to identify artifacts containing a vulnerable version of CivetWeb. Further contextual analysis can determine the applicability of CVE in each scanned artifact, i.e. whether CVE-2020-27304 is actually exploitable.

In general terms, the context analyzer should perform the following steps to determine susceptibility to CVE-2020-27304:

  1. Detect all calls to the exported API mg_handle_form_request

  2. Analyze all the callbacks that were specified as the 2nd argument of mg_handle_form_request (the field_found callbacks)

  3. Check if any of the callbacks writes data to the output argument of the path, where the data is tainted (compared to parsing the data stream) by the input argument of the filename

  4. Check that the user has not implemented their own path filtering mechanism on the input argument of the filename

Conclusion and acknowledgments

To conclude, we strongly recommend anyone using a web library or designing their own web library to consider path traversal attacks and disinfect all filenames from potential user entries (or better yet – implement them in accordance with the relevant RFCs).

We would like to thank the people in charge of CivetWeb, for having validated and solved the problem in a short time and in a very thorough manner.

In addition to exposing new vulnerabilities and security threats, JFrog provides developers and security teams with easy access to the latest information relevant to their software with automated security analysis by JFrog Xray. Keep following us for product updates, including automated Contextual Applicability Analysis for Critical Vulnerability Exposure (CVE), saving developers time and effort by resolving only issues that have a real impact on safety.

Disclaimer

JFrog Ltd. published this content on October 19, 2021 and is solely responsible for the information it contains. Distributed by Public, unedited and unmodified, on October 20, 2021 12:50:03 AM UTC.

Leave A Reply

Your email address will not be published.