More recon hackery

git-svn-id: file:///home/svn/incoming/trunk@3585 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2006-04-02 22:33:34 +00:00
parent 3aa45638df
commit b4189e521d
17 changed files with 2426 additions and 67 deletions

View File

@ -1 +1 @@
3.0 Alpha Release 3
3.0 Alpha Release 4

View File

@ -20,3 +20,10 @@ create table services (
'name' VARCHAR(255),
'desc' VARCHAR(1024)
);
create table vulns (
'id' INTEGER PRIMARY KEY NOT NULL,
'service_id' INTEGER,
'name' VARCHAR(255),
'data' TEXT
);

Binary file not shown.

View File

@ -54,6 +54,26 @@ class ReadableText
tbl.to_s + "\n"
end
#
# Dumps an auxiliary's actions
#
def self.dump_auxiliary_actions(mod, indent = '', h = nil)
tbl = Rex::Ui::Text::Table.new(
'Indent' => indent.length,
'Header' => h,
'Columns' =>
[
'Name',
'Description'
])
mod.actions.each_with_index { |target, idx|
tbl << [ target.name || 'All' ]
}
tbl.to_s + "\n"
end
#
# Dumps the table of payloads that are compatible with the supplied
# exploit.

View File

@ -16,8 +16,10 @@ class Auxiliary < Msf::Module
#
# Auxiliary mixins
#
require 'msf/core/auxiliary/recon'
require 'msf/core/auxiliary/tcp'
require 'msf/core/auxiliary/udp'
#
# Returns MODULE_AUX to indicate that this is an auxiliary module.
#

View File

@ -0,0 +1,17 @@
module Msf
###
#
# This module provides methods for establish a connection to a remote host and
# communicating with it.
#
###
module Auxiliary::Recon
def report_host(host)
p host
end
end
end

View File

@ -1,15 +1,14 @@
#module Msf
#
module Msf
###
#
# This module provides methods for establish a connection to a remote host and
# communicating with it.
#
###
#module Auxiliary::Remote::Tcp
#
# include Exploit::Remote::Tcp
#
#end
#end
module Auxiliary::Tcp
include Exploit::Remote::Tcp
end
end

View File

@ -0,0 +1,14 @@
module Msf
###
#
# This module provides methods for establish a connection to a remote host and
# communicating with it.
#
###
module Auxiliary::Udp
include Exploit::Remote::Udp
end
end

View File

@ -99,22 +99,38 @@ class DBManager
#
# This method iterates the services table calling the supplied block with the
# host and service instances of each entry.
# TODO: use the find() block syntax instead
# service instance of each entry.
#
def each_service(&block)
services.each do |service|
block.call(service)
end
end
#
# This methods returns a list of all services in the database
#
def services
Service.find(:all)
end
#
# This method iterates the vulns table calling the supplied block with the
# vuln instance of each entry.
#
def each_vuln(&block)
vulns.each do |vulns|
block.call(vulns)
end
end
#
# This methods returns a list of all vulnerabilities in the database
#
def vulns
Vuln.find(:all)
end
def get_host(context, address, comm='')
host = Host.find(:first, :conditions => [ "address = ? and comm = ?", address, comm])
if (not host)
@ -125,21 +141,38 @@ class DBManager
return host
end
def get_service(host, proto, port)
port = Service.find(:first, :conditions => [ "host_id = ? and proto = ? and port = ?", host.id, proto, port])
if (not port)
port = Service.create(
:host => host,
def get_service(context, host, proto, port)
rec = Service.find(:first, :conditions => [ "host_id = ? and proto = ? and port = ?", host.id, proto, port])
if (not rec)
rec = Service.create(
:host_id => host.id,
:proto => proto,
:port => port,
:state => ServiceState::Unknown
:state => ServiceState::Up
)
framework.events.on_db_service(context, host, port)
framework.events.on_db_service(context, rec)
end
return port
return rec
end
def get_vuln(context, service, name, data='')
vuln = Vuln.find(:first, :conditions => [ "name = ? and service_id = ?", name, service.id])
if (not vuln)
vuln= Vuln.create(
:service_id => service.id,
:name => name,
:data => data
)
framework.events.on_db_vuln(context, vuln)
end
return vuln
end
def has_host?(addr)
Host.find(:first, :conditions => [ "address = ?", addr])
end
end
end

View File

@ -26,15 +26,20 @@ class DBManager
@usable = false
@active = false
begin
require 'rubygems'
require_gem 'activerecord'
# This double-rescue is required to detect active record when
# it has been installed outside of gems
begin
begin
require 'rubygems'
require_gem 'activerecord'
@usable = true
rescue LoadError
require 'activerecord'
@usable = true
end
require 'msf/core/db_objects'
@usable = true
rescue ::Exception => e
elog("DBManager is not enabled due to load error: #{e.to_s}")
elog("DB is not enabled due to load error: #{e.to_s}")
end
end

View File

@ -16,6 +16,20 @@ end
# Service object definition
class Service < ActiveRecord::Base
def host
Host.find(:first, :conditions => [ "id = ?", host_id ])
end
end
# Vuln object definition
class Vuln < ActiveRecord::Base
def service
Service.find(:first, :conditions => [ "id = ?", service_id ])
end
def host
Host.find(:first, :conditions => [ "id = ?", service.host_id ])
end
end
end

View File

@ -253,5 +253,24 @@ class NoNopsSucceededError < RuntimeError
end
end
##
#
# Plugin exceptions
#
##
class PluginLoadError < RuntimeError
include Exception
attr_accessor :reason
def initialize(reason='')
self.reason = reason
super
end
def to_s
"This plugin failed to load: #{reason.to_s}"
end
end
end

View File

@ -798,6 +798,12 @@ class Core
else
print_error("No exploit module selected.")
end
when "actions"
if (mod and mod.auxiliary?)
show_actions(mod)
else
print_error("No auxiliary module selected.")
end
end
}
end
@ -808,7 +814,7 @@ class Core
def cmd_show_tabs(str, words)
res = %w{all encoders nops exploits payloads aux plugins}
if (active_module)
res.concat(%w{ options advanced evasion targets })
res.concat(%w{ options advanced evasion targets actions })
end
return res
end
@ -1073,13 +1079,22 @@ class Core
when 'Msf::OptAddress'
case o.name
when 'RHOST'
res << option_values_last_target()
option_values_target_addrs().each do |addr|
res << addr
end
when 'LHOST'
res << Rex::Socket.source_address()
else
end
when 'Msf::OptPort'
case o.name
when 'RPORT'
option_values_target_ports().each do |port|
res << port
end
end
if (res.empty?)
res << (rand(65534)+1).to_s
end
@ -1133,13 +1148,39 @@ class Core
end
#
# Provide the last target address
# Provide the target addresses
#
def option_values_last_target
# Replace this once we start tracking these things...
return Rex::Socket.source_address()
def option_values_target_addrs
res = [ ]
res << Rex::Socket.source_address()
return res if not framework.db.active
framework.db.each_host do |host|
res << host.address
end
return res
end
#
# Provide the target ports
#
def option_values_target_ports
res = [ ]
return res if not framework.db.active
return res if not self.active_module.datastore['RHOST']
host = framework.db.has_host?(self.active_module.datastore['RHOST'])
return res if not host
framework.db.each_service do |service|
if (service.host_id == host.id)
res << service.port.to_s
end
end
return res
end
protected
#
@ -1205,7 +1246,12 @@ protected
mod_targs = Serializer::ReadableText.dump_exploit_targets(mod, ' ')
print("\nExploit targets:\n\n#{mod_targs}\n") if (mod_targs and mod_targs.length > 0)
end
def show_actions(mod) # :nodoc:
mod_actions = Serializer::ReadableText.dump_auxiliary_actions(mod, ' ')
print("\nAuxiliary actions:\n\n#{mod_actions}\n") if (mod_actions and mod_actions.length > 0)
end
def show_advanced_options(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_advanced_options(mod, ' ')
print("\nModule advanced options:\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)

View File

@ -177,7 +177,6 @@ class Driver < Msf::Ui::Driver
rcfd.write(data)
rcfd.close
rescue ::Exception => e
#
end
end

View File

@ -11,8 +11,6 @@ module Msf
class Plugin::DBSQLite3 < Msf::Plugin
###
#
# This class implements an event handler for db events
@ -22,6 +20,14 @@ class Plugin::DBSQLite3 < Msf::Plugin
def on_db_host(context, host)
puts "New host event: #{host.address}"
end
def on_db_service(context, service)
puts "New service event: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state}"
end
def on_db_vuln(context, vuln)
puts "New vuln event: host=#{vuln.host.address} port=#{vuln.service.port} proto=#{vuln.service.proto} name=#{vuln.name}"
end
end
###
@ -36,7 +42,7 @@ class Plugin::DBSQLite3 < Msf::Plugin
# The dispatcher's name.
#
def name
"DBDispatcher"
"Database Backend"
end
#
@ -44,10 +50,13 @@ class Plugin::DBSQLite3 < Msf::Plugin
#
def commands
{
"db_hosts" => "List all hosts in the database db",
"db_services" => "List all services in the database db",
"db_insert" => "Insert a new host into the db",
"db_test" => "Test",
"db_hosts" => "List all hosts in the database",
"db_services" => "List all services in the database",
"db_vulns" => "List all vulnerabilities in the database",
"db_add_host" => "Add one or more hosts to the database",
"db_add_port" => "Add a port to host",
"db_import_nessus_nbe" => "Import a Nessus scan result file (NBE)",
# "db_import_nmap_xml" => "Import a Nmap scan results file (-oX)",
}
end
@ -56,31 +65,79 @@ class Plugin::DBSQLite3 < Msf::Plugin
print_status("Host: #{host.address}")
end
end
def cmd_db_services(*args)
framework.db.each_service do |host, service|
print_status("Service: host=#{host.address} port=#{service.port} port=#{service.proto}")
framework.db.each_service do |service|
print_status("Service: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state}")
end
end
def cmd_db_insert(*args)
print_status("Inserting #{args.length.to_s} hosts...")
def cmd_db_vulns(*args)
framework.db.each_vuln do |vuln|
puts "Vuln: host=#{vuln.host.address} port=#{vuln.service.port} proto=#{vuln.service.proto} name=#{vuln.name}"
end
end
def cmd_db_add_host(*args)
print_status("Adding #{args.length.to_s} hosts...")
args.each do |address|
framework.db.get_host(nil, address)
end
end
def cmd_db_test(*args)
framework.db.get_host(nil, "1.2.3.4")
framework.db.get_host(nil, "1.2.3.5")
framework.db.get_host(nil, "1.2.3.6")
framework.db.each_host do |host|
print_status("Host: #{host.address}")
end
end
def cmd_db_add_port(*args)
if (not args or args.length < 3)
print_status("Usage: db_add_port [host] [port] [proto]")
return
end
host = framework.db.get_host(nil, args[0])
return if not host
service = framework.db.get_service(nil, host, args[2].downcase, args[1].to_i)
return if not service
print_status("Service: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state}")
end
def cmd_db_import_nessus_nbe(*args)
if (not (args and args.length == 1))
print_status("Usage: db_import_nessus [nessus.nbe]")
return
end
if (not File.readable?(args[0]))
print_status("Could not read the NBE file")
return
end
fd = File.open(args[0], 'r')
fd.each_line do |line|
r = line.split('|')
next if r[0] != 'results'
addr = r[2]
nasl = r[4]
hole = r[5]
data = r[6]
m = r[3].match(/^([^\(]+)\((\d+)\/([^\)]+)\)/)
next if not m
host = framework.db.get_host(nil, addr)
next if not host
service = framework.db.get_service(nil, host, m[3].downcase, m[2].to_i)
service.name = m[1]
service.save
vuln = framework.db.get_vuln(nil, service, "NSS-#{nasl.to_s}", data)
end
end
end
def initialize(framework, opts)
super
@ -94,8 +151,8 @@ class Plugin::DBSQLite3 < Msf::Plugin
FileUtils.copy(odb, ndb)
if (not framework.db.connect("adapter" => "sqlite3", "dbfile" => ndb))
print_status("Failed to connect to the database :(")
return
File.unlink(ndb)
raise PluginLoadError.new("Failed to connect to the database")
end
@dbh = DBEventHandler.new
@ -107,7 +164,7 @@ class Plugin::DBSQLite3 < Msf::Plugin
def cleanup
framework.events.remove_db_subscriber(@dbh)
remove_console_dispatcher('DBDispatcher')
remove_console_dispatcher('Database Backend')
end
#
@ -122,7 +179,7 @@ class Plugin::DBSQLite3 < Msf::Plugin
# more than 60 characters, but there are no hard limits.
#
def desc
"Loads a new SQLite3 db and intializes it"
"Loads a new sqlite3 database backend"
end
protected

63
plugins/db_tracker.rb Normal file
View File

@ -0,0 +1,63 @@
module Msf
###
#
# This class hooks all socket calls and updates the database with
# data gathered from the connection parameters
#
###
class Plugin::DB_Tracer < Msf::Plugin
###
#
# This class implements a socket communication tracker
#
###
class DBTracerEventHandler
include Rex::Socket::Comm::Events
def on_before_socket_create(comm, param)
end
def on_socket_created(comm, sock, param)
# Ignore local listening sockets
return if not sock.peerhost
if (sock.peerhost != '0.0.0.0' and sock.peerport)
host = param.context['Msf'].db.get_host(param.context, sock.peerhost)
return if not host
port = param.context['Msf'].db.get_service(param.context, host, param.proto, sock.peerport)
return if not port
end
end
end
def initialize(framework, opts)
super
if(not framework.db.active)
raise PluginLoadError.new("The database backend has not been initialized")
end
@eh = DBTracerEventHandler.new
Rex::Socket::Comm::Local.register_event_handler(@eh)
end
def cleanup
Rex::Socket::Comm::Local.deregister_event_handler(@eh)
end
def name
"db_tracker"
end
def desc
"Monitors socket calls and updates the database backend"
end
end
end

File diff suppressed because it is too large Load Diff