Certificates guarantee the origin and integrity of the message, package, application or document they are signing. Since public key cryptography is used to protect the content, we can be sure that the information within cannot be modified without breaking the encryption envelope. If the origin is trusted and the integrity is maintained, the signed content can be accessed safely.
Unfortunately, this isn’t where the story ends. While certificates are secure encryption envelopes, the ways they get implemented to protect the content they are signing is often too loose to prevent tampering. For many different reasons, programmers are allowed to add or change content post-signing which causes the overall security of the system to suffer. Depending on the way certificates are used to implement integrity checks, there are different approaches to bypassing validation.
When it comes to code signing, there are two primary ways certificates are used to validate the content integrity. They both come with their own set of validation challenges.
Form 1: Certificate and signed content within the same object
In this example, the certificate is usually appended to the end of the message, package, application or document it is signing. Certificate data includes a validation checksum that guarantees the integrity of the signed content. The way validation checksum is computed, and the data it digests for it, often leaves a few blind spots that are left unverified.
To demonstrate the weakness of this approach, we’ll take a look at how authenticode digital signatures work when applied to portable executable files.
Example of authenticode hash verification process
The file format visualization makes it apparent that certain fields within it must be left unverified for the certificate to be appended to the content in the first place. This includes the content checksum, the physical location, and the size of the appended certificate. These are all unknown until the signing process is completed.
Since the size of the certificate is unknown prior to signing, it cannot be included in the data verified by integrity checks. One can simply append data to the end of the digital certificate to bypass integrity checks. By simply tweaking the structure of this data to make it look like a part of the certificate, the integrity verification passes successfully.
All unverified data poses a huge risk. There’s no way of telling if the person signing the file placed it there or if somebody else did. And that, by definition, makes it a target for misuse.
Unlike the portable executable file format that is parsed from the beginning of the file, there are other formats that are parsed from the end. So, a mashup of a PE file that has a ZIP archive after its certificate can be parsed as both. Since a JAVA application is packaged as a simple ZIP archive, we can create a file which is both a Windows and a JAVA application. If we have a single certificate validation pipeline, the file will appear as a validly signed Windows application even though it allows the untrusted JAVA application to run without any verification of its code.
Other mashups and clashes are also possible. As long as the appended format is parsed from the end, both can coexist within the same file without breaking the certificate integrity checks.
This kind of an attack on integrity validation processes has been discussed at the BlackHat conference in 2016. The team from Deep Instinct held a presentation titled Certificate Bypass: Hiding and Executing Malware from a Digitally Signed Executable.
ReversingLabs solutions protect its users from this kind of misuse by prohibiting whitelisting when any non-verifiable content is found, whether we’re validating a portable executable or any other digitally signed format. Furthermore, all appended data is extracted and inspected recursively through our static analysis engine. This way, we extract and inspect both the portable executable and the JAVA application from the given example.
Form 2: Certificate and signed content within different objects
In this example, the certificate is usually found alongside the message, package, application or document it is signing. Certificate data includes a validation checksum that guarantees the integrity of the signed content list.
With this approach, there are three separate element types: the certificate, the content list and the content itself. Due to this multi-file approach, these elements tend to be grouped together in a single package for ease of deployment. That, however, introduces a new class of integrity validation problems.
To demonstrate the weakness of this approach, we’ll take a look at how digital signatures work when applied to Android mobile application packages.
Example of Android certificate verification process
Two major problems can be spotted when inspecting the visualization above. First, new content can be simply added to the package. Since the newly added content isn’t present on the content list, it will not be covered by validation. Depending on how the signed application is designed, it may be possible to access and use the unsigned content without additional origin checks. That’s why the integrity validation check must be strictly implemented to prevent all content additions post-signing.
Second, the content can be path squashed. Packages allow duplication of content by design. It is therefore possible to create multiple entries within the package that are different, but share the same file path. That’s why it is crucial that the processes that load the package and those that validate integrity use the same set of rules when it comes to package parsing. Therefore, strict integrity validation must eliminate the risk of verifying one file and then running another.
This kind of an attack on integrity validation processes has been discussed at the BlackHat conference in 2013. The team from BlueBox held a presentation titled Android: One Root to Own Them All.
ReversingLabs solutions understand path squashing and prohibit whitelisting in cases where it can be misused to bypass package integrity validation.
Digital signing is usually an afterthought when it comes to file format design. Because of that, the integrity validation piece tends to have limitations that allow content additions or changes post-signing. Whenever such an opportunity arises, it is bound to be misused by both the people creating legitimate content and the ones trying to hide malware within it. This uncertainty makes it hard to outright ban such misuse, but our security models can be adapted to lessen its impact. ReversingLabs actively prohibits whitelisting when it encounters such cases. More importantly, it alerts the developers that such behavior introduces risk and that it should be avoided. Those notifications are just a small piece of a larger picture in which ReversingLabs solutions enhance secure code development.
Code signing has a huge impact on creating, shipping and deploying secure code. We will cover this topic in great depth in our upcoming blogs.