Skip to content

Commit

Permalink
Land #19064, SNMP TCP support
Browse files Browse the repository at this point in the history
  • Loading branch information
smcintyre-r7 committed Apr 10, 2024
2 parents 53efed1 + 71538a8 commit 76145c3
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 5 deletions.
53 changes: 48 additions & 5 deletions lib/metasploit/framework/login_scanner/snmp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class SNMP

DEFAULT_TIMEOUT = 2
DEFAULT_PORT = 161
DEFAULT_PROTOCOL = 'udp'.freeze
DEFAULT_VERSION = '1'.freeze
DEFAULT_QUEUE_SIZE = 100
LIKELY_PORTS = [ 161, 162 ].freeze
Expand All @@ -27,6 +28,10 @@ class SNMP
# @return [String]
attr_accessor :version

# The SNMP protocol to use
# @return [String]
attr_accessor :protocol

# The number of logins to try in each batch
# @return [Integer]
attr_accessor :queue_size
Expand All @@ -37,6 +42,12 @@ class SNMP
in: ['1', '2c', 'all']
}

validates :protocol,
presence: true,
inclusion: {
in: ['udp', 'tcp']
}

validates :queue_size,
presence: true,
numericality: {
Expand Down Expand Up @@ -191,10 +202,26 @@ def process_logins(opts = {})
process_responses(1.0)
end

def recv_wrapper(sock, max_size, timeout)
res = nil
if protocol == 'udp'
res = sock.recvfrom(max_size, timeout)
elsif protocol == 'tcp'
ready = ::IO.select([sock], nil, nil, timeout)
if ready
res = sock.recv_nonblock(max_size)
# Put into an array to mimic recvfrom
res = [res, host, port]
end
end

res
end

# Process any responses on the UDP socket and queue the results
def process_responses(timeout = 1.0)
queue = []
while (res = sock.recvfrom(65535, timeout))
while (res = recv_wrapper(sock, 65535, timeout))

# Ignore invalid responses
break if !(res[1])
Expand All @@ -212,7 +239,7 @@ def process_responses(timeout = 1.0)
community: response[:community],
host: host,
port: port,
protocol: 'udp',
protocol: protocol,
service_name: 'snmp',
proof: response[:proof],
status: Metasploit::Model::Login::Status::SUCCESSFUL,
Expand All @@ -237,12 +264,22 @@ def send_snmp_write_request(version, community, data)
)
end

def send_wrapper(sock, pkt, host, port, flags)
if protocol == 'tcp'
return sock.send(pkt, flags)
end

if protocol == 'udp'
return sock.sendto(pkt, host, port, 0)
end
end

# Send a SNMP request on the existing socket
def send_snmp_request(pkt)
resend_count = 0

begin
sock.sendto(pkt, host, port, 0)
send_wrapper(sock, pkt, host, port, 0)
rescue ::Errno::ENOBUFS
resend_count += 1
if resend_count > MAX_RESEND_COUNT
Expand Down Expand Up @@ -347,10 +384,15 @@ def parse_snmp_response(pkt)
# Create a new socket for this scanner
def configure_socket
shutdown_socket if sock
self.sock = ::Rex::Socket::Udp.create(

self.sock = ::Rex::Socket.create({
'PeerHost' => host,
'PeerPort' => port,
'Proto' => protocol,
'Timeout' => connection_timeout,
'Context' =>
{ 'Msf' => framework, 'MsfExploit' => framework_module }
)
})
end

# Close any open socket if it exists
Expand All @@ -362,6 +404,7 @@ def shutdown_socket
# Sets the SNMP parameters if not specified
def set_sane_defaults
self.connection_timeout = DEFAULT_TIMEOUT if connection_timeout.nil?
self.protocol = DEFAULT_PROTOCOL if protocol.nil?
self.port = DEFAULT_PORT if port.nil?
self.version = DEFAULT_VERSION if version.nil?
self.queue_size = DEFAULT_QUEUE_SIZE if queue_size.nil?
Expand Down
6 changes: 6 additions & 0 deletions modules/auxiliary/scanner/snmp/snmp_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def initialize
register_options(
[
Opt::RPORT(161),
OptEnum.new('PROTOCOL', [true, 'The SNMP protocol to use', 'udp', ['udp', 'tcp']]),
OptEnum.new('VERSION', [true, 'The SNMP version to scan', '1', ['1', '2c', 'all']]),
OptString.new('PASSWORD', [ false, 'The password to test' ]),
OptPath.new('PASS_FILE', [ false, "File containing communities, one per line",
Expand All @@ -51,6 +52,7 @@ def run_host(ip)
scanner = Metasploit::Framework::LoginScanner::SNMP.new(
host: ip,
port: rport,
protocol: datastore['PROTOCOL'],
cred_details: collection,
stop_on_success: datastore['STOP_ON_SUCCESS'],
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
Expand Down Expand Up @@ -91,6 +93,10 @@ def rport
datastore['RPORT']
end

def protocol
datastore['PROTOCOL']
end




Expand Down

0 comments on commit 76145c3

Please sign in to comment.