One of the basic checks which all malware protection should make is whether apps and other code have been correctly signed. Details of a bug revealed in Twitter today by Patrick Wardle, of Securita Security and Objective-See, demonstrate that most anti-malware tools can easily be spoofed into accepting completely fictitious certificates.
The problem lies buried in a macOS Global Function,
SecStaticCodeCheckValidity(), which is used by almost all signature-checking tools and apps (including Apple’s command line tools) to validate the signature of a file. Apple’s description of this function reads:
This function obtains and verifies the signature on the code specified by the code object. It checks the validity of all sealed components, including resources (if any). It validates the code against a code requirement if one is specified. The call succeeds if all these conditions are satisfactory.
It is possible for a malware author to trick this function into returning a successful result, claiming that there is a valid certificate from Apple, although there is nothing of the kind.
macOS Gatekeeper doesn’t appear to be affected by this, so it should still return reliable results. However, the flawed function is used by most, perhaps all, other anti-malware tools. Malware which exploits this vulnerability could therefore pass this stage of their checks.
Patrick has found a workaround, and has already updated Objective-See’s invaluable signature-checking tool What’s My Sign?, which shouldn’t now succumb to this spoofing. If you rely on any other malware checking tools, such as an anti-virus product, you may want to install the updated What’s My Sign? (version 1.4.1) and perform manual checks until that product has been updated to address this problem.
Anti-virus and security product vendors should already be busy preparing updates to all their apps.
Patrick Wardle points out that this bug was first discovered and reported by Josh Pitts. He also reports that
SecStaticCodeCheckValidity() does work if you tell it to perform strict verification, or to verify all the architectures in the file. However, its default flags (which should validate the ‘native’ architecture which will run when you run the code) fail in this case, resulting in this incorrect behaviour.