
Peeling Back the Layers on Powershell Empire
This blog post is the second in the series on Powershell Empire. If you missed the first post, you can find it here.
Multi/launcher: How does it work?
In the previous post, we used the multi/launcher Powershell stager to create an Empire agent. We also disabled our antivirus, Windows Defender, for testing purposes. This time we will leave it on and try to bypass it.

As expected, an unmodified multi/launcher payload is detected and blocked by Defender.

What actually happens when we paste this into the Windows command prompt? Let's analyze this one-liner to figure out what it does step by step. The first step to find out is to disable the base64 encoding on the generated Powershell one-liner. To do this, simply set Base64 False.

As in other languages like Bash or Python, Powershell uses the semicolon character to stack lines of code on the same line. The above code really runs multiple Powershell commands one after the other. We can remove the semicolons and place each command on its own line for readability.

This is the first stage of the Empire agent, called Stage0 by the Empire Project.
A few things to notice here:
- Since Powershell is not case sensitive, the stager uses random case wherever possible to throw off simple string detections. This obfuscation isn't very effective these days.
- The stager creates a new
WebClientobject and sets the domain and port ($ser), user agent ($u), and page ($t) to connect back to the Empire server. The stager uses this WebClient to download the next stage, Stage1, from the Empire server. - Empire generates a random key (
$k) for the stager that can decrypt the downloaded data into Stage1 Powershell code. - Lastly, the downloaded Stage1 script is run in memory via
Invoke-Expression, which in this case is abbreviated toIEX.
If we remove the IEX at the end, we can see the downloaded and decrypted data instead of executing it.

Again, the Empire stagers are deliberately meant to be hard to read, so we need to clean up this code before we can analyze it.
Below is the prettified Stage1 code:
Stage1 code largely does the same thing as Stage0 code. It performs a key exchange with the server to set up AES encryption. It uses the previous WebClient to download the final Stage2 Empire agent code. It then decrypts and runs it.
To download (instead of run) the Stage2 Empire code, we can replace the Invoke-Expression with a Write-Output.

Finally the Stage2 downloaded code is Empire's actual agent code.
Defending ourselves from the Defenders.
Powershell has matured from the early days of its release, and it is now easier than ever for defenders to gain visibility into the Powershell run on their computers. For this reason, it's a good assumption that Antivirus/other security software is looking every line of Powershell you run.
We can use Event Viewer to view Powershell execution logs at the following path: Event Viewer > Applications and Services Logs > Microsoft > Windows > Powershell > Operational.

The good news is no human being can look at all of these Powershell logs. The bad news is security software will be. When modifying Empire, we only need to bypass automated detection.
As a co-worker of mine once said, "Antivirus is just fancy Grep." Antivirus simply scans for suspicious strings in our Powershell code. The solution: remove all of the "dirty words" that Antivirus would potentially be looking for. Function names are a good place to start. Here are a list of function names taken from Stage1 and Stage2 that could give us away:
- Start-Negotiate
- ConvertTo-Rc4ByteStream
- Get-HexString
- Set-Delay
- Get-Delay
- Set-LostLimit
- Get-LostLimit
- Set-Killdate
- Get-Killdate
- Set-WorkingHours
- Get-WorkingHours
- Get-Sysinfo
- Invoke-ShellCommand
- Start-AgentJob
- Get-AgentJobCompleted
- Receive-AgentJob
- Stop-AgentJob
- Update-Profile
- Get-FilePart
- Encrypt-Bytes
- Decrypt-Bytes
- New-RoutingPacket
- Decode-RoutingPacket
- Encode-Packet
- Decode-Packet
- Process-Tasking
- Process-TaskingPackets
Empire already does function name aliasing for the two worst offenders, Invoke-Empire and Invoke-Mimikatz, which means these two don't make the list.
There are probably better ways to change these function names in Empire, but a little bit of sed will do the job.
Run this script from the root of the Empire directory to replace all instances of these function names. When we look at the event log, we can see these function names are replaced with random names.

This replacement by itself isn't quite enough to bypass Defender. The replacements above only affect Stage1 and Stage2, but do not modify the multi/launcher Stage0. We need to change our Stage0 launcher code a little bit to bypass Defender. Luckily, Empire comes with some obfuscation functionality built in (but only for Stage0).
We can simple set Obfuscation True in the multi/launcher menu to turn obfuscation on.

When we run the above one-liner, Defender lets it right through.

We saw it only takes a little bit of time and tinkering to get Empire past Defender.
