Wednesday, September 21, 2016

AMSI: How Windows 10 Plans to Stop Script-Based Attacks and How Well It Does It

Last month I gave a talk about Microsoft's AntiMalware Scan Interface (AMSI) at Black Hat USA. The talk and this post details my experiments with AMSI.

I first encountered AMSI while using some of the PowerShell scripts from Nishang on a Windows 10 box in my lab. I noticed that some of the scripts didn't work even if loaded from memory which was very interesting. Being a long time user of PowerShell in my pen tests, I was interested in the technique being used to detect scripts from Nishang in memory. After a quick search, I stumbled upon this excellent TechNet article which introduces AMSI. From that article, this article and documentation of AMSI, following detection abilities and features are claimed with AMSI:
  • Memory and Stream scanning. This means that the input method - disk, memory/stream or manual input makes no difference on the detection capabilities.
  • Scripts are submitted to the AntiVirus/AntiMalware product by AMSI when the de-obfuscated plain code is presented to the script host. This means that obfuscation should help only to a limited extent.
  • Since the scripts are "picked up" when submitted to the scripting host, code which doesn't utilize powershell.exe but uses System.Automation DLL will also be analyzed.

And when I tested AMSI with different tools and techniques, detection rate was indeed better than what I expected.

Major techniques which were tested and detected by AMSI:

Executing scripts from memory - Using the -EncodedCommand parameter of powershell.exe and the famous one liner download-execute.

Execution of everyone's favorite, Invoke-Mimikatz:
When AMSI was disabled:

When AMSI was enabled (default on Windows 10):

Executing scripts without using powershell.exe - Using separate runspace (p0wnedshell, psattack) and using System.Automation.Dll (nps, Powerpick)

Unusual Storage - Scripts loaded from WMI namespaces, Registry Keys and Event Logs.

Application whitelisting bypass methods - InstallUtil, regsrv32 and rundll32

All of the techniques were detected by AMSI! While the detection was no surprise given that AMSI steps in at the script host level, still, this looked intimidating! More so because Windows Defender supports AMSI by default on Windows 10.  I quickly started looking for different ways to avoid or bypass AMSI.  Turned out that there are bunch of techniques that can be used to bypass or avoid AMSI.

Bypass or Avoid AMSI

Force use PowerShell v2: PowerShell v2 doesn't support AMSI at the time of writing. If .Net 3.0 is available on a target Windows 10 machine - which is not default - PowerShell v2 can be started  with the -Version option.

Another interesting way is to change the signature of the PowerShell script so that the AntiVirus to which AMSI submits our script doesn't detect it as malicious. To play with the signatures Windows Defender have for scripts, lets play with one of the scripts from Nishang, Gupt-Backdoor, which gets detected as malicious by AMSI.

Lets remove the help section, all the functionality and replace the function and variable names with random strings.

 And the result is:

Apparently, among other things, Windows Defender looks for specific function and variable names. Actually, this should not be a surprise as I know of few antiviruses which use Twitter handles of PowerShell hackers as a signature.

Manual obfuscation of a huge script such as Invoke-Mimikatz could not be done manually. Fortunately, the obfuscate functionality of the awesome ISE-Steroids module is very effective! Lets obfuscate Invoke-Mimikatz from Nishang.
Now, when the obfuscated version is loaded, there is no detection.

Make sure that the function calls are made from the script before obfuscation. 
This is very interesting! As per the articles mentioned at beginning of this post, AMSI has additional calls if any sort of obfuscation, even base64, is used in the script.This obfuscation getting past AMSI has been a sort of mystery for me.This probably has more to do with the signatures available with Windows Defender than with AMSI. I welcome comments on this specific thing as I am unable to understand why Invoke-Mimikatz was not detected if the plain de-obfuscated code was submitted to AMSI.

Unload AMSI

This built-in cmdlet can be used to make AMSI ineffective by disabling protection offered by Windows Defender.

Below command can be used to disable real time monitoring for Windows Defender

There are some 'gotchas' with the technique though:
  • A notification is shown to the user
  • Needs to be run from an elevated shell
  • Event ID 5001 (Microsoft-Windows-Windows Defender/Operational) - Windows Defender Real-Time Protection was disabled.
Another command can be used, this is useful for avoiding detection of in-memory download execute one liner.
This command doesn't show any notification to the user but:
  • An elevated shell is still required and;
  • Event ID 5004 (Microsoft-Windows-Windows Defender/Operational)  - Windows Defender Real-Time Protection feature (IE Downloads and Outlook Express attachments) configuration has changed.
DLL Hijacking - Method used in p0wnedshell
Cornelis de Plaa (@Cneelis) discovered this brilliant method and implemented it in his awesome p0wnedshell. There is a detailed blog post about the method. It is a DLL hijacking method where amsi.dll is dropped in the current working directory while loading the p0wnedshell runspace. The dll is loaded by the runspace and exits immediately to unload AMSI. 

So p0wnedshell successfully bypasses AMSI. But there is another interesting part of the security mechanism, PowerShellv5 supports automatic script block logging. The scripts loaded by p0wnedshell generate Event ID 4104 (Microsoft-Windows-PowerShell/Operational) – Suspicious script block logging (due to successful loading of scripts in memory).

Reflection - Matt Graeber's method
Matt Graeber (@mattifestation) tweeted an awesome one line AMSI bypass. Like many other things by Matt, this is my favorite. It doesn't need elevated shell and there is no notification to the user but the automatic script block logging, like in the case of p0wnedshell, generates Event ID 4104. Turns out that it is the script block logging which is the real headache. There are a bunch of script logging bypasses I am aware of, discovered by other PowerShell hackers, but not public yet.

Anyway, I like this method because it can be used with existing PowerShell script execution methods.
For example, lets bypass AMSI using a client side attack and get a meterpreter on the target Windows 10 box. Lets generate a weaponized MS Word document using Nishang's Out-Word and instruct it to download and execute a PowerShell meterpreter.
As soon as a target opens the Word file and click on "Enable Content", this happens:
Sweet! We bypassed AMSI in a client side attack!

AMSI is certainly not the security silver bullet which many organizations (wrongly) keep looking for but it is indeed an improvement in Windows security.

My slides for the Black Hat preso are here:

Hope this was useful. Please leave feedback and comments!

Wednesday, May 25, 2016

Practical use of JavaScript and COM Scriptlets for Penetration Testing

I have been following Casey Smith's brilliant work on JavaScript and COM Scriptlets. After looking at his work, I started playing with the code. I was interested in developing easy and customizable ways to use JavaScript, SCT files, rundll32 and regvr32 for...well...interesting things. After using some weeknights and weekends, I give you following PowerShell scripts (all available in Nishang):



Based on JSRAT by Casey, Invoke-JSRatRundll uses rundll32.exe to execute JavaScript on a target which provides a Reverse PowerShell Shell over HTTP. Why? Because it is so cool. Also, it is file-less, the client part is just a single command and most importantly, another method to pwn targets :) The script and the client part are intelligent enough to figure out if there is a proxy in use and also to use first proxy from multiple proxies from Internet Explorer settings. Also, based on the method mentioned here, Invoke-JSRatRundll doesn't leaver rundll32.exe running on the target, when "exit" command is used from the spawned reverse shell, so a clean exit. 

The listener, on the attacker's machine, needs to be run from elevated PowerShell session.
This is how it looks like in action:

Start the listener
The above listener provides the following command to be run on a target. Please note that will need to remove newlines:
When the command is executed on the target:
We get a connect back on the listener:
Nice! A proxy aware,  file-less, Reverse PowerShell Session.

The client part (one-line command) can be used whenever we have the ability to execute a command on the target. Below is an example of using the client part with Out-Word from Nishang. Note that the the double quotes in client part need to be escaped by using double-quotes two times.
When a target user opens the Word file and chooses to enable Macros, the listener will receive a connect back from the target machine. Bingo!

One thing to note in Invoke-JSRatRundll is that a window pops-up temporarily whenever a command is executed on the target. It is because of the use of Exec method of WScript. The Run method which provides for silent execution could not be used as it did not return the output without storing the output temporarily somewhere on the target.



This script utilizes regsvr32.exe for providing a Reverse PowerShell session over HTTP. Use of regsvr32, the technique which has been termed as "Squiblydoo", has added benefits. regsvr32.exe takes care of proxy by itself, the execution is file-less and AFAIK, leaves no traces on the target after a clean exit. 

The listener needs to be run from an elevated PowerShell on the attacker's machine. This is how it looks like in action:
 The above listener provides the following command to be run on the target:
As soon as the command is executed on a target, using a client side attack, or any other method:

This script also shows a window momentarily on the target machine for the same reason as Invoke-JSRatRundll



Use this script to generate rundll32.exe one line commands. The generated command can be used on a target to run PowerShell commands and scripts or a reverse PowerShell session over TCP.

Here is how to generate a command. 
Now, if the rundll32 command is executed on a target using client side attack or other methods, the payload will get executed.

During testing it was not possible to execute larger scripts (specially the encoded ones due to the increased length). The added advantage with this script is it can be used with a simple netcat listener on a Linux machine as well. There is no need to run a special listener unlike in the above two scripts.
Start a netcat/Powercat listener. Run Out-RundllCommand with the -Reverse switch:
 When the generated rundll32 command is executed on the target:

Also, the execution is silent on the target machine. Please note that this script leaves rundll32.exe running on the target machine.



This script is useful for client side attacks. Using this script, we can create "weaponized" JavaScript files which can be sent to a target user to execute PowerShell scripts and commands. Once a user executes the file (a double click opens the file using Windows Script Host, wscript.exe), the specified payload gets executed on the target with the privileges of the current user. The default name of the generated file is Style.js. 

Once again, it was not possible to execute large scripts, therefore, there is no option of specifying a script path. An example is included in the script to execute a reverse PowerShell session over TCP.


This script generates a SCT file which can be used with regsvr32.exe to execute PowerShell scripts and commands. The default name of the generated file is UpdateCheck.xml. This file needs to be hosted on a web server and the one-liner regsvr is to be executed on the target.  Note that, in case a PayloadURL is provided, two connections are made from the target environment. This first one to pull the SCT file and the second one to download the PowerShell script.

Like Out-JS only small scripts can be executed using Out-SCT. An example is included in the help of this script which explains usage of a Reverse PowerShell session over TCP without having to download a script. 

Usage with metasploit

Some of the above scripts can be used to get a meterpreter session in the following ways:

Create a PowerShell meterpreter payload using msfvenom:

Host the generated payload on a web server.

Using Out-SCT
Pass the URL where meterprer PowerShell script is hosted to Out-SCT.
Now, host the generated SCT file on a web server. When the generated regsvr32 command is executed on a target, this will happen:

Awesome! A reverse HTTPS meterpreter from a file-less execution which is also helpful in avoiding Applocker!

Using Out-JS
Pass the URL to Out-JS.
When the generated Style,js is executed on a target, we will get a connect back on msfconsole!

Using Out-RundllCommand
Pass the URL to Out-RundllCommand.
Once again, when the generated rundll32 command is executed on a target, a meterpreter will pop-up in the msfconsole.

That is all for this post, all the scripts are available in the GitHub repository of Nishang. Hope you liked it. Please leave feedback and comments.

Join me for a two days training "Offensive PowerShell for Red and Blue Teams" at Shakacon, Honolulu (2 days - July 11th - 12th, 2016) -

Sunday, February 28, 2016

Getting Domain Admin with Kerberos Unconstrained Delegation

A recent penetration test was one of the rare ones where it was not possible to locate a domain admin credential (password/hash/ticket) using the usual methods. I already had Administrator access to one of the server thanks to a file upload feature in an in-house log management dashboard running over WAMP (WAMP runs with SYSTEM privileges). I got access to few more servers by using hashes of a domain user who was local admin on couple more servers and some more similar stuff, but still no luck. 

Anyway, after looking around for Active Directory and Kerberos related attacks for a while, it was time for reconsidering the attack approach. Recall the first thing which comes to mind when we fail at server side attacks? Absolutely! Client side attacks. I could drop some emails with attachments and links and hope for hitting a user machine which leads me to a server which has a Domain Admin token. The client, for his own reasons, wanted me to keep all the connect back shells/requests from phishing within the internal network and there was absolutely no outgoing traffic allowed towards my VPN machine.(Diagram build with
So, either I needed to setup multiple listeners on one of the compromised servers which can handle multiple connect back shells or some way to use an existing service as a listener for my phishing attacks. Since I am lazy :) I decided to go with the second option, that is, using an existing service. While enumerating the domain after initial foothold, I saw that a web server had Kerberos Unconstrained Delegation enabled.

Once I realized Kerberos Unconstrained Delegation was enabled, I could attempt to exploit this scenario using a technique Sean Metcalf (@PyroTek3) spoke about last year and published on  ( Sean covers how exploiting a server with Kerberos Unconstrained Delegation can lead to credential theft of DA credentials resulting in Active Directory compromise by tricking a Domain Admin into connecting to any Kerberos service on the server.

So, all that needed to be done was creating phishing emails and use them to connect back to the server where I had admin access and wait for a domain admin to fall for an email.

Here is how I did it (replicated in my lab).
1. pfptlab-build is the server where we have admin access with RDP, PowerShell Remoting etc.
2. pfptlab-web is the server where we can execute commands as admin but it is not directly accessible.

Searching for computers with Unconstrained Delegation

By using the built-in Active Directory PowerShell Module. This module is available by default on Windows Server 2012. From an elevated shell on the server with admin access (pfptlab-build) use the below commands:
I have wrapped up above commands in a script Get-Unconstrained.ps1 found in the ActiveDirectory category of Nishang.

Another way of searching for computers with Unconstrained Delegation is using Powerview:

Setting up the "Listener"

On the server where unconstrained delegation is enabled (pfptlab-web in the lab), we can enumerate existing tickets using Invoke-Mimikatz. Keep in mind that we have admin access to the server with the help of hash of a domain user who is local admin on that server. Please note that we can pass the ticket as well but the expiry time of the ticket will play a spoilsport here as we need to wait till a domain admin connects to the machine.

We can use the hash of domain user webadmin which is a local admin on the pfptlab-web, the server with unconstrained delegation:
This is how the output of these commands look like:
Now, let's list tickets on pfptlab-web, the server with Unconstrained Delegation. Since, we have direct access to the pfptlab-build machine, let's *drop the script on disk* there and use below commands to use it in a stateful session on pfptlab-web without touching disk. Remember that below commands need to be run in the PowerShell console opened by over-passing the hash of the webadmin user:

An alternate way with a catch!
A quick thing to note here. If we try to use below command (to execute Invoke-Mimikatz on pfptlab-web without dropping the script to disk on pftplab-build) there will be an error.
Because, we cannot pass named parameters in the -ArgumentList parameter. It is not possible to pass "-Command '"sekurlsa::tickets"'" in the above case. We can pass only the positional parameters. To overcome this I changed the positions of the parameters. I assigned position 0 to the "Command" parameter of Invoke-Mimikatz and the above command worked successfully. Now the catch! If I add "/export" to the ArgumentList parameter in the above command, it fails as PowerShell passes it to the Invoke-Mimikatz as second parameter. If anyone is able to do that successfully, please share!

So, assuming that we have enumerated the Domain Administrator accounts already and one of them is the "Administrator", to know if a domain admin has connected we can use the following ugly method:
May be someone will automate this in a much cleaner way. If a ticket of the Domain Administrator, Administrator, is saved by Mimikatz, the second command above should list it. But, no Domain Admin ticket on pfptlab-web, yet.

Preparing email

Fortunately, the client's internal mail server allowed email relaying so sending phishing emails was not a problem. I was able to get access to email ids with a combination of AD usernames and couple of email excel files I got my hands on. After sharing the emails with the client, he removed emails of some guys from the management. One of the multiple email templates used was:
While I am no expert in crafting phishing emails, I would like you to note some points in the above email:
- No intimidation but a balanced tone of Authority.
- Use of jargon but not too obscure words, as if I was really trying to explain complex things in simple terms to the user. 
- Requirment of urgent action by the target user.
- Command which displays a lot of output.
- Providing an alternate way to the user if they can't access the share which makes me look more helpful.
Though I tried to pick the "email culture" of the client from the emails I exchanged, surely, this email could be written in a lot better way.

Using the below command, email was sent to users.
This is  how the email looked in like in mailbox of one of the targets.


After sending email, I started checking the tickets for Domain Administrator by running Invoke-Mimikatz repeatedly and soon there were more than one domain administrators who complied to whatever they were asked to do :D
Now, in my opinion, the best way to use the tickets is to copy them to the pfptlab-build server as we have direct connectivity to it. Using the below command we can copy all the tokens from the pfptlab-web to pfptlab-build machine.
Now, we can use one of the Administrators tickets copied locally to elevate our privileges to Domain Administrator:
Awesome! Finally Domain Admin access. Let the victory dance begin :D :D

Here is a quick video to demonstrate the attack:

After getting the DA access, I gathered some business related data to demonstrate actual impact to the client management.

Please leave feedback and comments.

Learn penetration testing of a highly secure, live Windows network with me in PowerShell for Penetration Testers Training at:

CanSecWest, Vancouver (4 days - March 12-15th, 2016) -