This time I am trying something different. I am in no way, shape or form capable in malware analysis but I was thinking if it could be useful to run a live malware on a device with MDE agent installed. This could potentially provide great telemetry data to generate ideas for threat hunting purposes. In this instance, I just wanted to pick up a random malicious ISO file and stumbled upon this:
This seems to be potentially IcedID loader which would be great for the example I guess. So I downloaded the sample, moved it to the lab and double clicked to open the file. The contents of the file were pretty much expected, an LNK file with everything else being hidden:
This shortcut then pointed to a script under AT folder stored on the same ISO file. The first script is executed with the following command line: ‘cmd.exe /c ““F:\at\thenWaySomeManyThem.bat” “‘. Then, it continues to execute malicious javascript file with the following command: ‘“WScript.exe” “F:\at\himCanBeTwoGive.js” ru123ndll12332123’. Even by looking only at the command line, it is quite easy to see what is the next step, running something with rundll32.exe: ‘rundll32.exe” at/veryIntoAlsoTimeI.txt,#1’. Then, the rundll32.exe connect to a public IP address, likely trying to download additional code. When looking at the contents, these files are of course present on the ISO file, but malware analysis is not really the point of this blog post so I am not going to dwell deeper to that.
Process tree of the malware launch
So this example is super simple. All four steps here can be added to a advanced hunting query very simply. First things first, I’ll create query target the process start events, with having all three processes intact.
DeviceProcessEvents
| where FileName =~ "rundll32.exe"
| where InitiatingProcessFileName =~ "wscript.exe"
| where InitiatingProcessParentFileName =~ "cmd.exe"
| project Timestamp,DeviceName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessParentFileName
Easy. Now, adding the network connection requires a simple join, only thing adding a little complexity is that the join has to be made with the rundll32.exe process, so this requires renaming the fields (or dropping off the grandparent process from the first part of the query).
DeviceProcessEvents
| where FileName =~ "rundll32.exe"
| where InitiatingProcessFileName =~ "wscript.exe"
| where InitiatingProcessParentFileName =~ "cmd.exe"
| project Timestamp,DeviceName, InvestigatedProcessName=FileName, InvestigatedProcessCommandLine = ProcessCommandLine,InvestigatedProcessStartTime = ProcessCreationTime, InvestigatedProcessId = ProcessId, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessParentFileName
| join (
DeviceNetworkEvents
| where InitiatingProcessFileName =~ "rundll32.exe"
| where RemoteIPType == "Public"
| project DeviceName, InvestigatedProcessName=InitiatingProcessFileName, InvestigatedProcessCommandLine = InitiatingProcessCommandLine,InvestigatedProcessStartTime = InitiatingProcessCreationTime, InvestigatedProcessId = InitiatingProcessId, RemoteIP, RemoteUrl
) on DeviceName, InvestigatedProcessCommandLine, InvestigatedProcessId, InvestigatedProcessName, InvestigatedProcessStartTime
| project-away DeviceName1, InvestigatedProcessCommandLine1, InvestigatedProcessId1, InvestigatedProcessName1, InvestigatedProcessStartTime1
This should work, but unfortunately when I executed the malware the events did not end up to advanced hunt. They were present on the timeline but not in the advanced hunt, which was likely cause by the license that I had active at the time. Unfortunately, I didn’t realize that the license which I had did not enable the full blown MDE events. When I changed the license and ran the malware again, it did not initiate the network connection.
The next query adds less restricted filters to the process events. This should make the query a little more universal.
DeviceProcessEvents
| where FileName has_any ("rundll32.exe","regsvr32.exe")
| where InitiatingProcessFileName has_any ("wscript.exe","powershell.exe","cmd.exe","pwsh.exe")
| project Timestamp,DeviceName, InvestigatedProcessName=FileName, InvestigatedProcessCommandLine = ProcessCommandLine,InvestigatedProcessStartTime = ProcessCreationTime, InvestigatedProcessId = ProcessId, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessParentFileName
| join (
DeviceNetworkEvents
| where InitiatingProcessFileName has_any ("rundll32.exe","regsvr32.exe")
| where RemoteIPType == "Public"
| project DeviceName, InvestigatedProcessName=InitiatingProcessFileName, InvestigatedProcessCommandLine = InitiatingProcessCommandLine,InvestigatedProcessStartTime = InitiatingProcessCreationTime, InvestigatedProcessId = InitiatingProcessId, RemoteIP, RemoteUrl
) on DeviceName, InvestigatedProcessCommandLine, InvestigatedProcessId, InvestigatedProcessName, InvestigatedProcessStartTime
| project-away DeviceName1, InvestigatedProcessCommandLine1, InvestigatedProcessId1, InvestigatedProcessName1, InvestigatedProcessStartTime1
And at this stage I really just wanted to verify that the logic works so I rolled back the virtual machine, launched the same malware once more and was able to verify that the queries catches this particular malware.
The query results.
Aaand it seems to work as I intended to. Of course this is still super targeted. One idea to catch this kind of malware would be to look for image loads where the extension is something else than .dll. This can be then joined to the network events similarly to the previous query.
DeviceImageLoadEvents
| where InitiatingProcessFileName has_any ("rundll32.exe","regsvr32.exe")
| where FileName !endswith ".dll"
| join (
DeviceNetworkEvents
| where InitiatingProcessFileName has_any ("rundll32.exe","regsvr32.exe")
| where RemoteIPType == "Public"
) on InitiatingProcessFileName, InitiatingProcessId, InitiatingProcessCreationTime, InitiatingProcessCommandLine
| project Timestamp, DeviceName, FileName, FolderPath, SHA1, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteIP, RemoteUrl, RemotePort, InitiatingProcessParentFileName
This also seems to be working fine and could catch things that are not caught with the first queries. The idea of this blog post was not really to continue the subject from the previous one, but apparently it partly did. I did like the idea of running live malware and then analyzing how that could be caught with the advanced hunt queries and will likely revisit this in the future blogs too.
Also, I finally added Github repository for storing the queries. I have no metadata there and likely never will have, as the queries are explained in this blog. They are there so it is easier to copy them than from the actual blog post. The repository is available here: https://github.com/JouniMi/Threathunt.blog/tree/main
Github link to queries in this post: https://github.com/JouniMi/Threathunt.blog/blob/main/live_mw_for_hunting_purposes