|
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