Meta-artifacts of MetaStealer, a macOS infostealer
Preknowledge
- Golang binaries are compiled with all dependencies statically linked within the binary, and binaries can be cross-compiled easily to other platforms, including our beloved macOS with minimal effort.
- Third-party packages are imported within their fully qualified name and provide a source, like
github.com/google.com/uuid
- These characteristics enable us to do some neat things:
- Review dependencies to derive information about binary capability.
- Generate fingerprints (a dependency, or a group of dependencies) for binary identification.
- Provide a lead for intelligence, if third-party packages are available in open-sources.
- In effect, this is a similar technique to Import Address Table Analysis1.
๐ฆ Sample Identification
Sample Properties
Property | Value |
---|---|
SHA-256 | 2b8dbc84b9d381d686cc5165e8f7be20efdc9bf054c25ff3bdbe2964526c281e |
Filetype | Macho-O 64-bit x86_64 executable |
Names | /services , wild |
๐ MetaStealer - Static Analysis
Build Info Dependencies
Reviewing the Build Info Dependencies (provided by GoReSym2), we note the presence of:
- github.com/google/uuid (v1.3.0)
- github.com/jaskaur18/gary-macos-stealer-golang (devel)
- github.com/kardianos/service (v1.2.2)
This indicates that the module, jaskaur18/gary-macos-stealer-golang
is built into the binary. From its name alone it is identified that it is a macOS Stealer, but the (devel) also indicates to us that this is not a published or properly versioned module.
It is noted within the VirusTotal corpus, there are 4 other samples that contain this dependency3 and also the string jaskaur18
4 has other samples repositories that sound suspicious.
Strings
Go binaries are chunky and strings are not null-terminated; making it difficult to make sense of strings output5. However, the presence of osx-mac[.]com helps identify that this is related to MetaStealer (as discussed later.)
URLs
https://api.osx-mac[.]com
https://ifconfig[.]me/ipidna
File Paths
/Library/Keychains/login.keychain-db0123456789abcdefghijklmnopqrstuvwxyz444089209
๐งจ MetaStealer - Dynamic Analysis
Detonating this malware within a virtual machine environment revealed:
Targeted Data
Although not exhaustive, the following data was staged to a temporary location on disk files.tar.gz
. It is important to note that a limitation to “what files were touched” is that the malware may have some intelligence about looking at which files to touch; for instance, if there is no Google Chrome installed on the device it will not open the Google Chrome passwords directory.
Fortunately, macOS’s Transparency, Consent and Control (TCC)6 mechanism alerts end-users when many of these protected folders are to be read.
Data | Comment |
---|---|
login.keychain-db | User’s keychain7 |
keychain | User’s keychain7 |
/Documents/* | Files from User’s Documents folder |
/Music/* | Files from User’s Music folder |
/Downloads/* | Files from User’s Downloads folder |
/Desktop/* | Files from User’s Desktop folder |
/Pictures/* | Files from User’s Pictures folder |
/Movies/* | Files from User’s Movies folder |
/Public/Drop Box/ | Files from User’s Public folder |
Keychain Access Methodology
macOS’s Keychain is intended to only be read by the user; so access is blocked by default. The sample achieve keychain access by masquearding as an official macOS dialog. It was also noted that if an incorrect password was observed, the password dialog will reapear asking for the same information.
osascript -e display dialog "MacOS wants to access the System Preferences, enter your password to allow this" default answer "" with title "System Preferences" with text buttons {"Allow"} with icon file posix file "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/LockedIcon.icns" default button 1 with hidden answer
Persistence Mechanism(s)
Persistence is achieved via calling a LaunchAgent with RunAtLoad enabled calling a dropped binary containing the infostealer. The application leverages techniques to masquerade the intention of this via hidden files as misleading service names. It should be noted that macOS did 13.5.2 (Build 22G91) did provide an alert to us that a Background Item was added.
Binary Drop
/Users/king/.services/.services SHA256:dfef6ae5775d5cf69a6a5275fc22ddf7a4c17cb00ba3cdcba910dd19ea2fe2c0
LaunchAgent Installation
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
<false/>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>App Background Service</string>
<key>ProgramArguments</key>
<array>
<string>/Users/king/.services/services</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>SessionCreate</key>
<false/>
<key>StandardErrorPath</key>
<string>/Users/king/App Background Service.err.log</string>
<key>StandardOutPath</key>
<string>/Users/king/App Background Service.out.log</string>
</dict>
</plist>
Exfiltration
The following connections were observed on execution of the sample. Additional runs of the bacground service resulted in the same IP Addresses and the presence within Strings informs us that this is not likely dynamically retrieved. As we have observed connectivity to a known Metastealer domain and IP address, as well as byte transfer we can say with confidence that this is a MetaStealer variant.8
Network Connections (enriched w/ requestedDomain)
"connections": [
{
"interface": "en0",
"protocol": "TCP",
"remoteAddress": "13.125.88.10",
"remotePort": "443",
"remoteHostName": "ec2-13-125-88-10.ap-northeast-2.compute.amazonaws.com",
"state": "Established",
"requestedDomain": "api.osx-mac[.]com"
},
{
"interface": "en0",
"protocol": "TCP",
"remoteAddress": "34.160.111.145",
"remotePort": "443",
"remoteHostName": "145.111.160.34.bc.googleusercontent.com",
"state": "Established",
"requestedDomain": "34.160.111.145"
},
{
"interface": "en0",
"protocol": "TCP",
"remoteAddress": "13.125.88.10",
"remotePort": "443",
"remoteHostName": "ec2-13-125-88-10.ap-northeast-2.compute.amazonaws.com",
"state": "Established",
"requestedDomain": "api.osx-mac[.]com"
}
Anything out of the ordinary for an infostealer?
Both static and dynamic analysis has not shown anything abnormal of an infostealer[11]. That being said, there may be some code-paths that I had not been able to trigger or other things missed.
In Cutter, we note the symbol sym._main.executeExternalExecutable
.
executeExternalExecutable
two system calls, _runtime.newobject
and _runtime.newproc
. This suggests allocating space in memory and then running said allocated memory as a process. This could be risky; depending whether on what the object being allocated and ran is.
X-Refs indicate that this happens prior to the BGServiceStart method; so it does appear unrelated to the persistence mechanism.
๐ต๏ธโโ๏ธ Detection Opportunities
TBD
๐ง Final thoughts
- As the binary is one of few samples not stripped; we can infer capabilities of the current
gary-macos-stealer
. New additions or subtractions to the modules may allow us to infer how any new campaigns may be structured. - We can leverage the GitHub username to identify the individual, and their activity. For instance, if we see that they have starred a popular C2 macOS library, this may allude to the fact that they will be expanding the environment.
Dependency Names
Core
core.GetLog
core.GetTask
Module
modules.CreateKeychain
modules.GetBrowserNewWallets
modules.GetBrowserProfiles
modules.GetBrowsers
modules.GetBrowsers.func1
modules.GetBrowsers.func1.1
modules.GetBrowsers.func2
modules.GetFiles
modules.GetKeychain
modules.GetMetamasks
modules.GetNewCoinomi
modules.GetNewExodus
modules.GetNewWallets
modules.GetNewWallets.func1
modules.GetNewWallets.func2
modules.GetTelegram
modules.MetamaskPopup
modules.SendLog
modules.SendLog.func1
modules._ptr_Files.GetFiles
modules._ptr_Files.GetFiles.func1
modules._ptr_Files.GetFiles.func1.1
modules._ptr_Files.GetFiles.func2
modules._ptr_Files.GetFiles.func3
modules._ptr_Keychain.DecryptKeychain
modules._ptr_Keychain.DumpKeyChain
modules._ptr_Keychain.DumpKeyChain.func1
modules._ptr_Keychain.ExtractSafeStoragePassword
modules._ptr_Keychain.UploadKeychain
modules.getApplicationPath
modules.getChromeProfiles
modules.getChromeProfilesList
modules.getFirefoxProfileData
modules.getFolders
modules.init
Utils
utils.CloneExecutable
utils.CloneExecutable.func1
utils.CloneExecutable.func2
utils.CopyFileToFolder
utils.CopyFileToFolder.func1
utils.CopyFileToFolder.func2
utils.CopyFolder
utils.CopyFolderWithSubDirectories
utils.CopyFolderWithSubDirectories.func1
utils.CopyFolderWithSubDirectories.func2
utils.DisplayErrorPopup
utils.DownloadImage
utils.DownloadImage.func1
utils.DownloadImage.func2
utils.ExtractAndUploadFiles
utils.ExtractAndUploadFiles.func1
utils.GetApplicationPath
utils.GetHostname
utils.GetIP
utils.GetIP.func
utils.GetProfileSections
utils.MetamaskDecrypter
utils.MetamaskDecrypter.func1
utils.PostApi
utils.PostApi.func1
utils.PostApi.func2
utils.PostTGLog
utils.PostTGLog.func1
utils.RunExecutableInBackground
utils.ZipFolder
utils.ZipFolder.func1
utils.ZipFolder.func1.1
utils.ZipFolder.func2
utils.ZipFolder.func3
utils.ZipFolder.func4
utils.init
https://reverseengineering.stackexchange.com/questions/16870/import-table-vs-import-address-table ↩︎
https://www.digitalocean.com/community/tutorials/importing-packages-in-go#step-1-using-standard-library-packages ↩︎
https://www.virustotal.com/gui/search/goresym%253Agithub.com%252Fjaskaur18/files ↩︎
https://www.sentinelone.com/labs/alphagolang-a-step-by-step-go-malware-reversing-methodology-for-ida-pro/ ↩︎
https://book.hacktricks.xyz/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-tcc ↩︎
https://eclecticlight.co/2022/10/15/explainer-keychain-basics/ ↩︎ ↩︎
https://appleinsider.com/articles/23/09/16/macos-metastealer-attacks-go-after-business-user-data ↩︎