{"id":8213,"date":"2019-04-09T12:00:00","date_gmt":"2019-04-09T09:00:00","guid":{"rendered":"https:\/\/blog.eset.ee\/et\/2019\/04\/09\/oceanlotus-macos-malware-update\/"},"modified":"2019-04-09T12:00:00","modified_gmt":"2019-04-09T09:00:00","slug":"oceanlotus-macos-malware-update","status":"publish","type":"post","link":"https:\/\/blog.eset.ee\/et\/en\/2019\/04\/09\/oceanlotus-macos-malware-update\/","title":{"rendered":"OceanLotus: macOS malware update"},"content":{"rendered":"<p>Early in March 2019, a new macOS malware sample from the OceanLotus group was uploaded to VirusTotal, a popular online multi-scanner service. This backdoor executable bears the same features as the previous macOS variant we looked at, but its structure has changed and its detection was made harder. Unfortunately, we couldn&#8217;t find the dropper associated with this sample so we do not know the initial compromise vector.<\/p>\n<p>We <a href=\"https:\/\/www.welivesecurity.com\/03\/20\/fake-or-fake-keeping-up-with-oceanlotus-decoys\/index.html\">recently published a detailed update about OceanLotus<\/a> and how its operators employ a wide range of techniques to gain code execution, achieve persistence, and leave as little trace as possible on a Windows system. OceanLotus is also known to have a malicious macOS component. This article details what has changed from the previous macOS <a href=\"https:\/\/blog.trendmicro.com\/trendlabs-security-intelligence\/new-macos-backdoor-linked-to-oceanlotus-found\/\">version analyzed by Trend Micro<\/a> and describes how, while analyzing this variant\u2019s code, you can automate string decryption using the IDA Hex-Rays API.<\/p>\n<h1>Analysis<\/h1>\n<p>The following three sections of this blogpost describe the analysis of the sample with the SHA-1 hash <span>E615632C9998E4D3E5ACD8851864ED09B02C77D2<\/span>. The file is named flashlightd and is detected by ESET products as OSX\/OceanLotus.D.<\/p>\n<h2>Anti-debug and anti-sandbox<\/h2>\n<p>As usual for OceanLotus macOS binaries, the sample is packed with UPX, but most packer identification tools do not recognize it as such, probably because they mostly include a signature that relies on the presence of a \u201cUPX\u201d string, and further, Mach-O signatures are less common and not as regularly updated. This particular characteristic makes static detection more difficult. Once unpacked, one interesting thing is that the entry point is located at the beginning of the <span>__cfstring<\/span> section in the <span>.TEXT<\/span> segment. This section has the flag attributes seen in Figure 1.<\/p>\n<\/p>\n<div><a  href=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-1-wm-1.png\" data-rel=\"lightbox-gallery-0\" data-rl_title=\"\" data-rl_caption=\"\" data-magnific_type=\"gallery\" title=\"\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"320\" src=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-1-wm-1.png\" width=\"585\"><\/a><\/p>\n<p><i>Figure 1. MACH-O <span>__cfstring<\/span> section attributes<\/i><\/p>\n<\/div>\n<p>As seen in Figure 2, the fact that the code is in the <span>__cfstring<\/span> section tricks some disassembly tools to display the code as strings.<\/p>\n<\/p>\n<div><a  href=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-2-wm2.png\" data-rel=\"lightbox-gallery-0\" data-rl_title=\"\" data-rl_caption=\"\" data-magnific_type=\"gallery\" title=\"\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"65\" src=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-2-wm2.png\" width=\"585\"><\/a><\/p>\n<p><i>Figure 2. The backdoor code is defined as data by IDA<\/i><\/p>\n<\/div>\n<p>When run, the binary first creates a thread as an anti-debugging watchdog whose sole purpose is to continuously check if a debugger is present. In order to do that, this thread:<\/p>\n<ul>\n<li>Tries to detach any debugger by calling <span>ptrace <\/span>with <span>PT_DENY_ATTACH<\/span> as a request parameter<\/li>\n<li>Checks if some exception ports are open by calling the <span>task_get_exception_ports<\/span> function<\/li>\n<li>Checks if a debugger is attached, as seen in Figure 3, by verifying if the <span>P_TRACED<\/span> flag is set in the current process<\/li>\n<\/ul>\n<div><a  href=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-3-wm.png\" data-rel=\"lightbox-gallery-0\" data-rl_title=\"\" data-rl_caption=\"\" data-magnific_type=\"gallery\" title=\"\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"167\" src=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-3-wm.png\" width=\"585\"><\/a><\/p>\n<p><i>Figure 3. Check if a debugger is attached via <span>sysctl<\/span> function<\/i><\/p>\n<\/div>\n<p>If the watchdog detects that a debugger is present the <span>exit <\/span>function is called. Moreover, the sample then checks its environment by issuing the following two commands:<br \/>\n<span>ioreg -l | grep -e &#8220;Manufacturer&#8221;<\/span> and <span>sysctl hw.model<\/span><br \/> and checks the return value against a hardcoded list of known virtualization system strings: oracle, vmware, virtualbox or parallels. Finally, the command:<br \/>\n<span>system_profiler SPHardwareDataType 2&gt;\/dev\/null | awk &#8216;\/Boot ROM Version\/ {split($0, line, &#8220;:&#8221;);printf(&#8220;%s&#8221;, line[2]);}<\/span><br \/> checks if the machine is one of the following: &#8220;MBP&#8221;, \u201cMBA\u201d, \u201cMB\u201d, \u201cMM\u201d, \u201cIM\u201d, \u201cMP\u201d and \u201cXS\u201d. These codes represent the model of the system. For instance, \u201cMBP\u201d stands for MacBook Pro, \u201cMBA\u201d stands for MacBook Air and so on\u2026<\/p>\n<h2>Major updates<\/h2>\n<p>Even though the backdoor commands have not changed since the Trend Micro article, we noticed a few other modifications. The C&amp;C servers used for this sample are quite recent as their creation date is 2018-10-22.<\/p>\n<ul>\n<li><span>daff.faybilodeau[.]com<\/span><\/li>\n<li><span>sarc.onteagleroad[.]com<\/span><\/li>\n<li><span>au.charlineopkesston[.]com<\/span><\/li>\n<\/ul>\n<p>The URL resource used has changed to <span>\/dp\/B074WC4NHW\/ref=gbps_img_m-9_62c3_750e6b35<\/span>.<\/p>\n<p>The first packet that is sent to the C&amp;C server contains more information regarding the host machine. All data gathered by the commands in the following table are included.<\/p>\n<\/p>\n<table>\n<thead>\n<tr>\n<th>Commands<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<ul>system_profiler SPHardwareDataType 2&gt;\/dev\/null <\/p>\n<li>awk &#8216;\/Processor \/ {split($0,line,&#8221;:&#8221;); printf(&#8220;%s&#8221;,line[2]);}&#8217;<\/li>\n<p>machdep.cpu.brand_string<\/p>\n<\/ul>\n<\/td>\n<td>Gather processor information<\/td>\n<\/tr>\n<tr>\n<td>\n<ul>system_profiler SPHardwareDataType 2&gt;\/dev\/null <\/p>\n<li>awk &#8216;\/Memory\/ {split($0,line, &#8220;:&#8221;); printf(&#8220;%s&#8221;, line[2]);}&#8217;<\/li>\n<\/ul>\n<\/td>\n<td>Gather memory information<\/td>\n<\/tr>\n<tr>\n<td>ifconfig -l<\/td>\n<td>Gather network interface MAC addresses<\/td>\n<\/tr>\n<tr>\n<td>\n<ul>ioreg -rd1 -c IOPlatformExpertDevice <\/p>\n<li>awk &#8216;\/IOPlatformSerialNumber\/ { split($0, line, &#8220;&#8221;&#8221;); printf(&#8220;%s&#8221;, line[4]); }&#8217;<\/li>\n<\/ul>\n<\/td>\n<td>Retrieves the serial number of the device<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>On top of this configuration change, this sample does not use the <a href=\"https:\/\/curl.haxx.se\/libcurl\/\">libcurl<\/a> library for network exfiltration. Instead, it uses an external library. To locate it, the backdoor tries to decrypt each file in the current directory using AES-256-CBC with the key <span>gFjMXBgyXWULmVVVzyxy <\/span>padded with zeroes. Each file is \u201cdecrypted\u201d and saved as <span>\/tmp\/store <\/span>and an attempt to load it as a library made using the <a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/System\/Conceptual\/ManPages_iPhoneOS\/man3\/dlopen.3.html\">dlopen<\/a> function. When a decryption attempt results in a successful call to dlopen, the backdoor then retrieves the exported functions <span>Boriry <\/span>and <span>ChadylonV<\/span><strong>,<\/strong> which seem to be responsible for the network communication with the server. As we do not have the dropper or other files from the original sample\u2019s location, we could not analyse this library. Moreover, since the component is encrypted, a YARA rule based on these strings would not match the file found on disk.<\/p>\n<p>As described in the analysis of the group\u2019s previous macOS backdoor, a <em>clientID<\/em> is created. This identifier is the MD5 hash of the return value of one of the following commands:<\/p>\n<ul>\n<li><span>ioreg -rd1 -c IOPlatformExpertDevice | awk &#8216;\/IOPlatformSerialNumber\/ { split($0, line, &#8220;&#8221;&#8221;); printf(&#8220;%s&#8221;, line[4]); }&#8217;<\/span><\/li>\n<li><span>ioreg -rd1 -c IOPlatformExpertDevice | awk &#8216;\/IOPlatformUUID\/ { split($0, line, &#8220;&#8221;&#8221;); printf(&#8220;%s&#8221;, line[4]); }&#8217;<\/span><\/li>\n<li><span>ifconfig en0 | awk &#8216;\/ether \/{print $2}&#8217;<\/span> (obtain the MAC address)<\/li>\n<li>an unknown command (&#8220;<span>x1ex72x0a<\/span>&#8220;) which used to be \u201cuuidgen\u201d in the previous samples<\/li>\n<\/ul>\n<p>Before being hashed, the character \u201c0\u201d or \u201c1\u201d is appended to the return value indicating root privileges. This <em>clientID<\/em> is stored in <span>\/Library\/Storage\/File System\/HFS\/25cf5d02-e50b-4288-870a-528d56c3cf6e\/pivtoken.appex<\/span> if the code runs as root, or in <span>~\/Library\/SmartCardsServices\/Technology\/PlugIns\/drivers\/snippets.ecgML<\/span> otherwise. This file is normally hidden via the <a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/System\/Conceptual\/ManPages_iPhoneOS\/man2\/chflags.2.html\">_<span>chflags<\/span><\/a> function and its timestamp is modified using the \u201c<span>touch \u2013t<\/span>\u201d command with a random value.<\/p>\n<h2>String decryption<\/h2>\n<p>Like previous variants, the strings are encrypted using AES-256-CBC (hex-encoded key: <span>9D7274AD7BCEF0DED29BDBB428C251DF8B350B92<\/span> padded with zeroes and the IV is filled with zeroes) using the <span><a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/System\/Conceptual\/ManPages_iPhoneOS\/man3\/CCCrypt.3cc.html\">CCCrypt<\/a><br \/>\n<\/span>function. The key has changed from previous versions but since the group is still using the same algorithm to encrypt strings, decryption could be automated. Along with this article, we are releasing an IDA script leveraging the Hex-Rays API to decrypt the strings present in the binary. This script may help future analysis of OceanLotus and the analysis of existing samples that we have not yet been able to obtain. At the core of this script lies a generic method to obtain the arguments passed to a function. Moreover, it looks for the parameter assignments in order to find their values. This method could be reused to retrieve the list of arguments of a function and then pass them to a callback.<\/p>\n<p>Knowing the prototype of the <em>decrypt<\/em> function, the script first finds all cross-references to this function, finds all the arguments, decrypts the data and puts the plaintext inside a comment at the address of the cross-reference. In order for the script to work correctly, the custom alphabet used by the base64 decode function must be set in the script and the global variable containing the length of the key must be defined (as a DWORD in this case; see Figure 4).<\/p>\n<\/p>\n<div><a  href=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-4-wm.png\" data-rel=\"lightbox-gallery-0\" data-rl_title=\"\" data-rl_caption=\"\" data-magnific_type=\"gallery\" title=\"\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"113\" src=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-4-wm.png\" width=\"691\"><\/a><\/p>\n<p><i>Figure 4. Defining the global variable <em><span>key_len<\/span><\/em><\/i><\/p>\n<\/div>\n<p>In the <em>Function<\/em> window, you can right-click the decryption function and click \u201cExtract and decrypt arguments\u201d. The script should put the decrypted strings in comments, much as in Figure 5.<\/p>\n<\/p>\n<div><a  href=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-5-wm.png\" data-rel=\"lightbox-gallery-0\" data-rl_title=\"\" data-rl_caption=\"\" data-magnific_type=\"gallery\" title=\"\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"501\" src=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-5-wm.png\" width=\"691\"><\/a><\/p>\n<p><i>Figure 5. Decrypted text is put into comments<\/i><\/p>\n<\/div>\n<p>This conveniently lists the decrypted strings together in IDA\u2019s <em>xrefs to<\/em> window for that function, as seen in Figure 6.<\/p>\n<\/p>\n<div><a  href=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-6-wm.png\" data-rel=\"lightbox-gallery-0\" data-rl_title=\"\" data-rl_caption=\"\" data-magnific_type=\"gallery\" title=\"\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"311\" src=\"https:\/\/web-assets.esetstatic.com\/wls\/2019\/04\/Figure-6-wm.png\" width=\"691\"><\/a><\/p>\n<p><i>Figure 6. <em>Xrefs<\/em> to of <em><span>f_decrypt<\/span><br \/>\n<\/em>function<\/i><\/p>\n<\/div>\n<p>The final script can be found on our <a href=\"https:\/\/github.com\/eset\/malware-research\/tree\/master\/oceanlotus\/\">Github repository<\/a>.<\/p>\n<h1>Conclusion<\/h1>\n<p>As recently documented in another of our <a href=\"https:\/\/www.welivesecurity.com\/03\/20\/fake-or-fake-keeping-up-with-oceanlotus-decoys\/index.html\">articles<\/a>, the OceanLotus group keeps improving and updating its toolset, and once again, it has improved its tools for targeting Mac users. The code has not changed that much, but because many Mac users don\u2019t run security software on their machines, the need to evade detection is of less importance. ESET products already detected this file when we found it. Since the network library used for the C&amp;C communication is now encrypted on the disk, the exact network protocol used remains unknown.<\/p>\n<h1>Indicators of Compromise (IoCs)<\/h1>\n<p>The IoCs in this blogpost, as well as the MITRE ATT&amp;CK attributes, are also available in our <a href=\"https:\/\/github.com\/eset\/malware-ioc\/tree\/master\/oceanlotus\">GitHub repository<\/a>.<\/p>\n<h2>Domain names<\/h2>\n<ul>\n<li><span>daff.faybilodeau[.]com<\/span><\/li>\n<li><span>sarc.onteagleroad[.]com<\/span><\/li>\n<li><span>au.charlineopkesston[.]com<\/span><\/li>\n<\/ul>\n<h2>URL resource<\/h2>\n<ul>\n<li><span>\/dp\/B074WC4NHW\/ref=gbps_img_m-9_62c3_750e6b35<\/span><\/li>\n<\/ul>\n<h2>File paths<\/h2>\n<ul>\n<li><span>~\/Library\/SmartCardsServices\/Technology\/PlugIns\/drivers\/snippets.ecgML<\/span><\/li>\n<li><span>\/Library\/Storage\/File System\/HFS\/25cf5d02-e50b-4288-870a-528d56c3cf6e\/pivtoken.appex<\/span><\/li>\n<li><span>\/tmp\/store<\/span><\/li>\n<\/ul>\n<table>\n<thead>\n<tr>\n<th>Sample analyzed<\/th>\n<th>SHA-1 hash<\/th>\n<th>ESET detection name<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>fleshlightd<\/td>\n<td>E615632C9998E4D3E5ACD8851864ED09B02C77D2<\/td>\n<td>OSX\/OceanLotus.D<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h1><a href=\"https:\/\/attack.mitre.org\/matrices\/enterprise\/macos\/\">MITRE ATT&amp;CK techniques<\/a><\/h1>\n<\/p>\n<table>\n<thead>\n<tr>\n<th>Tactic<\/th>\n<th>ID<\/th>\n<th>Name<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td rowspan=\"5\">Defense Evasion<\/td>\n<td><a href=\"https:\/\/attack.mitre.org\/techniques\/T1158\/\"><b>T1158<\/b><\/a><\/td>\n<td>Hidden Files and Directories<\/td>\n<td>The backdoor hides the <em>clientID <\/em> file via <span><strong>chflags<\/strong><\/span> function.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/attack.mitre.org\/techniques\/T1107\/\"><b>T1107<\/b><\/a><\/td>\n<td>File Deletion<\/td>\n<td>The backdoor can receive a \u201cdelete\u201d command.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/attack.mitre.org\/techniques\/T1222\/\"><b>T1222<\/b><\/a><\/td>\n<td>File Permissions Modification<\/td>\n<td>The backdoor changes the permission of the file it wants to execute to 755.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/attack.mitre.org\/techniques\/T1027\/\"><b>T1027<\/b><\/a><\/td>\n<td>Obfuscated Files or Information<\/td>\n<td>The library used for network exfiltration is encrypted with AES-256 in CBC mode.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/attack.mitre.org\/techniques\/T1099\/\"><b>T1099<\/b><\/a> (macOS)<\/td>\n<td>Timestomp<\/td>\n<td>The timestamp of the file storing the clientID is modified with a random value.<\/td>\n<\/tr>\n<tr>\n<td>Discovery<\/td>\n<td><a href=\"https:\/\/attack.mitre.org\/techniques\/T1082\/\"><b>T1082<\/b><\/a><\/td>\n<td>System Information Discovery<\/td>\n<td>The backdoor performs a fingerprint of the machine on its first connection to the C&amp;C server.<\/td>\n<\/tr>\n<tr>\n<td>Exfiltration<\/td>\n<td><a href=\"https:\/\/attack.mitre.org\/techniques\/T1022\/\"><b>T1022<\/b><\/a><\/td>\n<td>Data Encrypted<\/td>\n<td>The backdoor encrypts the data before exfiltration.<\/td>\n<\/tr>\n<tr>\n<td>Command and Control<\/td>\n<td><a href=\"https:\/\/attack.mitre.org\/techniques\/T1094\/\"><b>T1094<\/b><\/a><\/td>\n<td>Custom Command and Control Protocol<\/td>\n<td>The backdoor implements a specific format for the packet involving random values. See <a href=\"https:\/\/blog.trendmicro.com\/trendlabs-security-intelligence\/new-macos-backdoor-linked-to-oceanlotus-found\/\">Trend Micro article<\/a>.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"wls-source\"><a href=\"https:\/\/www.welivesecurity.com\/2019\/04\/09\/oceanlotus-macos-malware-update\/\" rel=\"nofollow noopener\" target=\"_blank\">Read the full analysis on WeLiveSecurity \u2192<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Latest ESET research describes the inner workings of a recently found addition to OceanLotus\u2019s toolset for targeting Mac users<\/p>\n","protected":false},"author":5,"featured_media":8214,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2878],"tags":[],"class_list":["post-8213","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-eset-research"],"acf":[],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/posts\/8213","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/comments?post=8213"}],"version-history":[{"count":0,"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/posts\/8213\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/media\/8214"}],"wp:attachment":[{"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/media?parent=8213"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/categories?post=8213"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.eset.ee\/et\/en\/wp-json\/wp\/v2\/tags?post=8213"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}