Aside from safety properties, can we use static analysis tools to detect security issues? Yes, as we will show by discussing a programming error in uftpd, an ftp server implemented in C. In particular, we will show how the error influences both safety as well as security and under which conditions it can be exploited. Furthermore, we will give a quick glance at techniques used to minimize the issue’s impact or to avoid this and comparable errors from the get go.

Recap: Safety vs. security

Safety (more precisely: functional safety, in the sense of ISO/IEC 61508, ISO 26262, and other derived standards) refers to the protection from errors or malfunctions, in particular with respect to dangers or risks of injury, loss of live or property or other undesired outcomes.

Several programming standards defining safety conditions and how to appropriately develop software and systems exist. An example prominently used in the automotive industry, the MISRA C software development guidelines were introduced in 1998 and have been updated several times since.

In contrast to functional safety, software security is more focused on deliberate actions explicitly targeted at providing harm. Rather than asking whether a system can cause harm due to a malfunction, security considerations deal with the question whether an attacker can make a system cause harm. Again, different coding guidelines for the avoidance of security issues are available. For instance, the SEI CERT C Coding Standard aims at safety, reliability and security simultaneously. With the ISO/IEC TS 17961:2013 an international norm for the development of security-critical software has been established.

As we will show below, software flaws often have both a safety as well as a security aspect. Accordingly, the aforementioned standards link to each other in various places and are interconnected. For several of them, mappings from one to another are provided. Safety standards such as the MISRA guidelines have taken up security aspects as well and vice-versa.

Example: CVE-2020-5204

Context

Our issue can be found as CVE-2020-5204 in common vulnerability databases such as vulndb. The issue has initially been discovered by Aaron Esau. It resides in the part of uftpd responsible for handling the PORT command of the file transfer protocol (FTP). The PORT command is send by the client to the server to make it open a reverse connection to the client. The client can then use this connection to transfer files.

To allow the server to connect back to them, clients need to provide an IP address and a port number. As FTP is a cleartext protocol, the client simply sends a string formatted as follows: PORT(ip1,ip2,ip3,ip4,port1,port2). The server then uses ip1 to ip4 as the four groups of an IPv4 IP address and calculates the port to connect to as port = (port1 * 256) + port2.

The issue

Following, let’s have a look at how uftpd used to extract the IP address from the given user command. Before the maintainers fixed the issue, the code looked as follows:

cve-2020-5204 error in safety and security

The parameters ip1,ip2,ip3,ip4,port1,port2 extracted from the command send by the client reside in strINET_ADDRSTRLEN is equal to 16, which is large enough to store an IPv4 address. Three bytes are used per group (each containing one to three digits). Three additional bytes are used for the dots and the null terminator. Using sscanf, the six numbers are extracted from str and stored in individual integer variables. Afterwards, sprintf is used to recombine them into a string properly representing an IP address. However, sprintf does not check the size of the buffer it writes to in any way! In consequence, if the client provides numbers which are too large, sprintf will write more than what can be stored in addr. Anything following addr on the stack will be overwritten, resulting in a classic stack buffer overflow.

Impact to safety and security

To examine the impact of the issue, we have extracted the code shown above into a simple example application. If executed with number in valid ranges, the application behaves as expected:

Once one of the parameters is too large, sprintf overwrites and thus replaces parts of the stack, preventing execution from continuing properly:

The program terminates immediately, which would be unacceptable for any safety critical component. Furthermore, when it comes to security, an attacker can use the buffer overflow to overwrite parts of the stack. In particular, anybody able to connect can overwrite the return address. Ultimately, this could lead to an attacker gaining control over the uftpd process and potentially allow execution of arbitrary code.

Luckily, because of the %d in the format strings of both sscanf and sprintf, the buffer and thus the rest of the stack can only be overwritten by characters occurring in numbers: the numerals 0 to 9 and the -. In consequence, an attacker cannot overwrite the return address arbitrarily, diminishing the potential impact of an attack.

The bugfix

To prevent the buffer overflow in the first place, sprintf was replaced by snprintf, which requires the caller to provide a maximum size to write and thus prevents overwriting:

error bugfix

Mitigation and avoidance

Stack buffer overflows are a very common issue. The Common Weakness Enumeration lists them in their list of the Top 25 Most Dangerous Software Weaknesses. Buffer Overflows have been responsible for some of the most prominent issues, with impacts ranging from databases to warships. In consequence, different techniques for their avoidance have been developed.

Stack canaries and randomization

The idea behind a stack canary is to place a random integer on the stack just before the return pointer. When using a buffer overflow to replace the pointer to gain control over the process, the canary is overwritten as well. Before a routine actually returns, the canary is verified. If it has been changed, the systems knows an overflow has occurred and stops execution.

With randomization, the address space used by an application is ordered and allocated more randomly. This effectively makes it harder to exploit a buffer overflow with malicious intent. Again, the possible security impact is reduced but the application still crashes.

Static analysis tools

Static analysis tools can detect the potential stack buffer overflow in our example during the implementation phase. This allows developers to replace any offending calls with better alternatives. In particular, for our example, generic description of the tool, as the Axivion Suite, offers several rule sets that would have uncovered the issue:

References and further information

  • [cert] SEI CERT C Coding Standard: Rules for Developing Safe, Reliable, and Secure Systems (2016 Edition)
  • [iso17961] CAN/CSA-ISO/IEC TS 17961:2018-01-01, Programming languages, their environments and system software interfaces – C secure coding rules
  • Software quality is not a myth: Real examples

Share:

Legal Notice

This text is the intellectual property of the author and is copyrighted by coderskitchen.com. You are welcome to reuse the thoughts from this blog post. However, the author must always be mentioned with a link to this post!

Leave a Comment

Related Posts

10-step grey-box pentest
Ruschil Ray

10-step grey-box pentest

This 10-step grey-box pentest strategy has proven to not only be effective but also efficient – as it uses a minimum number of test cases

Daniel Lehner

Reducing efforts in system testing

Which are the best methods to reduce efforts in system testing? In this second part of the Coders Kitchen interview, system testing experts Hans Quecke

Hey there!

Subscribe and get a monthly digest of our newest quality pieces to your inbox.