After a CVE on open source software has been discovered and a fix has been released, a fruitful practice for security researchers is to go deep into the nature of the CVE and the fix.
In addition to curiosity, this good practice helps professionals and researchers extend their knowledge and improve their understanding of security vulnerabilities.
Being an engineer at Checkmarx, the main tool that comes to mind to deep dive into the nature of vulnerabilities is the Checkmarx Static Application Security Testing (SAST) engine.
This blog post will go into details about the nature of two separate vulnerabilities, CVE-2022-3602 and CVE-2022-3786, which hit the news at the beginning of November impacting a very well-known and largely adopted open source software package, OpenSSL. We will explore their fix and how Checkmarx solutions can detect such vulnerable code and support developers with remediation.
CVE-2022-3602 and CVE-2022-3786
The official page from OpenSSL, dealing with November’s CVEs (CVE-2022-3786 and CVE-2022-3602) can be found here.
The two vulnerabilities affect OpenSSL up to version 3.0.6, and they involve a file named punycode.c, which is one of the files that manage the parsing of specific encoding of domain names (known as punycode).
With both vulnerabilities, “A buffer overrun can be triggered in X.509 certificate verification, specifically in name constraint checking”, and they have been classified as CWE-120 by NIST, as a “Classical Buffer Overflow.”
Generally, in C language, it is important to securely manage memory buffers to avoid any value written in a buffer from being reused elsewhere in the code and being interpreted with unexpected semantics. It’s worth noting that in C, buffers include strings too!
Traditionally, strings are represented as a region of memory containing data terminated with a NULL character. Different string handling methods may rely on this NULL character to determine the length of the string. If a buffer that does not contain a NULL terminator is passed to one of these functions, the function will read past the end of the buffer or will lead to unexpected behaviors, such as buffer overflows.
Let’s go through some technical details on the nature of the two OpenSSL vulnerabilities.
It is a buffer overflow related to the function ossl_punycode_decode, where there is a check on the size of a buffer for larger-than (>) values but omits the equals-to (=) values out of any check, as seen below.
The red highlight is the old version of the ossl_punycode_decode source code (OpenSSL 3.0.6), while the green one is the fixed version (OpenSSL 3.0.7).
The check at line 184 was leaving the case “=” unchecked, letting data with the same size of max_out variable to reach the next lines in the program and enter the further part of the function.
The fix addresses such a case, by adding the “=” case to the ones that must be excluded with return 0.
According to this evidence, the buffer overflow is due to the absence of a proper check against the size of a buffer which EQUALS the maximum, while there are cases defined to address sizes that are larger (return 0) and smaller (just continue).
Technically, this case is similar to off-by-one vulnerabilities, where an application does not properly manage buffers which are exactly the size of the maximum expected, due to several assumptions on the data structures received in input.
Various assumptions can be done on data structures received in input, and they all deal about trusting the source of such input, in term of its content, its format, and its size; to build secure code, assumptions should be avoided.
Instead, sanitization and validation techniques should be implemented in the code: sanitization is the activity of removing extraneous data from a given input, transforming it into harmless data, compatible with business rules and security policies (e.g. removing special characters from a string before using it as a parameter in SQL); validation, on the other hand, is the activity of checking the content of a given input and rejecting any input that does not comply with application’s constraints (e.g. rejecting any string that is greater or equals to the size of a memory buffer).
Checkmarx’s Codebashing training platform offers several lessons to teach developers how to write secure code in C, addressing proper methods to manage structures such as buffers, stacks, and heaps, which can help developers avoid introducing vulnerabilities in their code, such as CVE-2022-3602.
For example, regarding off-by-one, Checkmarx’s gamified platform shows the student a part of vulnerable code and its side effects at runtime, both in memory and interactively:
In this scenario, the vulnerable code is robust when the buffer is larger or smaller than the expected size; however, it is not safe when exactly 8 characters are entered.
t is a buffer overflow related to the function ossl_punycode_decode, which manages several cases of writing characters (chars) to a buffer, before using that buffer in further contexts, such as reading it as a string.
OpenSSL 3.0.7 introduced the use of this PUSHC macro, to manage operations in buffers properly, as stacks:
The macro is then used in place of old 3.0.6 “memcpy” functions, everywhere it is needed.
Similar to the previous example above, the red highlight is the old version of the ossl_punycode_decode source code (OpenSSL 3.0.6), while the green one is the fixed version (OpenSSL 3.0.7).
The change on line 301 manages the absence of the NULL character, which may lead to unexpected behaviors if the just populated stack is used in other contexts (e.g., as a string!).
Checkmarx SAST has a specific query for C/C++ Language which is called “Improper_Null_Termination.” It is in the category of Buffer Overflows, and it has High severity.
Its goal is to identify buffers that have not been properly terminated by NULL characters.
By scanning OpenSSL 3.0.6 with Checkmarx SAST, the punycode file appears in two results related to line 276 and 297 for Improper Null Termination query:
The description of the finding at line 276 states:
“The buffer outptr in openssl-openssl-3.0.6\crypto\punycode.c at line 276 does not have a null terminator. Any subsequent operations on this buffer that treat it as a null-terminated string will result in unexpected or dangerous behavior.”
By scanning OpenSSL 3.0.7 with the same preset, the two vulnerabilities appear as fixed:
Any application may present vulnerabilities due to the large size of applications, inheritances from older versions, mistakes, or errors. As evident with the recently identified OpenSSL vulnerabilities, even well-maintained and mature applications may present vulnerabilities that could be all but impossible to be identified by a manual review of the code.
At the same time, the security awareness of developers is a key factor to produce and maintain secure code.
Checkmarx SAST and Checkmarx Codebashing can help in raising the bar of security in your company and in your developers and security champions. Both solutions are fully integrated into our Checkmarx One™ Application Security Platform.
To learn more or see for yourself, request a demo today!