toastsec

Meta-artifacts of MetaStealer, a macOS infostealer

Preknowledge


๐Ÿฆ  Sample Identification

Sample Properties

PropertyValue
SHA-2562b8dbc84b9d381d686cc5165e8f7be20efdc9bf054c25ff3bdbe2964526c281e
FiletypeMacho-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 jaskaur184 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.

DataComment
login.keychain-dbUser’s keychain7
keychainUser’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. X-Ref of metaStealer’s ExecuteExternalExecutable


๐Ÿ•ต๏ธโ€โ™‚๏ธ Detection Opportunities

TBD

๐Ÿง  Final thoughts

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