Add support for link-local scopes
parent
9c887eb457
commit
e46745b761
|
@ -0,0 +1,9 @@
|
|||
class AddScopeToHosts < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :hosts, :scope, :text
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :hosts, :scope
|
||||
end
|
||||
end
|
|
@ -235,6 +235,8 @@ class DBManager
|
|||
if wspace.kind_of? String
|
||||
wspace = find_workspace(wspace)
|
||||
end
|
||||
|
||||
address, scope = address.split('%', 2)
|
||||
return wspace.hosts.find_by_address(address)
|
||||
end
|
||||
|
||||
|
@ -259,6 +261,7 @@ class DBManager
|
|||
# :os_lang -- something like "English", "French", or "en-US"
|
||||
# :arch -- one of the ARCH_* constants
|
||||
# :mac -- the host's MAC address
|
||||
# :scope -- interface identifier for link-local IPv6
|
||||
#
|
||||
def report_host(opts)
|
||||
|
||||
|
@ -275,6 +278,9 @@ class DBManager
|
|||
|
||||
if not addr.kind_of? Host
|
||||
addr = normalize_host(addr)
|
||||
addr, scope = addr.split('%', 2)
|
||||
opts[:scope] = scope if scope
|
||||
|
||||
unless ipv46_validator(addr)
|
||||
raise ::ArgumentError, "Invalid IP address in report_host(): #{addr}"
|
||||
end
|
||||
|
@ -313,7 +319,7 @@ class DBManager
|
|||
host.state = HostState::Alive if not host.state
|
||||
host.comm = '' if not host.comm
|
||||
host.workspace = wspace if not host.workspace
|
||||
|
||||
|
||||
if host.changed?
|
||||
msf_import_timestamps(opts,host)
|
||||
host.save!
|
||||
|
@ -1222,6 +1228,7 @@ class DBManager
|
|||
# Deletes a host and associated data matching this address/comm
|
||||
#
|
||||
def del_host(wspace, address, comm='')
|
||||
address, scope = address.split('%', 2)
|
||||
host = wspace.hosts.find_by_address_and_comm(address, comm)
|
||||
host.destroy if host
|
||||
end
|
||||
|
@ -1255,6 +1262,7 @@ class DBManager
|
|||
# Look for an address across all comms
|
||||
#
|
||||
def has_host?(wspace,addr)
|
||||
address, scope = addr.split('%', 2)
|
||||
wspace.hosts.find_by_address(addr)
|
||||
end
|
||||
|
||||
|
@ -5220,8 +5228,9 @@ class DBManager
|
|||
norm_host = nil
|
||||
|
||||
if (host.kind_of? String)
|
||||
# If it's an IPv4 addr with a host on the end, strip the port
|
||||
if host =~ /((\d{1,3}\.){3}\d{1,3}):\d+/
|
||||
|
||||
# If it's an IPv4 addr with a port on the end, strip the port
|
||||
if Rex::Socket.is_ipv4?(host) and host =~ /((\d{1,3}\.){3}\d{1,3}):\d+/
|
||||
norm_host = $1
|
||||
else
|
||||
norm_host = host
|
||||
|
|
|
@ -168,7 +168,7 @@ class Db
|
|||
default_columns = ::Msf::DBManager::Host.column_names.sort
|
||||
virtual_columns = [ 'svcs', 'vulns', 'workspace' ]
|
||||
|
||||
col_search = [ 'address', 'mac', 'name', 'os_name', 'os_flavor', 'os_sp', 'purpose', 'info', 'comments' ]
|
||||
col_search = [ 'address', 'mac', 'name', 'os_name', 'os_flavor', 'os_sp', 'purpose', 'info', 'comments']
|
||||
|
||||
default_columns.delete_if {|v| (v[-2,2] == "id")}
|
||||
while (arg = args.shift)
|
||||
|
@ -235,7 +235,8 @@ class Db
|
|||
print_status("Time: #{host.created_at} Host: host=#{host.address}")
|
||||
if set_rhosts
|
||||
# only unique addresses
|
||||
rhosts << host.address unless rhosts.include?(host.address)
|
||||
addr = (host.scope ? host.address + '%' + host.scope : host.address )
|
||||
rhosts << addr unless rhosts.include?(addr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -271,8 +272,8 @@ class Db
|
|||
|
||||
tbl << columns
|
||||
if set_rhosts
|
||||
# only unique addresses
|
||||
rhosts << host.address unless rhosts.include?(host.address)
|
||||
addr = (host.scope ? host.address + '%' + host.scope : host.address )
|
||||
rhosts << addr unless rhosts.include?(addr)
|
||||
end
|
||||
if mode == :delete
|
||||
host.destroy
|
||||
|
@ -363,7 +364,7 @@ class Db
|
|||
print_error("Invalid output filename")
|
||||
return
|
||||
end
|
||||
output_file = File.expand_path(output_file)
|
||||
output_file = ::File.expand_path(output_file)
|
||||
when '-R','--rhosts'
|
||||
set_rhosts = true
|
||||
rhosts = []
|
||||
|
@ -443,9 +444,10 @@ class Db
|
|||
columns = [host.address] + col_names.map { |n| service[n].to_s || "" }
|
||||
tbl << columns
|
||||
if set_rhosts
|
||||
# only unique addresses
|
||||
rhosts << host.address unless rhosts.include?(host.address)
|
||||
addr = (host.scope ? host.address + '%' + host.scope : host.address )
|
||||
rhosts << addr unless rhosts.include?(addr)
|
||||
end
|
||||
|
||||
if (mode == :delete)
|
||||
service.destroy
|
||||
delete_count += 1
|
||||
|
@ -458,7 +460,7 @@ class Db
|
|||
print_line tbl.to_s
|
||||
else
|
||||
# create the output file
|
||||
File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
|
||||
::File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
|
||||
print_status("Wrote services to #{output_file}")
|
||||
end
|
||||
|
||||
|
@ -621,7 +623,7 @@ class Db
|
|||
print_error("Invalid output filename")
|
||||
return
|
||||
end
|
||||
output_file = File.expand_path(output_file)
|
||||
output_file = ::File.expand_path(output_file)
|
||||
when "-p","--port"
|
||||
unless (arg_port_range(args.shift, port_ranges, true))
|
||||
return
|
||||
|
@ -737,8 +739,8 @@ class Db
|
|||
cred.destroy
|
||||
end
|
||||
if set_rhosts
|
||||
# only unique addresses
|
||||
rhosts << cred.service.host.address unless rhosts.include?(cred.service.host.address)
|
||||
addr = (cred.service.host.scope ? cred.service.host.address + '%' + cred.service.host.scope : cred.service.host.address )
|
||||
rhosts << addr unless rhosts.include?(addr)
|
||||
end
|
||||
creds_returned += 1
|
||||
end
|
||||
|
@ -748,7 +750,7 @@ class Db
|
|||
print_line tbl.to_s
|
||||
else
|
||||
# create the output file
|
||||
File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
|
||||
::File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
|
||||
print_status("Wrote services to #{output_file}")
|
||||
end
|
||||
|
||||
|
@ -852,8 +854,8 @@ class Db
|
|||
host = note.host
|
||||
msg << " host=#{note.host.address}"
|
||||
if set_rhosts
|
||||
# only unique addresses
|
||||
rhosts << host.address unless rhosts.include?(host.address)
|
||||
addr = (host.scope ? host.address + '%' + host.scope : host.address )
|
||||
rhosts << addr unless rhosts.include?(addr)
|
||||
end
|
||||
end
|
||||
if (note.service)
|
||||
|
@ -1003,13 +1005,13 @@ class Db
|
|||
return
|
||||
end
|
||||
args.each { |glob|
|
||||
files = Dir.glob(File.expand_path(glob))
|
||||
files = ::Dir.glob(::File.expand_path(glob))
|
||||
if files.empty?
|
||||
print_error("No such file #{glob}")
|
||||
next
|
||||
end
|
||||
files.each { |filename|
|
||||
if (not File.readable?(filename))
|
||||
if (not ::File.readable?(filename))
|
||||
print_error("Could not read file #{filename}")
|
||||
next
|
||||
end
|
||||
|
@ -1285,13 +1287,13 @@ class Db
|
|||
def cmd_db_connect(*args)
|
||||
return if not db_check_driver
|
||||
if (args[0] == "-y")
|
||||
if (args[1] and not File.exists? File.expand_path(args[1]))
|
||||
if (args[1] and not ::File.exists? ::File.expand_path(args[1]))
|
||||
print_error("File not found")
|
||||
return
|
||||
end
|
||||
file = args[1] || File.join(Msf::Config.get_config_root, "database.yml")
|
||||
if (File.exists? File.expand_path(file))
|
||||
db = YAML.load(File.read(file))['production']
|
||||
file = args[1] || ::File.join(Msf::Config.get_config_root, "database.yml")
|
||||
if (::File.exists? ::File.expand_path(file))
|
||||
db = YAML.load(::File.read(file))['production']
|
||||
cmd_db_driver(db['adapter'])
|
||||
framework.db.connect(db)
|
||||
return
|
||||
|
|
|
@ -239,10 +239,12 @@ module Socket
|
|||
# on Windows.
|
||||
#
|
||||
def self.gethostbyname(host)
|
||||
if (dotted_ip?(host))
|
||||
if (is_ipv4?(host))
|
||||
return [ host, host, 2, host.split('.').map{ |c| c.to_i }.pack("C4") ]
|
||||
end
|
||||
if (is_ipv4?(host))
|
||||
return [ host, [], 2, host.split('.').map{ |c| c.to_i }.pack("C4") ]
|
||||
end
|
||||
|
||||
if is_ipv6?(host)
|
||||
host, scope__id = host.split('%', 2)
|
||||
end
|
||||
|
||||
::Socket.gethostbyname(host)
|
||||
|
@ -278,7 +280,7 @@ module Socket
|
|||
# Resolves a host to raw network-byte order.
|
||||
#
|
||||
def self.resolv_nbo(host)
|
||||
self.gethostbyname(Rex::Socket.getaddress(host, true))[3]
|
||||
self.gethostbyname( Rex::Socket.getaddress(host, true) )[3]
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -53,25 +53,37 @@ class RangeWalker
|
|||
return nil if not parseme
|
||||
ranges = []
|
||||
parseme.split(', ').map{ |a| a.split(' ') }.flatten.each { |arg|
|
||||
|
||||
opts = {}
|
||||
|
||||
# Handle IPv6 first (support ranges, but not CIDR)
|
||||
if arg.include?(":")
|
||||
addrs = arg.split('-', 2)
|
||||
|
||||
|
||||
# Handle a single address
|
||||
if addrs.length == 1
|
||||
# IPv6 ranges are not yet supported (or useful)
|
||||
return false unless Rex::Socket.is_ipv6?(arg)
|
||||
|
||||
addr = Rex::Socket.addr_atoi(arg)
|
||||
ranges.push [addr, addr, true]
|
||||
addr, scope_id = addrs[0].split('%')
|
||||
opts[:scope_id] = scope_id if scope_id
|
||||
|
||||
return false unless Rex::Socket.is_ipv6?(addr)
|
||||
addr = Rex::Socket.addr_atoi(addr)
|
||||
ranges.push [addr, addr, true, opts]
|
||||
next
|
||||
end
|
||||
|
||||
addr1, scope_id = addrs[0].split('%')
|
||||
opts[:scope_id] = scope_id if scope_id
|
||||
|
||||
addr2, scope_id = addrs[0].split('%')
|
||||
( opts[:scope_id] ||= scope_id ) if scope_id
|
||||
|
||||
return false if not (Rex::Socket.is_ipv6?(addr1) and Rex::Socket.is_ipv6?(addr2))
|
||||
|
||||
# Handle IPv6 ranges in the form of 2001::1-2001::10
|
||||
return false if not (Rex::Socket.is_ipv6?(addrs[0]) and Rex::Socket.is_ipv6?(addrs[1]))
|
||||
addr1 = Rex::Socket.addr_atoi(addrs[0])
|
||||
addr2 = Rex::Socket.addr_atoi(addrs[1])
|
||||
ranges.push [addr1, addr2, true]
|
||||
addr1 = Rex::Socket.addr_atoi(addr1)
|
||||
addr2 = Rex::Socket.addr_atoi(addr2)
|
||||
|
||||
ranges.push [addr1, addr2, true, opts]
|
||||
next
|
||||
|
||||
# Handle IPv4 CIDR
|
||||
elsif arg.include?("/")
|
||||
|
@ -90,7 +102,7 @@ class RangeWalker
|
|||
|
||||
expanded = expand_cidr(arg)
|
||||
if expanded
|
||||
ranges += expanded
|
||||
ranges.push [ expanded[0], expanded[1], false, {} ]
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
@ -99,7 +111,7 @@ class RangeWalker
|
|||
elsif arg =~ /[^-0-9,.*]/
|
||||
# Then it's a domain name and we should send it on to addr_atoi
|
||||
# unmolested to force a DNS lookup.
|
||||
Rex::Socket.addr_atoi_list(arg).each { |addr| ranges.push [addr, addr] }
|
||||
Rex::Socket.addr_atoi_list(arg).each { |addr| ranges.push [addr, addr, false, opts] }
|
||||
|
||||
# Handle IPv4 ranges
|
||||
elsif arg =~ /^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})-([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$/
|
||||
|
@ -108,19 +120,22 @@ class RangeWalker
|
|||
begin
|
||||
addrs = [Rex::Socket.addr_atoi($1), Rex::Socket.addr_atoi($2)]
|
||||
return false if addrs[0] > addrs[1] # The end is greater than the beginning.
|
||||
ranges.push [addrs[0], addrs[1]]
|
||||
ranges.push [addrs[0], addrs[1], false, opts]
|
||||
rescue Resolv::ResolvError # Something's broken, forget it.
|
||||
return false
|
||||
end
|
||||
else
|
||||
expanded = expand_nmap(arg)
|
||||
if expanded
|
||||
ranges += expanded
|
||||
ranges.push [ expanded[0], expanded[1], false, {} ]
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
# Remove any duplicate ranges
|
||||
ranges = ranges.uniq
|
||||
|
||||
return ranges
|
||||
end
|
||||
|
@ -150,6 +165,11 @@ class RangeWalker
|
|||
@curr_addr = @ranges[@curr_range][0]
|
||||
end
|
||||
addr = Rex::Socket.addr_itoa(@curr_addr, @ranges[@curr_range][2])
|
||||
|
||||
if @ranges[@curr_range][3][:scope_id]
|
||||
addr = addr + '%' + @ranges[@curr_range][3][:scope_id]
|
||||
end
|
||||
|
||||
@curr_addr += 1
|
||||
return addr
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue