Showing posts with label Powershell. Show all posts
Showing posts with label Powershell. Show all posts

Wednesday, October 31, 2018

Using ActiveDirectory module for Domain Enumeration from PowerShell Constrained Language Mode

This is a quick post to make notes of something which I have been using and teaching for sometime.

We can use Micorosft's PowerShell ActiveDirectory module without RSAT and administrative privileges. I came to know about this from this blog post.

So, if you have access to a Server which has the module installed (like a DC), copy the Microsoft.ActiveDirectory.Management.dll from C:\Windows\Microsoft.NET\assembly\GAC_64\Microsoft.ActiveDirectory.Management to your own machine and then use the Import-Module cmdlet to import the DLL:
Please note that if you run Get-Command -Module ActiveDirectory, it would not return anything. To get that, copy the module directory as well from the server from following location: C:\Windows\System32\WindowsPowerShell\v1.0\Modules\ActiveDirectory\. Then, use Import-Module, first the DLL and then the module:
UPDATE (16-Nov-2018) - It is now possible to load the module from memory by using Import-ActiveDirectory.ps1. Thanks to a PR by @D1iv3:
There are many benefits like very low chances of detection by AV, very wide coverage by cmdlets (I leave the usage of cmdlets for a later post :P), good filters for cmdlets, signed by Microsoft etc.

I have uploaded a copy of module from Server 2016 on Github: https://github.com/samratashok/ADModule

The biggest benefit is that this module works flawlessly in PowerShell Constrained Language Mode (CLM) :)
That is all!

Sunday, January 14, 2018

A Critique of Logging Capabilities in PowerShell v6

PowerShell 6 was released couple of days back. PowerShell v6 is the core version, that is, it is open source, cross platform and it is NOT Windows PowerShell which continues to be the default one on Windows. As per this blog by PowerShell Team, going forward, PowerShell core is the future (Windows PowerShell will still get critical bug-fixes.)
PowerShell Team, over past 2-3 years, has constantly improved the security controls in PowerShell. The defining moment was, of course, PowerShell ♥ the Blue Team where the PowerShell Team detailed many interesting features like System-wide Transcription, Deep Script Block Logging, AntiMalware Scan Interface, Protected Event Logging, Constrained Language Mode (with Applocker "Allow" mode) etc. Comparing PowerShell v2 - which comes installed by default in Windows 7 - with PowerShell 5.1 which is the default for Windows 10, the effort to restrict, track and log PowerShell usage on a box is clearly visible and effective.

Having used PowerShell for 7+ years for red team assessments and penetration tests, I look forward to every major release of PowerShell to change and upgrade my techniques and methodologies. With PowerShell 5.1, as an attacker, I am actually afraid that whatever I do on a foothold or launchpad box may be logged and (hopefully) monitored. During my Offensive PowerShell and Active Directory training, the attendees who are industry practitioners and researchers, always appreciate the logging capabilities of PowerShell and try to implement them in their organization's networks.

But with PowerShell v6, PowerShell logging features have been drastically reduced! This is almost certainly because v6 is based on .NET Core but there has been no authoritative word about it. This post is to compare the most interesting logging capabilities of PowerShell v6 with Windows PowerShell 5.1.

Deployment

All the enhanced logging capabilities PowerShell has, can be deployed using Group Policy. But this doesn't hold true for v6! To enable whatever logging for v6, a script RegisterManifest.ps1 (found in the $PSHOME directory) needs to be executed on each machine to register PowerShellCore event provider (PowerShell remoting can be used to run this script on scale). Thanks Satoshi for pointing this out.

The ability to configure logging from Group Policy is much easier to manage and harder to tamper with whereas the PowerShellCore event provider can be unregistered by using the "-UnRegister" parameter of the script.

System-wide Transcription

When System-wide transcription is enabled, all the activity for every PowerShell host (powershell.exe, powershell_ise.exe, System.Management.Automation.dll or other custom host) is logged to the specified directory or the user's "My Documents" directory if none is specified. With proper implementation, that is, forwarding logs to secure storage and correlation, system-wide transcription could be very effective in detecting PowerShell attacks. 

This is how system-wide transcription looks like for PowerShell 5.1 (The execution is using InstallUtil)
PowerShell v6 does not support system-wide transcription.

Script Block Logging

PowerShell v5.1 has two types of script block logging: Warning level auto logging and Verbose logging that can be configured. Warning level auto logging logs known bad/suspicious commands and script blocks and logs them in Microsoft-Windows-PowerShell/Operational log as Event ID 4104 Warning. When Verbose logging is turned on, which can be done using Group Policy, PowerShell commands are logged as Event ID 4104 Verbose.
Yes, there are public bypasses for script block logging as blogged by Ryan Cobb here and here, still, it increases attacker costs.

PowerShell v6 has no automatic script block logging. But when The PowerShellCore provider is created, the suspicious script blocks are logged with Event ID 4103 in the PowerShellCore logs.
 
Interestingly, while testing the warning level logs, I found out that v6 excels over v5.1 and logs less false positives. For example, one of suspicious strings (see code here) "GetMembers" is logged by 5.1 even if it is just executed senselessly.
But in case of v6, the above is not logged unless, there is a proper use of "GetMembers".
I find this very interesting and will have an in-depth look at it later on. May be, it could help in some interesting findings.

AntiMalware Scan Interface (AMSI)

AMSI provides the content of a script tor script block to the registered antivirus before execution takes place. This enables the antivirus to detect known bad scripts and script blocks regardless of input method (disk, memory, manual) and even encoded and obfuscated scripts. I spoke about AMSI at BlackHat USA 2016 and did a detailed blog post.

Fortunately, AMSI is enabled for PowerShell v6 as well. Although, Matt's bypass still works with just a minor modification.
But, once again, since it still increases cost to an attacker, its great to have AMSI in v6.

Constrained Language Mode

If "Allow mode" is enforced for Applocker or Device Guard, PowerShell is restricted automatically to the Constrained Language Mode which restricts Windows API, interaction with COM etc. See Language Modes

That is not the case with v6!

 

Introducing the PowerShell Upgrade Attack

PowerShell downgrade attack is popular with red teams. If you can run PowerShell v2, ALL security measures we have seen are bypassed as v2 simply doesn't support them. Lee provided an excellent guide on how to detect and prevent such attacks. If v2 is blocked or no required .NET version is installed, what to do? Simply run pwsh from your PowerShell session and you will drop in a new PowerShell session (v6 - if installed) which has minimal security features compared to v5/5.1. I am calling it the PowerShell Upgrade Attack :P. On a serious note, please keep in mind that Windows PowerShell - with enhanced logging - is the default one on Windows OS. Also, v6 is not an update, it needs to be installed separately. Windows PowerShell and PowerShell Core can be installed on a single machine and both will work independently.

So, what next?

I hold the PowerShell Team in high regard (for creating such a useful tool, being open to criticism and acting on the feedback) and quite confident (and hope) that they will address these shortcomings soon. Jeffery already tweeted that the Constrained Language Mode will be fixed in 6.1. But, if your production environment is working fine with Windows PowerShell v5/5.1, I would not advise to install v6 on any system (at least not the production ones).

UPDATE (25-Jan-2018) - The PowerShell Core Roadmap is published and there is no mention of bringing Core logging in parity with Windows PowerShell 5.1. Thankfully, the DeviceGuard/Applocker policy enforcement will get fixed.

Thursday, March 23, 2017

Using SQL Server for attacking a Forest Trust

Recently I started playing with the awesome PowerUpSQL tool by guys at NetSPI. I was interested in the ability to attack an Active Directory (AD) environment using access to a SQL Server, that is, not leaving the database layer as long as possible. Fortunately, during a Red team engagement few weeks back, I had a chance to play with PowerUpSQL extensively. Turns out that it is very much possible to enumerate and attack not only the current domain but a trusting forest in a Two-Way External Trust as well from the database layer. Let's have a look at it!

Network Diagram
I have mapped the client network to my lab on a much smaller scale.  We have access to the SQL Server ops-sqlsrvone where we have public privileges and can communicate to only selected machines on the defensiveps.com forest. 

Cross Forest Enumeration
It is possible to enumerate the current domain accounts using PowerUpSQL using interesting fuzzing methods. In our lab setup we know that there is a trust relationship from offensiveps with a forest called defensiveps (we can use PowerView, netdom or Get-ADTrust). But PowerUpSQL does not provide a way of specifying an alternate domain to enumerate accounts. We can change a single variable in the code to use an alternate domain.
Now, it is possible to enumerate interesting information from the target domain which is in a different forest. After modifying the value of $Domain variable, import the PowerUpSQL module and run the below command:
Neat! We got a list of target domain's users, groups, computers etc.

The enumeration done above helped in listing SQL Servers in the defensiveps domain. Now, mimicking the network I encountered during the assessment, it is possible to access only dps-sqlsrvdev, couple of DCs and some terminal servers in the defensiveps network directly. So, let's enumerate dps-sqlsrvdev:

Database logins
Note that our current user is listed as a login above and that is why it is possible to enumerate the above. Let's check the current privileges we have:
No sysadmin privileges. We can check it manually as well (I am using HeidiSQL as a client):

We can go ahead with a brute-force attack as there are some interesting SQL server logins and generally, account lockouts are not enabled in SQL Server databases and nobody really looks at the logs of authentication failure in SQL Server, at least, on non-production servers. But we are not going to do that right now.

Linked Servers
We can also enumerate linked servers for dps-sqlsrvdev. Let's do it:
Nice! A server, dps-sqlsrvtwo, in the defensiveps domain - which we enumerated earlier as well - is linked to the current database. Note that it is possible to run arbitrary SQL queries on the linked database even if we have only public privileges on both the initial and destination servers with the privileges configured in the link. Read more about hacking SQL Server links in the amazing blog by Antti. Link enumeration can be done manually as well:
So, dps-sqlsrvdev has a linked server dps-sqlsrvtwo.

Now, to execute queries on the destination server (dps-sqlsrvtwo) we can use Openquery as suggested by Antti in the blog linked above. Let's see our current user and if we have sysadmin privileges:

Turns out that we have only public privileges with a user called dbuser and the target server is SQL Server 2016 SP1.

Now, we can try various methods from PowerUpSQL for privilege escalation on SQL Server. The problem is we can't access dps-sqlsrvtwo directly and AFAIK, there is no way to execute these commands on a linked server using the tool. So, we need to try the methods manually, one by one. During the Red Team assessment, I found out a user which we can impersonate on a linked server. So, let's use that in our lab setup as well. To list all the users which we can impersonate from our current user can be listed using the following SQL query stolen directly from this amazing blog by Scott. We are going to use the query inside Openquery so that it can be executed on the linked server:
Looks like we can impersonate a user called "reportsuser". But a command like below is most likely to fail:
Why? Because, apparently, it is not possible to use EXECUTE AS without getting our privileges revert to the original 'dbuser'. I tried WITH NO REVERT option as well but soon realized that it may work only when sending the query directly to a database. Please see this MSDN documentation on EXECUTE AS.

No luck there! Let's look for another interesting privilege escalation avenue - trustworthy database. Read this very useful blog, once again by Scott, to understand more about trustworthy database. We can use the following query - taken from the blog referenced above -  to enumerate trustworthy databases on the target linked server:
A trustworthy database 'reports_db'! Let's list users with db_owner role on the server:
Now, let's see if our current user - dbuser - is db_owner of reports_db on the linked server. In place of checking the role, let's try to create a stored procedure in the reports_db database which can help us in privilege escalation. Please note that to create a stored procedure RPC Out must be enabled for the linked server - which is not enabled by default but quite common in case of linked servers. The idea is to create a stored procedure which gets executed as OWNER which is the user 'sa'. Use below query to create a stored procedure on the linked database.
Our stored procedure makes dbuser a sysadmin. Now, let's execute the stored procedure.

Neat! Now we can access all databases and tables on the target server. PowerUpSQL provides very useful commands for pillaging a database (and that is what I used first in the assessment to capture some juicy data) but we are not going to use them. See this blog post for details about that.

In many cases, this is one of the major goals of red team assessments, staying within the database layer we have access to multiple SQL servers across forest trust and juicy information stored within them. Since we have not done anything very unusual or noisy up to now, there are very low chances of detection. In fact, in my lab I have Microsoft Advanced Threat Analytics (ATA) set up and there was no detection of the attack. Obviously, because we did not communicate to the domain controller at all and ATA looks at only the DC traffic. Take that ATA!

Since, RPC Out is enabled on the linked server and we have sysadmin privileges, it is possible to enable xp_cmdshell and achieve OS command execution! Please note that if xp_cmdshell was already enabled on the linked server, we could execute OS commands without RPC Out while using only Openquery! Use below to enable xp_cmdshell
And let's see the privileges of the database process:

Great! Looks like the SQL server process is running with a domain user (sqlprodadmin) privileges. We can now hunt for a DA token from the normal domain user privileges we have on dps-sqlsrvtwo. Let's use the awesome PowerView for the DA token hunting. Remember that we cannot access our linked server dps-sqlsrvtwo directly and we do not have command execution on dps-sqlsrvdev. To load PowerView on dps-sqlsrvtwo, we can download and execute it in memory using PowerShell one-liner.
The one-liner needs to be encoded so that the URL doesn't mess up with the syntax of SQL query. Also, make sure that PowerView is modified a bit to include call to functions in the script itself and to receive the output the function calls must be piped to Out-Host.
And let's execute the encoded command:
Awesome! Looks like on the server dps-srvjump a DA token is available and our current user has local admin access. Let's dump NTLM hash of the DA - Administrator from dps-srvjump using Invoke-Mimikatz.
Finally, let's use these hashes with Invoke-Mimikatz to run a command on the DC of defensiveps. The DC of defensiveps is accessible from our machine in the offensiveps forest.

Bingo! DA access in the target forest!

We started with a non-admin domain user and worked our way to multiple SQL Servers while staying only at the database layer. We also got domain admin/enterprise admin in a trusting forest! :)

Mitigations

SQL Server Level
Multiple common mitigations like having limited linked databases and not enabling RPC Out on linked servers would have helped. Also, restricted allocation of privileges, even the public login, will help. One of the databases we encountered later on was running with a domain user's privileges. This is disastrous as it opens up many opportunities for privilege escalation on the domain level! Restricting privileges with which the database processes run is always desired.

Forest Level
Many improvements can be made. Allowing a local administrator on a box where a Domain Admin can log in is very very dangerous and results in disastrous situations like the one we saw above. If there is a box where DAs' privileges are required no other administrative account should be present. Logs will also tell you about a successful DA authentication from a forest if someone is looking for such information. Also, Selective Authentication can help in forest trust scenarios.

A note on ATA
I have Microsoft ATA setup in the lab where all the attacks took place. Since, ATA is the new sheriff in town let's discuss it a bit. ATA detect anomalies by looking at the traffic destined to the DC(s) by port mirroring. If we can limit ourselves to those attacks and techniques where there is no or minimal interaction with a DC, it is possible to avoid ATA and still get access to the most interesting machines and information. ATA thrives on Red Teamer/attacker's desire of going for DA rights as soon as possible. It is not always necessary to go after DA and use Golden ticket/Skeleton key/Credentials replay attacks for achieving the goal of an assessment unless, of course, you want to brag about it in your report :D Of course, there are bypasses for ATA as well but why bypass it when you can avoid it :)

Hope you enjoyed the post. Please leave comments, feedback and questions.

Tuesday, November 22, 2016

Exfiltration of User Credentials using WLAN SSID

I was playing with Windows Hosted Network feature couple of days back. A hopefully useful idea which came to my mind was using the name of the hosted SSID for exfiltration. Since, SSID names support maximum 32 bytes the choice of data to exfiltrate is not really wide. Something like user credentials is small enough to fit in this limited space.

I wrote a PowerShell script which allows use to exfiltrate data using only SSID names. I give you Invoke-SSIDExfil.ps1. Here is the source code. This script provides for multiple options to exfiltrate data. Since, we are mostly after user credentials, the script uses logic from Invoke-CredentialsPhish to show a credentials prompt to the user to capture credentials in clear text. The captured credentials are then encoded using ROT13 (not going to call ROT13 encryption though that may be the technically correct term) and a Windows Hosted Network is created and started with SSID name set as to the encoded value in the form Domain:Username:Password. Below is the script in action. Please note that the script must be executed from an elevated shell:
And this is how  - if we are in physical proximity of the target - the SSID looks like:
Now, we can decode the user credentials using Invoke-SSIDExfil script's -Decode option.

Neat! From my past experience, such scripts are useful for impressive demonstrations.

The script can be used as a payload in targeted client side attacks, Human Interface Devices (Kautilya), authenticated command execution and other techniques.

Using the -StringToExfiltrate and -ExfilOnly parameters, it is also possible to exfiltrate a small piece of data without showing a credential prompt to the user.

An update to the Gupt-Backdoor

While working on this script, I revisited Gupt-Backdoor. That backdoor is quite impressive as well when it comes to demonstrations. I blogged about it here. An improvement to that backdoor has been added which allows to pass a one line PowerShell downloand and execute cradle for PowerShell v3 onwards. Also, ROT13 encoding has been implemented to make SSID names less suspicious. Below command can be used to start the backdoor on a target and tell that an encoded command will be provided to it:
And this is how a Wireless AP can be started to send instructions to the backdoor.

And the execution looks like below. The backdoor downloads and executes Get-WLAN-Keys from Nishang:
Small but useful improvements!

Hope you enjoyed the post! 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):

 

Invoke-JSRatRundll

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.

 

Invoke-JSRatRegsvr

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:
Great!

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

 

Out-RundllCommand

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:
Nice!

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

 

Out-JS

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.

Out-SCT

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) - https://www.shakacon.org/trainings/offensive-powershell-for-red-and-blue-teams-by-nikhil-mittal/