|
6 | 6 | require 'msf/core'
|
7 | 7 |
|
8 | 8 | class Metasploit3 < Msf::Auxiliary
|
9 |
| - |
10 | 9 | include Msf::Exploit::Remote::SNMPClient
|
11 | 10 | include Msf::Auxiliary::Report
|
12 | 11 | include Msf::Auxiliary::Scanner
|
| 12 | + include SNMP |
13 | 13 |
|
14 | 14 | def initialize
|
15 | 15 | super(
|
16 | 16 | 'Name' => 'SNMP Windows Username Enumeration',
|
17 |
| - 'Description' => "This module will use LanManager OID values to enumerate local user accounts on a Windows system via SNMP", |
| 17 | + 'Description' => ' |
| 18 | + This module will use LanManager/psProcessUsername OID values to |
| 19 | + enumerate local user accounts on a Windows/Solaris system via SNMP |
| 20 | + ', |
18 | 21 | 'Author' => ['tebo[at]attackresearch.com'],
|
19 | 22 | 'License' => MSF_LICENSE
|
20 | 23 | )
|
21 |
| - |
22 | 24 | end
|
23 | 25 |
|
24 | 26 | def run_host(ip)
|
| 27 | + peer = "#{ip}:#{rport}" |
25 | 28 | begin
|
26 | 29 | snmp = connect_snmp
|
27 | 30 |
|
28 |
| - if snmp.get_value('sysDescr.0') =~ /Windows/ |
29 |
| - |
30 |
| - @users = [] |
31 |
| - snmp.walk("1.3.6.1.4.1.77.1.2.25") do |row| |
32 |
| - row.each { |val| @users << val.value.to_s } |
33 |
| - end |
| 31 | + sys_desc = snmp.get_value('sysDescr.0') |
| 32 | + if sys_desc.blank? || sys_desc.to_s == 'Null' |
| 33 | + vprint_error("#{peer} No sysDescr received") |
| 34 | + return |
| 35 | + end |
| 36 | + sys_desc = sys_desc.split(/[\r\n]/).join(' ') |
34 | 37 |
|
35 |
| - print_good("#{ip} Found Users: #{@users.sort.join(", ")} ") |
| 38 | + sys_desc_map = { |
| 39 | + /Windows/ => '1.3.6.1.4.1.77.1.2.25', |
| 40 | + /Sun/ => '1.3.6.1.4.1.42.3.12.1.8' |
| 41 | + } |
36 | 42 |
|
| 43 | + matching_oids = sys_desc_map.select { |re, _| sys_desc =~ re }.values |
| 44 | + if matching_oids.empty? |
| 45 | + vprint_warning("#{peer} Skipping unsupported sysDescr: '#{sys_desc}'") |
| 46 | + return |
37 | 47 | end
|
| 48 | + users = [] |
38 | 49 |
|
39 |
| - disconnect_snmp |
| 50 | + matching_oids.each do |oid| |
| 51 | + snmp.walk(oid) do |row| |
| 52 | + row.each { |val| users << val.value.to_s } |
| 53 | + end |
| 54 | + end |
| 55 | + unless users.empty? |
| 56 | + users.sort! |
| 57 | + users.uniq! |
| 58 | + print_good("#{peer} Found #{users.size} users: #{users.join(', ')}") |
| 59 | + end |
40 | 60 |
|
41 | 61 | report_note(
|
42 |
| - :host => rhost, |
43 |
| - :port => datastore['RPORT'], |
44 |
| - :proto => 'udp', |
45 |
| - :sname => 'snmp', |
46 |
| - :update => :unique_data, |
47 |
| - :type => 'snmp.users', |
48 |
| - :data => @users |
| 62 | + host: rhost, |
| 63 | + port: rport, |
| 64 | + proto: 'udp', |
| 65 | + sname: 'snmp', |
| 66 | + update: :unique_data, |
| 67 | + type: 'snmp.users', |
| 68 | + data: users |
49 | 69 | )
|
50 |
| - |
51 |
| - |
52 |
| - rescue ::SNMP::UnsupportedVersion |
53 |
| - rescue ::SNMP::RequestTimeout |
54 |
| - rescue ::Interrupt |
55 |
| - raise $! |
56 |
| - rescue ::Exception => e |
57 |
| - print_error("Unknown error: #{e.class} #{e}") |
| 70 | + rescue ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion |
| 71 | + # too noisy for a scanner |
| 72 | + ensure |
| 73 | + disconnect_snmp |
58 | 74 | end
|
59 |
| - |
60 | 75 | end
|
61 |
| - |
62 | 76 | end
|
0 commit comments