CodeQL queries 1.25
Skip to end of metadata
Go to start of metadata

Name: Uncontrolled data used in a WebClient

Description: The WebClient class allows developers to request resources, accessing resources influenced by users can allow an attacker to access local files.

ID: cs/webclient-path-injection

Kind: path-problem

Severity: error

Precision: high

Query: TaintedWebClient.ql
/**
 * @name Uncontrolled data used in a WebClient
 * @description The WebClient class allows developers to request resources,
 *              accessing resources influenced by users can allow an attacker to access local files.
 * @kind path-problem
 * @problem.severity error
 * @precision high
 * @id cs/webclient-path-injection
 * @tags security
 *       external/cwe/cwe-099
 *       external/cwe/cwe-023
 *       external/cwe/cwe-036
 *       external/cwe/cwe-073
 */

import csharp
import TaintedWebClientLib
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph

from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ flows to here and is used in a method of WebClient.",
  source.getNode(), "User-provided value"

The WebClient class provides a variety of methods for data transmission and communication with a particular URI. Despite of the class' naming convention, the URI scheme can also identify local resources, not only remote ones. Tainted by user-supplied input, the URI can be leveraged to access resources available on the local file system, therefore leading to the disclosure of sensitive information. This can be trivially achieved by supplying path traversal sequences (../) followed by an existing directory or file path.

Sanitization of user-supplied URI values using the StartsWith("https://") method is deemed insufficient in preventing arbitrary file reads. This is due to the fact that .NET ignores the protocol handler (https in this case) in URIs like the following: "https://../../../../etc/passwd".

Recommendation

Validate user input before using it to ensure that is a URI of an external resource and not a local one. Potential solutions:

  • Sanitize potentially tainted paths using System.Uri.IsWellFormedUriString.
Example

In the first example, a domain name is read from a HttpRequest and then this domain is requested using the method DownloadString. However, a malicious user could enter a local path - for example, "../../../etc/passwd" instead of a domain. In the second example, it appears that the user is restricted to the HTTPS protocol handler. However, a malicious user could still enter a local path, since as explained above the protocol handler will be ignored by .net. For example, the string "https://../../../etc/passwd" will result in the code reading the file located at "/etc/passwd", which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords.

using System;
using System.IO;
using System.Web;
using System.Net;

public class TaintedWebClientHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext ctx)
    {
        String url = ctx.Request.QueryString["domain"];

        // BAD: This could read any file on the filesystem. (../../../../etc/passwd)
		using(WebClient client = new WebClient()) {
			ctx.Response.Write(client.DownloadString(url));
        }

        // BAD: This could still read any file on the filesystem. (https://../../../../etc/passwd)
        if (url.StartsWith("https://")){
            using(WebClient client = new WebClient()) {
                ctx.Response.Write(client.DownloadString(url));
            }
        }

        // GOOD: IsWellFormedUriString ensures that it is a valid URL
        if (Uri.IsWellFormedUriString(url, UriKind.Absolute)){
            using(WebClient client = new WebClient()) {
                ctx.Response.Write(client.DownloadString(url));
            }
        }
    }
}

References