Earlier today, Google’s VirusTotal published a blog post about a new way to bypass code signing in Windows via JAR files:
Microsoft Windows keeps the Authenticode signature valid after appending any content to the end of Windows Installer (.MSI) files signed by any software developer. This behaviour can be exploited by attackers to bypass some security solutions that rely on Microsoft Windows code signing to decide if files are trusted. The scenario is especially dangerous when the appended code is a malicious JAR because the resulting file has a valid signature according to Microsoft Windows and the malware can be directly executed by Java.
In short, an attacker can append a malicious JAR to a MSI file signed by a trusted software developer (like Microsoft Corporation, Google Inc. or any other well-known developer), and the resulting file can be renamed with the .jar extension and will have a valid signature according Microsoft Windows. For example, via the command “copy /b signed.msi + malicious.jar signed_malicious.jar”. The victim can be infected with just a double-click in such a file.
Here are some quick thoughts from our research team – note that we were not involved in this effort and have no insider knowledge. This is entirely based on public sources.
How can ZIP and EXE files be combined?
First of all, how is it possible that the same exact file can be executable both by Windows and Java? The trick lies in how Windows executable files work – as described in Microsoft’s documentation. Basically, the OS reads the file from the beginning, looking at the magic value of “MZ” followed by headers, then followed by the file content. We are going to assume that there is a table in the file that tells the reader how long each segment is, and therefore it is possible to append arbitrary data to the end of the file without it breaking.
A JAR file, however, is essentially a ZIP file. ZIP files have their index or central directory in the end of the file, and it is possible to prepend data in the beginning of the file and that file still being valid. That means that you can combine a Windows executable that is read from the beginning and rely on its headers and tables to tell the reader where to stop, and do the same for the ZIP content in the end of the file. Both files remain valid, while combined together. Also, while the example provided by VirusTotal is a JAR file, the same trick would work for other ZIP-based formats like Microsoft Office (DOCX/XSLX/etc), OpenOffice (ODT/ODS/etc), etc. Of course, this assumes that the software reading these files goes to the central directory of the ZIP and doesn’t check the magic value in the beginning.
Here is an modified example of PE files from Wikipedia, and a ZIP file example from OASIS, showing the direction in which file content is read:
What is Microsoft Code Signing / Authenticode?
As per the original blog post and other technical documentation from Microsoft, the code signing in question is Authenticode which is used by Microsoft for Windows executables, drivers, and other files. The purpose it to make sure the file originated from a trusted publisher. There is also a command line tool included in Windows called “SignTool” which is used for signing and verifying files.
The way code signing works is described in a Microsoft technical document here. It is essentially a digital signature using PCKS7 and special X.509 certificates (code signing certificates issued by CAs). It is connected to the same PKI infrastructure as SSL certificates with some additional checks by CAs when issuing the certificate (not at sign time). Like all other digital signatures, it is essentially some sort of a hash signed by a private key of the holder of the certificate which is then verified by the public key in the X.509 certificate. The certificate itself is verified against public PKI infrastructure just like SSL.
Example appears below (from Microsoft documentation):
Bypassing Code Signing
In a standard digital signature scenario such as PGP or S/MIME, the entire content of the message is hashed to produce a message digest using a function like SHA. That hash is then digitally signed using the sender’s private key. Note that the entire message is hashed – this allowing the receiver to check if it was modified or not, not just bits and pieces.
One of the common refrains in security is “never roll your own crypto”, which in this case includes choosing what to hash. In the case of Authenticate, it appears that the file hash does not cover the entire file. As described in this document, information in the end of the file (after the second “remaining content” above) ARE NOT included in the hash (emphasis added):
Information past of the end of the last section. The area past the last section (defined by highest offset) is not hashed. This area commonly contains debug information. Debug information can generally be considered advisory to debuggers; it does not affect the actual integrity of the executable program. It is quite literally possible to remove debug information from an image after a product has been delivered and not affect the functionality of the program. In fact, this is sometimes done as a disk-saving measure. It is worth noting that debug information contained within the specified sections of the PE Image cannot be removed without invaliding the Authenticode signature.
This means that it is trivial to simply append another file like a JAR to the end of another digitally signed file, then rename it a JAR and have the resulting file look valid in Windows since the digital signature check will stop before reading the content of the JAR file. At the same time, the file will be executable by Java since it will read from the end ignoring any of the signed content appearing in the beginning. The same would apply for other ZIP based formats like Microsoft Word and this may allow an attacker to send a malicious document while masquerading it as a legit one. Additionally it appears from the blog post that some A/V and security products use the Authenticode signature as a shortcut to validate files so they don’t need to scan them.
Another possible use of this technique is to make attribution murky since some analysts may take the Authenticode signature at face value and not realize that the malware inside may not be from the publisher that signed the file.
An additional idea would be to use this trick to exfiltrate data out of an organization by putting the extra data in the end of the file. This assumes that the DLP and similar tools monitoring outbound traffic rely on the Authenticode signature as well.
Microsoft’s code signing method isn’t the only one that exists. Similar methods exists for Java, Adobe AIR, Android, MacOS, Debian, etc. Further research is needed to see if similar issues exist in other code signing schemes.
(Written by Yakov Shafranovich)