We recently made some of the biggest changes to Empire since its release at BSidesLV in 2015. This post will summarize many of the modifications for the Empire 2.0 beta release, but also check out @enigma0x3‘s and my “A Year in the Empire” presentation we gave at Derbycon 6 for more information (slides here). This also marks an expansion of the Empire Development Team, which now includes @enigma0x3, @sixdub, @rvrsh3ll, @xorrior, and @killswitch_gui. The beta code is current in the 2.0_beta branch of the newly-relocated Empire repository – we want to stress again that this code is beta, so use with caution until it’s properly tested and merged to the master branch. We also still need to work out a proper methodology for migrating agents from 1.X to 2.X, which we’re hoping to work out in the next few weeks.
The original motivation for PowerShell Empire started almost as a thought exercise in late 2014. While various PowerShell projects implemented many of the capabilities of a modern RAT (keylogging, screenshots, the amazing Mimikatz, etc.), there wasn’t a pure PowerShell agent that brought everything together.
Nearly a year later, in late 2015/early 2016, we ran into another situation. We were preparing for an OS X-heavy client and realized that the public toolsets available at the time didn’t satisfy our customer’s requirements. The result of a frantic month of coding, EmPyre was built starting from PowerShell Empire’s code base mainly due to the fact that we had < 30 days to develop a fully-functioning capability in order to accomplish our objectives. We would not consider ourselves to be OS X experts, and simply didn’t have the time to develop a ‘native’ OS X rat (and controller) from scratch in that time. We went with the ‘living off the land’ philosophy we pursued with PowerShell Empire, this time opting for a Python 2.7 stdlib compliant agent that would also work for Linux.
After months of development and the BSides LV 2016 presentation with @424f424f and @killswitch_gui, many people naturally asked “are these projects going to be integrated?“. With the huge overlap between the two codebases, this made sense, and would simplify our lives when bugs were found in both projects. @enigma0x3, @xorrior, @424f424f, @sixdub, @killswitch_gui, and I are happy to announce that this is now a reality. The 2.0_beta branch of the Empire project contains the new code base, and will eventually be merged into master after additional testing. The rest of this post will briefly cover some of the new 2.0 features.
First, a grab-bag of mods vs. 1.6:
- For the PowerShell launcher/stager:
- RC4 was implemented for first stage obfuscation instead of XOR
- @mattifestation‘s AMSI bypass implemented in the stage0 launcher
- staging now uses HMAC/nonces
- For OS X/Python, lots of new stagers! @xorrior will have a more detailed post on these in the coming weeks:
- Epoch-syncing was removed- we know this introduces a possibility of packet replay, but too many users had too many issues with the epoch-syncing approach.
- Vastly increased debugging output. Use ––debug to output debug information to output to empire.debug, and ––debug 2 to display the same information to the screen.
- If agents are ‘orphaned’ they will restage to the control server.
- HTTP listener redone with Flask.
- Improved Kerberoasting module with credentials/get_spn_tickets.
- BloodHound module (situational_awareness/network/bloodhound) will execute collection and output to CSVs.
- We implemented @enigma0x3’s fancy new eventvwr UAC bypass that doesn’t drop a DLL to disk. The module is privesc/bypassuac_eventvwr and has been set as the alias for “bypassuac <LISTENER>” in the agent menu.
- Lots of code rot removed, several files got some fresh paint.
What’s still broken:
- The CLI options and RESTful API need some love before release.
- Misc. communication errors that we’re working though with the new core
New Packet Structure
In starting the redesign, we soon realized that the underlying packet structure needed to be redone. For example, agents implementing peer-to-peer approaches (like SMB) will need to be able to figure out how to route packets to other agents, despite each agent having a negotiated session key. Here’s how the Empire 1.X packet spec looks:
RC4s = RC4 encrypted with the shared staging key
HMACs = SHA1 HMAC using the shared staging key
AESc = AES encrypted using the client's session key
HMACc = SHA1 HMAC using the client's session key
Current Empire 1.0 spec:
AESc(client packet data)
| AES IV | Enc Packet Data | HMACc |
| 16 | % 16 bytes | 20 |
Client packet data decrypted:
| Type | Counter | Length | Value | ... (stackable)
| 4 | 4 | 4 | <Length> |
And here’s how the Empire 2.X packet spec looks:
Each client packet is wrapped in a metadata/routing ‘packet’ that’s encrypted using RC4 and the pre-determined server staging key. This means that every agent in the C2 mesh can decrypt the metadata packet, allowing it to route packets as appropriate. This also simplified handling multiple languages on the server side, allowing Python and PowerShell agents to communicate on the same port for HTTP[S]. These specs are also at the top of ./lib/common/packets.py.
Python and PowerShell, Brothers in Arms
One of the big goals of the 2.0 release was to combine the PowerShell Empire and Python EmPyre code bases while maintaining as fluid of a transition for existing users as possible.
Listeners that handle multiple languages (more information in the following section) can easily generate language-specific launchers for the same listener:
Additionally, stager modules are now separated by operating system, and take a Language parameter:
Agent language types are now broken out on the main display menu. Interact <AGENT> will drop you into a language-appropriate menu (PowerShell or Python), keeping the UI seamless. Also, usemodule [tab] will tab-complete only modules appropriate for the language type:
Multiple language types can be supported for a single listener- the above screenshot shows a PowerShell agent running on a Windows target and Python agents running on both Linux and OS X, all communicating on the same listener and port. This is possible due to the revamped packet structure, which lets us extract the language type from the metadata packet and task data appropriately.
The other big goal with Empire 2.0 was the modularization of listeners. Previously, listener and staging logic was spread throughout a number of places, making modifications quite difficult. Listeners are now single self-contained modules that you can drag and drop into an Empire instance. This changes the UI just a bit:
It also makes listener modification much easier. A great example is the listeners/http_com module. This module uses hidden Internet Explorer COM objects to communicate instead of Net.WebClient. Since client launcher/stager/agent generation along with server logic are all handled in the same module, it’s now relatively easy to modify the communication pattern, e.g. to use a different cookie value or to embed commands in a webpage comment.
It’s also now possible to build listeners that communicate through third-party sites, as @enigma0x3 and I demonstrated in our DerbyCon presentation. While we are not planning on releasing third-party C2 modules (or accept them in pull requests), we will be releasing a third party ‘template’ module and associated post that walks through how you could build one yourself.
We’ve had a blast devving Empire and EmPyre over the last year, and want to extend a serious thank you to everyone who contributed fixes, modules, testing cycles, and ideas for the project. The public response has been amazing, and we’re hoping to continue expanding features for the project going forward. After some additional mods and testing are completed, the 2.0_beta branch will be merged into master, with a final 1.6 release package remaining available.