Earlier this week Apple issued an update to macOS Big Sur bringing it up to version 11.3. This update included a security fix for a vulnerability within the macOS Gatekeeper security system, and given the ID of “CVE 2021-30657”. This vulnerability was disclosed to Apple by an expert macOS Security Researcher Cedric Owens (Twitter: @cedowens, GitHub: cedowens).
This vulnerability exploits a logic bug within the macOS policy subsystem (“syspolicyd”) that allows for "apps'' crafted in a specific manner to get executed and completely bypass the usual signing requirements imposed by the Gatekeeper system.
MacOS apps usually have a directory structure that looks like <Name>.app/Contents/MacOS/<Name>”. This last file is usually a Mach-O file that shares the same name as the app that is executed. Normally Gatekeeper checks to ensure that this Mach-O file has been signed and notarized if it contains the quarantine attribute "com.apple.quarantine", which is appended automatically to any files downloaded from sources such as web browsers or AirDrop.
Cedric took that knowledge and asked the question, "What if I replace the Mach-O file with a script? Since scripts are not checked by Gatekeeper." I think we all know how this test turned out at this point or you wouldn't be here reading this blog post.
So, how can we mitigate this vulnerability? The very best way would be to update to Big Sur 11.3 or install the Catalina Security Update 2021-002. If those are not feasible we can use Uptycs to monitor for similar behavior. We will be adding an alert for this behavior into an upcoming release, but in the meantime, you can add the following as a SQL-based Alert Rule:
SELECT upt_time AS time,
upt_hostname AS hostname,
pid AS processId,
path,
cmdline AS cmdLine,
uid AS userId,
ancestor_list AS ancestorList,
sha256
FROM process_events
WHERE parent = 1
AND cmdline LIKE '%/Contents/MacOS/%'
AND (
path LIKE '/bin/%sh'
OR path LIKE '/System/Library/Frameworks/%.framework/Versions/%/bin/%'
)
AND upt_time >= :from
AND upt_time < :to
AND upt_added = TRUE
ORDER BY upt_time DESC
If reading SQL queries isn't your thing, let's break it down and understand what we're looking for here.
SELECT upt_time AS time,
upt_hostname AS hostname,
pid AS processId,
path,
cmdline AS cmdLine,
uid AS userId,
ancestor_list AS ancestorList,
sha256
FROM process_events
This SELECT statement is just asking for specific columns from the process_events table and renames them with an AS statement to make reading easier.
Next we have the WHERE clause. This is the meat and potatoes of our SQL query and specifies the parameters we want to look for.
WHERE parent = 1
AND cmdline LIKE '%/Contents/MacOS/%'
AND (
path LIKE '/bin/%sh'
OR path LIKE '/System/Library/Frameworks/%.framework/Versions/%/bin/%'
)
AND upt_time >= :from
AND upt_time < :to
AND upt_added = TRUE
Our last line `ORDER BY upt_time DESC` is just to make sure that any results returned will show with the latest entries at the top of the table.
That's all there is to it. I believe the false-positive rate on this query should be low in most environments. I've tested it against things like Automator scripts and they don't trigger this alert because their parent process isn't launchd.
All credit for this vulnerability and relevant information goes to Cedric Owens.
Thanks to his fantastic blog post as well as the incredibly in-depth post by Patrick Wardle of Objective-See ().
Read both of those if you want all of the technical details on this exploit and how it works.