Talos Vulnerability Report

TALOS-2023-1731

SNIProxy wildcard backend hosts buffer overflow vulnerability

March 30, 2023
CVE Number

CVE-2023-25076

SUMMARY

A buffer overflow vulnerability exists in the handling of wildcard backend hosts of SNIProxy 0.6.0-2 and the master branch (commit: 822bb80df9b7b345cc9eba55df74a07b498819ba). A specially crafted HTTP or TLS packet can lead to arbitrary code execution. An attacker could send a malicious packet to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

SNIProxy 0.6.0-2
SNIProxy Master 822bb80df9b7b345cc9eba55df74a07b498819ba

PRODUCT URLS

SNIProxy - https://github.com/dlundquist/sniproxy

CVSSv3 SCORE

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

CWE

CWE-120 - Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’)

DETAILS

SNIProxy (https://github.com/dlundquist/sniproxy) is an open source application that reverse proxies HTTP and TLS connections based on the requested hostname. It is distributed via package manager on several Linux distributions.

When wildcard backend hosts are used in SNIProxy configuration, an attacker could achieve remote code execution or denial of service by sending a crafted HTTP, TLS or DTLS packet.

The latest version on GitHub and the 0.6.0-2 Debian package were determined to be vulnerable. Note that while the original repository hasn’t been updated in several years, there are several forks of the original repository which are more active and may also contain this bug.

SNIProxy contains functions to parse addresses and hostnames, usually obtained by parsing the HTTP Host header or from a TLS server name indication (SNI) extension header. The new_address() function parses arbitrary hostname or address strings into a usable format. This function is called when parsing the configuration file, and, more importantly, when parsing hostnames that are to be sent to a wildcard backend.

Example wildcard configuration (note the asterisk on the right side):

table my_hosts {
    [a-z0-9]*\\.example\\.com *:443
}

Normally, TLS libraries such as OpenSSL do not allow SNI hostname values to exceed 256 bytes. However, SNIProxy does not use an external library for this functionality. It implements its own basic parsing on the TLS header values, which allow longer values to be parsed. The same also applies to the HTTP “Host” header, which itself has no maximum length in an HTTP request. As such, SNIProxy will extract and accept hostnames of arbitrary lengths.

During code inspection, an issue was observed in the new_address() function in the code block that parses IPv6 address strings (e.g. “[ff02::1]”). The issue arises because the source length is used in a string copy rather than destination length when copying into a stack buffer of size 262. The source length is calculated based on the distance between the opening and closing square brackets, which can be more than 262 due to the behavior noted above with unrestricted hostname lengths. Because of this, the call to strncpy will overflow the ip_buf buffer, resulting in a stack buffer overflow.

char ip_buf[262];
... snip ...
/* [IPv6 address] */
memset(&s, 0, sizeof(s));
if (hostname_or_ip[0] == '[' &&
        (port = strchr(hostname_or_ip, ']')) != NULL) {
    len = (size_t)(port - hostname_or_ip - 1); // len can be longer than 262
    ...
    strncpy(ip_buf, hostname_or_ip + 1, len); // buffer overflow here
    ip_buf[len] = '\0';

Exploit Proof of Concept

Configure an SNIProxy instance with the following configuration:

listen 0.0.0.0 443 {
    proto tls 
    table my_hosts
}

table my_hosts {
    .*test\\.example\\.com *:443
}

Attached is a proof-of-concept that will either crash SNIProxy outright, or, in the case of missing compiler mitigations, may redirect SNIProxy’s execution flow to a specified memory address (in this case, the invalid address 0xdeadbeefdeadbeef).

Mitigation

This is a suggested patch for the affected code in the new_address() function in address.c, which prevents the string copy from overflowing the destination and ensures that the resultant buffer is null terminated: strncpy(ip_buf, hostname_or_ip + 1, sizeof(ip_buf)); ip_buf[sizeof(ip_buf) - 1] = '\0';

VENDOR RESPONSE

The maintainer patched this in the following diff:
https://github.com/dlundquist/sniproxy/commit/f8d9a433fe22ab2fa15c00179048ab02ae23d583

TIMELINE

2023-03-16 - Initial Vendor Contact
2023-03-17 - Vendor Disclosure
2023-03-17 - Vendor Patch Release
2023-03-30 - Public Release

Credit

Discovered by Keane O'Kelley of Cisco ASIG.