Note: All Tasks are related to the same attack. You may use information identified during, for example, Task 1 as actual data while trying to perform Task 2.

172.31.4.249 is a Linux server belonging to our organization

71.39.18.125 is the IP address is the external interface of our firewall

Task 1. Hunt for PowerShell Empire

After studying about PowerShell Empire on the below resources, identify traces/artifacts that can be used to hunt for it.

First try to locate default settings that attackers may have left unchanged. Then, start going backwards starting from the network level first.

Hint: https://github.com/EmpireProject/Empire/blob/master/setup/cert.sh

When looking at the cert.sh, we can see the default key that is created uses C=US as the subject of the certificate. Let’s hunt for that!

index=botsv2 sourcetype=stream:tcp ssl_issuer="C = US"

Once the query is completed, we can look at the src. The SSL subject/issuer value of “C = US” was seen on four internal systems.

Bonus (for advanced hunting): We could have accelerated our search by using the tstats command as follows.

index=botsv2 sourcetype=stream:tcp ssl_issuer="C = US"
| top src_ip dest_ip
| sort - count

Solutions

A data model is a hierarchically structured search-time mapping of semantic knowledge about one or more datasets. It encodes the domain knowledge necessary to build a variety of specialized searches of those datasets.

Goals of a Datamodel:

  • Make it easy to share/reuse domain knowledge [Admins/power users build data models]
  • Acceleration of large datasets to make searching more efficient
  • Provide an interface for ‘non-technical users’ interact with data via pivot UI

To list all available datamodels in your environment, execute the search below.

| datamodel
| spath displayName
| stats values(displayName)

index=botsv2 45.77.65.211
| stats count by sourcetype
| sort - count

We notice that we have web and Sysmon logs containing that indicator/IP. This means that this IP isn’t being blocked at the network level and that it has reached the system level.

The available firewall logs can indicate the workstations/servers that communicated with that IP the most:

index=botsv2 45.77.65.211 sourcetype=pan:traffic
| stats count by src_ip dest_ip
| sort - count

We obtain a similar view of the situation through Suricata logs:

index=botsv2 45.77.65.211 sourcetype=suricata
| stats count by src_ip dest_ip
| sort - count

Let’s check Suricata’s inbound alerts:

index=botsv2 src=45.77.65.211 sourcetype=suricata
index=botsv2 45.77.65.211 sourcetype=stream:http
| stats count by src_ip dest_ip
| sort - count

Let’s investigate the identified IPs above one by one.

172.31.4.249

The indicator IP (45.77.65.211) has a tremendous amount of events generated with a destination of 172.31.4.249. Note that 172.31.4.249 is a Linux server belonging to our organization.

index=botsv2 sourcetype=stream:http src_ip=45.77.65.211 dest_ip=172.31.4.249

It is not uncommon to come across strange-looking user-agents during an attack or penetration test. If we click on the *http_user_agent* field, we see w3af.org – an open source web application security scanner.

71.39.18.125

index=botsv2 45.77.65.211 sourcetype=stream:http 71.39.18.125

71.39.18.125 is the external interface of our firewall. We may want to investigate this further later.

index=botsv2 45.77.65.211 sourcetype=stream:http src_ip=10.0.2.109

Nothing that can advance our hypothesis about PowerShell Empire being executed comes up.

It is about time we move our attention to host centric data through Microsoft Sysmon logs:

index=botsv2 45.77.65.211 sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
| stats count by src_ip dest_ip
| sort - count

We see a large amount of events coming from a single server, Venus (10.0.1.101) communicating to our indicator.

index=botsv2 sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational" dest=45.77.65.211*

Once the search is completed, we notice that all returned events are running PowerShell. We also notice a lot of Network Connect Sysmon events. It is not common to see PowerShell performing network connections.

Let’s analyze these Network Connection Sysmon events related with powershell.exe further:

index=botsv2 sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational" dest=45.77.65.211*
| stats values(dest_port) as dest_port values(host) as host values(src_ip) as src_ip values(src_port) as src_port by process,dest,user

The user executing these events are either the SYSTEM account or a frothly domain account called service3.

By using the timechart command we can see that this network activity took place between 8/23 and 8/26. We are focusing on the service3 user.

index=botsv2 sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational" dest_ip=45.77.65.211* user=FROTHLY\\service3
| timechart count by src_ip

Let’s dig deeper into what has been executing through the service3 account:

index="botsv2" sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational" user=FROTHLY\\service3
| stats values(CommandLine) by Computer,process,ParentImage

Not only we can see malicious PowerShell commands being executed but we also notice *whoami.exe* and *ftp.exe* being executed by PowerShell (which is suspicious). These three suspicious processes appear in both venus.frothly.local and wrk-klagerf.frothly.local.

The output also contains */admin/get.php*. Asking for this file is characteristic of PowerShell Empire! Other strings may also exist that can indicate the existence of PowerShell Empire in our environment.

Reference: https://github.com/EmpireProject/Empire/blob/master/data/agent/agent.py

Task 2. Hunt for FTP exfiltration

Let’s start with the available sourcetypes for this hunt focusing on August 2017.

index=botsv2 ftp
| stats count by sourcetype
| sort - count

Let’s now try to identify an IP/indicator.

index=botsv2 ftp sourcetype=suricata
| stats count by src_ip dest_ip
| sort - count
index=botsv2 ftp sourcetype=stream:ftp
| stats count by src_ip dest_ip
| sort - count
index=botsv2 ftp sourcetype=pan:traffic
| stats count by src_ip dest_ip
| sort - count

Let’s step away from the network level for a bit and focus on the endpoint level. First, Sysmon events related to FTP by host.

index=botsv2 ftp sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational"
| stats count by host
| sort - count

Then, Sysmon events related to FTP by CommandLine:

index=botsv2 ftp sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational"
| stats count by CommandLine

Back to the network now, let’s try to see inside the FTP traffic.

index=botsv2 ftp sourcetype=stream:ftp src_ip=* dest_ip=160.153.91.7

The interesting fields to browse are: flow_id, reply_content, method, method_parameter, filename

Let’s refine our search:

index=botsv2 sourcetype=stream:ftp src_ip=* dest_ip=160.153.91.7 method!=PORT method!=TYPE method!=NLST
| table _time src_ip filename method method_parameter reply_content
| sort + _time

Looking at the results you will notice the exact same sequence of actions taking place at both 10.0.2.107 and 10.0.2.109. We can see 3 executables, a DLL, a MSI installer for python, a python script and a hwp file extension (Korean word processing application).

index=botsv2 sourcetype=stream:ftp src_ip=* dest_ip=160.153.91.7

Now you can view which files were uploaded/exfiltrated:

index=botsv2 sourcetype=stream:ftp src_ip=* dest_ip=160.153.91.7
| stats count by filename

Finally, focus on the DLL files:

index=botsv2 (singlefile.dll OR winsys32.dll)
| reverse
index=botsv2 sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational" (singlefile.dll OR winsys32.dll)
| table _time host user CommandLine ParentCommandLine
| reverse
index=botsv2 sourcetype=wineventlog (singlefile.dll OR winsys32.dll)
| stats count by host

Search for the other files that were downloaded:

index=botsv2 sourcetype!=stream:ftp (dns.py OR nc.exe OR psexec.exe OR python-2.7.6.amd64.msi OR wget64.exe OR winsys64.dll OR *.hwp)
| stats count by host
index=botsv2 sourcetype!=stream:ftp (dns.py OR nc.exe OR psexec.exe OR python-2.7.6.amd64.msi OR wget64.exe OR winsys64.dll OR *.hwp)
| reverse
| search host="venus"

Task 3. Hunt for DNS exfiltration

With the IP address of 160.153.91.7, we can leverage this indicator to determine if any exfiltration was being attempted using DNS.

index=botsv2 sourcetype=stream:dns 160.153.91.7
| stats count by src_ip

Let’s start investigating 10.0.2.107:

index=botsv2 sourcetype=stream:dns 160.153.91.7 src_ip=10.0.2.107

If we click the name field we notice a curious-looking domain. Let’s investigate further:

index=botsv2 sourcetype=stream:dns hildegardsfarm.com
| stats count by dest_ip
| sort - count

We notice almost 70K events for this domain! Let’s look into the queries:

index=botsv2 sourcetype=stream:dns hildegardsfarm.com "query{}"="*"
| table _time query{} src_ip dest_ip

Let’s leverage URL Toolbox to refine our search. We will reference the mozilla list and run the ut_parse_extended macro against the query field, calculate Shannon entropy score:

index=botsv2 sourcetype=stream:dns hildegardsfarm.com "query{}"="*" query *.hildegardsfarm.com
| eval query{}=mvdedup(query)
| eval list="mozilla"
| `ut_parse_extended(query{},list)`
| `ut_shannon(ut_subdomain)`
| table src_ip dest_ip query{} ut_subdomain ut_shannon

Entropy scores greater than 3 are considered high and can often be used to determine if domains or urls are algorithmically generated.

index=botsv2 sourcetype=stream:dns hildegardsfarm.com "query{}"="*" query *.hildegardsfarm.com
| eval query{}=mvdedup(query)
| eval list="mozilla"
| `ut_parse_extended(query{},list)`
| `ut_shannon(ut_subdomain)`
| eval sublen = length(ut_subdomain)
| table ut_domain ut_subdomain ut_shannon sublen
| stats count avg(ut_shannon) as avg_entropy avg(sublen) as avg_sublen stdev(sublen) as stdev_sublen by ut_domain

Generally, a high average entropy, high subdomain length and low standard deviation of the length, coupled with a high event count could be indicative of a DNS exfiltration attempt.

Task 4. Hunt for adversary infrastructure

We already know that our 10.0.2.107 endpoint communicated with the 45.77.65.211 IP indicator. Let’s extract the certificate’s sha256 hash:

index=botsv2 sourcetype=stream:tcp dest_ip=45.77.65.211 src_ip=10.0.2.107
| stats count by ssl_cert_sha256

Submit the IP Indicator to virustotal.com. The initial results show as clean, but under Communicating Files there are three malicious files associated to the IP Address. By clicking on one or more of these files you now have an opportunity to expand your indicators of compromise list.

Task 5. Hunt for lateral movement through WMI

Based on JPCERT guidance, we can craft a search using Sysmon:

index=botsv2 sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational" EventCode=1 ParentImage="C:\\Windows\\System32\\svchost.exe" CurrentDirectory="C:\\Windows\\system32\\" CommandLine="C:\\Windows\\system32\\wbem\\wmiprvse.exe -secured -Embedding" ParentCommandLine="C:\\Windows\\system32\\svchost.exe -k DcomLaunch" User="NT AUTHORITY\\NETWORK SERVICE" Image="C:\\Windows\\System32\\wbem\\WmiPrvSE.exe"
| stats count by host
index=botsv2 sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational" EventCode=3 Image="C:\\Windows\\System32\\svchost.exe" User="NT AUTHORITY\\NETWORK SERVICE"

Let’s focus on Teymur Kheirklabarov’s advice on hunting for remote execution via WMI (systems with Network 4624 Event followed by Sysmon Process Creations).

index=botsv2 (sourcetype=wineventlog (EventCode=4624 Logon_Type=3)) OR (sourcetype="xmlwineventlog:microsoft-windows-sysmon/operational" ParentCommandLine!="*\\svchost.exe" EventCode=1)
| eval login=mvindex(Logon_ID,1)
| eval user_id=mvindex(Security_ID,1)
| eval session=lower(coalesce(login,LogonId))
| transaction session startswith=(EventCode=4624) mvlist=ParentImage
| search eventcount>1
| eval Parent_Process=mvindex(ParentImage, 1)
| table _time dest_ip session host user_id Parent_Process Image CommandLine

To see all events during identified sessions on venus and wrk-klagerf:

index=botsv2 ((Logon_ID=0x171491a OR LogonId=0x171491a) host=venus)
| table _time EventCode TaskCategory Account_Name Security_ID Process_Command_Line CommandLine ParentCommandLine
| reverse
index=botsv2 ((Logon_ID=0xf9b47f OR LogonId=0xf9b47f) host=wrk-klagerf)
| table _time EventCode TaskCategory Account_Name Security_ID Process_Command_Line CommandLine ParentCommandLine
| reverse