Module: Msf::Auxiliary::UDPScanner

Includes:
Scanner
Defined in:
lib/msf/core/auxiliary/udp_scanner.rb

Overview

This module provides methods for scanning UDP services

Instance Method Summary collapse

Methods included from Scanner

#check, #run, #scanner_progress, #scanner_show_progress, #seppuko!

Instance Method Details

#initialize(info = {}) ⇒ Object

Initializes an instance of an auxiliary module that scans UDP


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 18

def initialize(info = {})
  super

  register_options(
  [
    Opt::CHOST,
    OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
  ], self.class)

  register_advanced_options(
  [
    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('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]),

  ], self.class)
end

#run_batch(batch) ⇒ Object

Start scanning a batch of IP addresses


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 44

def run_batch(batch)
  @udp_sock = Rex::Socket::Udp.create({
    'LocalHost' => datastore['CHOST'] || nil,
    'Context'   => { 'Msf' => framework, 'MsfExploit' => self }
  })
  add_socket(@udp_sock)

  @udp_send_count = 0

  # Provide a hook for pre-scanning setup
  scanner_prescan(batch)

  # Call the including module once per IP
  batch.each do |ip|
    scan_host(ip)
  end

  # Catch any stragglers
  stime = Time.now.to_f

  while Time.now.to_f < ( stime + datastore['ScannerRecvWindow'] )
    scanner_recv(1.0)
  end

  # Provide a hook for post-scanning processing
  scanner_postscan(batch)
end

#run_batch_sizeObject

Define our batch size


39
40
41
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 39

def run_batch_size
  datastore['BATCHSIZE'].to_i
end

#scan_host(ip) ⇒ Object

Called for each IP in the batch


145
146
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 145

def scan_host(ip)
end

#scanner_postscan(batch) ⇒ Object

Called after the scan block


157
158
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 157

def scanner_postscan(batch)
end

#scanner_prescan(batch) ⇒ Object

Called before the scan block


153
154
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 153

def scanner_prescan(batch)
end

#scanner_process(data, shost, sport) ⇒ Object

Called for each response packet


149
150
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 149

def scanner_process(data, shost, sport)
end

#scanner_recv(timeout = 0.1) ⇒ Object

Process incoming packets and dispatch to the module Ensure a response flood doesn't trap us in a loop Ignore packets outside of our project's scope


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 110

def scanner_recv(timeout=0.1)
  queue = []
  while (res = @udp_sock.recvfrom(65535, timeout))

    # Ignore invalid responses
    break if not res[1]

    # Ignore empty responses
    next if not (res[0] and res[0].length > 0)

    # Trim the IPv6-compat prefix off if needed
    shost = res[1].sub(/^::ffff:/, '')

    # Ignore the response if we have a boundary
    next unless inside_workspace_boundary?(shost)

    queue << [res[0], shost, res[2]]

    if queue.length > datastore['ScannerRecvQueueLimit']
      break
    end
  end

  queue.each do |q|
    scanner_process(*q)
  end

  queue.length
end

#scanner_send(data, ip, port) ⇒ Object

Send a packet to a given host and port


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/msf/core/auxiliary/udp_scanner.rb', line 73

def scanner_send(data, ip, port)

  resend_count = 0
  begin

    @udp_sock.sendto(data, ip, port, 0)

  rescue ::Errno::ENOBUFS
    resend_count += 1
    if resend_count > datastore['ScannerMaxResends']
      vprint_error("#{ip}:#{port} Max resend count hit sending #{data.length}")
      return false
    end

    scanner_recv(0.1)

    ::IO.select(nil, nil, nil, 0.25)

    retry

  rescue ::Rex::ConnectionError
    # This fires for host unreachable, net unreachable, and broadcast sends
    # We can safely ignore all of these for UDP sends
  end

  @udp_send_count += 1

  if @udp_send_count % datastore['ScannerRecvInterval'] == 0
    scanner_recv(0.1)
  end

  true
end