Detecting Powershell Empire

One of my favorite utilities to use as a Network Administrator is Powershell. There are so many tasks that can be performed with Powershell for automation and administering a network at scale, that it is almost becoming necessary to use it to manage a network nowadays. Because of it's ability to effectively manage a network, it can also be used to exploit a network and there are now utilities being built for exploiting Powershell. For those that aren't familiar with it, Powershell Empire is a framework aimed at making exploitation of a Windows environment easier and faster through the use of Powershell. It essentially creates a server/client relationship with any machine that an attacker has placed an agent on, and gives the attacker the ability to execute any commands on the compromised machine, as well as a lot of built exploitation modules such as Mimikatz without ever having to upload the files as everything is run in memory.

As a defender, logs can be overwhelming at times and when we try to automate the process of identifying abnormal behavior in a network we sometimes look for key signatures to alert on malicious activity. Powershell Empire's agents run in memory, so it generates very few logs. It also attempts to obfuscate it's initiation script whenever a new agent is deployed, so attempting to monitoring Powershell ScriptBlock logs can prove to be almost impossible. With it's ability to essentially hide it's activity and the ability to execute several built in exploitation modules, this makes Powershell Empire somewhat of a nightmare for analysts to detect. The only way you can effectively identify Powershell Empire's usage is through Sysmon.

There are two ways to effectively detect Powershell Empire with Sysmon and that is with Event ID 1 and 3. Upon a new installation of an agent, both of these events will trigger. Event ID 1 will look like the following:



The Sysmon Event ID 1 "CommandLine" output will always begin with the full path to Powershell with the "-NoP -sta -w 1 -enc" switches and a long base64 encoded string following. The first thing you would want to check is to make sure you are currently monitoring Powershell usage with Sysmon. To make sure you have configured Sysmon to include powershell.exe usage, you will need to add an include entry for powershell.exe in both Event ID 1 & 3's configuration in your Sysmon.xml configuratio file(If you are using ion-storm's Sysmon config, which I highly recommend, this is already taken care of for you). Once you have Sysmon configured to log Powershell usage, and you will want to configure conditions to trigger alerts based on the "CommandLine" field beginning with powershell's full path and include the switches all the way to the -enc portion of the script that is executed above. As of this day, any default type of connection that is made to a Powershell Empire host follows the same syntax. 

The second way that can be utilized to identify Powershell Empire in the environment, and my preferred way, is by monitoring Sysmon Event ID 3. The event log looks like such below:


It is very rare that I initiate an external network connection utilizing Powershell, and by monitoring this type of event, it helps you identify not only when someone may be using Powershell Empire, but also utilizing Powershell to download/upload files as well. This is approach is also more useful than just monitoring Event ID 1 as if someone has already deployed the Powershell Empire agents in your environment, you may not get those Event ID 1 logs that are generated, but as the agent is scheduled to check in, you will always receive an event log entry from Sysmon Event ID 3. The simplest way to monitor for this event is monitor for any Event ID 3, with the "Image" being set to powershell.exe and the Destination IP address being an external IP address, or if you prefer, any IP address.

As stated earlier, Powershell is on the rise in being used for malicious intent and it is becoming a necessity to monitor it's usage. If you have not done so already, I highly recommend deploying Sysmon, and make sure you are monitoring Powershell in your Sysmon configuration, as I stated earlier even if you are performing Powershell ScriptBlock monitoring, it is quite difficult to detect Powershell Empire's usage through typical conditional rules and Sysmon simply makes detecting it quite easy.

Scapy - Part 1

Creating a custom local ICMP rule is one of the easiest ways to make sure Snort is capturing traffic in the way you assume it should be. The issue though is sometimes we want to create our own custom rules, and in my opinion the only way to test those rules is to create a custom packet. One of my favorite applications for this is Scapy. Scapy is a python application that allows you to create any type of packet you want right from your terminal allowing you to add specific strings or hex characters in your payloads to assist in triggering your snort rules. This may sound a bit more difficult than it is, but hopefully these series of posts will make this a bit easier.

Trying to remember everything about flag and field of a packet can sometimes be overwhelming so for right now since we are testing just basic Snort rules, the only thing you really need to worry about is a source and destination IP, source and destination port, and the payload itself. Because Scapy is developed with Python, Python will be required to have been installed, as well as Scapy having been downloaded. I'm going to assume you have already gotten this far. To begin with an example, we are going to look at this simple rule that triggers when a DNS query is made containing the string "teamviewer". Here is the snort rule below:

alert udp $HOME_NET any -> $EXTERNAL_NET 53 (msg:"APP-DETECT Teamviewer control server ping"; flow:to_server; content:"teamviewer"; fast_pattern:only; metadata:service dns; reference:url,; classtype:policy-violation; sid:24094; rev:1;)

As you can see, the above snort rule simply alerts when a UDP packet is sent to destination port 53, and contains the string "teamviewer". In this instance it may be easier to just open a browser and go to but this will not always be the case. To test this rule with Scapy the following will need to be executed to create our custom packet:

  1. ip=IP(src="")
  2. ip.dst=""
  3. UDP=UDP(sport=23432,dport=53)
  4. data="teamviewer"
  5. packet=ip/UDP/data
  6. send(packet)

Below is an explanation of each command above (All the variable names below can be changed, I just like to keep it uniform like this):

  1. A variable called IP was created and the IP function was called and set the source IP of our created packet to
  2. The IP object is called and is passed the destination function which sets the destination IP address to
  3. A variable called UDP is created and the UDP function is called and the source port is set to 23432 and the destination port is set to 53.
  4. A variable called data is created and the string "teamviewer" is assigned to the variable.
  5. The final variable packet is created and the ip packet, UDP datagram, and essentially the payload are all assigned the packet variable to create your packet.
  6. Once the packet is created, the send function is called and the packet is passed as a parameter to the function and the packet is sent on it's way.

If the packet happens to pass your Snort sensor that has the above teamviewer rule enabled, an alert will be generated, letting you know that this rule was triggered.

Depending on how your rules are created, it is not always this easy, but as long as the Snort Rule does not have flow:established, this approach will trigger any type of rule similar to the above. If you have any questions let me know, The next post I plan on going a bit more in-depth to explain how to handle situations where a TCP connection is required as well as how to trigger rules with multiple recursive content triggers.


Managed Service Accounts

There used to be a time that I would get an itch to deploy Managed Service Accounts, but as soon as I started to implement them, I would remember why I always leave my services as basic user accounts. For some reason, creating MSA's through ADUC just isn't a reliable option so we are left to configuring these MSA's through Powershell. Most of us are not experts in Powershell and rely on the documentation that Microsoft provides us, but for some reason there are instances the explanations are so vague that you end up more confused than before you started.   To add to the confusion there are only a small number of walkthrough's dedicated to this seemingly simple task, that not only add to confusion as they do not explain any of the switches  or what they are doing. Hopefully this post will help clarify some of your questions so you can get your MSA's up and running. This post will apply to Windows Server 2012R2, and possibly any other after that but I have not tested it on those yet. Just to help the simple minded people like myself understand a bit better, we will assume we are simply creating a MSA for some service called "SwelcherFTP" and the MSA account name will simply be "saftp". We will also assume our DC name is "DC1", and our remote server is "FTP1". To start off with, I'm going to go over the pseudo-code of the process to help you all understand what is needed. Some additional assumptions that will be made are that the service you will be running will be on a remote server (for some reason every tutorial shows creating the MSA on the DC, which just doesn't apply in the real world).

  1. Identify the needs/requirements of the application you are running. More than likely it will require the Service Account to run as Local Administrator, because that appears to be the only way anyone can program an application. (I'll dedicate another post in the future on how to run a service not as a Local Administrator.)
  2. We will create the KDS key, this will generate the passwords for the MSA. Pay special attention to the syntax of this because for some reason Microsoft made it to where after executing this part of the command, you have to wait 10 hours before you can create a MSA, the command that will be posted below will be a work around.
  3. We will create the MSA, this can be on any computer that has the rights to create accounts. Whichever computer you execute this on it will also need the RSAT Powershell Module installed, which is essentially the Active Directory Powershell Module AKA "Import-Module Active Directory."
  4. We will designate the remote server that is allowed to use the MSA.
  5. Then we will need to add the MSA to the remote server by essentially installing the MSA on the remote server. This means that the same RSAT Powershell Module will need to be on the remote server that you are wanting to install the MSA. For whatever reason there is not a switch that allows you to specify which remote computer to install the MSA on, which is a pain because most servers don't have the RSAT Powershell module installed on them, and you have to manually go install it.
  6. After the account has been installed, only then will your remote server be able to use the MSA. Whether the application will start or not is a different story, because as I stated above, you will more than likely have to add the MSA to the Local Administrators group because that seems to be the norm nowadays.

Now here are the Powershell commands to run and an explanation of what each one is doing will follow below.

  1. Execute on DC1: Add-KDSRootKey -EffectiveTime ((get-date).addhours(-10))
  2. Execute on DC1: New-ADServiceAccount -SamAccountName saftp -DNSHostName saftp.local.domain
  3. Execute on DC1: Set-ADServiceAccount -Identity saftp -PrincipalsAllowedtoRetrieveManagedPassword FTP1$
  4. Execute on FTP1: Import-Module ActiveDirectory
  5. Execute on FTP1: Install-ADServiceAccount -Identity saftp
  6. Execute on FTP1: *This isn't a Powershell command" apply the appropriate permissions, which more than likely is just Local Administrator.
  7. Execute on FTP1: *This isn't a Powershell command" add the MSA to the service SwelcherFTP in Services, and remove any password that may have been populated into the password field.
  8. SwelcherFTP should now be running as the MSA saftp.

Why it is that complicated, I do not know, but for some reason Microsoft didn't want us to just right click, add a new MSA, select the servers we want this account to be able to logon as, and be on our way. To clarify a few things, I will explain each Powershell command, which is only steps 1-5.

  1. According to Microsoft the Add-KDSRootKey command generates a new key for the Group Distribution Service, which effectively manages the passwords for your MSA in this instance, which is why we have to execute the command. The -EffectiveTime switch can also be changed to -EffectiveImmediately, but the EffectiveImmediately switch doesn't mean that the KDSRootKey will be effective immediately. It means it will be ready in 10 hours when it has replicated to all the other Domain Controllers. To get around this we pass the -EffectiveTime switch and instead of doing the math ourselves, we simply just call the get-time command and subtract 10 hours from the result of get-time, and we set that as our EffectiveTime for our new KDSRootKey.
  2. New-AdServiceAccount simply creates a new service account. The -Name switch simply names the service account. Here's where things get a bit tricky as Microsoft's documentation doesn't explain what this next switch is that is required, -DNSHostName. The -DNSHostName switch is wanting you to create the actual FQDN for the service account itself. Maybe I've never managed a Domain large enough to where this every changes, but in our instance we just added saftp.local.domain.
  3. This command, Set-ADServiceAccount, allows you to change criteria of the called service account. Again the -Identity switch specifies which MSA we are wanting to alter. The -PrincipalsAllowedtoRetrieveManagedPassword, is wanting you to pass which computer account is allowed to contact the DC to retrieve the password for the MSA, which in our case will be the remote FTP1 server. Notice how the syntax though is FTP1$, you will need to add the $ at the end. This command can actually be passed in the New-ADServiceAccount command in step 2, but for whatever reason I've always had issues if I do not execute the Set-ADServiceAccount command.
  4. Imports the AD powershell module.
  5. Install-ADServiceAccount installs the specified service account on whichever server you are wanting the MSA to be used on.

There really isn't much to it, but the documentation on the process isn't very good, hopefully Microsoft will make this process less painful in the future.