REPORT Operation 99 North Korean State Sponsored Supply Chain Attack on Tech Innovation Executive Summary The SecurityScorecard STRIKE team has uncovered an ongoing cyberattack targeting software developers, orchestrated by the Lazarus Group, a North Korean state-sponsored hacking unit. Identified on January 9th and named Operation 99, this campaign builds on tactics seen in past Lazarus operations, such as the 2021 Operation Dream Job, but with a sharper focus on infiltrating development environments. Unlike the fake job descriptions aimed at defense contractors in Operation Dream Job, Operation 99 targets developers in Web3 and cryptocurrency fields. Attackers pose as recruiters on platforms like LinkedIn, enticing victims with project tests or code reviews. Victims are tricked into cloning malicious Git repositories that connect to a command-and-control (C2) server, initiating a series of data-stealing implants. Once deployed, these implants extract source code, secrets, cryptocurrency wallet keys, and other sensitive data from development environments. This campaign emphasizes the increasing risk to developers in high-stakes industries, where intellectual property and digital assets are prime targets for the purpose of financial gains. Key Takeaways Sophisticated Targeting of Developers The Lazarus Group is targeting software developers with a specialized focus on those seeking freelance work in Web3 and cryptocurrency sectors. Unlike previous campaigns like Operation Dream Job, which targeted job seekers with fake job descriptions, Operation 99 lures developers with coding projects tied to fake recruitment schemes. Attackers create deceptive LinkedIn profiles and direct victims to clone malicious GitLab repositories. These repositories exploit the trust of victims, compromising their systems and enabling the theft of high-value data. This tactic demonstrates a deliberate evolution in Lazarus Group’s strategy, shifting from broad phishing attempts to targeted attacks on a critical link in the tech supply chain: developers. Multi-Stage Malware with Modular Design The attackers use a layered malware delivery system with modular components that adapt to different targets. Downloaders like Main99 retrieve and execute payloads such as Payload 99/73, brow99/73, and MCLIP, which perform tasks including: • Keylogging and clipboard monitoring. • File exfiltration from development environments. • Browser credential theft. This modular framework enables the malware to function across multiple platforms, including Windows, macOS, and Linux. By embedding the malware into developer workflows, the attackers aim to compromise not only individual victims but also the projects and systems they contribute to. Advanced Command and Control (C2) Infrastructure The campaign uses sophisticated C2 infrastructure hosted at Stark Industries LLC to deploy payloads and maintain control over compromised systems. These servers use heavily obfuscated Python scripts, often compressed with ZLIB, to evade detection. The infrastructure dynamically tailors malware for specific targets, ensuring compatibility with the victim’s operating system and environment. This adaptability demonstrates the Lazarus Group’s technical capability to execute precise attacks, making detection and mitigation significantly more challenging. Focused Theft of Developer and Cryptocurrency Data The malware specifically targets data from software development environments, including: • Source code. • Secrets and configuration files. • Cryptocurrency-related assets like wallet keys and mnemonics. By compromising developer accounts, attackers not only exfiltrate intellectual property but also gain access to cryptocurrency wallets, enabling direct financial theft. The targeted theft of private and secret keys could lead to millions in stolen digital assets, furthering the Lazarus Group’s financial goals. The customization of payloads for high-value targets reflects a strategic intent to exploit the intersection of technology and cryptocurrency, aligning with the group’s history of using stolen data to fund North Korea’s regime. Campaign By analyzing netflow data, the STRIKE team has been able to identify impacted victims across the globe, highlighting the extensive reach of this campaign. This time, the impersonation involves a fake recruiter falsely claiming to represent COIN Property for a cryptocurrency-related project. However, the supposed recruiter does not exist. As of January 10th, the fraudulent LinkedIn profile has been taken down and is no longer accessible. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Global Impacted Victims mailto:info%40securityscorecard.io?subject= This time, the impersonation involves a fake recruiter falsely claiming to represent COIN Property for a cryptocurrency-related project. However, the supposed recruiter does not exist. As of January 10th, the fraudulent LinkedIn profile has been taken down and is no longer accessible. We also observed the adversary impersonating the COO at Cowchain sending a follow up email from the email cowchain610@gmail.com. The repository masquerades as the codebase for a coin voting and promotion system purportedly associated with the company COIN Property. The README file further instructs victims to clone a GitLab repository named "coin promoting Webapp." This analysis delves deeper into the broader context, uncovering the tactics and implants used to target developers. Building on our investigation of a similar campaign from a few months ago, this research explores the capabilities of these implants, their methods of targeting, and how they extract data from infected victims. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Fake Recruiter Profile mailto:info%40securityscorecard.io?subject= Comparison to October Attack STRIKE analyzed a campaign that was conducted against Software Developers back in October 2024. This attack is similar to the previous campaign that used C2 servers with component downloads over port 1224. However the previous operation, while it used similar TTPs, we did notice the delivery and obfuscation to be very different. For example the file downloaded from the BROW end-point (see the analysis later) is different between the October 2024 attack and Jan 2025 attack. We won’t compare every function or every component from the previous attack, but highlight some of the differences. Functionally, they accomplish the same thing, however some of their techniques differ. The decoded BROW file for October also does not utilize sType and gType values for campaign and variants. In the October file the hostname function for the C2 is different and it obfuscates the C2 address, while the latest attack uses that is clear text. In the October campaign the implant implemented a self destruction mechanism, which is not present in this latest attack. C2 Infrastructure Analysis When the code from the repository is executed, it establishes a connection to the IP address 5[.]253[.]43[.]122, which is hosted by the provider Stark Industries Solutions Ltd. The domain it resolves to is vm3462807.stark-industries.solutions, indicating that its a VM. This IP address hosts an Apache server configured to deliver various payloads, which appear to be intended as the second-stage execution on the victim's machine. Based on the scan data from our Internet collections this is a Windows machine running an Apache hence the directory exposure leak observed later in our analysis. The server appeared to contain a directory D:\backend+server\assets\payload\ which is interesting as there may be custom backend server code that is running the operations and enabling interaction with victims. Furthermore, interacting with the server over port 1224 reveals behavior consistent with serving targeted payloads. Specifically, querying the server results in payloads named in the format pay5346_. While no results were returned for the numeric suffix 30, we successfully downloaded pay5346_31 and pay5346_32 as well as many others that had a similar naming convention. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com October Campaign Implant self destruction Payload not found, but reveals some information about the directory https://securityscorecard.com/blog/inside-a-north-korean-phishing-operation-targeting-devops-employees/ mailto:info%40securityscorecard.io?subject= In other directories there were obfuscated scripts following the same pattern main5346_221_, that was found with the payload scripts. These directory paths and naming conventions all tie into campaign and version identifiers. So for example 5346 may be a version and 221 is a sub-variant, later we see in the analysis that these values are configured in the scripts. The server doesn’t have directory traversal enabled, rather the backend is set up to deliver specific payloads if you know the exact path. Additionally, we successfully downloaded a script called main5346_224, which contains a heavily obfuscated Base64 string compressed using ZLIB. The actual python script being returned by the server is an obfuscated script loader, below is just a short example of what this function looks like. The base64 string in this script is reversed (the order of the characters are backwards) in order to obfuscate and make it harder for analysis. The input to this script is the large base64 block which it then reverses it, decodes the base64, de-compresses it using ZLIB and finally executes the resulting output on the target system. To further complicate matters the script is encoded at a depth of 65 layers, each stage decodes an additional compressed reverse order base64 string. The final resulting file is a human readable Python script which is the actual malware. We discovered (as covered later in the analysis) the original function used to obfuscate the payloads and components. We will describe its behavior here and how it works. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Main script not found, but reveals some information about the directory _ = lambda __ : __import__('zlib').decompress(__import__('base64'). b64decode(__[::-1]));exec((_)(b'==Qd1IcSf8/fffu/adrfcIp3opDuzpv')) Original Obfuscator function mailto:info%40securityscorecard.com?subject= The string RandVar = ? is replaced with a Randomized value. The input script data is repeatedly obfuscated using a combination of ZLIB compression, base64 encoding and string reversal. The general steps it takes • The scripts data is encoded into UTF-8 bytes • The bytes are compressed with ZLIB • The compressed bytes are base64 encoded • The resulting base64 string is string reversed The obfuscation process is applied multiple times in a loop. Each layer wraps the previous one in an exec statement so the obfuscated script will unwrap itself. At the end it results in a script that can unpack itself, deobfuscate and execute final payload. Since the obfuscation method was unknown and this code was also obfuscated, STRIKE developed a script to decode the multiple layers. By analyzing the Python scripts, we can identify aspects of the code that provide insights into the methods and content delivered to the victim. Delivery of Payloads Once you have decoded the Python scripts there are two variables hardcoded. These variables contain the main version and sub-variant. Our hypothesis is that the malicious git repo contained one of these initial downloaders. The sType and gType variables in pay99_71.py for example are used as parameters to customize the HTTP GET requests to the C2 server. They form part of the URL path (e.g., /payload/99/71), allowing the attacker to identify the campaign (sType) and specify the target group, payload type, or version (gType). These parameters enable the C2 server to deliver tailored payloads based on the context provided by the script, making the attack more dynamic and adaptable. This mechanism also allows attackers to manage different payloads and campaigns without modifying the script, enhancing the flexibility and scalability of their operations. Implant Analysis Main5346 We analyzed the downloaded file main5346_224.py, which was heavily obfuscated and compressed to around 65 layers, ultimately yielding a downloader. This framework shares significant similarities with Main99, functioning as a modular downloader. The script appears to exist in multiple versions, differentiated by the sType and gType values, with two distinct variations identified so far: 5346 and 99. It constructs URLS dynamically using the sType and gType values. In this case there are three different components downloaded and executed from the C2 server. • Payload: Endpoint /payload/5346/224 • Browse: Endpoint /brow/5346/224 • Mclip: Endpoint /mclip/5346/224 ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Resulting script Obfuscation loop mailto:info%40securityscorecard.io?subject= Notably, the framework is designed to detect the operating system of the target device (macOS or Windows) and dynamically download the appropriate payload, showcasing its adaptability and platform-specific targeting capabilities. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Opening function from main5346_224.py with Payload downloader sType and gType configurations Downloader function for MCLIP and BROW mailto:info%40securityscorecard.io?subject= Main99 Main99 is a variant of Main5346. Main99 is a modular downloader malware designed to retrieve and execute additional payloads from a Command and Control (C2) server at 5.253.43.122. Main99 relies entirely on the functionality of the downloaded modules, making it simpler and more lightweight. It specifically retrieves three distinct payloads (payload, brow, and mclip) and executes them, storing files in a hidden directory (~/.n2) for persistence. Main99 acts purely as a downloader, with no direct malicious actions, but its structured approach suggests it is part of a broader and more coordinated malware delivery system. The script communicates with a remote server at http://5.253.43.122:1224 to fetch and execute payloads based on predefined identifiers. It uses HTTP requests to specific endpoints (/payload, /brow, /mclip) to download malicious files, stores them in a hidden directory, and executes them stealthily on the target system. The script has three functions—download_payload, download_browse, and download_mclip—each responsible for downloading files from specific endpoints (/payload, /brow, /mclip) on the remote server. After downloading, it executes the files stealthily using subprocess.Popen. This process ensures the malicious payloads are fetched and run without user consent or notification. The primary payload downloader function is outlined below. This function is responsible for downloading the pay_.py script and executing it on the target system. It includes logic to determine whether the operating system is macOS and adjusts its behavior accordingly. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Main Code indicating C2 Payload Download function mailto:info%40securityscorecard.io?subject= Payload5346 A component downloaded (pay5346_224.py) by Main5346 and executed as the primary payload. This implant performs system data collection (OS details, hostname, version, username and UUID). This implant communicates to a remote server over ports 1224 and 2242 which are hardcoded into the implant code. The implant uses HTTP requests to send data to the server and retrieve commands. The attacker can interact in real-time with the infected systems through a persistent connection. Some of the endpoints it will interact with. • /keys: Sends system and network information. • /uploads: Uploads files from the victim's machine. • /brow: Downloads additional payloads. Function to send collected system information to the C2. There is also a function to search for sensitive files and upload them to a C2. This function shown below copies the clipboard and sends it via commands such as SSH_CLIP to the C2. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Function to send system information to C2 Function to upload a file Searching for sensitive files Run Copy Clipboard mailto:info%40securityscorecard.io?subject= The implant also has the capability of receiving and executing arbitrary commands from the C2, indicating more than just data exfiltration. It creates a persistent connection over port 2242 to maintain a persistent connection with the victim. The following function will listen for commands from the self.cmds dictionary. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com SSH clip function Persistent client connection function Listening function mailto:info%40securityscorecard.io?subject= The commands are mapped in the Shell class using the self.cmds dictionary. Each integer represents a command code, mapped to a corresponding handler function. What commands can the actual implant receive? There are several commands ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Extracted command dictionary from Shell function The shell function for commands mailto:info%40securityscorecard.io?subject= it can receive from the C2. SSH_OBJ can execute arbitrary commands on the infected system (cd, ls, dir). Can run programs or scripts. Sends the output back to the C2 server. 1. SSH_CMD terminates all Python processes on the infected machine. 2. SSH_CLIP sends the clipboard data stored in the e_buf value to the C2. 3. SSH_RUN downloads and executes a payload from the /brow endpoint on the C2 4. SSH_UPLOAD handles file uploads to the C2 server 5. SSH_KILL terminates specific browsers (chrome and brave) 6. SSH_ANY downloads and executes a specific tool (AnyDesk) or payload from /adc endpoint 7. SSH_ENV searches and uploads environment related files (API keys, passwords,secret, config, etc) The implant has the capability of executing 3rd stage payloads via the BROW endpoint. The URL is constructed dynamically based on sType and gType values such as /brow//. The following function describes the execution logic of the implant determining multi platform such as Windows, MacOS and Linux. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Function to download 3rd stage payload Payload execution function mailto:info%40securityscorecard.io?subject= Payload 99_31, Payload99_71 & Payload99_73 A component downloaded (pay99_31.py & pay99_71) by Main99 and executed as the primary payload. This payload is functionally the same as pay5346_224.py that was downloaded by Main5346. The only difference is sType and gType variables that indicate campaigns and target groups that we are speculating. Furthermore, pay99_73.py is also functionally the same as pay5346_224.py. Brow 99_73 We were able to successfully download brow99_73.py from the /brow end-point on the C2 server. This is downloaded in the payload main functions via the brow_down function. We will provide an analysis here of the implant and its capabilities and how it is different from the other pay files. This script downloaded was particularly interesting as it contained two implants at different stages of the de-obfuscation process. The first implant was successfully decoded after stage 65 and the implant is designed to target browsers and extract sensitive information. The implant brow99 targets MacOS, Linux and Windows and contains functions to both extract saved passwords, but also to decrypt them as well. This implant targets major browsers and will extract the encrypted password content. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Function to extract the content from these Browsers mailto:info%40securityscorecard.io?subject= The implant has the capability of decrypting the passwords for various operating system browsers. The following is the function to get the encryption key for Windows based browsers. It is using the Windows API win32crypt.CryptUnprotectData to decrypt the Browsers master key. On Windows, decryption will involve extracting the AES key, deriving the initial vector (IV) and decrypting the data using AES- GCM or the CryptrUnprotectData function. The following is the function that performs this. The process for Linux based systems is a bit different and the keys are accessed in a different manner. The implant will get the encryption key from GNOME keyring via secretstorage. The following function will get the encryption key for the browser. Get encryption key for Windows Windows Browser password decryption. Get encryption key for Linux based Browsers ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com mailto:info%40securityscorecard.io?subject= On Linux machines, the process to decrypt a password involves reading from the Login Data from the SQLite DB. It will then perform decryption using AES. The decryption process for MacOS is the same as Linux, however extracting the encryption key is a bit different. The saved password will be retrieved from the keychain using the security command. The saved password is processed using PBKDF2 to derive the AES key. The following is the function that will decrypt the keychain to an AES key. MacOS get encryption key MacOS Keychain Decryption Decrypt Linux Browser Passwords ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com mailto:info%40securityscorecard.io?subject= The following function will prepare the data to be sent to the C2 server. Further it will format the encrypted data into a human readable string. The implant will combine the decrypted data (self.pretty_print) with the browsers file path to create a content string (cc). This is an example of what the content could look like for the variable CC This function described above is called to assemble the data into a human readable string to be sent to the C2. Finally the implant is sending the data via HTTP post to the C2 based on the hardcoded host values. Format the decrypted data into human readable ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Function to prepare data for C2 Example Hardcoded C2 hosts mailto:info%40securityscorecard.io?subject= MCLIP The MCLIP implant (mclip15_99.py) was successfully obtained from the C2 server which is downloaded by Main99 and Main5346. The main functionalities of this code is keyboard and clipboard monitoring and exfiltration. The C2 server is also different, but also hosted at the same provider (Stark Industries LLC). This c2 appears to be specifically established to interact with this MCLIP implant. This implant communicates over port 1224 to 95[.]164[.]7[.]171 and is configured to use sType 15 and gType 99 which appears to be part of the 99 operation. The following is an analysis of this implant and its general capabilities. The code is organized into two parts, keyboard hooking, logging and transmission to C2 and similarly for clipboard. The following is the function to hook the keyboard and monitor keyboard activity. The implant will save the data and send it to the C2 server via the /api/clip endpoint. The following is the function that will save the captured data and send it to the C2. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Keyboard hooking process mailto:info%40securityscorecard.io?subject= Unknown Code Later in the obfuscated script (brow15_99.py) after encoding stage 115 is another rather large sophisticated Python implant, which appears to be incomplete and cut-off. What’s interesting is the Python script contains the original obfuscator that was used to create the obfuscation on the files downloaded from the C2. The implant appears to be getting some payload from XOR encrypted Pastebin URLs. Further, it makes a bunch of references to a TSUNAMI payload which STRIKE hasn’t analyzed, and its role is unknown. It decodes an array of URLs using the following XOR which in return presents a bunch of Pastebin URLs. XOR encryption function ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com Obfuscation Function Function to decode the URLs mailto:info%40securityscorecard.io?subject= Conclusion The ongoing "Operation 99" campaign orchestrated by the Lazarus Group exemplifies the increasing sophistication and adaptability of state-sponsored cyber threats. By targeting software developers interested in Web3 and cryptocurrency sectors, the attackers exploit a critical link in the technology supply chain. Their use of fake recruitment schemes, malicious Git repositories, and modular malware frameworks underscores their strategic focus on high-value data, including source code, configuration files, and cryptocurrency credentials. The campaign's reliance on obfuscated, multi-stage implants and dynamic payload delivery highlights the advanced capabilities of the adversary. The identified Command and Control (C2) infrastructure further demonstrates their ability to tailor attacks across different operating systems while maintaining operational stealth. This campaign not only reaffirms the persistent threat posed by the Lazarus Group but also serves as a stark reminder of the vulnerabilities within developer ecosystems. As these attacks evolve, it is critical for organizations and developers to adopt proactive security measures, including enhanced code repository verification, robust endpoint defenses, and heightened vigilance against social engineering tactics. The STRIKE team's findings contribute valuable insights into mitigating these complex threats and safeguarding the technology community against future attacks. ©2024 SecurityScorecard Inc. All Rights Reserved. SecurityScorecard.com info@securityscorecard.com mailto:info%40securityscorecard.io?subject=