Skip to content

Instantly share code, notes, and snippets.

@GoodOlClint
Created June 26, 2021 05:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GoodOlClint/ef4e316a4b5ad5edd194aa811d94e7c5 to your computer and use it in GitHub Desktop.
Save GoodOlClint/ef4e316a4b5ad5edd194aa811d94e7c5 to your computer and use it in GitHub Desktop.
function ReverseBytes
{
param([UInt32]$Value)
return (($value -band 0x000000FF) -shl 24) -bor (($value -band 0x0000FF00) -shl 8) -bor (($value -band 0x00FF0000) -shr 8) -bor (($value -band 0xFF000000 -shr 24))
}
function FlipHex
{
param([NETLOGON_NT_VERSION]$flags)
[UInt32] $f = [UInt32]$flags
if([BitConverter]::IsLittleEndian)
{ $f = ReverseBytes($f) }
$str = '{0:x}' -f $f
for ($i = $str.Length - 2; $i -ge 0; $i -= 2)
{ $str = $str.Insert($i, '\') }
return $str
}
function SubArray
{
param
(
[byte[]] $Array,
[int] $Offset,
[int] $Length
)
$result = New-Object byte[] $Length
[Array]::Copy($Array, $Offset, $result, 0, $Length)
return $result
}
function AddByteArray
{
param(
[byte[]] $Array,
[int] $Offset,
[int] $Length
)
$result = $Array[$Offset];
foreach ($ret in (SubArray -Array $Array -Offset ($Offset + 1) -Length ($Length - 1)))
{ $result += $ret }
return $result;
}
[Flags()]
enum NETLOGON_NT_VERSION
{
NETLOGON_NT_VERSION_1 = 0x00000001
NETLOGON_NT_VERSION_5 = 0x00000002
NETLOGON_NT_VERSION_5EX = 0x00000004
NETLOGON_NT_VERSION_5EX_WITH_IP = 0x00000008
NETLOGON_NT_VERSION_WITH_CLOSEST_SITE = 0x00000010
NETLOGON_NT_VERSION_AVOID_NT4EMUL = 0x01000000
NETLOGON_NT_VERSION_PDC= 0x10000000
NETLOGON_NT_VERSION_IP = 0x20000000
NETLOGON_NT_VERSION_LOCAL = 0x40000000
NETLOGON_NT_VERSION_GC = 0x80000000
}
enum OperationCode
{
LOGON_PRIMARY_QUERY = 7
LOGON_PRIMARY_RESPONSE = 12
LOGON_SAM_LOGON_REQUEST = 18
LOGON_SAM_LOGON_RESPONSE = 19
LOGON_SAM_PAUSE_RESPONSE = 20
LOGON_SAM_USER_UNKNOWN = 21
LOGON_SAM_LOGON_RESPONSE_EX = 23
LOGON_SAM_PAUSE_RESPONSE_EX = 24
LOGON_SAM_USER_UNKNOWN_EX = 25
}
[Flags()]
enum DS_FLAG
{
DS_PDC_FLAG = 0x00000001
DS_GC_FLAG = 0x00000004
DS_LDAP_FLAG = 0x00000008
DS_DS_FLAG = 0x00000010
DS_KDC_FLAG = 0x00000020
DS_TIMESERV_FLAG = 0x00000040
DS_CLOSEST_FLAG = 0x00000080
DS_WRITABLE_FLAG = 0x00000100
DS_GOOD_TIMESERV_FLAG = 0x00000200
DS_NDNC_FLAG = 0x00000400
DS_SELECT_SECRET_DOMAIN_6_FLAG = 0x00000800
DS_FULL_SECRET_DOMAIN_6_FLAG = 0x00001000
DS_WS_FLAG = 0x00002000
DS_DS_8_FLAG = 0x00004000
DS_DS_9_FLAG = 0x00008000
DS_DNS_CONTROLLER_FLAG = 0x20000000
DS_DNS_DOMAIN_FLAG = 0x40000000
DS_DNS_FOREST_FLAG = 0x80000000
}
#https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/b0ef9479-78d8-40c1-b6d2-0baad834ed39
function DecompressDNSStrings
{
param(
[byte[]] $InputBuffer,
[int] $StringCount,
[int] $Current,
[ref] $LastPos
)
[int] $deCompressedCount = 0
[int] $localCurrent = 0
[int] $inputBufferSize = $InputBuffer.Length
[bool] $success = $true
$LastPos.Value = 0
[System.Collections.Stack] $location = [System.Collections.Stack]::new()
[string[]]$OutputBuffer = @()
$enc = [system.Text.Encoding]::UTF8
for ($i = 1; $i -le $StringCount; $i++)
{
[int] $dnsNameLen = 0
[int] $firstLabel = 0
$s = [string]::Empty
do
{
[byte] $labelSize = $InputBuffer[$Current]
if ($labelSize -eq 0)
{
$OutputBuffer += $s
$deCompressedCount++
if ($location.Count -gt 0)
{
for ($n = 0; $n -le $location.Count; $n++)
{ $Current = $location.Pop() }
}
else { $Current++ }
$LastPos.Value = $Current + $labelSize;
break
}
elseif (($labelSize -band [byte]0xC0) -ne 0)
{
$Current++
$location.Push($Current + 1)
$labelSize = $InputBuffer[$Current]
if ($labelSize -gt $inputBufferSize)
{ $success = $false }
$Current = $labelSize
continue
}
else
{
if (($labelSize + $Current) -ge $1inputBufferSize)
{ $success = $false }
if ($firstLabel -eq 0)
{ $firstLabel = 1 }
else
{
$s += '.'
$dnsNameLen++
}
$s += $enc.GetString((SubArray -Array $InputBuffer -Offset ($Current + 1) -Length $labelSize))
$dnsNameLen += $labelSize;
$Current = $Current + 1 + $labelSize;
}
} while ($Current -lt $inputBufferSize);
if ($i -ne $deCompressedCount)
{ throw new Exception("Decompression error"); }
}
return $OutputBuffer
}
class NETLOGON_SAM_LOGON_RESPONSE_EX
{
[OperationCode] $Opcode
[UInt16] $Sbz
[DS_FLAG] $Flags
[Guid] $DomainGuid
[string] $DnsForestName
[string] $DnsDomainName
[string] $DnsHostName
[string] $NetbiosDomainName
[string] $NetbiosComputerName
[string] $UserName
[string] $DcSiteName
[string] $ClientSiteName
[NETLOGON_NT_VERSION] $NtVersion
[UInt16] $LmNtToken
[UInt16] $Lm20Token
NETLOGON_SAM_LOGON_RESPONSE_EX([byte[]]$ByteArray)
{
$lastPos = 0
$this.Opcode = [OperationCode](AddByteArray -Array $ByteArray -Offset 0 -Length 2)
$this.Sbz = AddByteArray -Array $ByteArray -Offset 2 -Length 2
$this.Flags = [DS_FLAG](AddByteArray -Array $ByteArray -Offset 4 -Length 4)
$guidArray = SubArray -Array $ByteArray -Offset 8 -Length 16
$this.DomainGuid = [Guid]::new([byte[]]$guidArray)
$output = DecompressDNSStrings -InputBuffer $ByteArray -StringCount 8 -Current 24 -LastPos ([ref]$lastPos)
$this.DnsForestName = $output[0];
$this.DnsDomainName = $output[1];
$this.DnsHostName = $output[2];
$this.NetbiosDomainName = $output[3];
$this.NetbiosComputerName = $output[4];
$this.UserName = $output[5];
$this.DcSiteName = $output[6];
$this.ClientSiteName = $output[7];
$this.NtVersion = [NETLOGON_NT_VERSION](AddByteArray -Array $ByteArray -Offset $lastPos -Length 4)
$this.LmNtToken = AddByteArray -Array $ByteArray -Offset ($lastPos + 4) -Length 2
$this.Lm20Token = AddByteArray -Array $ByteArray -Offset ($lastPos + 6) -Length 2
}
}
function Send-LDAPPing
{
param(
[string]$ComputerName,
[string]$DomainName
)
[System.Reflection.Assembly]::LoadWithPartialName('System.DirectoryServices.Protocols') | Out-Null
$ntver = FlipHex([NETLOGON_NT_VERSION]::NETLOGON_NT_VERSION_LOCAL -bor [NETLOGON_NT_VERSION]::NETLOGON_NT_VERSION_5EX)
$ldapIdentifier = [System.DirectoryServices.Protocols.LdapDirectoryIdentifier]::new($ComputerName, $true, $true)
$ldapConnection = [System.DirectoryServices.Protocols.LdapConnection]::new($ldapIdentifier)
$ldapSearch = [System.DirectoryServices.Protocols.SearchRequest]::new($null, ('(&(DnsDomain={0})(NtVer={1}))'-f $DomainName, $ntver), 'Base', 'netlogon')
[TimeSpan] $myTimeout = [TimeSpan]::new(0, 0, 0, 1)
$ldapConnection.AuthType = 'Anonymous'
$ldapConnection.AutoBind = $false
$ldapConnection.Timeout = $myTimeout
$response = $ldapConnection.SendRequest($ldapSearch, $myTimeout)
Write-Output ([NETLOGON_SAM_LOGON_RESPONSE_EX]::new([byte[]]($response.Entries[0].Attributes["netlogon"][0])))
$ldapConnection.Dispose()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment