|
4 | 4 | ##
|
5 | 5 |
|
6 | 6 | class MetasploitModule < Msf::Auxiliary
|
| 7 | + include Msf::Auxiliary::Report |
7 | 8 | include Msf::Auxiliary::Scanner
|
8 | 9 | include Msf::Exploit::Remote::DCERPC
|
9 | 10 | Netlogon = RubySMB::Dcerpc::Netlogon
|
| 11 | + @@dport = nil |
10 | 12 |
|
11 | 13 | def initialize(info = {})
|
12 | 14 | super(
|
@@ -35,50 +37,64 @@ def initialize(info = {})
|
35 | 37 | register_options(
|
36 | 38 | [
|
37 | 39 | OptPort.new('RPORT', [false, 'The netlogon RPC port']),
|
38 |
| - OptPath.new('USER_FILE', [true, 'Path to the file containing the list of usernames to enumerate']) |
| 40 | + OptPath.new('USER_FILE', [true, 'Path to the file containing the list of usernames to enumerate']), |
| 41 | + OptBool.new('DB_ALL_USERS', [ false, "Add all enumerated usernames to the database", false ]) |
39 | 42 | ]
|
40 | 43 | )
|
41 | 44 | end
|
42 | 45 |
|
43 |
| - class DsrGetDCNameEx2Request < BinData::Record |
44 |
| - attr_reader :opnum |
45 |
| - |
46 |
| - endian :little |
47 |
| - |
48 |
| - uint32 :computer_name, initial_value: 0x00000000 |
49 |
| - logonsrv_handle :account_name |
50 |
| - ndr_uint32 :allowable_account_control_bits, initial_value: 0x200 |
51 |
| - uint32 :domain_name, initial_value: 0x00000000 |
52 |
| - uint32 :guid, initial_value: 0x00000000 |
53 |
| - uint32 :site_name, initial_value: 0x00000000 |
54 |
| - uint32 :flags, initial_value: 0x00000000 |
55 |
| - |
56 |
| - def initialize_instance |
57 |
| - super |
58 |
| - @opnum = 34 |
59 |
| - end |
60 |
| - end |
61 |
| - |
62 | 46 | def bind_to_netlogon_service
|
63 |
| - @dport = datastore['RPORT'] |
64 |
| - if @dport.nil? || @dport == 0 |
65 |
| - @dport = dcerpc_endpoint_find_tcp(datastore['RHOST'], Netlogon::UUID, '1.0', 'ncacn_ip_tcp') |
66 |
| - fail_with(Failure::NotFound, 'Could not determine the RPC port used by the Microsoft Netlogon Server') unless @dport |
| 47 | + @@dport = datastore['RPORT'] |
| 48 | + if @@dport.nil? || @@dport == 0 |
| 49 | + @@dport = dcerpc_endpoint_find_tcp(datastore['RHOST'], Netlogon::UUID, '1.0', 'ncacn_ip_tcp') |
| 50 | + fail_with(Failure::NotFound, 'Could not determine the RPC port used by the Microsoft Netlogon Server') unless @@dport |
67 | 51 | end
|
68 |
| - handle = dcerpc_handle(Netlogon::UUID, '1.0', 'ncacn_ip_tcp', [@dport]) |
| 52 | + handle = dcerpc_handle(Netlogon::UUID, '1.0', 'ncacn_ip_tcp', [@@dport]) |
69 | 53 | print_status("Binding to #{handle}...")
|
70 | 54 | dcerpc_bind(handle)
|
71 | 55 | end
|
72 | 56 |
|
73 | 57 | def dsr_get_dc_name_ex2(username)
|
74 |
| - request = DsrGetDCNameEx2Request.new(account_name: username) |
75 |
| - |
| 58 | + request = Netlogon.const_get("DsrGetDcNameEx2Request").new( |
| 59 | + computer_name: nil, |
| 60 | + account_name: username, |
| 61 | + allowable_account_control_bits: 0x200, |
| 62 | + domain_name: nil, |
| 63 | + domain_guid: nil, |
| 64 | + site_name: nil, |
| 65 | + flags: 0x00000000 |
| 66 | + ) |
76 | 67 | begin
|
77 | 68 | raw_response = dcerpc.call(request.opnum, request.to_binary_s)
|
78 | 69 | rescue Rex::Proto::DCERPC::Exceptions::Fault
|
79 | 70 | fail_with(Failure::UnexpectedReply, "The Netlogon RPC request failed for username: #{username}")
|
80 | 71 | end
|
81 |
| - raw_response |
| 72 | + Netlogon.const_get("DsrGetDcNameEx2Response").read(raw_response) |
| 73 | + end |
| 74 | + |
| 75 | + def report_username(domain, username) |
| 76 | + service_data = { |
| 77 | + address: datastore['RHOST'], |
| 78 | + port: @@dport, |
| 79 | + service_name: 'netlogon', |
| 80 | + protocol: 'tcp', |
| 81 | + workspace_id: myworkspace_id |
| 82 | + } |
| 83 | + |
| 84 | + credential_data = { |
| 85 | + origin_type: :service, |
| 86 | + module_fullname: fullname, |
| 87 | + username: username, |
| 88 | + realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN, |
| 89 | + realm_value: domain, |
| 90 | + }.merge(service_data) |
| 91 | + |
| 92 | + login_data = { |
| 93 | + core: create_credential(credential_data), |
| 94 | + status: Metasploit::Model::Login::Status::UNTRIED |
| 95 | + }.merge(service_data) |
| 96 | + |
| 97 | + create_credential_login(login_data) |
82 | 98 | end
|
83 | 99 |
|
84 | 100 | def run_host(_ip)
|
@@ -106,8 +122,11 @@ def load_usernames(file_path)
|
106 | 122 |
|
107 | 123 | def enumerate_user(username)
|
108 | 124 | response = dsr_get_dc_name_ex2(username)
|
109 |
| - if response[-4, 4] == "\x00\x00\x00\x00" |
110 |
| - print_good("#{username} exists") |
| 125 | + if response.error_status == 0 |
| 126 | + print_good("#{username} exists -> DC: #{response.domain_controller_info.domain_controller_name.encode('UTF-8')}") |
| 127 | + if datastore['DB_ALL_USERS'] |
| 128 | + report_username(response.domain_controller_info.domain_name.encode('UTF-8'), username) |
| 129 | + end |
111 | 130 | else
|
112 | 131 | print_error("#{username} does not exist")
|
113 | 132 | end
|
|
0 commit comments