Hello You#

Many features have been added to the lab since the last post, including Microsoft Defender for Endpoint (MDE) telemetry, DNS-related logs, and more. These additions, however, will not be the focus of this article, as a separate blog post is being prepared to cover them in detail

While working through the HTB File Transfers module, I tested many of the techniques discussed and discovered several effective ways to hunt for them. What really surprised me was the quality of MDE telemetry as we’ll explore in this blog

Here’s what the lab setup currently looks like:

We’ll be focusing on the activity happening between atklnx01 & ws01 as I only installed Microsoft Defender for Endpoint MDE with P2 license on it, the rest let’s say are spiritually protected and we’re just focusing on our golden child ws01

Let’s get started

FTP Activity#

File Download#

On the attacking machine atklnx01 I installed pyftpdlib and started an ftp server

sudo pip3 install pyftpdlib
sudo python3 -m pyftpdlib --port 21

Tried here to download note.txt from atklnx01 using Net.WebClient

I observed many DeviceNetworkEvents with FtpConnectionInspected which gives you a really similar details as zeek FTP logs but the ws01 point of view

You can use this KQL to look for FTP activities in your tenant

DeviceNetworkEvents
| where ActionType == "FtpConnectionInspected"
| where AdditionalFields.command == "RETR"
| extend cwd_ = tostring(AdditionalFields.cwd)
| where AdditionalFields.direction == "Out"
| extend reply_msg_ = tostring(AdditionalFields.reply_msg)
| extend user_ = tostring(AdditionalFields.user)
| where RemotePort == 21
| extend mime_type_ = tostring(AdditionalFields.mime_type)
| extend command_ = tostring(AdditionalFields.command)
| extend arg_ = tostring(AdditionalFields.arg)
| project-reorder TimeGenerated, LocalIP, RemoteIP, DeviceName, reply_msg_, user_, command_, arg_, cwd_

RETR FTP command - A client issues the RETR command after successfully establishing a data connection when it wishes to download a copy of a file on the server.

I wanted to check another way of file download using ftp.exe, I created ftpcommands.txt file which contains commands to connect and get flag.txt and exit

This activity triggered the Windows Defender Firewall. From the attacker’s point of view, if enough privileges were available, an additional command could be executed to modify the firewall settings and allow the file transfer to proceed without interruption

From the atklnx01 we see that the activity timed out

The command execution and connection status were logged

We also see that Windows security alert was logged as well

as this command was executed

rundll32.exe C:\Windows\System32\FirewallControlPanel.dll,ShowNotificationDialog /ETOnly 0 /OnProfiles 7 /OtherAllowed 0 /OtherBlocked 0 /OtherEdgeAllowed 0 /NewBlocked 4 "C:\windows\system32\ftp.exe"

The command uses rundll32.exe to invoke a function (ShowNotificationDialog) from the FirewallControlPanel.dll library in order to display a Windows Firewall notification.

File Upload#

We’ll add the switch --write to the python command we ran earlier on atklnx01 to allow file upload

Similarly we used net.WebClient object

Really similiar to the previous query but we look for STOR

STOR FTP command - A client issues the STOR command after successfully establishing a data connection when it wishes to upload a copy of a local file to the server.

DeviceNetworkEvents
| where ActionType == "FtpConnectionInspected"
| where AdditionalFields.command == "STOR"
| extend cwd_ = tostring(AdditionalFields.cwd)
| where AdditionalFields.direction == "Out"
| extend reply_msg_ = tostring(AdditionalFields.reply_msg)
| extend user_ = tostring(AdditionalFields.user)
// | where RemotePort == 21
| extend mime_type_ = tostring(AdditionalFields.mime_type)
| extend command_ = tostring(AdditionalFields.command)
| extend arg_ = tostring(AdditionalFields.arg)
| project-reorder TimeGenerated, LocalIP, RemoteIP, DeviceName, reply_msg_, user_, command_, arg_, cwd_

Impacket SMB Sever Activity#

To start impacket-smbserver with a folder as our share, now the server is running we just have to copy a file from that share

We connected to that share and we see a file creation during that period, I checked here sysmon logs but the same commands can be observed in DeviceEvents & DeviceProcessEvents

Unfortunately here I didn’t enable or get the PowerShell\ScriptBlockLogging logs however it would be good idea to implement it, but still MDE telemetry saves the day because it logs some PowerShell command execution

You can check the PowerShellCommand action type in DeviceEvents to see PowerShell commands but I’m not 100% to which extent it logs PowerShell commands, that’s why I need to get the PowerShell\ScriptBlockLogging logs and compare them with what I already have

However, for now this does the job but you can make it better by also search for domains instead of just looking for IPs

DeviceEvents
| where ActionType == "PowerShellCommand"
| extend ParsedFields = parse_json(AdditionalFields)
| extend CommandString = tostring(ParsedFields.Command)
| where CommandString matches regex @"copy \\\\[0-9]{1,3}(\.[0-9]{1,3}){3}\\[^\\]+(\\[^\\]+)*"
| parse CommandString with "copy \\\\" IP:string "\\" ShareName:string "\\" *
| project-reorder TimeGenerated, DeviceName, InitiatingProcessAccountUpn, ActionType, CommandString, IP, ShareName, ProcessId, InitiatingProcessId, InitiatingProcessParentId

Immediately after this event a DeviceNetworkEvents will be generated with connection success to the attacker machine

DeviceNetworkEvents
| where ActionType == "ConnectionSuccess"
| where InitiatingProcessAccountDomain == "nt authority"
| where InitiatingProcessAccountName == "system"
| where LocalIPType == "Private"
| where RemotePort == 445
| project-reorder TimeGenerated, DeviceName, LocalIP, Protocol,RemoteIPType, RemotePort

What really stand out in detecting Impacket-smbserver is some unique names and version type that can be found in the DeviceNetworkEvents with the action type NtlmAuthenticationInspected

Which can be detected using:

DeviceNetworkEvents
| where ActionType == "NtlmAuthenticationInspected"
| where AdditionalFields.direction == "Out"
| where RemotePort == 445
| extend hostname_ = tostring(AdditionalFields.hostname)
| extend server_dns_computer_name_ = tostring(AdditionalFields.server_dns_computer_name)
| extend server_dns_domain_name_ = tostring(AdditionalFields.server_dns_domain_name)
| extend server_nb_computer_name_ = tostring(AdditionalFields.server_nb_computer_name)
| extend server_nb_domain_name_ = tostring(AdditionalFields.server_nb_domain_name)
| extend server_version_ = tostring(AdditionalFields.server_version)
| where server_version_ == "255.255 65535 255"
| extend ts_ = tostring(AdditionalFields.ts)
| extend uid_ = tostring(AdditionalFields.uid)
| extend username_ = tostring(AdditionalFields.username)
| where  strlen(server_dns_computer_name_) == 8 
| where  strlen(server_dns_domain_name_) == 8 
| where  strlen(server_nb_computer_name_) == 8 
| where  strlen(server_nb_domain_name_) == 8 

When a connection is made to a system running impacket-smbserver, MDE logs this interaction with some key characteristics:

  • Several server identity fields (such as DNS and NetBIOS names) contain randomly generated 8-character strings and they re-generate everytime you run the tool
  • The server version is reported as 255.255 65535 255, which stands out as highly suspicious as in normal environments we don’t see such version

Detecting Impacket-smbserver with Authentication#

We can use the -user and -password flags to specify authentication credentials for the SMB share

sudo impacket-smbserver share -smb2support /tmp/smbshare -user test -password test

Back to ws01 we mount the share using:

net use n: \\192.168.220.133\share /user:test test

We observed an explicit login attempt to atklnx01 machine, recorded with Event ID 4648:

This activity is also captured in the DeviceLoginEvents table:

In this scenario, access to the SMB share was initiated via Windows Explorer:

When a remote share is accessed this way, shell link (.lnk) files are created and stored under:

AppData\Roaming\Microsoft\Windows\Recent\<share-name>\

These .lnk files follow the naming format:

<share name> (<share IP address>) (<mounted drive letter>).lnk

This activity is also logged in the Security Event Log:

Additionally, In the DeviceProcessEvents we can see also all execution related to both mounting and unmounting operations:

Lolbins - CertReq#

LOLBins (Living-off-the-Land Binaries) are legitimate system binaries that are sometimes abused by adversaries to perform malicious actions while evading detection by avoiding the use of their own tools

I’m considering writing a query to detect all types of file upload and download activity involving LOLBins. But for now, here’s one scenario I simulated using CertReq.exe along with a detection query I wrote for it

DeviceProcessEvents
| extend 
    RemoteUrl = extract(@"-config\s+(http[s]?://[^\s]+)", 1, ProcessCommandLine),
    UploadedFile = extract(@"-config\s+http[s]?://[^\s]+\s+([^\s]+)", 1, ProcessCommandLine)
| where FileName =~ "certreq.exe"
| where ProcessCommandLine has "-Post"
    and ProcessCommandLine contains "http"
| extend parent = tostring(InitiatingProcessFileName)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), ProcessCount = count()
    by DeviceName, AccountName, ProcessCommandLine, parent, InitiatingProcessCommandLine, InitiatingProcessSHA256, RemoteUrl, UploadedFile
| join kind=inner (
    DeviceNetworkEvents
    | where InitiatingProcessFileName =~ "certreq.exe"
    | project DeviceName, NetworkTime=TimeGenerated, RemoteIP, RemotePort, InitiatingProcessCommandLine
) on DeviceName

The End#

And yeah this is it for today’s article, hope you enjoyed it

Until Next Time