Stealing the LIGHTSHOW (Part One) — North Korea's UNC2970
Mandiant
Written by: Mandiant Intelligence and Consulting
Since June 2022, Mandiant has been tracking a campaign targeting Western Media and Technology companies from a suspected North Korean espionage group tracked as UNC2970. In June 2022, Mandiant Managed Defense detected and responded to an UNC2970 phishing campaign targeting a U.S.-based technology company. During this operation, Mandiant observed UNC2970 leverage three new code families: TOUCHMOVE, SIDESHOW, and TOUCHSHIFT. Mandiant suspects UNC2970 specifically targeted security researchers in this operation. Following the identification of this campaign, Mandiant responded to multiple UNC2970 intrusions targeting U.S. and European Media organizations through spear-phishing that used a job recruitment theme and demonstrated advancements in the groups ability to operate in cloud environments and against Endpoint Detection and Response (EDR) tools.
UNC2970 is suspected with high confidence to be UNC577, also known as Temp.Hermit. UNC577 is a cluster of North Korean cyber activity that has been active since at least 2013. The group has significant malware overlaps with other North Korean operators and is believed to share resources, such as code and complete malware tools with other distinct actors. While observed UNC577 activity primarily targets entities in South Korea, it has also targeted other organizations worldwide.
UNC2970 has historically targeted organizations with spear phishing emails containing a job recruitment theme. These operations have multiple overlaps with public reporting on “Operation Dream Job” by Google TAG, Proofpoint, and ClearSky.
UNC2970 has recently shifted to targeting users directly on LinkedIn using fake accounts posing as recruiters. UNC2970 maintains an array of specially crafted LinkedIn accounts based on legitimate users. These accounts are well designed and professionally curated to mimic the identities of the legitimate users in order to build rapport and increase the likelihood of conversation and interaction. UNC2970 uses these accounts to socially engineer targets into engaging over WhatsApp, where UNC2970 will then deliver a phishing payload either to a target’s email, or directly over WhatsApp. UNC2970 largely employs the PLANKWALK backdoor during phishing operations as well as other malware families that share code with multiple tools leveraged by UNC577. Mandiant recently published a blog post detailing UNC2970 activity that was identified by Mandiant Managed Defense during proactive threat hunting. This activity was initially clustered as UNC4034 but has since been merged into UNC2970 based on multiple infrastructure, tooling, and tactics, techniques, and procedures (TTP) overlaps.
When you're done reading this post, don't forget to check out part two on LIGHTSHIFT and LIGHTSHOW.
Summary
In June 2022, Mandiant Managed Defense detected and responded to an UNC2970 phishing campaign targeting a U.S.-based technology company. During this operation, Mandiant observed UNC2970 leverage three new code families: TOUCHMOVE, SIDESHOW, and TOUCHSHIFT. Mandiant suspects UNC2970 specifically targeted security researchers in this operation. Following the identification of this campaign, Mandiant responded to multiple UNC2970 intrusions targeting U.S. and European Media organizations through spear-phishing that used a job recruitment theme.
Initial Access
When conducting phishing operations, UNC2970 engaged with targets initially over LinkedIn masquerading as recruiters. Once UNC2970 contacts a target, they would attempt to shift the conversation to WhatsApp, where they would continue interacting with their target before sending a phishing payload that masqueraded as a job description. In at least one case, UNC2970 continued interacting with a victim even after the phishing payload was executed and detected, asking for screenshots of the detection.
The phishing payloads primarily utilized by UNC2970 are Microsoft Word documents embedded with macros to perform remote-template injection to pull down and execute a payload from a remote command and control (C2). Mandiant has observed UNC2970 tailoring the fake job descriptions to specific targets.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig2-lure_vhxk.max-1600x1600.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig2-lure_vhxk.max-1600x1600.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig2-lure_vhxk.max-1600x1600.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig2-lure_vhxk.max-1600x1600.png)
Figure 1: UNC2970 lure document
The C2 servers utilized by UNC2970 for remote template injection have primarily been compromised WordPress sites, a trend observed in other UNC2970 code families as well as those used by other DPRK groups. At the time of analysis, the remote template was no longer present on the C2, however following this phishing activity, Mandiant identified it beaconing to a C2 associated with PLANKWALK.
In the most recent UNC2970 investigation, Mandiant observed the group returning to WhatsApp to engage their targets. This activity overlaps with a recent blog post by MSTIC on operations from ZINC, as well as the previously mentioned Mandiant blog post from July 2022.
The ZIP file delivered by UNC2970 contained what the victim thought was a skills assessment test for a job application. In reality, the ZIP contained an ISO file, which included a trojanized version of TightVNC that Mandiant tracks as LIDSHIFT. The victim was instructed to run the TightVNC application which, along with the other files, are named appropriately to the company the victim had planned to take the assessment for.
In addition to functioning as a legitimate TightVNC viewer, LIDSHIFT contained multiple hidden features. The first was that upon execution by the user, the malware would send a beacon back to its hardcoded C2; the only interaction this needed from the user was the launching of the program. This lack of interaction differs from what MSTIC observed in their recent blog post. The initial C2 beacon from LIDSHIFT contains the victim’s initial username and hostname.
LIDSHIFT’s second capability is to reflectively inject an encrypted DLL into memory. The injected DLL is a trojanized Notepad++ plugin that functions as a downloader, which Mandiant tracks as LIDSHOT. LIDSHOT is injected as soon as the victim opens the drop down inside of the TightVNC Viewer application. LIDSHOT has two primary functions: system enumeration and downloading and executing shellcode from the C2.
LIDSHOT sends the following information back to its C2:
Computer Name
Product name as recorded in the following registry key
SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProductNameIP address
Process List with User and Session ID associate per process
Establish Foothold
In multiple investigations, Mandiant has observed UNC2970 deploy PLANKWALK to establish footholds within environments. PLANKWALK is a backdoor written in C++ that communicates over HTTP and utilizes multiple layers of DLL sideloading to execute an encrypted payload. PLANKWALK is initially executed through a launcher that will import and execute a second stage launcher expected to be on disk.
Observed First Stage Launcher names:
destextapi.dll
manextapi.dll
pathextapi.dll
preextapi.dll
Wbemcomn.dll
Once loaded and executed, the secondary launcher will attempt to decrypt and execute an encrypted PLANKWALK sample on disk that matches the following pattern:
C:\ProgramData\Microsoft\Vault\cache<three numerical digits>.db
Once executed, PLANKWALK will decrypt an on-host encrypted configuration file that contains the C2 for the backdoor. The C2 for PLANKWALK has largely been co-opted by legitimate WordPress sites.
Following the deployment of PLANKWALK, Mandiant observed UNC2970 leverage a wide variety of additional tooling, including Microsoft InTune to deploy a shellcode downloader.
Tool Time: Kim “The Toolman” Taylor
During their operations, Mandiant has observed UNC2970 use a wide range of custom, post-exploitation tooling to achieve their goals. One of UNC2970's go-to tools has been a dropper tracked as TOUCHSHIFT. TOUCHSHIFT allows UNC2970 to employ follow-on tooling that range from keyloggers and screenshot utilities, to full featured backdoors.
TOUCHSHIFT
TOUCHSHIFT is a malicious dropper that masquerades as mscoree.dll
or netplwix.dll
. TOUCHSHIFT is typically created in the same directory and simultaneously as a legitimate copy of a Windows binary. TOUCHSHIFT leverages DLL Search Order Hijacking to use the legitimate file to load and execute itself. TOUCHSHIFT has been observed containing one to two various payloads which it executes in-memory. Payloads that have been seen include TOUCHSHOT, TOUCHKEY, HOOKSHOT, TOUCHMOVE, and SIDESHOW.
To appear legitimate, the file uses over 100 exports that match common system export names. However, the majority all point to the same empty function. The malicious code has been seen located in exports LockClrVersion
or UsersRunDllW
in different instances.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig3-malicious-export_mqol.max-1200x1200.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig3-malicious-export_mqol.max-1200x1200.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig3-malicious-export_mqol.max-1200x1200.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig3-malicious-export_mqol.max-1200x1200.png)
Figure 2: Malicious export alongside several of the dummy exports
When TOUCHSHIFT contains a second payload, it takes a single character command line option as its first argument to determine which of the two payloads to execute.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig4-command-line_lrtp.max-500x500.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig4-command-line_lrtp.max-500x500.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig4-command-line_lrtp.max-500x500.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig4-command-line_lrtp.max-500x500.png)
Figure 3: Checking command line options
To unpack its payload(s), TOUCHSHIFT generates a decryption key by XOR encoding its second argument and the first 16 characters of the legitimate executable’s file name.
For example, in one instance Mandiant observed the arguments -CortanaUIFilter
, XOR encoded with the hardcoded key 009WAYHb90687PXkS
, and printfilterpipel
, which was XOR encoded with the hardcoded key .sV%58&.lypQ[$=
and was loaded by the file printfilterpipelinesvc.exe
. In another instance, the argument used was --forkavlauncher
and the loading file was C:\windows\Branding\Netplwiz.exe
.
Once the code is unpacked, it is then loaded into a memory location created by a call to VirtualAlloc
and executed from there.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig5-unpacked-payload_jdfe.max-1200x1200.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig5-unpacked-payload_jdfe.max-1200x1200.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig5-unpacked-payload_jdfe.max-1200x1200.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig5-unpacked-payload_jdfe.max-1200x1200.png)
Figure 4: Beginning of unpacked payload in memory
Once the payload(s) has/have been executed, the main portion of TOUCHSHIFT will sleep for a period of time allowing the payload(s) to continue executing.
TOUCHSHIFT-ing into Gear — Follow on payloads
TOUCHSHOT
TOUCHSHOT takes screenshots of the system on which it is running and saves them to a file to be retrieved by the threat actor at a later time. TOUCHSHOT is configured to take a screenshot every three seconds, and then uses ZLIB to compress the images. The compressed data is then appended to a file that it creates and continues appending new screenshots to this file until the file reaches five megabytes in size, at which point it will create a new file with the same naming convention. TOUCHSHOT was seen embedded in the same instance of TOUCHSHIFT as TOUCHKEY (discussed later in the post).
TOUCHSHOT will create a file in the C:\Users\{user}\AppData\Roaming\Microsoft\Windows\Themes\
directory, and will name the file ~DM{####}P.dat
, where the four numbers are pseudo-randomly generated. Once TOUCHSHOT has generated the file name, it attempts to create a handle to the file. If the return value indicates that the file does not exist, it will then create the file. This check is performed as part of a loop that continues until a new file needs to be created. After each iteration of the loop, TOUCHSHOT will then take a screenshot, which is appended to the staging file.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig6-directory-path_cjyx.max-900x900.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig6-directory-path_cjyx.max-900x900.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig6-directory-path_cjyx.max-900x900.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig6-directory-path_cjyx.max-900x900.png)
Figure 5: Generation of the directory path
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig7-file-name_cjuf.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig7-file-name_cjuf.max-800x800.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig7-file-name_cjuf.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig7-file-name_cjuf.max-800x800.png)
Figure 6: Generation of file name with pseudo-random numbers
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig8-creating-handle_vllz.max-1500x1500.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig8-creating-handle_vllz.max-1500x1500.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig8-creating-handle_vllz.max-1500x1500.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig8-creating-handle_vllz.max-1500x1500.png)
Figure 7: Creating a handle to the file or creating it
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig9-screenshot_veiw.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig9-screenshot_veiw.max-800x800.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig9-screenshot_veiw.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig9-screenshot_veiw.max-800x800.png)
Figure 8: Taking a screenshot
TOUCHKEY
TOUCHKEY is a keylogger that captures keystrokes and clipboard data, both of which are encoded with a single-byte XOR and saved to a file. As with TOUCHSHOT, these files need to be acquired by the threat actor through additional means.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig10-xor-data_ykzc.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig10-xor-data_ykzc.max-800x800.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig10-xor-data_ykzc.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig10-xor-data_ykzc.max-800x800.png)
Figure 9: XOR’ing data with byte 0x62 before writing to the staging file
TOUCHKEY creates two files in the C:\Users\{user}\AppData\Roaming\Microsoft\Windows\Templates\
directory. The file name Normal.dost
is used for storing the captured keystrokes, while the file name Normal.docb
is used for the clipboard data. The full paths are then passed into their own thread, where the keystrokes or clipboard data will be captured and appended to their respective files.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig11-path-generation-img.max-1000x1000.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig11-path-generation-img.max-1000x1000.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig11-path-generation-img.max-1000x1000.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig11-path-generation-img.max-1000x1000.png)
Figure 10: Path generation for the staging files
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig12-adding-file-names_wuca.max-1000x1000.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig12-adding-file-names_wuca.max-1000x1000.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig12-adding-file-names_wuca.max-1000x1000.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig12-adding-file-names_wuca.max-1000x1000.png)
Figure 11: Adding file names to the full path and creating the threads
In one of the created threads, TOUCHKEY will open the clipboard and grab the data that is stored within it. In the other thread, TOUCHKEY will set a hook into the keyboard, and record any keys that are pressed.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig13-capturing-clipboard-data-.max-1100x1100.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig13-capturing-clipboard-data-.max-1100x1100.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig13-capturing-clipboard-data-.max-1100x1100.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig13-capturing-clipboard-data-.max-1100x1100.png)
Figure 12: Capturing the clipboard data
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig14-capturing-keystrokes-img.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig14-capturing-keystrokes-img.max-800x800.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig14-capturing-keystrokes-img.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig14-capturing-keystrokes-img.max-800x800.png)
Figure 13: Capturing keystrokes
HOOKSHOT
HOOKSHOT is a tunneler that leverages a statically linked implementation of OpenSSL to communicate back to its C2. While it connects over TCP, it does not make use of a client certificate for encryption.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig15-openssl_ihfe.max-1100x1100.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig15-openssl_ihfe.max-1100x1100.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig15-openssl_ihfe.max-1100x1100.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig15-openssl_ihfe.max-1100x1100.png)
Figure 14: Example of OpenSSL statically linked in the file
HOOKSHOT takes an encoded argument containing two IP and port pairs, which it will leverage for communicating with its C2.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig16-separating-ips-ports_zigl.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig16-separating-ips-ports_zigl.max-800x800.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig16-separating-ips-ports_zigl.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig16-separating-ips-ports_zigl.max-800x800.png)
Figure 15: Separating IP’s and ports
HOOKSHOT will then create a socket using these two IP addresses, and tunnel traffic across them utilizing TLSv1.0.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig17-socket-creation_szae.max-900x900.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig17-socket-creation_szae.max-900x900.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig17-socket-creation_szae.max-900x900.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig17-socket-creation_szae.max-900x900.png)
Figure 16: Socket creation
TOUCHMOVE
TOUCHMOVE is a loader that decrypts a configuration file and a payload, both of which must be on disk, and then executes the payload. TOUCHMOVE generates an RC6 key to decrypt the two files by querying the system’s BIOS date, version, manufacturer, and product name. Once decrypted, the results are XOR encoded with a hardcoded key. If the generated RC6 key is incorrect, the configuration and payload files will not successfully decrypt, indicating that UNC2970 compiles instances of TOUCHMOVE after having already conducted reconnaissance on the target victim system. Once the RC6 key is successfully generated, a handle is created to the configuration file, and the decryption process is conducted. If the configuration file is successfully decrypted, the payload’s full path is located within it, and the same decryption process then occurs on the payload. Following this, the payload is executed.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig18-bios-query-strings_qfzi.max-1600x1600.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig18-bios-query-strings_qfzi.max-1600x1600.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig18-bios-query-strings_qfzi.max-1600x1600.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig18-bios-query-strings_qfzi.max-1600x1600.png)
Figure 17: Bios query strings
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig19-handle-config-file-img.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig19-handle-config-file-img.max-800x800.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig19-handle-config-file-img.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig19-handle-config-file-img.max-800x800.png)
Figure 18: Creating a handle to the configuration file
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig20-handle-payload-img.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig20-handle-payload-img.max-800x800.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig20-handle-payload-img.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig20-handle-payload-img.max-800x800.png)
Figure 19: Creating a handle to the payload
SIDESHOW
SIDESHOW is a backdoor written in C/C++ that communicates via HTTP POST requests with its C2 server. The backdoor is multi-threaded, uses RC6 encryption, and supports at least 49 commands, which can be seen in Table 1. Capabilities include arbitrary command execution (WMI capable); payload execution via process injection; service, registry, scheduled task, and firewall manipulation; querying and updating Domain Controller settings; creating password protected ZIP files; and more. SIDESHOW does not explicitly establish persistence; however, based on the multitude of supported commands it may be commanded to establish persistence.
SIDESHOW derives a system-specific RC6 key using the same registry values as TOUCHMOVE and uses the generated key to decrypt the same configuration file from disk that TOUCHMOVE decrypted. The decrypted configuration file contains a list of C2 URLs to which SIDESHOW communicates using HTTP POST requests. SIDESHOW iterates this C2 URL list and attempts to authenticate to each C2 URL until it is successful. Once successful, SIDESHOW enters a state of command processing and sends additional HTTP POST requests to retrieve commands. SIDESHOW attempts to use the system's default HTTP User-Agent string during C2 communications; however, if not available it uses the hard-coded HTTP User-Agent string:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/97.0.4692.99 Safari/537.36 Edg/97.0.1072.69
When communicating to its C2 server via HTTP POST requests, SIDESHOW forms a URI parameter string consisting of a mix of randomly selected and hard-coded URI parameters.
Authentication requests use the following URI parameter string format:
1<param_1>=<hex_seed>&<param_2>=pAJ9dk4OVq85jxKWoNfw1AG2C&<param_3>=
<16_random_hex_chars>
The first URI parameter value comes from SIDESHOW’s configuration and is used to seed the random function.
The second URI parameter value, pAJ9dk4OVq85jxKWoNfw1AG2C
, is hardcoded and likely an authentication credential.
The third URI parameter value, <16_random_hex_chars>
, is a session identifier (<session_id>
) used for future communications and consists of two subcomponents:
<8_random_hex_based_on_seed>
<8_random_hex_based_on_tickcount>
The first URI parameter's value, <hex_seed>
, is used as a random seed value to derive the first eight hexadecimal characters (<8_random_hex_based_on_seed>
), whereas the last eight hexadecimal characters (<8_random_hex_based_on_tickcount>
) are derived using the CPU's current tick count as the random seed value. This results in the value <8_random_hex_based_on_seed>
being deterministic, while <8_random_hex_based_on_tickcount>
is pseudo-random.
The following is an example authentication URI parameter string:
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig21-building-URI-parameter-stri.max-900x900.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig21-building-URI-parameter-stri.max-900x900.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig21-building-URI-parameter-stri.max-900x900.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig21-building-URI-parameter-stri.max-900x900.png)
Figure 20: Building of URI parameter string
SIDESHOW parses the response and considers it a successful authentication if it contains the string <!DOCTYPE html>
.
Command requests use the following URI parameter string format (notice that the <param_2>
and <param_3>
have switched locations in the string).
1<param_1>=<5_random_digits>&<param_3>=2<session_id>&<param_2>=<6_random_digits>
Example command URI parameter string:
1other=37685&session=2184B280E341AE63F&page=593881
SIDESHOW parses the command response body and extracts data following the string <!DOCTYPE html>
. SIDESHOW then appears to Base64 decode and RC6 decrypt the extracted data. SIDESHOW responds to the commands listed in Table 1 (commands are described on a best effort basis).
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig22-switch-statement-img.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig22-switch-statement-img.max-800x800.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig22-switch-statement-img.max-800x800.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig22-switch-statement-img.max-800x800.png)
Figure 21: Switch statement following parsing of command
Reaching for the Clouds: Intune with CLOUDBURST
In at least one investigation, Mandiant identified the threat actors leveraging Microsoft Intune, Microsoft's endpoint management solution, to deploy malware to hosts in the environment. Mandiant suspects that this method of malware deployment was used due to the absence of a VPN solution for remote machines. In order to remotely execute code, the attackers leveraged the Microsoft Intune management extension (IME) to upload custom PowerShell scripts containing malicious code to various hosts in the client environment. While conducting forensic analysis on a host, Mandiant identified the following Microsoft IME related PowerShell script command line arguments:
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -
executionPolicy bypass -file "C:\Program Files (x86)\Microsoft Intune Management
Extension\Policies\Scripts\42fb3cca-48dd-4412-a11a-245384544402_f391eded-82d3-4506-8bf4-9213f6f4d586.ps1
At the time of analysis, Mandiant was unable to acquire the PS1 file itself, however; Mandiant was able to acquire a full copy of the PS1 file from local Microsoft IME logs identified on a host, located at:
C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension-
YYYYMMDD-HHMMSS.log
The entry in the local logs appeared as follows:
<![LOG[[PowerShell] response payload is [{"AccountId":"[userGUID]","PolicyId":"f391eded-82d3-4506-8bf4-
9213f6f4d586","PolicyType":1,"DocumentSchemaVersion":"1.0","PolicyHash":"P23cVfMyHLECSGPt1T6YYcoxhCLWKS05jX5M
ukC3MIw=","PolicyBody":"$EnModule = \"[Base64_encoded_CLOUDBURST_payload]"\r\n$DeModule =
[System.Convert]::FromBase64CharArray($EnModule, 0, $EnModule.Length)\r\nSet-Content
\"C:\\ProgramData\\mscoree.dll\" -Value $DeModule -Encoding Byte\r\nCopy-Item
\"C:\\Windows\\System32\\PresentationHost.exe\" -Destination \"C:\\ProgramData\"\r\nStart-Process -
NoNewWindow -FilePath \"C:\\ProgramData\\PresentationHost.exe\" -ArgumentList \"-
embeddingObject\"\r\n","PolicyBodySize":null,"PolicyScriptParameters":null,"ContentSignature":"
[Base64_encoded_signing_certificate]","isTombStoned":false,"isRecurring":false,"isFullSync":false,"ExecutionContext":0,
"InternalVersion":1,"EnforceSignatureCheck":false,"RunningMode":1,"RemediationScript":null,"RunRemediation":false,"
RemediateScriptHash":null,"RemediationScriptParameters":null,"ComplianceRules":null,"ExecutionFrequency":0,"
RetryCount":0,"BlockExecutionNotifications":false,"ModifiedTime":null,"Schedule":null,"IsFirstPartyScript":false,"TargetType":0,
"ScriptApplicabilityStateDueToAssignmentFilters":null,"AssignmentFilterIdToEvalStateMap":{},"HardwareConfigurationMetadata":null}]]LOG]!><time="06:59:15.2941778" date="6-9-2022" component="IntuneManagementExtension" context="" type="1" thread="5" file="">
The malicious PowerShell script was used to decode the Base64 encoded CLOUDBURST payload and drop it on disk as C:\ProgramData\mscoree.dll
. The script would then write a copy of C:\Windows\System32\PresentationHost.exe
to C:\ProgramData
and execute it with the argument -embeddingObject
. PresentationHost.exe
is a legitimate Windows binary used by UNC2970 to sideload CLOUDBURST.
Upon execution, PresentationHost.exe
would load the CLOUDBURST payload into memory. Upon further analysis of the Microsoft IME endpoint logs, Mandiant identified a unique GUID, f391eded-82d3-4506-8bf4-9213f6f4d586
, in the PolicyID field, which is a "Unique identifier of the Policy in the data warehouse". The Intune Data Warehouse provides insight and information about an enterprise mobile environment, such as historical Intune data and Intune data refreshed on a daily occurence. The identified GUID also matched the GUID of the PowerShell script file name and the GUID observed in an IME associated registry key.
When reviewing the Intune Tenant admin Audit logs, Mandiant identified the same GUID under the ObjectID field. The Intune Tenant audit logs shows records of activities that generate a change in Intune, including create, update (edit), delete, assign, and remote actions. The logs revealed that the threat actors used a previously compromised account to perform a create, assign, patch, and finally a delete action of a Device Management Script, using the Target Microsoft.Management.Services.Api.DeviceManagementScript
and the GroupID f391eded-82d3-4506-8bf4-9213f6f4d586
.
Further analysis revealed that ObjectID GUIDs referenced in the Intune Tenant admin Audit logs maps to the ID of Mobile App assignment groups.
At the time of analysis, the GroupID f391eded-82d3-4506-8bf4-9213f6f4d586
, was no longer present in the Intune Endpoint management admin center, and was likely deleted by the threat actors.
In order to determine malicious usage of Microsoft Intune, Mandiant performed the following analysis steps:
- Analyzed AzureAD sign-in logs for evidence of suspicious logons to the Microsoft Intune application
- Analyzed Microsoft Intune audit logs for evidence of unexpected deployments and performed the following:
- Utilized the GroupID GUID to search for the presence of the following endpoint artifacts:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
IntuneManagementExtension\Policies\<UserGUID>\<suspicious ObjectID GUID>C:\Program Files (x86)\Microsoft Intune Management Extension\
Policies\Scripts\<UserGUID>_<suspicious ObjectID GUID>.ps1
- Utilized the GroupID GUID to search for the presence of the following endpoint artifacts:
- Analyzed Microsoft Intune audit logs for evidence of unexpected deployments and performed the following:
- For hosts that had the aforementioned artifacts, the following was performed:
- Acquired the PS1 file(s) and analyzed for malicious code
- Performed traditional endpoint analysis
Mandiant tracks the malware being distributed via InTune as CLOUDBURST. CLOUDBURST is a downloader written in C that communicates via HTTP. The malware attempts to make itself look like a legitimate version of mscoree.dll
, but contains fake exports, the same way that TOUCHSHIFT uses fake exports. One variant of CLOUDBURST made use of legitimate open-source software that was added as exports, in addition to the fake exports. The actual export with malicious code is CorExitProcess
. The CorExitProcess
export expects the single argument -embeddingObject.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig23-comparing-arguments.max-1300x1300.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig23-comparing-arguments.max-1300x1300.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig23-comparing-arguments.max-1300x1300.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig23-comparing-arguments.max-1300x1300.png)
Figure 22: Comparing command line argument with -embeddingObject
Once the aforementioned command line argument has been verified, CLOUDBURST builds the domain as a stack string, and sends out the two following requests to the C2 server:
hxxps://[c2domain]/wp-content/plugins/contact.php?gametype=
<random_dword>&type=O8Akm8aV09Nw412KMoWJd
hxxps://[c2domain]/wp-content/plugins/contact.php?
gametype=tennis&type=k<random_dword>
Following the network connections, CLOUDBURST conducts a host survey, in which it will determine the Product Name, Computer Name, and enumerate running processes.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig24-calling-functions.max-900x900.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig24-calling-functions.max-900x900.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig24-calling-functions.max-900x900.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig24-calling-functions.max-900x900.png)
Figure 23: Calling functions to enumerate the host
Upon completion of the host enumeration, CLOUDBURST then downloads and executes shellcode from the C2 server. At this time, Mandiant was unable to recover and identify the purpose of the shellcode downloaded by CLOUDBURST.
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig25-memory-space.max-700x700.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig25-memory-space.max-700x700.png)
![https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig25-memory-space.max-700x700.png](https://storage.googleapis.com/gweb-cloudblog-publish/images/lightshow1-fig25-memory-space.max-700x700.png)
Figure 24: Allocating and populating memory space, and executing the shellcode
Outlook and Implications
The identified malware tools highlight continued malware development and deployment of new tools by UNC2970. Although the group has previously targeted defense, media, and technology industries, the targeting of security researchers suggests a shift in strategy or an expansion of its operations. Technical indicators and the group’s TTPs link it to TEMP.Hermit, although this latest activity suggests the group is adapting their capabilities as more of their targets move to cloud services. To learn more about how UNC2970 further enabled its operations, please see part two of our research.
Campaign Tracking
Mandiant will continue to monitor UNC2970’s campaigns and intrusion operations and will provide notable and dynamic updates regarding changes in tactics and techniques, the introduction of tools with new capabilities, or the use of new infrastructure to carry out their mission.
For more insights into how Mandiant tracks this and similar campaigns, see our Threat Campaigns feature within Mandiant Advantage Threat Intelligence.
Recommended Mitigations
Hardening Azure AD and Microsoft Intune
Mandiant has observed UNC2970 leverage weak identity controls in Azure AD combined with Microsoft Intune’s endpoint management capabilities to effectively deploy malicious PowerShell scripts onto unsuspecting endpoints.
Increasing Azure AD identity protections and limiting access to Microsoft Intune is essential in mitigating the attacker activity observed by Mandiant. Organizations should consider implementing the following hardening controls:
Cloud-Only Accounts: Organizations should utilize cloud-only accounts for privileged access within Azure AD (e.g., Global Admins, Intune Administrator) and never assign privileged access to synced accounts from on-premises identity providers such as Active Directory. Additionally, admins should utilize a separate “daily-driver” account for day-to-day activities such as sending email or web-browsing. Dedicated admin accounts should be utilized to carry out administrative functions only.
Enforce Strong Multi-Factor Authentication Methods: Organizations should consider enforcing enhanced and phishing-resistant Multi-Factor Authentication (MFA) methods for all users and administrators. Weak MFA methods commonly include SMS, Voice (phone call), OTPs, or Push notifications and should be considered for removal. MFA enhancements for non-privileged users should include contextual information regarding the MFA request such as number-matching, application name, and geographic location. For privileged accounts, Mandiant recommends the enforcement of hardware tokens or FIDO2 Security Keys as-well as requiring MFA per each sign-in regardless of location (e.g., Trusted Network, Corporate VPN). As an initial roll out for enhanced MFA methods, organizations should focus on all accounts with administrative privileges in Azure AD. Microsoft has additional information regarding contextual MFA settings.
Privileged Identity Management (PIM) Solution: Mandiant recommends that organizations consider utilizing a PIM solution. A PIM solution should include a Just-In-Time (JIT) access capability which will provide access when requested, for a specific duration of time, and should initiate an approval flow, prior to providing an account access to a highly privileged role (e.g., Global Administrator or Intune Administrator).
Conditional Access Policies (CAPs) to Enforce Security Restrictions in Azure AD: A CAP allows organizations to set requirements for accessing cloud apps such as Intune, based on various conditions including location and device platform. Mandiant recommends that Organizations utilize CAPs to restrict Azure administrative functions to only compliant and registered devices in Azure AD and only from a specific subset of trusted IPs or ranges. Microsoft has more information on leveraging CAPs to access Cloud Apps.
Azure Identity Protection: Azure Identity Protection is a security feature within Azure Active Directory that allows organizations to automate the detection and remediation of identity-based risks. Identity Protection analyzes user account activity as-well as sign-in activity to identify potentially compromised accounts or unauthorized authentication requests. Identity Protection data can be leveraged to enhance Conditional Access Policies by enforcing access controls based on user or sign-in risk. Additionally, Identity Protection risk data should be exported to a Security Information and Event Management (SIEM) solution for further correlation and analysis. Note: Azure Identity Protection requires an Azure AD Premium P2 License.
Multi Admin Approval with Intune: To prevent unauthorized changes, organizations utilizing Intune should implement the Multi Admin Approval feature. This feature enforces a multiple administrative approval process that requires secondary admin approval before modifying or creating Script and App deployments. Note: As of February 2023, Multi Admin Approval is in Public Preview and does not yet support request notifications. Requests will need to be manually communicated to expedite the approval workflow. Microsoft has more information regarding Multi Admin Approval.
Additional Security Controls
Block Office Macros: While Microsoft has changed the default behavior of Office applications to block macros from the internet, Mandiant still recommends Organizations proactively deploy policies to control and enforce the behavior of office files containing macros. Microsoft has more information on using policies to manage how Office handles macros.
Disable Disk Image Auto-Mount: Mandiant has observed UNC2970 utilize trojanized ISO files containing malicious payloads to bypass security controls and trick victims into executing malware. On Windows systems, the option to mount an ISO by “right-clicking” the file then selecting “Mount” from the context menu can be removed by deleting the registry keys associated with image file types (.iso, .img, .vhd, .vhdx). Deleting these registry keys will also prevent a user from auto-mounting an image file by “double-clicking” the file.
Enhance PowerShell Logging: Increase PowerShell logging to provide security engineers and investigators the visibility needed to detect malicious activity and provide a historical record of how PowerShell was used on systems. For additional details regarding enhancing PowerShell logging, please reference to the Mandiant blog post, “Greater Visibility Through PowerShell Logging”.
Indicators of Compromise
Mandiant Security Validation Actions
Organizations can validate their security controls using the following actions with Mandiant Security Validation.
Signatures
PLANKWALK
rule M_Hunt_APT_PLANKWALK_Code_String {
meta:
author = "Mandiant"
description = "Detects a format string containing code and token found in PLANKWALK"
strings:
$hex = { 63 6F 64 65 [1-6] 3D 25 64 26 [1-6] 75 73 65 72 [1-6] 3D 25 73 26 [1-6] 74 6F 6B 65 }
condition:
(uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) and $hex
}
LIDSHIFT
rule M_APT_Loader_Win_LIDSHIFT_1 {
meta:
author = "Mandiant"
description = "Detects LIDSHIFT implant"
strings:
$anchor1 = "%s:%s:%s" ascii
$encloop = { 83 ?? 3F 72 ?? EB ?? 8D ?? ?? B8 ?? 41 10 04 F7 ?? 8B ?? 2B ?? D1 ?? 03 ?? C1 ?? 05 6B ?? 3F 2B ?? 42 0F ?? ?? ?? 41 ?? ?? }
condition:
uint16(0) == 0x5a4d and all of them
}
LIDSHOT
rule M_APT_Loader_Win_LIDSHOT_1 {
meta:
author = "Mandiant"
description = "Detects LIDSHOT implant"
strings:
$code1 = { 4C 89 6D ?? 4C 89 6D ?? C7 45 ?? 01 23 45 67 C7 45 ?? 89 AB CD EF C7 45 ?? FE DC BA 98 C7 45 ?? 76 54 32 10 4C 89 6C 24 ?? 48 C7 45 ?? 0F 00 00 00 C6 44 24 ?? 00 }
$code2 = { B8 1F 85 EB 51 41 F7 E8 C1 FA 03 8B CA C1 E9 1F 03 D1 6B CA 19 }
$code3 = { C7 45 ?? 30 6B 4C 6C 66 C7 45 ?? 55 00 }
condition:
uint16(0) == 0x5a4d and all of them
}
CLOUDBURST
rule M_APT_Loader_Win_CLOUDBURST_1 {
meta:
author = "Mandiant"
strings:
$anchor1 = "Microsoft Enhanced Cryptographic Provider v1.0" ascii wide
$code1 = { 74 79 70 }
$code2 = { 65 71 75 69 }
$code3 = { 62 6F 78 69 }
$code4 = { E8 ?? ?? ?? ?? FF C6 B8 99 99 99 99 F7 EE D1 FA 8B C2 C1 E8 1F 03 D0 8D 04 16 8D 34 90 85 F6 75 ?? }
$str1 = "%s%X"
condition:
uint16(0) == 0x5a4d and all of them
}
TOUCHSHIFT
rule M_DropperMemonly_TOUCHSHIFT_1 {
meta:
author = "Mandiant"
description = "Hunting rule for TOUCHSHIFT"
strings:
$p00_0 = {0943??eb??ff43??b0??eb??e8[4]c700[4]e8[4]32c0}
$p00_1 = {4c6305[4]ba[4]4c8b0d[4]488b0d[4]ff15[4]4c6305[4]ba[4]4c8b0d[4]488b0d}
condition:
uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and
(
($p00_0 in (70000..90000) and $p00_1 in (0..64000))
)
}
SIDESHOW
rule M_APT_Backdoor_Win_SIDESHOW_1 {
meta:
author = "Mandiant"
description = "Detects string deobfuscation function in SIDESHOW, may also detect other variants of malware from the same actor"
strings:
$code1 = { 41 0F B6 ?? 33 ?? 48 ?? ?? 0F 1F 80 00 00 00 00 3A ?? 74 ?? FF ?? 48 FF ?? 83 ?? 48 72 ?? EB ?? 41 0F ?? ?? 2B ?? ?? 39 8E E3 38 83 ?? 48 F7 ?? C1 ?? 04 8D ?? ?? C1 ?? 03 2B ?? ?? 39 8E E3 38 }
condition:
uint16(0) == 0x5a4d and (all of them)
}
TOUCHKEY
rule M_Hunting_TOUCHKEY {
meta:
author = "Mandiant"
description = "Hunting rule For TOUCHKEY"
strings:
$a1 = "Normal.dost"
$a2 = "Normal.docb"
$c1 = "[SELECT]" ascii wide
$c2 = "[SLEEP]" ascii wide
$c3 = "[LSHIFT]" ascii wide
$c4 = "[RSHIFT]" ascii wide
$c5 = "[ENTER]" ascii wide
$c6 = "[SPACE]" ascii wide
condition:
(uint16(0) == 0x5A4D) and uint32(uint32(0x3C)) == 0x00004550
and filesize < 200KB and (5 of ($c*)) and $a1 and $a2
}
TOUCHSHOT
rule M_Hunting_TOUCHSHOT {
meta:
author = "Mandiant"
description = "Hunting rule For TOUCHSHOT"
strings:
$path = "%s\\Microsoft\\Windows\\Themes\\" wide
$format = "%04d%02d%02d-%02d%02d%02d"
$s1 = "EnumDisplaySettingsExW" ascii
$s2 = "GetSystemMetrics" ascii
$s3 = "GetDC" ascii
$s5 = "ReleaseDC" ascii
condition:
(uint16(0) == 0x5A4D) and uint32(uint32(0x3C)) == 0x00004550
and filesize < 200KB and (3 of ($s*)) and $path and $format
}
HOOKSHOT
rule M_Hunting_HOOKSHOT {
meta:
author = "Mandiant"
description = "Hunting rule for HOOKSHOT"
strings:
$p00_0 = {8bb1[4]408873??85f675??488b81[4]488b88[4]4885c974??e8}
$p00_1 = {8bf3488bea85db0f84[4]4c8d2d[4]66904c8d4424??8bd6488bcd}
condition:
uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and
(
($p00_0 in (470000..490000) and $p00_1 in (360000..380000))
)
}
Acknowledgements
Special thanks to John Wolfram, Rich Reece, Colby Lahaie, Dan Kelly, Joe Pisano, Jeffery Johnson, Fred Plan, Omar ElAhdan, Renato Fontana, Daniel Kennedy, and all the members of Mandiant Intelligence and Consulting that supported these investigations. We would also like to thank Lexie Aytes for creating Mandiant Security Validation (MSV) actions, as well as Michael Barnhart, Jake Nicastro, Geoff Ackerman, and Dan Perez for their technical review and feedback.