Reapply PR #4113 (removed via #4175)

bug/bundler_fix
Tod Beardsley 2014-11-11 15:06:43 -06:00
parent 2a6d288fe8
commit 7e05f88399
No known key found for this signature in database
GPG Key ID: BD63D0A3EA19CAAC
4 changed files with 159 additions and 13 deletions

View File

@ -8,7 +8,7 @@
# inherit_from: .rubocop_todo.yml # inherit_from: .rubocop_todo.yml
Style/ClassLength: Metrics/ClassLength:
Description: 'Most Metasploit modules are quite large. This is ok.' Description: 'Most Metasploit modules are quite large. This is ok.'
Enabled: true Enabled: true
Exclude: Exclude:
@ -25,14 +25,14 @@ Style/Encoding:
Description: 'We prefer binary to UTF-8.' Description: 'We prefer binary to UTF-8.'
EnforcedStyle: 'when_needed' EnforcedStyle: 'when_needed'
Style/LineLength: Metrics/LineLength:
Description: >- Description: >-
Metasploit modules often pattern match against very Metasploit modules often pattern match against very
long strings when identifying targets. long strings when identifying targets.
Enabled: true Enabled: true
Max: 180 Max: 180
Style/MethodLength: Metrics/MethodLength:
Enabled: true Enabled: true
Description: >- Description: >-
While the style guide suggests 10 lines, exploit definitions While the style guide suggests 10 lines, exploit definitions
@ -44,6 +44,11 @@ Style/MethodLength:
Style/Encoding: Style/Encoding:
Enabled: false Enabled: false
# %q() is super useful for long strings split over multiple lines and
# is very common in module constructors for things like descriptions
Style/UnneededPercentQ:
Enabled: false
Style/NumericLiterals: Style/NumericLiterals:
Enabled: false Enabled: false
Description: 'This often hurts readability for exploit-ish code.' Description: 'This often hurts readability for exploit-ish code.'

View File

@ -241,10 +241,10 @@ end
def scanner_show_progress def scanner_show_progress
pct = scanner_progress pct = scanner_progress
if(pct >= (@range_percent + @show_percent)) if pct >= (@range_percent + @show_percent)
@range_percent = @range_percent + @show_percent @range_percent = @range_percent + @show_percent
tdlen = @range_count.to_s.length tdlen = @range_count.to_s.length
print_status("Scanned #{"%.#{tdlen}d" % @range_done} of #{@range_count} hosts (#{"%.3d" % pct.to_i}% complete)") print_status(sprintf("Scanned %#{tdlen}d of %d hosts (%d%% complete)", @range_done, @range_count, pct))
end end
end end

View File

@ -8,33 +8,36 @@ module Msf
# #
### ###
module Auxiliary::UDPScanner module Auxiliary::UDPScanner
include Auxiliary::Scanner include Auxiliary::Scanner
# A hash of results of a given batch run, keyed by host
attr_accessor :results
# #
# Initializes an instance of an auxiliary module that scans UDP # Initializes an instance of an auxiliary module that scans UDP
# #
def initialize(info = {}) def initialize(info = {})
super super
register_options( register_options(
[ [
Opt::CHOST, Opt::RPORT,
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]), OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
OptInt.new('THREADS', [true, "The number of concurrent threads", 10])
], self.class) ], self.class)
register_advanced_options( register_advanced_options(
[ [
Opt::CHOST,
Opt::CPORT,
OptInt.new('ScannerRecvInterval', [true, 'The maximum numbers of sends before entering the processing loop', 30]), OptInt.new('ScannerRecvInterval', [true, 'The maximum numbers of sends before entering the processing loop', 30]),
OptInt.new('ScannerMaxResends', [true, 'The maximum times to resend a packet when out of buffers', 10]), OptInt.new('ScannerMaxResends', [true, 'The maximum times to resend a packet when out of buffers', 10]),
OptInt.new('ScannerRecvQueueLimit', [true, 'The maximum queue size before breaking out of the processing loop', 100]), OptInt.new('ScannerRecvQueueLimit', [true, 'The maximum queue size before breaking out of the processing loop', 100]),
OptInt.new('ScannerRecvWindow', [true, 'The number of seconds to wait post-scan to catch leftover replies', 15]), OptInt.new('ScannerRecvWindow', [true, 'The number of seconds to wait post-scan to catch leftover replies', 15])
], self.class) ], self.class)
end end
# Define our batch size # Define our batch size
def run_batch_size def run_batch_size
datastore['BATCHSIZE'].to_i datastore['BATCHSIZE'].to_i
@ -44,6 +47,7 @@ module Auxiliary::UDPScanner
def run_batch(batch) def run_batch(batch)
@udp_sock = Rex::Socket::Udp.create({ @udp_sock = Rex::Socket::Udp.create({
'LocalHost' => datastore['CHOST'] || nil, 'LocalHost' => datastore['CHOST'] || nil,
'LocalPort' => datastore['CPORT'] || 0,
'Context' => { 'Msf' => framework, 'MsfExploit' => self } 'Context' => { 'Msf' => framework, 'MsfExploit' => self }
}) })
add_socket(@udp_sock) add_socket(@udp_sock)
@ -155,12 +159,25 @@ module Auxiliary::UDPScanner
queue.length queue.length
end end
def cport
datastore['CPORT']
end
def rport
datastore['RPORT']
end
# #
# The including module override these methods # The including module may override some of these methods
# #
# Called for each IP in the batch # Builds and returns the probe to be sent
def build_probe
end
# Called for each IP in the batch. This will send all necessary probes.
def scan_host(ip) def scan_host(ip)
scanner_send(build_probe, ip, rport)
end end
# Called for each response packet # Called for each response packet
@ -169,11 +186,12 @@ module Auxiliary::UDPScanner
# Called before the scan block # Called before the scan block
def scanner_prescan(batch) def scanner_prescan(batch)
vprint_status("Sending probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
@results = {}
end end
# Called after the scan block # Called after the scan block
def scanner_postscan(batch) def scanner_postscan(batch)
end end
end end
end end

View File

@ -0,0 +1,123 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Auxiliary::UDPScanner
def initialize(info = {})
super(
update_info(
info,
# TODO: fill in all of this
'Name' => 'UDP Scanner Example',
'Description' => %q(
This module is an example of how to send probes to UDP services
en-masse, analyze any responses, and then report on any discovered
hosts, services, vulnerabilities or otherwise noteworthy things.
Simply address any of the TODOs.
),
'Author' => 'Joe Contributor <joe_contributor[at]example.com>',
'References' =>
[
['URL', 'https://example.com/~jcontributor']
],
'DisclosureDate' => 'Mar 15 2014',
'License' => MSF_LICENSE
)
)
register_options(
[
# TODO: change to the port you need to scan
Opt::RPORT(12345)
], self.class)
# TODO: add any advanced, special options here, otherwise remove
register_advanced_options(
[
OptBool.new('SPECIAL', [true, 'Try this special thing', false])
], self.class)
end
def setup
super
# TODO: do any sort of preliminary sanity checking, like perhaps validating some options
# in the datastore, etc.
end
# TODO: construct the appropriate probe here.
def build_probe
@probe ||= 'abracadabra!'
end
# TODO: this is called before the scan block for each batch of hosts. Do any
# per-batch setup here, otherwise remove it.
def scanner_prescan(batch)
super
end
# TODO: this is called for each IP in the batch. This will send all of the
# necessary probes. If something different must be done for each IP, do it
# here, otherwise remove it.
def scan_host(ip)
super
end
# Called for each response packet
def scanner_process(response, src_host, _src_port)
# TODO: inspect each response, perhaps confirming that it is a valid
# response for the service/protocol in question and/or analyzing it more
# closely. In this case, we simply check to see that it is of reasonable
# size and storing a result for this host iff so. Note that src_port may
# not actually be the same as the original RPORT for some services if they
# respond back from different ports
return unless response.size >= 42
@results[src_host] ||= []
# TODO: store something about this response, perhaps the response itself,
# some metadata obtained by analyzing it, the proof that it is vulnerable
# to something, etc. In this example, we simply look for any response
# with a sequence of 5 useful ASCII characters and, iff found, we store
# that sequence
/(?<relevant>[\x20-\x7E]{5})/ =~ response && @results[src_host] << relevant
end
# Called after the scan block
def scanner_postscan(_batch)
@results.each_pair do |host, relevant_responses|
peer = "#{host}:#{rport}"
# report on the host
report_host(host: host)
# report on the service, since it responded
report_service(
host: host,
proto: 'udp',
port: rport,
name: 'example',
# show at most 4 relevant responses
info: relevant_responses[0, 4].join(',')
)
if relevant_responses.empty?
vprint_status("#{peer} Not vulnerable to something")
else
print_good("#{peer} Vulnerable to something!")
report_vuln(
host: host,
port: rport,
proto: 'udp',
name: 'something!',
info: "Got #{relevant_responses.size} response(s)",
refs: references
)
end
end
end
end