As a SOC analyst we are often tasked with finding out either pentester or malicious
activity that occurs in the monitored environment and creating signatures for
these findings. In a recent pentesing engagement (after of course running freely in the
network), they shared that they used the Impacket tools for much of their movement.
This short series will be analyzing some of the various tools offered in the
Impacket set. Through this analysis we will attempt to identify elements of the tools
that signatures can be created for. Although attackers have a seemingly limitless amount of
tools, in your analysis you may discover a shared immutable principle between these tools
that may lend insight to attack techniques in general.
We will begin with impacket tool psexec.py. The original psexec, written by Windows guru
and all around savage Mark Russinovich, was created to help administrators remote
into hosts and perform their administrative duties. It can also be an excellent tool for
lateral movement in an environment. Psexec.py uses RemcomSVC to perform the same
functions psexec can. As explained in the github page for RemcomSvc, it is :
“a small (10KB upx packed) remoteshell / telnet replacement that lets you execute processes on remote
windows systems, copy files on remote systems, process their output and stream it back. It allows execution
of remote shell commands directly with full interactive console without having to install any client software.”Source.
Below is a great succinct description provided in an article titled ‘Psexec Demystified’ on
how PSExec works:
[PSExec] has a Windows Service image inside of its executable.
- It takes this service and deploys it to the Admin$ share on the remote machine
- It then uses the DCE/RPC interface over SMB to access the Windows Service Control Manager API.
It turns on the PSExec service on the remote machine. - The PSExec service then creates a named pipe that can be used to send commands to the system.”Source.
We will go through each step with the psexec.py version with network traffic and host log examples.
1. It takes this service and deploys it to the Admin$ share on the remote machine.
The Admin share is typically used to deploy software on a remote machine. Source. With Psexec.py,
This is completed by authenticating to the remote machine with NTLM over SMB,
though Kerberos authentication can be used as well. The first oddity that stands out after
authenticating, is that psexec.py sends an SMB Create Request file named “BETO “
to the remote host. Once it receives a response, it sends a setinfo command that requests
the file to be deleted when closed. According to Microsoft the setinfo packet is sent by a
client to, “ request either creation of or access to a file. In case of a named pipe or printer,
the server MUST create a new file.” By going through the code I can see that the author's
name is beto with a twitter handle of @agsolino. Perhaps the author did it to ensure they
can create files on the $ADMIN share. Following this action, psexec.py connects back to
the $ADMIN share and writes a randomly generated eight character executable.
The sha1 hash for this exe is 23873bf2670cf64c2440058130548d4e4da412dd.
2. It then uses the DCE/RPC interface over SMB to access the Windows Service Control
Manager API. It turns on the PSExec service on the remote machine.
In order to complete this part, the attacker must connect to the dce-rpc svcctl interface
which is, “used to manage Windows services via the SCM (Service Control Manager)”, Source
and perform the following operations illustrated in the figure below.
These were gathered from the dce_rpc.log from bro that I would highly recommend using as it
is not only a great logging framework but a powerful scripting language as well.
When psexec.py performs the OpenSCManager operation it identifies the MachineName as DUMMY.
When I used both remcom and the original psexec, they identified the machine name with the
ip address of the remote host. This activity could also be viewed by looking for the windows event
code 7045, a new service being installed and other ways through the windows logs that we will go
through in the signatures section.
3. The PSExec service then creates a named pipe that can be used to send commands to the system.
This last action is completed through the IPC(Inter Process Communication) share which
allows for this type of communication between two remote hosts. In order for named pipe
communications to occur, two packets must be sent: the SMB IOCTL request and Create
Request File packets. The SMB IOCTL packet requires the following before it is sent:
- “A handle to the TreeConnect identifying the connection to the IPC$ share
- The name of the named pipe, omitting any prefixes such as "\pipe\".Source.
What matters to us, is the identification of the connection to the IPC$ share and the name of the named
pipe. For psexec.py, the names for the named pipes are RemCom_communication,
RemCom_stdin[a-z0-9]{8}, RemCom_stdout[a-z0-9]{8} and RemCom_stderr[a-z0-9]{8}.
The Create Request File packet contains the access mask for each of these named pipes requests,
which is the other significant aspect to make note of. The access mask provides insight into what the
attacker wants to do when they access the remote host. For the RemCom_communication named
pipe pictured below, it contains the access mask of 0x0012019f. This is the same access mask many
msrpc named pipes request when establishing a communication channel. Remcom stdin, requests 0x6,
which is write and append and stdout and stderr both request 0x1, which is read. By looking at these
access masks and knowing their values, you can infer that psexec.py allows for some form of
interactive communication over this named pipe.
Signatures
The signatures we will be creating, will be from Windows event logs forwarded to Splunk, since,
at least in my limited experience, network taps are almost never placed where you want them;
typically being placed at the perimeter, making every network defender cry :(. If you want to follow
along, I would recommend installing Splunk in your home lab. DA_667 has released a book on how
to create a lab and there’s an awesome section on how to install Splunk.
We can begin with some easy ones that generate an alert from some of the strings we pointed out
earlier.
iindex=wineventlog sourcetype=wineventlog:security EventCode=5145 Relative_Target_Name="BETO"
| table _time Source_Address Account_Name Share_Name Share_Path Relative_Target_Name Access_Mask
index=wineventlog sourcetype=wineventlog:security Relative_Target_Name="RemCom*" EventCode=5145
| table _time Source_Address Account_Name ComputerName Share_Name Relative_Target_Name Access_Mask
Some others would require you to profile the activity that occurs in the network.
Should users/service accounts be accessing the $ADMIN share in your environment?
If so, who does? From what IP? Is that IP always the same? Why do they usually access this share and on which hosts
does this activity typically occur? Even looking for writes to the Admin share may yield some interesting discoveries:
does this activity typically occur? Even looking for writes to the Admin share may yield some interesting discoveries:
index=wineventlog sourcetype=wineventlog:security EventCode=5145
(Access_Mask=0x120196 OR Access_Mask=0x2 OR Access_Mask=0x6 OR Access_Mask=0x130197) | table _time Source_Address Account_Name ComputerName Share_Name Relative_Target_Name Access_Mask
Again though, there may be service accounts that trigger these queries, so it's best to run these first as far back as you can to filter out false positives or to determine whether this is applicable in your environment.
What about services installed on a host? How many times does this occur and by which user accounts?
sourcetype="WinEventLog:Security" index=wineventlog EventCode=5145
AND (Access_Mask="0x2" OR Access_Mask="0x6" OR Access_Mask="0x12019f")
| bucket _time span=3s
| rex "(?<masks>(0x2|0x6|0x12019f))"
| stats values(Relative_Target_Name) AS Relative_Target_Name values(Account_Name) AS Account_Name
values(Source_Address) AS Source_Address dc(masks) AS distinct_masks by _time ComputerName
| search distinct_masks=3
| table _time Source_Address Account_Name ComputerName Relative_Target_Name distinct_masks
This signature is a bit different from the other ones. As the other ones look for identifiable
strings, this one is more for the behavioral aspect. It looks for for a write to a share (0x2)
along with the write and append (0x6) and for the create file request (0x12019f)
within a small period of time on the same host. This signature was a revision of one created by
jackcr in his blog findingbad.blogspot.com. Jackr is an excellent resource for developing and
honing your analytical process when looking for adversaries. Source
| bucket _time span=1s
| stats values(Process_Command_Line) AS Process_Command_Line values(Relative_Target_Name) AS Relative_Target_Name values(Account_Name) AS Account_Name by _time ComputerName
| search Relative_Target_Name!="NULL" AND Process_Command_Line!="NULL"
| table _time Account_Name ComputerName Process_Command_Line Relative_Target_Name
This signature, pictured below, looks for writes to an smb share and command line
execution within a one second time span. The selection of access masks are relatively rare,
thus when those are used I would want to observe if there was any command line activity within
that time.
index=wineventlog (sourcetype="wineventlog:security" EventCode=5145 Access_Mask=0x2
OR Access_Mask=0x120196 OR Access_Mask=0x6) OR
(sourcetype="wineventlog:system" EventCode=7045)
| rex field=Service_File_Name "(?<file_name>[^\\\]*$)"
| bucket _time span=1s
| stats values(file_name) AS file_name values(Relative_Target_Name)
AS Relative_Target_Name values(EventCode) AS EventCode values(Account_Name)
AS Account_Name by _time ComputerName
| search file_name!="NULL" AND Relative_Target_Name!="NULL"
| table _time Account_Name file_name Relative_Target_Name ComputerName
This signature is very similar to the previous query however it looks for service created rather than
process executed.
index=wineventlog (sourcetype="wineventlog:security" EventCode=5145 Access_Mask=0x2
OR Access_Mask=0x120196 OR Access_Mask=0x6 OR Access_Mask=0x130197)
OR (sourcetype="wineventlog:system" EventCode=7045)
| rex field=Service_File_Name "(?<process>[^\\\]*$)"
| streamstats count by EventCode process Relative_Target_Name
| bucket _time span=1s
| stats values(process) AS process values(Relative_Target_Name) AS Relative_Target_Name values(EventCode) AS EventCode by _time ComputerName
| eval status = if(match(process,Relative_Target_Name), "Match", "No Match")
| search status="Match"
This signature looks for whether process executed and the file written to the share are the same within a one second time span and if they match, return the results.
Sources:
http://www.hsc.fr/ressources/articles/win_net_srv/msrpc_svcctl.html
https://msdn.microsoft.com/en-us/library/gg258352.aspx ( IOCTL named pipe stuff)