Issues found via fuzzing by Guido Vranken

In June 2017, Guido Vranken found a number of issues with OpenVPN. One issue was a slow memory leak due to mis-use of the OpenSSL API. He contacted us to say that FreeRADIUS had the same issue as OpenVPN. We fixed that issue immediately in the the v2.x.x branch, and also fixed it in the v3.0.x branch, and the v4.0.x branch. The v3.1.x branch is unsupported, and has been deleted. Similarly, we do not discuss the v0 or v1 releases, as those are end of life and unsupported.

In order to improve the security of FreeRADIUS, we asked Guido to try fuzzing FreeRADIUS. He spent a week working with us, and managed to find a number of issues. We worked together to create and validate fixes for all of them. His blog contains a short note on the subject.

The short summary is that if your RADIUS server is on a private network, accessible only by managed devices, you are likely safe. If your RADIUS server is part of a roaming consortium, then anyone within that consortium can attack it. If your RADIUS server is on the public internet, then you are not following best practices, and anyone on the net can attack your systems.

Secure coding in C

Given the scope of these issues, there needs to be a statement on the security aspects of coding in C. In short, C is a terrible language for security. We have understood this for many years, and have taken pro-active steps to deal with the limitations of C. For example, we worked with Coverity as far back as 2007 to scan FreeRADIUS.

Starting from version 3, all versions of the server have built with zero compiler warnings. All releases have passed static analyis by Coverity, Clang analyzer, and cppcheck. We have also used PVS-Studio, with results here. Each static analysis tool has it's pros and cons, and each one usually finds things which are missed by all of the others.

We also have hundreds of regression tests, which check that "well formed" attributes and packets are decoded correctly, and that "malformed" attributes and packets do not cause misbehavior in the server.

As is apparent from this page, those processes are not enough to ensure secure C code. In short:

There are about as many issues disclosed in this page as in the previous ten years combined.

We will therefore be integrating the fuzzer into all future releases of the server. We will be updating our automated build system to run with memory sanitizers enabled. We strongly recommend that other software projects follow the same practices.

If multiple static analyers and hundreds of regression tests are not enough for us to find these security issues, they are probably not enough for you, either.


Summary of Issues

This page summarizes his findings, along with our response, analysis, and fixes. The items are labeled FR-GV-###, followed by which version(s) of the server are affected (v2, v3, etc.), and finally by a short description. His work led us to do additional tests, which found other issues that are labeled FR-AD-###.

The issues below were found via fuzzing and address sanitization checks. Not all are exploitable. Out of 15 issues, 5 have no possible exploit. Six (6) issues are only for DHCP, leaving 4 for RADIUS.

FR-GV-201 (v2,v3) Read / write overflow in make_secret()
FR-GV-202 (v2) Write overflow in rad_coalesce()
FR-GV-203 (v2) DHCP - Memory leak in decode_tlv()
FR-GV-204 (v2) DHCP - Memory leak in fr_dhcp_decode()
FR-GV-205 (v2) DHCP - Buffer over-read in fr_dhcp_decode_options()
FR-GV-206 (v2,v3) DHCP - Read overflow when decoding option 63
FR-GV-207 (v2) Zero-length malloc in data2vp()
FR-GV-301 (v3) Write overflow in data2vp_wimax()
FR-GV-302 (v3) Infinite loop and memory exhaustion with 'concat' attributes
FR-GV-303 (v3) DHCP - Infinite read in dhcp_attr2vp()
FR-GV-304 (v3) DHCP - Buffer over-read in fr_dhcp_decode_suboptions()
FR-GV-305 (v3) Decode 'signed' attributes correctly
FR-AD-001 (v2,v3) Use strncmp() instead of memcmp() for string data
FR-AD-002 (v3) String lifetime issues in rlm_python
FR-AD-003 (v3) Incorrect statement length passed into sqlite3_prepare

For some issues, the same or similar code appears in all versions of FreeRADIUS. i.e. from version 2, to version 3, and the "in development" v4.0.x branch. As a result, we present the findings by issue, and state which versions are affected. Where issues only apply one version, we show them for version 2, and then version 3. We do not discuss the v4.0.x branch here, as it has not had an official release. Finally, these issues affect all releases of FreeRADIUS version 2 and 3.

On July 17 2017, we will release versions 2.2.10 and 3.0.15 in order to address these issues. Guido has provided us with the source for the fuzzers. The fuzzers will be integrated into future releases of FreeRADIUS.

RADIUS Security

Before we discuss the issues, we must first give the reader some background on RADIUS security and associated best practices.

In general, RADIUS security can only be described as "poor". The protocol was designed in 1993, and uses MD5 to sign packets with a "shared secret". While MD5 has been broken, no one has shown that the attacks on MD5 can be extended to attack RADIUS. That is, packets which are signed with the shared secret are considered to be sent from a "trusted" source.

The design of RADIUS ensures that all packets except Access-Request are signed. In FreeRADIUS, this signature is checked prior to any packet decoding. This check ensures that only packets from "trusted" sources are accepted by the server. In most cases, therefore, only packets from those "trusted" sources can exploit these issues.

While the Access-Request packets are not signed by default, RADIUS provides for a signature via the Message-Authenticator attribute. Again, packets signed via this method are from "trusted" sources, and only those sources can exploit these issues.

However, many NAS implementations do not send a Message-Authenticator attribute in Access-Request packets. In those situations, any attacker who can forge packets from the NAS to the RADIUS server can have those packets accepted by the server, and can exploit these issues.

This security issue in RADIUS has been known for over a decade. RFC 5080 Section 2.2.2 says in part:

We strongly recommend that vendors update their firmware to include a Message-Authenticator attribute in all Access-Request packets. Where this change is not possible, we strongly recommend that all RADIUS administrators ensure that RADIUS traffic is on a secure management network. That is, end users should not be able to send any network traffic to a RADIUS server.

All versions of FreeRADIUS from version 2.0.0 onwards have provided for a per-client configuration require_message_authenticator. This flag rejects all Access-Request packets which do not contain a valid Message-Authenticator attribute. We recommend that this flag be enabled where possible. Once this flag is set, even in old an un-patched versions of the server, the issues discussed here can only be exploited by "trusted" sources. Also, as of version 2.1.3, FreeRADIUS has ensured that proxied Access-Request packets always contain a Message-Authenticator attribute. This change ensures that all systems which receive Access-Request packets from a FreeRADIUS proxy can set the require_message_authenticator flag.

While this limitation minimizes the impact of these issues, it does not remove it entirely. Roaming agreements may provide for packets to be sent from parties who are largely unknown to the recipient, but who are within a "trusted" roaming coalition. We believe that breaches of trust by "trusted" parties are best dealt with via administrative means, and not technical ones. Still, we should still ensure that trusted parties are unable to exploit our trust in order to perform malicious actions.

Where is necessary to be part of a roaming consortium, administrators should ensure that all RADIUS traffic over the public Internet is encrypted with IPSec or TLS. We do not recommend placing a RADIUS server on the public net. Even independent of the issues disclosed here, the security of the RADIUS protocol is insufficient to guarantee safe operation on the public Internet.

DHCP Security

Finally, we note that the discussion above is about RADIUS security, and does not apply to DHCP. Unfortunately, DHCP protocol security can best be described as "in practice, non-existent". Unlike RADIUS, DHCP allows end users to send packets directly to DHCP servers. This capability means that it is harder for administrators to shield their DHCP servers from malicious parties.

We note that while FreeRADIUS includes DHCP functionality, it is not enabled by default. Administrators must take explicit action to configure it. As such, most FreeRADIUS sites are not vulnerable to the DHCP issues disclosed here. We still, however, recommend upgrading to a version which contains fixes for these issues.

Issues

The follow list describes each issue in detail. Included in each description are a statement in impact, exploit vector (where appropriate), a link to the fix, which versions are affected, and where appropriate, a CVE identifier.


FR-GV-201 (v2,v3) Read / write overflow in make_secret()

Issue: The make_secret() function does not properly check for output buffer size before writing data. It can perform a read or write overflow of up to 16 octets.

Impact: Minimal. The issue will be see when the server is sending a RADIUS packet that is almost at the maximum (4K octets), and the last attribute in the packet is an Ascend-Send-Secret (or similar) attribute. The data being written is an MD5 digest of the shared secret, concatenated to data which is under the attackers control.

The issue will also be seen when receiving a packet that has an Ascend-Send-Secret (or similar) attribute of the wrong size. The server will read data past the end of the attribute, up to a limit of 16 octets.

Exploit vector: Read or write overflow, by anyone who can send packets which are accepted by the server.

Home servers which send large Access-Accept responses, with an Ascend-Send-Secret attribute as the last one in the packet, and where the proxy does minimal packet editing, may be able crash a proxy which receives that Access-Accept and forwards it to a NAS.

Fix: Ensure that the make_secret() function checks for bounds on the encapsulating packet. Fixed in FR-GV-201 (v2), and in FR-GV-201 (v3).

Affected versions: 2.0.0 through 3.0.14, inclusive.

CVE: This issue has been assigned CVE-2017-10978. No remote code execution is possible. A denial of service is possible.


FR-GV-202 (v2) Write overflow in rad_coalesce

Issue: The rad_coalesce() function checks for WiMAX attributes which are too small, but it does not check for WiMAX attributes which are too large. As a result, the server can be convinced to read past the end of an attribute, and to write past the end of memory allocated via malloc().

The data being copied is taken from the attributes following the malformed WiMAX attribute, and is under the control of the attacker. While the packet has to be a "well formed" RADIUS packet, that requirement limits only the two octets which immediately follow the malformed WiMAX attribute. After that, there are up to 245 octets copied which are the complete control of the attacker.

This issue does not appear in version 3, as that code was re-written, and the rad_coalesce function does not exist in those branches. However, similar issues appear in the data2vp_wimax() function in version 3.

Impact: Write overflow, possibly remote exploit by anyone who can send packets which are accepted by the server.

Exploit vector: The issue happens when the server receives any packet containing malformed WiMAX attributes. One example of this issue is the following data: 1a 0a 00 00 60 b5 2c 04 80 00 1a 09 00 00 60 b5 2c fa 00. Similar formats can be used with other WiMAX attributes, e.g. where the 2c octet is replace by other values. The exploit here is the fa. That octet indicates that there are 250 octets of data remaining in the attribute, while in fact there is only one octet.

Fix: Check for attributes which are "too long", in addition to checking for attributes which are "too short". Fixed in FR-GV-202.

Affected versions: 2.0.0 through 2.2.9, inclusive.

CVE: This issue has been assigned CVE-2017-10979. Remote code execution is possible. A denial of service is possible.


FR-GV-203 (v2) DHCP - Memory leak in decode_tlv()

Issue: the decode_tlv() function leaked memory in certain circumstances.

Impact: Memory leak, potentially leading to memory exhaustion.

Exploit vector: Any network device capable of sending DHCP packets to FreeRADIUS, which sends option 82 with multiple sub-options.

Fix: Link all decoded attributes into the decoded packet. Fixed in FR-GV-203.

Affected versions: 2.0.0 through 2.2.9, inclusive.

CVE: This issue has been assigned CVE-2017-10980. No remote code execution is possible. A denial of service is possible.


FR-GV-204 (v2) DHCP - Memory leak in fr_dhcp_decode()

Issue: If option decoding fails, the fr_dhcp_decode() function would leak memory.

Impact: Memory leak, potentially leading to memory exhaustion.

Exploit vector: Any network device capable of sending DHCP packets to FreeRADIUS, which sends packets with malformed options.

Fix: Free partially decoded options on error. Fixed in FR-GV-204

Affected versions: 2.0.0 through 2.2.9, inclusive.

CVE: This issue has been assigned CVE-2017-10981. No remote code execution is possible. A denial of service is possible.


FR-GV-205 (v2) DHCP - Read overflow in fr_dhcp_decode_options()

Issue: The fr_dhcp_decode_options() function does not do proper bounds checks on option lengths, leading to out of bounds reads.

Impact: The server can read up to 253 octets more data than it should. Depending on memory layout, this read may initiate a page fault, and cause the server to crash.

Exploit vector: Any network device capable of sending DHCP packets to FreeRADIUS, which sends packets with malformed options.

Fix: Check for options which are "too long", in addition to checking for attributes which are "too short". Fixed in FR-GV-205.

Affected versions: 2.0.0 through 2.2.9, inclusive.

CVE: This issue has been assigned CVE-2017-10982. No remote code execution is possible. A denial of service is possible.


FR-GV-206 (v2,v3) DHCP - Read overflow when decoding option 63

Issue: The fr_dhcp_decode() function performed a strcmp() on binary data in an internal data structure, instead of checking the length of the option and doing a memcmp.

Impact: The server can read memory until it reaches a zero byte. Depending on memory layout, this read may initiate a page fault, and cause the server to crash.

Exploit vector: Any network device capable of sending DHCP packets to FreeRADIUS, which sends a DHCP option 63 with non-zero contents.

Fix: Examine option 60, instead of option 63, and check for option length. Fixed in FR-GV-206 (v2), and FR-GV-206 (v3).

Affected versions: 2.0.0 through 3.0.14, inclusive.

CVE: This issue has been assigned CVE-2017-10983. No remote code execution is possible. A denial of service is possible.


FR-GV-207 (v2) Zero-length malloc() in data2vp()

Issue: When decoding attributes of type "tlv", the decoder can call malloc() with an argument of zero.

Impact: None. The length of the allocated data is kept separately in the vp->length field. All dereferences to the allocated data are protected by a check for vp->length > 0

Exploit vector: None.

Fix: For general safety, the function was changed to avoid a zero-length malloc(). Fixed in FR-GV-207

Affected versions: 2.0.0 through 2.2.9, inclusive.

CVE: No CVE has been release as this issue has no impact, and exploitation does not cross a privilege boundary in a correct and realistic product deployment.


FR-GV-301 (v3) Write overflow in data2vp_wimax()

Issue: This issue is similar to FR-GV-202, as the code in v3 is based on the code in v2. However, as the issue is slightly different, it is listed separately.

Impact: Write overflow, possibly remote exploit by anyone who can send packets which are accepted by the server.

Exploit vector: Sending WiMAX attributes which have the "continuation" flag set, but for which there is no subsequent data.

Fix: Update checks for malformed attributes. Fixed in FR-GV-301, with a related patch in another patch.

Affected versions: 3.0.0 through 3.0.14, inclusive.

CVE: This issue has been assigned CVE-2017-10984. Remote code execution is possible. A denial of service is possible.


FR-GV-302 (v3) Infinite loop and memory exhaustion with 'concat' attributes

Issue: When the server receives zero-length attributes marked 'concat' in the dictionaries, it could go into an infinite loop and exhaust memory.

Impact: Infinite loop and memory exhaustion, by anyone who can send packets which are accepted by the server.

Exploit vector: The issue happens when the server receives a packet containing the following attribute data: 4f 02, 89 02, 90 02, or b4 02.

Fix: Update decode_concat() function to return the bytes read from the packet, not the length of the attribute data. Fixed in FR-GV-302.

Affected versions: 3.0.0 through 3.0.14, inclusive.

CVE: This issue has been assigned CVE-2017-10985. No remote code execution is possible. A denial of service is possible.


FR-GV-303 (v3) DHCP - Infinite read in dhcp_attr2vp()

Issue: When decoding "string" options in an array, dhcp_attr2vp() could be convinced to call memchr() with a length argument of -1. This could result in an over-read until the first zero octet was found, or a page fault occured.

Impact: Possible infinite read overflow, or crash.

Exploit vector: Any network device capable of sending DHCP packets to FreeRADIUS, which sends string options to the server in an option array.

Fix: Perform better bounds checking on decoding string options in an array. Fixed in FR-GV-303.

Affected versions: 3.0.0 through 3.0.14, inclusive.

CVE: This issue has been assigned CVE-2017-10986. No remote code execution is possible. A denial of service is possible.


FR-GV-304 (v3) DHCP - Buffer over-read in fr_dhcp_decode_suboptions()

Issue: The fr_dhcp_decode_suboptions() function does not properly check if sub-options overflow the packet.

This issue is similar to FR-GV-205, as the code in v3 is based on the code in v2. However, as the issue is slightly different, it is listed separately.

Impact: The server can read up to a small number of octets more data than it should. Depending on memory layout, this read may initiate a page fault, and cause the server to crash.

Exploit vector: Any network device capable of sending DHCP packets to FreeRADIUS, which sends packets with malformed options.

Fix: Check for options which are "too long", in addition to checking for attributes which are "too short". Fixed in FR-GV-304.

Affected versions: 3.0.0 through 3.0.14, inclusive.

CVE: This issue has been assigned CVE-2017-10987. No remote code execution is possible. A denial of service is possible.


FR-GV-305 (v3) Decode 'signed' attributes correctly

Issue: Attributes of data type 'signed' would sometimes be created from uninitialized memory, instead of from the received packet.

Impact: Minimal. No overflow or exploit is possible. Instead, the attribute sometimes has a garbage value. There is only one 'signed' attribute, which is in the WiMAX dictionaries, and it is used only in certain limited situations.

Exploit vector: None.

Fix: Decode the attribute correctly. Fixed in FR-GV-305.

Affected versions: 3.0.0 through 3.0.14, inclusive.

CVE: None. No remote code execution is possible. No denial of service is possible. Exploitation does not cross a privilege boundary in a correct and realistic product deployment.


FR-AD-001 (v2,v3) Use strncmp() instead of memcmp() for string data

Issue: When reading data from configuration files, the server could over-read to to 4 octets of data.

Impact: Minimal.

Exploit vector: Administrators who have write access to the server configuration files.

Fix: Use strncmp() instead of memcmp() for bounded comparisons on C strings. Fixed in FR-AD-001 (v2), and in FR-AD-001 (v3).

Affected versions: 3.0.0 through 3.0.14, inclusive.


FR-AD-002 (v3) String lifetime issues in rlm_python

Issue: The PySys_SetPath() and PySys_SetName() functions require a long-lived pointer to the path / name.

Impact: Potential crash.

Exploit vector: Administrators who have write access to the server configuration files.

Fix: Use a long-lived string instead of a short-lived one. Fixed in FR-AD-002.

CVE: No CVE has been release as this issue has no impact, and exploitation does not cross a privilege boundary in a correct and realistic product deployment.


FR-AD-003 (v3) Incorrect statement length passed into sqlite3_prepare

Issue:

An incorrect statement length was passed into the sqlite3_prepare() function.

Impact: Potential crash.

Exploit vector: Administrators who have write access to the server configuration files.

Fix: Use the correct statement length. Fixed in FR-AD-003.

Affected versions: 3.0.0 through 3.0.14, inclusive.

CVE: No CVE has been release as this issue has no impact, and exploitation does not cross a privilege boundary in a correct and realistic product deployment.

<