On 2015-09-14, Marcello Duarte disclosed a vulnerability in FreeSWITCH on the Bugtraq mail list. This was assigned CVE-2015-7392 which reads:
Heap-based buffer overflow in the parse_string function in libs/esl/src/esl_json.c
in FreeSWITCH before 1.4.23 and 1.6.x before 1.6.2 allows remote attackers to execute arbitrary code via a trailing \u in a json string to cJSON_Parse
.
After investigation, Tenable found that this description is not fully accurate, and that the issue was not properly patched. It is still possible to trigger a heap overflow via crafted JSON in FreeSWITCH from version 1.4.4 to 1.6.2 (current), and 1.7.0 (development). Further, the original CVE entry only mentions exploitation in the third-party Event Socket library, but there are at least three other vectors of exploitation of the same (or similar) vulnerability in FreeSWITCH itself, one native to FreeSWITCH itself:
- FreeSWITCH command line via the “json” command (
switch_json.c
, local).
- Executing the FreeSWITCH command “json” via an Event Socket library connection to the Event Socket module (
switch_json.c
, local by default, remote potentially).
- Sending crafted JSON to the Verto module multicast listener (
switch_json.c
, remote).
- Malformed / malicious JSON traffic from the server to an ESL client (
esl_json.c
, remote and may require MitM)
The original Bugtraq disclosure indicates that the vulnerability was patched on September 14, 2015, and it is associated with a Jira ticket (inaccessible to the general public). Note that the patch fixes duplicate versions of the parse_string()
function in src/switch_json.c
, libs/libks/src/ks_json.c
, and libs/esl/src/esl_json.c
(the latter being the only file explicitly mentioned in the CVE entry).
The parse_string()
function at line 155 in esl_json.c
is supposed to take in a JSON string and convert it a normal (no escaped characters) C string. There are two things to consider; first, how the size of the string buffer is computed, and second, how the parser handles Unicode escaped values (i.e. \u0001). As mentioned in the Bugtraq disclosure, the return string buffer is calculated by counting the characters from the starting quote to the last unescaped quote (or NULL if it is encountered). The parser handles the escaped Unicode by identifying the “\u” and then passing the data one byte beyond the “u” to sscanf
. In the following code, *ptr at line one would contain “\” and *ptr in line five would contain “u”. CVE-2015-7392 describes the attack as a “trailing \u in a JSON string to cJSON_Parse
. This can be interpreted in two ways:
{ “key” : “value\u” }
{“key” : “value\u
The first JSON example will fail sscanf
conversion due to the ‘”’ character not being convertible. The second JSON example will also fail sscanf conversion since the NULL terminator is passed into sscanf. The break after sscanf
fails increments over the ‘u’ and returns back to the top of the while loop. Based on the description found in CVE-2015-7392, there is not sufficient information to cause the heap overflow. However, if we observe how sscanf
is used, we can find the overflow. The sscanf
man page says this about the return value:
“These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.”
However, as written, if sscanf returns greater than 0 the string pointer is always incremented by four. Therefore a JSON string such as the one provided below, where sscanf will only consume one character, will cause the parser to skip the ” and start writing beyond the end of the allocated buffer:
{ “heap” : “overflow\u1” aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa }
The published fix for CVE-2015-7392 changed line 42 (that steps over the ‘u’ character) to be “ if (*ptr) ptr++;”
. However, this doesn’t fix the issue since the root cause was with sscanf.
Details on the Vulnerability:
The CVE describes the vulnerability as a remote vulnerability in FreeSWITCH but cites the libs/esl/src/esl_json.c
files. It is interesting to note that code in the libs/esl/
directory is not actually native FreeSWITCH code, instead, it is a library to be used by third-party applications to communicate with FreeSWITCH. As such, the vulnerability, as described in the CVE, is not a remote vulnerability in FreeSWITCH, rather a remote vulnerability in third-party applications that use the Event Socket library to communicate with FreeSWITCH. The FreeSWITCH tool Fs_cli is an example that may be affected, as well as any of the third-party GUI for FreeSWITCH.
The original fix was also applied in two other locations: libs/libks/src/ks_json.c and src/switch_json.c
. Based on examination, it appears that libs/libks/src/ks_json.c
is unused code and therefore not exploitable. However, src/switch_json.c
is used in the FreeSWITCH base code. The first way this can be reached is via the FreeSWITCH command line. Specifically, the command “json” (part of mod_commands) is available to local users via CLI. When starting FreeSWITCH git master version (3f3b855 at the time of writing) using the following command:
user@host: ~/freeswitch$ sudo /usr/local/freeswitch/bin/freeswitch -conf ./conf/ -log ./log -db ./db
This gives a fairly wide attack surface in order to attempt to trigger the vulnerability remotely, enabling services on a variety of TCP and UDP ports. Of specific interest are UDP port 1337 and TCP port 8021.
UDP port 1337 is part of the Verto module, an interface for multicast traffic that accepts JSON-RPC as input. To trigger the heap overflow on this interface, an attacker needs to send a single UDP packet with the crafted JSON:
user@host: ~/freeswitch$ nc -u 192.168.1.12 1337
{ "heap" : "overflow\u1" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
^C
TCP port 8021 is part of the Event Socket Module (the server side of the Event Socket Library). This port is less interesting from an attack perspective because it is typically bound to 127.0.0.1 by default, it is password protected, and only IP addresses within an access control list can connect to it. In order to communicate with the Event Socket Module, it helps to understand the protocol or use the event socket library. You can find a suitable client using the event socket library in libs/esl/testclient.c
. The client, as written, will log into a FreeSWITCH instance at localhost using the default password (no username, password "ClueCon") and send it a “status” command, which FreeSWITCH will reply to with system health information. If we change line 12 from the esl_send_recv()
function to our own custom overflow string, we can trigger the exact same code path that caused the overflow in the FreeSWITCH command line that was mentioned earlier. This attack, of course, assumes you can overcome the ACL, password, and that the listener is not bound to localhost.
The vulnerable JSON parsing code in switch_json.c
was first introduced to the code base in 2010 at revision c5086b15174. However, no official release is exploitable with the above methods until version 1.4.4 (May 23, 2014). This is because the code does not appear to accept input from a user until the switch command is introduced to the command line. The code appears to originally exist to reformat system generated "events" into JSON (instead of "plain" or "xml").