As PowerSploit has grown and matured ever so slowly, I began to formalize how I thought offensive PowerShell code should be written – in other words, being mindful of the ease of weaponization and ease of use for the end-user pentester or red teamer. For example, I’ve asked the following of those wanting to commit new code to PowerSploit:
- Code should be designed to be modular: i.e. functionality should be encapsulated in the form of a function, not a script. Scripts are designed to be executed from disk – something we want to avoid as attackers.
- I strongly emphasized that code should be self-contained: i.e. weaponized code should not be in the business of resolving dependencies. This makes sense to a point. If you’re going to execute a PowerShell payload from a simple download cradle, what you download needs to contain the entire payload that you want to execute. As a result, most code in PowerSploit is categorized appropriately and grouped logically into single psm1 files that can be easily staged via a download cradle.
Recently, I’ve been a little harder on myself wanting to simplify code and what has resulted is what I think warrants a discussion on the trade-offs of software design and weaponization. As a perfect example, I removed Metasploit payload support from Invoke-Shellcode. Why? Because I think a function should do one thing and do it well. People have used Invoke-Shellcode extensively with the built-in Metasploit support and I know some will be upset. Here was my rationale in making that decision:
- I only supported 32-bit HTTP and HTTPS meterpreter stagers. Metasploit contains so many more payloads that I could have supported but then I would have had to maintain all of them. I don’t want that job.
- The Metasploit support was simple in practice. I simply downloaded the staged payload and executed the shellcode as a byte array. But my question was: why should Invoke-Shellcode be downloading anything? Shouldn’t it just execute shellcode? After all, Invoke-WebRequest is built-in to PowerShell and it’s proxy aware! Also, there’s a million different mechanisms by which you might want to obtain a shellcode payload – DNS TXT records, UDP, etc.
- Metasploit payloads can easily be generated with msfvenom.
Another design consideration involves code like Invoke-Mimikatz. Invoke-Mimikatz, loved by many, is a glorified wrapper around Invoke-ReflectivePEInjection – an amazing in-memory PE loader. There are several functions in PowerSploit that utilize Invoke-ReflectivePEInjection and it’s a huge maintenance headache when updates need to be made to Invoke-ReflectivePEInjection because there are at least three other functions that embed Invoke-ReflectivePEInjection that need to be updated too.
So here’s my personal pitch: I would advocate that all functions serve one single purpose and serve that single purpose well and that dependencies should be maintained separately. For example, rather than embedding Invoke-ReflectivePEInjection in InvokeMimkatz, it should call Invoke-ReflectivePEInjection and annotate Invoke-ReflectivePEInjection as a dependency (a practice I’ve implemented for a long time). Naturally, the problem with that approach would result in a more concerted weaponization effort. A red team operator would need to make sure that all dependencies were included in their intended payload – a potential operational headache. Empire modules can easily resolve these dependencies though by automatically declaring and combining dependencies which would be completely transparent to an operator. So Empire is a great example of weaponization done right all while enabling a developer like myself to separate out and simplify the logic in my attack tools.
So in my mind, the debate comes down to the following two arguments:
- Modularize everything. A function/cmdlet should do one thing and do it well. Dependency resolution would then be a requirement for weaponization.
- Package everything together so that users can immediately start using your offensive toolset without having to worry about stitching together an arbitrary list of dependencies.
As one of the primary devs of PowerSploit, I make the argument for #1 for the following reasons:
- Make my life easier, people! :P
- I feel that operators should have the flexibility of mixing and matching the functionality (or weaving a tapestry of evil, if you will ;) ) that they want to use. This does require more extensive knowledge of the language they’re using though – in this case, PowerShell.
- It makes code easier to maintain and easier for external contributions.
- Regarding PowerSploit specifically, my vision for it is that it should be a suite of tools to enable operators to pick, choose, and deploy the functionality they want. I prefer that PowerSploit not focus on weaponization because you have mature platforms like Empire and Cobalt Strike that already aim to solve that problem.
All that said, I hope I can open up a good dialog on the virtues of offensive software development and weaponization. Obviously, such a topic doesn’t apply to just PowerShell so I’d love to hear the opinions of those coping with my same struggles.