#### 2 - 4 October, 2024 / Dublin, Ireland # SUGARCOATING KANDYKORN: A SWEET DIVE INTO A SOPHISTICATED MACOS BACKDOOR ## Salim Bitam ### Elastic, The Netherlands #### salim.bitam@elastic.co www virusbulletin com ----- **ABSTRACT** KANDYKORN is a novel macOS backdoor recently discovered by Elastic Security Labs during an intrusion targeting blockchain engineers at a prominent crypto exchange platform. With macOS devices increasingly becoming prime targets, the discovery of KANDYKORN sheds light on new trends being adopted by cybercriminals and state-sponsored actors. Operating covertly, KANDYKORN employs a feature-rich multi-staged loader paired with a custom network protocol to facilitate a range of post-compromise activities. Its diverse functionality includes capabilities that enable lateral movement and data exfiltration while allowing the adversary to remain under the radar. KANDYKORN serves as a prime example of how mature threat groups are adapting to new techniques and targeting their victims. By leveraging social media platforms like Discord with enticing lures, these actors are finding new paths into highly targeted environments. **INTRODUCTION** _Elastic Security Labs disclosed a novel intrusion in late 2023 that specifically targeted blockchain engineers working for a_ cryptocurrency exchange platform. This intrusion exemplifies the advanced tactics employed by threat actors, combining custom-developed tools with publicly available open-source capabilities to achieve both initial access and post-exploitation objectives. This intrusion was discovered during an investigation into attempts to reflectively load a binary into memory on a macOS endpoint. Further analysis revealed that the intrusion began with a Python application disguised as a cryptocurrency arbitrage bot, which was distributed through a direct message on a public Discord server. This method of delivery highlights innovative and deceptive strategies used by attackers to exploit trusted communication channels. This paper will explore the specifics of the intrusion, detailing how the victim was compromised through social engineering tactics and the initial code used to achieve the initial stage of compromise. We will provide an in-depth analysis of KANDYKORN, focusing on its multi-stage loaders, the obfuscation techniques employed, and its diverse capabilities. Additionally, we will discuss the development of a custom tool designed to interact with KANDYKORN, enabling the simulation of the threat. **THE INGENIOUS IMPERSONATION: INITIAL COMPROMISE** The threat group behind KANDYKORN impersonated members of the blockchain engineering community on a public _Discord server frequented by the community members. Through social engineering, the attackers convinced an initial_ victim to download and decompress a ZIP archive containing malicious code. The victim believed they were installing an arbitrage bot, a software tool designed to profit from cryptocurrency rate differences between platforms. The software is a Python application packaged in a ZIP file titled Cross-Platform Bridges.zip. Decompressing it reveals a main.py script accompanied by a folder named order_book_recorder, housing 13 individual Python scripts. _Figure 1: Extracted ZIP with Python scripts._ The victim ran the Python script (main.py), which initially appeared benign. However, upon closer inspection of the other files within the downloaded package, a file named watcher.py caught our attention. This Python script contained a variable with a Google Drive URL, indicating a potential connection to an external resource. The script downloads the content and saves it to a file in ./_log/testSpeed.py. ----- _Figure 2: Python snippet downloading testSpeed.py._ The created file (./_log/testSpeed.py) is then imported as a module, executing the contents of the script. Upon completion of the execution, the file is deleted to cover its tracks. _Figure 3: Python snippet deletes testSpeed.py._ **The first wave: droppers and FinderTools** When executed, the newly dropped file (testSpeed.py) establishes an outbound network connection and fetches another Python file from a Google Drive URL, named FinderTools. This new file is saved to the /Users/Shared/ directory. _Figure 4: Outbound request to download FinderTools._ Next, testSpeed.py executes FinderTools, initializing a new outbound network connection with the following URL as an argument: tp-globa[.]xyz//OdhLca1mLUp/lZ5rZPxWsh/7yZKYQI43S/fP7savDX6c/bfC. _Figure 5: Execution of FinderTools._ _Figure 6: Outbound connection from FinderTools._ ----- ``` FinderTools is yet another dropper, downloading and executing a hidden second-stage payload (.sld) written to the /Users/Shared/ directory. ``` _Figure 7: Execution of .sld (SUGARLOADER)._ **SUGARLOADER’s hidden layers: decoding the .sld payload** The .sld file, a 64-bit macOS binary which we named SUGARLOADER, is an obfuscated binary used twice under two separate names, .sld and .log. The first instance of SUGARLOADER is located at /Users/shared/.sld. The second instance, renamed to .log, is employed as a persistence mechanism. **_Obfuscation_** The main code of SUGARLOADER is packed; before the execution of the start function __mod_init_func is executed, which contains the unpacking code for SUGARLOADER. Numerous junk instructions, opaque predicates and indirect jumps in memory are present within the packed code, complicating the analysis of the unpacking process. An easy way to unpack the code is to put a hardware breakpoint at the start of the packed code. It’s worth noting that a hardware breakpoint is essential due to the preliminary memory checksum validation performed with the CRC32 algorithm before unpacking occurs. _Figure 8: Assembly code obfuscation with dead code._ At the time of the research in late 2023 the sample had zero detections on VirusTotal, mainly due to the packed code. _Figure 9: SUGARLOADER binary with zero hits in VirusTotal._ **_Execution flow_** SUGARLOADER is a loader that fetches a macOS binary from the command-and-control server (C2) and reflectively loads it in memory. It can take the configuration (C2 address and port) from the command line or from a configuration file named /Library/Caches/com.apple.safari.ck. ----- _Figure 10: SUGARLOADER arguments handling pseudocode._ This configuration file is encrypted/decrypted using RC4 with a hard-coded 64-byte key and is utilized by both SUGARLOADER and KANDYKORN for establishing secure network communications. A C2 server can be identified either by a fully qualified URL (c2_urls) or by an IP address and port (c2_ip_address). The system supports two C2 servers: a primary server and a secondary fallback server. This redundancy is a common tactic employed by malicious actors to maintain persistent connectivity with the victim, even if the primary C2 server is taken down or blocked. Additionally, the malware includes a sleepInterval setting, which defines the default time interval it waits between executing separate actions. The last step taken by SUGARLOADER is to download and execute a final stage payload from the C2 server. It takes advantage of a technique known as reflective binary loading to execute the final stage, leveraging APIs such as ``` NSCreateObjectFileImageFromMemory or NSLinkModule. ``` _Figure 11: SUGARLOADER code injection._ SUGARLOADER reflectively loads KANDYKORN, creating a new file initially named appname, which we refer to as HLOADER. This name was taken directly from the process code signature’s signing identifier. _Figure 12: HLOADER code signature signing ID._ **HLOADER’s Discord deception: unravelling stage 3** HLOADER was identified through the use of a macOS binary code-signing technique previously associated with the DPRK’s Lazarus Group, notably seen in the 3CX intrusion [1]. Elastic Security Labs has recognized this technique as an indicator of DPRK campaigns, as highlighted in our June 2023 research publication on JOKERSPY [2]. HLOADER’s is a self-signed binary written in Swift; it’s main purpose is to create persistence on the system through execution flow hijacking [3] of the widely used chat application Discord. This application is often configured by users as a login item and launched when the system boots, making it an attractive target for takeover. It also indicates that the author had a clear understanding of their victims. ----- The purpose of this loader is to execute both the legitimate Discord bundle and the .log payload (SUGARLOADER), the latter of which is used to execute Mach-O binary files from memory without writing them to disk. The legitimate Discord binary, /Applications/Discord.app/Contents/MacOS/Discord, was renamed to .lock and replaced by HLOADER. _Figure 13: Renaming of Discord binary to .lock._ When executed, HLOADER performs a series of operations. First, it renames itself from Discord to MacOS.tmp. Then, it renames the legitimate Discord binary from .lock to Discord. Next, it executes both Discord and .log using ``` NSTask.launchAndReturnError. Finally, it renames both files back to their original names. ``` The process tree shown in Figure 14 visually depicts how persistence is obtained. The root node Discord is actually HLOADER disguised as the legitimate app. As presented above, it first runs .lock, which is in fact Discord, and, alongside, spawns SUGARLOADER as a process named .log. _Figure 14: Process tree analyser._ **Final form: unveiling KANDYKORN’s stage 4 payload** KANDYKORN is the final stage of this execution chain and possesses a full-featured set of capabilities to access and exfiltrate data from the victim’s computer. Elastic Security Labs was able to retrieve this payload from one C2 server which hadn’t been deactivated yet. KANDYKORN processes are forked and run in the background as daemons before loading their configuration file from ``` /Library/Caches/com.apple.safari.ck. ``` _Figure 15: KANDYKORN forking itself after loading its configuration._ ----- An intriguing aspect worth noting is that the binary of KANDYKORN appears to be compiled in debug mode; it contains all its symbols, allowing for comprehensive analysis and understanding of its internal structure and functionality. Additionally, the malware prints debugging information during execution. _Figure 16: KANDYKORN compiled in debug._ The configuration file is read into memory then decrypted using the same RC4 key, and parsed for C2 settings. The communication protocol is similar to prior stages using the victim ID value for authentication. _Figure 17: Commands handling of KANDYKORN._ ----- Below is the KANDYKORN command handler table: **ID** **Name** **Description** 0xD1 N/A Exit command. 0xD2 resp_basicinfo Gathers information about the system such as hostname, uid, osinfo, and image path of the current process, and reports back to the server. 0xD3 resp_file_dir Lists content of a directory and formats the output similar to ls -al, including type, name, permissions, size, acl, path, and access time. 0xD4 resp_file_prop Recursively reads a directory and counts the number of files, number of subdirectories, and total size. 0xD5 resp_file_upload Used by the adversary to upload a file from their C2 server to the victim’s computer. This command specifies a path, creates it, and then proceeds to download the file content and write it to the victim’s computer. 0xD6 resp_file_down Used by the adversary to transfer a file from the victim’s computer to their infrastructure. 0xD7 resp_file_zipdown Archives a directory and exfiltrates it to the C2 server. The newly created archive’s name has the following pattern /tmp/tempXXXXXXX. 0xD8 resp_file_wipe Overwrites file content to zero and deletes the file. This is a common technique used to impede recovery of the file through digital forensics on the filesystem. 0xD9 resp_proc_list Lists all running processes on the system along with their PID, UID and other information. 0xDA resp_proc_kill Kills a process by specified PID. 0xDB resp_cmd_send Executes a command on the system by using a pseudoterminal. 0xDC resp_cmd_recv Reads the command output from the previous command, resp_cmd_send. 0xDD resp_cmd_create Spawns a shell on the system and communicates with it via a pseudoterminal. Once the shell process is executed, commands are read and written through the /dev/pts device. 0xDE resp_cfg_get Sends the current configuration to the C2 from /Library/Caches/com.apple.safari.ck. 0xDF resp_cfg_set Downloads a new configuration file to the victim’s machine. This is used by the adversary to update the C2 hostname that should be used to retrieve commands from. 0xE0 resp_sleep Sleeps for a number of seconds. _Table 1: KANDYKORN command handler table._ The malware incorporates error code reporting to the C2 server, but with a limited range of values. For instance, the command process_module::resp_file_zipdown features two distinct error codes: the value 0xFFFFFC1A is designated to signify an issue encountered during ZIP manipulation, while 0xFFFFFC18 indicates a networking problem with the C2. |ID|Name|Description| |---|---|---| |0xD1|N/A|Exit command.| |0xD2|resp_basicinfo|Gathers information about the system such as hostname, uid, osinfo, and image path of the current process, and reports back to the server.| |0xD3|resp_file_dir|Lists content of a directory and formats the output similar to ls -al, including type, name, permissions, size, acl, path, and access time.| |0xD4|resp_file_prop|Recursively reads a directory and counts the number of files, number of subdirectories, and total size.| |0xD5|resp_file_upload|Used by the adversary to upload a file from their C2 server to the victim’s computer. This command specifies a path, creates it, and then proceeds to download the file content and write it to the victim’s computer.| |0xD6|resp_file_down|Used by the adversary to transfer a file from the victim’s computer to their infrastructure.| |0xD7|resp_file_zipdown|Archives a directory and exfiltrates it to the C2 server. The newly created archive’s name has the following pattern /tmp/tempXXXXXXX.| |0xD8|resp_file_wipe|Overwrites file content to zero and deletes the file. This is a common technique used to impede recovery of the file through digital forensics on the filesystem.| |0xD9|resp_proc_list|Lists all running processes on the system along with their PID, UID and other information.| |0xDA|resp_proc_kill|Kills a process by specified PID.| |0xDB|resp_cmd_send|Executes a command on the system by using a pseudoterminal.| |0xDC|resp_cmd_recv|Reads the command output from the previous command, resp_cmd_send.| |0xDD|resp_cmd_create|Spawns a shell on the system and communicates with it via a pseudoterminal. Once the shell process is executed, commands are read and written through the /dev/pts device.| |0xDE|resp_cfg_get|Sends the current configuration to the C2 from /Library/Caches/com.apple.safari.ck.| |0xDF|resp_cfg_set|Downloads a new configuration file to the victim’s machine. This is used by the adversary to update the C2 hostname that should be used to retrieve commands from.| |0xE0|resp_sleep|Sleeps for a number of seconds.| ----- _Figure 18: Process_module::resp_file_zipdown command pseudocode._ **NETWORK PROTOCOL** Both KANDYKORN and SUGARLOADER use the RC4 algorithm to encrypt their communications. When the malware first connects to the C2 server during the initialization phase, a handshake must be validated to proceed. The client generates a value using rand(), which, due to the lack of seeding, is predictable. This random value is sent to the C2 server, which responds with a nonce value. The malware then calculates a challenge by performing a left rotation of 16 bits on the nonce and doing a bitwise AND operation with the random value. The result is sent back to the server. If the server validates the challenge and it is correct, it responds with a constant value, 0x41C3372, allowing the malware to continue execution and establish a connection. Once the connection is established, the client sends its unique ID taken from the configuration file and awaits commands from the server. Subsequent data exchanges are serialized using a common schema for binary objects, with the content length sent first, followed by the payload. _Figure 19: Handshake pseudocode._ ----- The following is a packet capture showcasing the download of a binary from the C2 by SUGARLOADER. _Figure 20: Packet capture of an instance of KANDYKORN execution._ **TOOLS: CUSTOM SERVER** To support the malware analysis process for KANDYKORN, we developed a custom tool using Python that acts as the C2 server. This tool is designed to interact with the malware, allowing us to gain a deeper understanding of KANDYKORN’s features, control flow, and structures. By emulating the threat in a controlled environment, this tool facilitates the development of effective detection mechanisms. In order to simulate the whole flow, the server expects SUGARLOADER to connect first; it will then serve KANDYKORN from disk. After that, the user is presented with a list of commands to execute. Figure 21 is a code snippet of the implementation. _Figure 21: Custom server._ ----- **CONCLUSION** In this paper, we took a deep dive into the inner workings of KANDYKORN, an advanced macOS backdoor uncovered during an intrusion targeting engineers at a major crypto exchange platform. KANDYKORN represents a notable evolution in cyber threats, showcasing sophisticated features aimed at infiltrating and compromising macOS devices, which are increasingly becoming prime targets for cybercriminals. Operating discreetly, KANDYKORN employs a complex multi-stage loader and a custom network protocol to carry out various post‑compromise activities. Additionally, we have developed a custom tool to interact with KANDYKORN throughout our research. This tool not only facilitates the emulation of the threat in a controlled environment, but also serves as a valuable asset for researchers and defenders. It enables the ability to validate security measures and devise effective detection mechanisms. **REFERENCES** [1] Stepanic, D.; Sprooten, R.; Desimone, J.; Bousseaden, S.; Kerr, D. Elastic users protected from SUDDENICON’s [supply chain attack. Elastic Security Labs. 5 May 2023. https://www.elastic.co/security-labs/elastic-users-](https://www.elastic.co/security-labs/elastic-users-protected-from-suddenicon-supply-chain-attack) [protected-from-suddenicon-supply-chain-attack.](https://www.elastic.co/security-labs/elastic-users-protected-from-suddenicon-supply-chain-attack) [2] Wilhoit, C.; Bitam, S.; Goodwin, S.; Pease, A.; Ungureanu, R. Initial research exposing JOKERSPY. [Elastic Security Labs. 21 June 2023. https://www.elastic.co/security-labs/inital-research-of-jokerspy.](https://www.elastic.co/security-labs/inital-research-of-jokerspy) [3] [MITRE ATT&CK. Hijack Execution Flow. https://attack.mitre.org/techniques/T1574/.](https://attack.mitre.org/techniques/T1574/) [4] Wilhoit, C.; Ungureanu, R.; Goodwin, S.; Pease, A. Elastic catches DPRK passing out KANDYKORN. [Elastic Security Labs. 1 November 2023. https://www.elastic.co/security-labs/elastic-catches-dprk-passing-out-](https://www.elastic.co/security-labs/elastic-catches-dprk-passing-out-kandykorn) [kandykorn.](https://www.elastic.co/security-labs/elastic-catches-dprk-passing-out-kandykorn) **INDICATORS OF COMPROMISE (IOCs)** |INDICATORS OF COMPROMISE (IOCs)|Col2|Col3|Col4| |---|---|---|---| |Observable|Type|Name|Reference| |3ea2ead8f3cec030906dcbffe3efd5c5d77d5d37 5d4a54cca03bfe8a6cb59940|SHA-256|SUGARLOADER|.log .sld| |2360a69e5fd7217e977123c81d3dbb60bf4763a9 dae6949bc1900234f7762df1|SHA-256|HLOADER|Discord (fake) HLOADER| |http://tp-globa[.]xyz//OdhLca1mLUp/ lZ5rZPxWsh/7yZKYQI43S/fP7savDX6c/bfC|url||FinderTools C2 URL| |tp-globa[.]xyz|domain-name||FinderTools C2 domain| |192.119.64[.]43|ipv4-addr|tp-globa IP address|FinderTools C2 IP| |23.254.226[.]90|ipv4-addr||SUGARLOADER C2| |D9F936CE628C3E5D9B3695694D1CDE79E470E938 064D98FBF4EF980A5558D1C90C7E650C2362A21B 914ABD173ABA5C0E5837C47B89F74C5B23A7294C C1CFD11B|64 bytes key|RC4 key|SUGARLOADER KANDYKORN| -----