During my dismantling I discovered that calls were being made to external binaries. As an amateur PowerShell purist, I was determined to remove these external dependencies and replace them with equivalent .NET implementations. In particular, Netstat was being used to test for available ports and Nslookup was being used to craftily communicate with dnscat2 (very cool). I was able to write a helper function to replace Netstat. I ended up removing the dnscat2 functionality to exclude Nslookup, but I hope you'll agree that I made up for this by adding a covert channel of my own; more on that later.
Further along, I realized that the capture of command output had been over-engineered by redirecting the standard out/error of a process and attempting to asynchronously read from those streams. This required the use of additional functions and is the first contributor to excessive CPU usage. I found a simple remedy to this situation by running all user input in a scriptblock and letting PowerShell handle the output and errors for me.
What started as 40 lines of code...
...was reduced to less than 10 lines, and no extra function definitions.
Moreover, the excessive CPU usage arose from a by-design loop that continuously checks for completed asynchronous operations without any throttle control. You can test a simplified version of this yourself by opening Task Manager and having a look at PowerShell's CPU statistics while running the following one-liners.
With the CPU consumption cured, I was able to start sprinkling in my own improvements. Most notably, making up for the removal of dnscat2 functionality by adding in a covert communication channel that leverages SMB pipes for stealth. The beauty of SMB pipes is two-fold. First, they communicate over a port (445) that has to be open in a Windows domain and is usually open by default in non-domain scenarios. Second, all SMB pipe communications are owned by the System process; i.e. PID 4. This makes it especially difficult for investigators to determine that the connection was actually originating from PowerShell.
There is one caveat to the SMB pipe communications, in that the .NET classes supporting them weren't available until version 3.5.1. While this technically means that SMB pipes aren't fully supported in PowerShell v2, most machines that only have v2 installed also have .NET 3.5.1 installed. In my testing, the SMB pipes work flawlessly on Windows 7 with v2; but I have not tested back to Windows Vista or XP. With a covert comms-channel back in the mix, we can move on to weaponizing this code for field use.
Mick and Luke did a great job of packaging the code for execution and I used their implementation as the basis for my own. I've received several requests (and will likely oblige them in the near future) to package all of my version into a single script so that it will be more portable. My standard response to this request is that the packaging feature already exists via New-PowerCatPayload. This function was designed for weaponizing and outputs a customized script payload perfect for distribution to remote machines. Lets look at an example of how to do that, using WMI.
No comments:
Post a Comment