diff --git a/data/sql/migrate/20111203000000_inet_columns.rb b/data/sql/migrate/20111203000000_inet_columns.rb new file mode 100755 index 0000000000..cb8d140912 --- /dev/null +++ b/data/sql/migrate/20111203000000_inet_columns.rb @@ -0,0 +1,13 @@ +class InetColumns < ActiveRecord::Migration + + def self.up + change_column :hosts, :address, 'INET using address::INET' + remove_column :hosts, :address6 + end + + def self.down + change_column :hosts, :address, :text + add_column :hosts, :address6, :text + end + +end diff --git a/data/sql/migrate/20111204000000_more_inet_columns.rb b/data/sql/migrate/20111204000000_more_inet_columns.rb new file mode 100755 index 0000000000..56adf64625 --- /dev/null +++ b/data/sql/migrate/20111204000000_more_inet_columns.rb @@ -0,0 +1,17 @@ +class MoreInetColumns < ActiveRecord::Migration + + def self.up + change_column :wmap_requests, :address, 'INET using address::INET' + remove_column :wmap_requests, :address6 + change_column :wmap_targets, :address, 'INET using address::INET' + remove_column :wmap_targets, :address6 + end + + def self.down + change_column :wmap_requests, :address, :string, :limit => 16 + add_column :wmap_requests, :address6, :string, :limit => 255 + change_column :wmap_targets, :address, :string, :limit => 16 + add_column :wmap_targets, :address6, :string, :limit => 255 + end + +end diff --git a/lib/msf/core/auxiliary/jtr.rb b/lib/msf/core/auxiliary/jtr.rb index 0da4372f45..09ed9ae595 100644 --- a/lib/msf/core/auxiliary/jtr.rb +++ b/lib/msf/core/auxiliary/jtr.rb @@ -51,7 +51,7 @@ module Auxiliary::JohnTheRipper end when /x86_64-linux/ - ::FileUtils.chmod(755, "#{cpuinfo_base}/cpuinfo.ia64.bin") rescue nil + ::FileUtils.chmod(0755, "#{cpuinfo_base}/cpuinfo.ia64.bin") rescue nil data = `#{cpuinfo_base}/cpuinfo.ia64.bin` rescue nil case data when /mmx/ @@ -61,7 +61,7 @@ module Auxiliary::JohnTheRipper end when /i[\d]86-linux/ - ::FileUtils.chmod(755, "#{cpuinfo_base}/cpuinfo.ia32.bin") rescue nil + ::FileUtils.chmod(0755, "#{cpuinfo_base}/cpuinfo.ia32.bin") rescue nil data = `#{cpuinfo_base}/cpuinfo.ia32.bin` rescue nil case data when /sse2/ diff --git a/lib/msf/core/db.rb b/lib/msf/core/db.rb index 689bcdd0a5..e9c5905e9f 100644 --- a/lib/msf/core/db.rb +++ b/lib/msf/core/db.rb @@ -130,7 +130,7 @@ class DBManager ip_x = ip.to_x ip_i = ip.to_i when "String" - if ipv4_validator(ip) + if ipv46_validator(ip) ip_x = ip ip_i = Rex::Socket.addr_atoi(ip) else @@ -154,9 +154,17 @@ class DBManager return false end + def ipv46_validator(addr) + ipv4_validator(addr) or ipv6_validator(addr) + end + def ipv4_validator(addr) return false unless addr.kind_of? String - addr =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ + Rex::Socket.is_ipv4?(addr) + end + + def ipv6_validator(addr) + Rex::Socket.is_ipv6?(addr) end # Takes a space-delimited set of ips and ranges, and subjects @@ -164,7 +172,7 @@ class DBManager def validate_ips(ips) ret = true begin - ips.split(' ').each {|ip| + ips.split(/\s+/).each {|ip| unless Rex::Socket::RangeWalker.new(ip).ranges ret = false break @@ -267,7 +275,7 @@ class DBManager if not addr.kind_of? Host addr = normalize_host(addr) - unless ipv4_validator(addr) + unless ipv46_validator(addr) raise ::ArgumentError, "Invalid IP address in report_host(): #{addr}" end @@ -2215,7 +2223,7 @@ class DBManager # then it's an amap log @import_filedata[:type] = "Amap Log" return :amap_log - elsif (firstline =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) + elsif ipv46_validator(firstline) # then its an IP list @import_filedata[:type] = "IP Address List" return :ip_list @@ -2539,7 +2547,7 @@ class DBManager end next unless [addr,port,user,pass].compact.size == 4 - next unless ipv4_validator(addr) # Skip Malformed addrs + next unless ipv46_validator(addr) # Skip Malformed addrs next unless port[/^[0-9]+$/] # Skip malformed ports if bl.include? addr next @@ -4302,7 +4310,7 @@ class DBManager data = r[6] # If there's no resolution, or if it's malformed, skip it. - next unless ipv4_validator(addr) + next unless ipv46_validator(addr) if bl.include? addr next @@ -4407,7 +4415,7 @@ class DBManager hname = host.elements['HostName'].text end addr ||= host.elements['HostName'].text - next unless ipv4_validator(addr) # Skip resolved names and SCAN-ERROR. + next unless ipv46_validator(addr) # Skip resolved names and SCAN-ERROR. if bl.include? addr next else @@ -4477,7 +4485,7 @@ class DBManager hobj = nil addr = host['addr'] || host['hname'] - next unless ipv4_validator(addr) # Catches SCAN-ERROR, among others. + next unless ipv46_validator(addr) # Catches SCAN-ERROR, among others. if bl.include? addr next @@ -4791,7 +4799,7 @@ class DBManager hobj = nil addr = host['addr'] || host['hname'] - next unless ipv4_validator(addr) # Catches SCAN-ERROR, among others. + next unless ipv46_validator(addr) # Catches SCAN-ERROR, among others. if bl.include? addr next diff --git a/lib/msf/core/module.rb b/lib/msf/core/module.rb index dd025a7f0f..347cc1cc0f 100644 --- a/lib/msf/core/module.rb +++ b/lib/msf/core/module.rb @@ -601,7 +601,15 @@ class Module def debugging? (datastore['DEBUG'] || '') =~ /^(1|t|y)/i end - + + # + # Indicates whether the module supports IPv6. This is true by default, + # but certain modules require additional work to be compatible or are + # hardcoded in terms of application support and should be skipped. + # + def support_ipv6? + true + end # # This provides a standard set of search filters for every module. diff --git a/lib/msf/core/rpc/auth.rb b/lib/msf/core/rpc/auth.rb deleted file mode 100644 index 67b3e63235..0000000000 --- a/lib/msf/core/rpc/auth.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Msf -module RPC -class Auth < Base - - def login(user,pass) - - # handle authentication here - fail = true - @users.each do |u| - if(u[0] == user and u[1] == pass) - fail = false - break - end - end - - if fail - # Introduce a random delay in the response to annoy brute forcers - delay = [ ( rand(3000) / 1000.0 ), 0.50 ].max - ::IO.select(nil, nil, nil, delay) - - # Send back a 401 denied error - raise ::XMLRPC::FaultException.new(401, "authentication error") - end - - token = Rex::Text.rand_text_alphanumeric(32) - @tokens[token] = [user, Time.now.to_i, Time.now.to_i] - { "result" => "success", "token" => token } - end - - def logout(token) - @tokens.delete(token) - { "result" => "success" } - end - -end -end -end diff --git a/lib/msf/core/rpc/base.rb b/lib/msf/core/rpc/base.rb deleted file mode 100644 index 257bcd4685..0000000000 --- a/lib/msf/core/rpc/base.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Msf -module RPC -class Base - - def initialize(framework,tokens,users) - @framework = framework - @tokens = tokens - @users = users - end - -private - - def authenticate(token) - stale = [] - - # Force the encoding to ASCII-8BIT - token = token.unpack("C*").pack("C*") - - @tokens.each_key do |t| - user,ctime,mtime,perm = @tokens[t] - if ! perm and mtime + 300 < Time.now.to_i - stale << t - end - end - - stale.each { |t| @tokens.delete(t) } - - if not @tokens[token] - raise ::XMLRPC::FaultException.new(401, "authentication error") - end - - @tokens[token][2] = Time.now.to_i - end - -end -end -end - diff --git a/lib/msf/core/rpc/client.rb b/lib/msf/core/rpc/client.rb deleted file mode 100644 index 9617f3a5b1..0000000000 --- a/lib/msf/core/rpc/client.rb +++ /dev/null @@ -1,76 +0,0 @@ -require "xmlrpc/client" -require "rex" - -module Msf -module RPC - -# Loosely based on the XMLRPC::ClientS class -# Reimplemented for Metasploit - -class Client < ::XMLRPC::Client - - attr_accessor :sock, :token - - # Use a TCP socket to do RPC - def initialize(info={}) - - @buff = "" - self.sock = Rex::Socket::Tcp.create( - 'PeerHost' => info[:host], - 'PeerPort' => info[:port], - 'SSL' => info[:ssl] - ) - end - - # This override hooks into the RPCXML library - def do_rpc(request,async) - - begin - self.sock.put(request + "\x00") - - while(not @buff.index("\x00")) - if ::IO.select([self.sock], nil, nil, 30) - resp = self.sock.sysread(32768) - @buff << resp if resp - end - end - rescue ::Exception => e - self.close - raise EOFError, "XMLRPC connection closed" - end - - mesg,left = @buff.split("\x00", 2) - @buff = left.to_s - mesg - end - - def login(user,pass) - res = self.call("auth.login", user, pass) - if(not (res and res['result'] == "success")) - raise RuntimeError, "authentication failed" - end - self.token = res['token'] - true - end - - # Prepend the authentication token as the first parameter - # of every call except auth.login. Requires the - def call(meth, *args) - if(meth != "auth.login") - if(not self.token) - raise RuntimeError, "client not authenticated" - end - args.unshift(self.token) - end - super(meth, *args) - end - - def close - self.sock.close rescue nil - self.sock = nil - end - -end -end -end - diff --git a/lib/msf/core/rpc/console.rb b/lib/msf/core/rpc/console.rb deleted file mode 100644 index cbcedcf897..0000000000 --- a/lib/msf/core/rpc/console.rb +++ /dev/null @@ -1,87 +0,0 @@ -require 'pp' -require 'rex' -require 'msf/ui/web/driver' - -module Msf -module RPC -class Console < Base - - def initialize(framework,tokens,users) - super(framework, tokens, users) - @console_driver = Msf::Ui::Web::Driver.new(:framework => framework) - end - - def create(token) - authenticate(token) - cid = @console_driver.create_console - { - 'id' => cid, - 'prompt' => Rex::Text.encode_base64(@console_driver.consoles[cid].prompt || ''), - 'busy' => @console_driver.consoles[cid].busy || false, - 'encoding' => "base64" - } - end - - def list(token) - authenticate(token) - ret = [] - @console_driver.consoles.each_key do |cid| - ret << { - 'id' => cid, - 'prompt' => Rex::Text.encode_base64(@console_driver.consoles[cid].prompt || ''), - 'busy' => @console_driver.consoles[cid].busy || false, - 'encoding' => "base64" - } - end - {'consoles' => ret} - end - - def destroy(token, cid) - authenticate(token) - return { 'result' => 'failure' } if not @console_driver.consoles[cid] - res = @console_driver.destroy_console(cid) - { 'result' => res ? 'success' : 'failure' } - end - - def read(token, cid) - authenticate(token) - return { 'result' => 'failure' } if not @console_driver.consoles[cid] - { - "data" => Rex::Text.encode_base64(@console_driver.read_console(cid) || ''), - "prompt" => Rex::Text.encode_base64(@console_driver.consoles[cid].prompt || ''), - "busy" => @console_driver.consoles[cid].busy || false, - "encoding" => "base64" - } - end - - def write(token, cid, data) - authenticate(token) - return { 'result' => 'failure' } if not @console_driver.consoles[cid] - { "wrote" => @console_driver.write_console(cid, Rex::Text.decode_base64(data || '')) } - end - - def tabs(token, cid, line) - authenticate(token) - return { 'result' => 'failure' } if not @console_driver.consoles[cid] - { "tabs" => @console_driver.consoles[cid].tab_complete(line) } - end - - def session_kill(token, cid) - authenticate(token) - return { 'result' => 'failure' } if not @console_driver.consoles[cid] - @console_driver.consoles[cid].session_kill - { 'result' => 'success' } - end - - def session_detach(token, cid) - authenticate(token) - return { 'result' => 'failure' } if not @console_driver.consoles[cid] - @console_driver.consoles[cid].session_detach - { 'result' => 'success' } - end - - -end -end -end - diff --git a/lib/msf/core/rpc/core.rb b/lib/msf/core/rpc/core.rb deleted file mode 100644 index 66e4568145..0000000000 --- a/lib/msf/core/rpc/core.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Msf -module RPC -class Core < Base - - def initialize(framework, tokens, users, server=nil) - @server = server - super(framework, tokens, users) - end - - def version(token) - authenticate(token) - { "version" => ::Msf::Framework::Version, "ruby" => "#{RUBY_VERSION} #{RUBY_PLATFORM} #{RUBY_RELEASE_DATE}" } - end - - # - # Stop the RPC server. This method will never return a value to the client - # because the socket for communicating with it will be closed. - # - def stop(token) - authenticate(token) - @server.stop_rpc if @server - nil - end - -end -end -end diff --git a/lib/msf/core/rpc/db.rb b/lib/msf/core/rpc/db.rb deleted file mode 100644 index e67faa9882..0000000000 --- a/lib/msf/core/rpc/db.rb +++ /dev/null @@ -1,1352 +0,0 @@ -module Msf -module RPC -class Db < Base - -private - def db - @framework.db.active - end - - def workspace(wspace = nil) - if(wspace and wspace != "") - return @framework.db.find_workspace(wspace) - end - @framework.db.workspace - end - - def fix_options(opts) - newopts = {} - opts.each do |k,v| - newopts[k.to_sym] = v - end - newopts - end - - def opts_to_hosts(opts) - wspace = workspace(opts[:workspace]) - hosts = [] - if opts[:host] or opts[:address] - host = opts[:host] || opts[:address] - hent = wspace.hosts.find_by_address(host) - return hosts if hent == nil - hosts << hent if hent.class == Msf::DBManager::Host - hosts |= hent if hent.class == Array - elsif opts[:addresses] - return hosts if opts[:addresses].class != Array - conditions = {} - conditions[:address] = opts[:addresses] - hent = wspace.hosts.all(:conditions => conditions) - hosts |= hent if hent.class == Array - end - return hosts - end - - def opts_to_services(hosts,opts) - wspace = workspace(opts[:workspace]) - services = [] - if opts[:host] or opts[:address] or opts[:addresses] - return services if hosts.count < 1 - hosts.each do |h| - if opts[:port] or opts[:proto] - conditions = {} - conditions[:port] = opts[:port] if opts[:port] - conditions[:proto] = opts[:proto] if opts[:proto] - sret = h.services.all(:conditions => conditions) - next if sret == nil - services |= sret if sret.class == Array - services << sret if sret.class == Msf::DBManager::Service - else - services |= h.services - end - end - elsif opts[:port] or opts[:proto] - conditions = {} - conditions[:port] = opts[:port] if opts[:port] - conditions[:proto] = opts[:proto] if opts[:proto] - sret = wspace.services.all(:conditions => conditions) - services |= sret if sret.class == Array - services << sret if sret.class == Msf::DBManager::Service - end - return services - end - - def clean_nils(obj) - return '' if obj == nil - if obj.is_a? Hash - obj.each_key do |key| - obj[key] = clean_nils(obj[key]) - end - elsif obj.is_a? Array - obj.each_with_index do |ob, i| - obj[i] = clean_nils(ob) - end - end - obj - end - -public - - def hosts(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - opts = fix_options(xopts) - - conditions = {} - conditions[:state] = [Msf::HostState::Alive, Msf::HostState::Unknown] if opts[:only_up] - conditions[:address] = opts[:addresses] if opts[:addresses] - - wspace = workspace(opts[:workspace]) - - ret = {} - ret[:hosts] = [] - wspace.hosts.all(:conditions => conditions, :order => :address).each do |h| - host = {} - host[:created_at] = h.created_at.to_i - host[:address] = h.address.to_s - host[:address6] = h.address6.to_s - host[:mac] = h.mac.to_s - host[:name] = h.name.to_s - host[:state] = h.state.to_s - host[:os_name] = h.os_name.to_s - host[:os_flavor] = h.os_flavor.to_s - host[:os_sp] = h.os_sp.to_s - host[:os_lang] = h.os_lang.to_s - host[:updated_at] = h.updated_at.to_i - host[:purpose] = h.purpose.to_s - host[:info] = h.info.to_s - ret[:hosts] << host - end - ret - end - - def services(token, xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - opts[:workspace] = wspace if opts[:workspace] - hosts = [] - - if opts[:addresses] - conditions = {} - conditions[:address] = opts[:addresses] if opts[:addresses] - hosts = wspace.hosts.all(:conditions => conditions, :order => :address) - elsif opts[:host] || opts[:address] - host = @framework.db.get_host(opts) - hosts << host - end - - ret = {} - ret[:services] = [] - - a = @framework.db.get_host(opts) - - services = [] - if opts[:host] || opts[:address] || opts[:addresses] - hosts.each do |host| - sret = nil - if(opts[:proto] && opts[:port]) - sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port]) - else - sret = host.services - end - next if sret == nil - services << sret if sret.class == Msf::DBManager::Service - services |= sret if sret.class == Array - end - else - services = wspace.services - end - - return ret if (not services) - - services.each do |s| - service = {} - host = s.host - service[:host] = host.address || host.address6 || "unknown" - service[:created_at] = s[:created_at].to_i - service[:updated_at] = s[:updated_at].to_i - service[:port] = s[:port] - service[:proto] = s[:proto].to_s - service[:state] = s[:state].to_s - service[:name] = s[:name].to_s - service[:info] = s[:info].to_s - ret[:services] << service - end - ret - end - - - def vulns(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - opts[:workspace] = wspace if opts[:workspace] - - ret = {} - ret[:vulns] = [] - hosts = [] - services = [] - vulns = [] - # Get Matching Hosts - if opts[:addresses] - conditions = {} - conditions[:address] = opts[:addresses] if opts[:addresses] - hosts = wspace.hosts.all(:conditions => conditions, :order => :address) - elsif opts[:host] || opts[:address] - host = @framework.db.get_host(opts) - hosts << host - end - - #Get Matching Services - if opts[:host] || opts[:address] || opts[:addresses] - hosts.each do |host| - sret = nil - if(opts[:proto] && opts[:port]) - sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port]) - else - sret = host.services - end - next if sret == nil - services << sret if sret.class == Msf::DBManager::Service - services |= sret if sret.class == Array - end - elsif opts[:port] && opts[:proto] - sret = wspace.services.find_by_proto_and_port(opts[:proto],opts[:port]) - services << sret if sret.class == Msf::DBManager::Service - services |= sret if sret.class == Array - end - - #get list of vulns - if services.count > 0 - services.each do |s| - if opts[:name] - nret = s.vulns.find_by_name(opts[:name]) - else - nret = s.vulns - end - next if nret == nil - vulns << nret if nret.class == Msf::DBManager::Vuln - vulns |= nret if nret.class == Array - end - elsif hosts.count > 0 - hosts.each do |h| - if opts[:name] - nret = h.vulns.find_by_name(opts[:name]) - else - nret = h.vulns - end - next if nret == nil - vulns << nret if nret.class == Msf::DBManager::Vuln - vulns |= nret if nret.class == Array - end - else - nret = wspace.vulns - vulns << nret if nret.class == Msf::DBManager::Vuln - vulns |= nret if nret.class == Array - end - - vulns.each do |v| - vuln = {} - reflist = v.refs.map { |r| r.name } - if(v.service) - vuln[:port] = v.service.port - vuln[:proto] = v.service.proto - else - vuln[:port] = nil - vuln[:proto] = nil - end - vuln[:time] = v.created_at.to_i - vuln[:host] = v.host.address || v.host.address6 || nil - vuln[:name] = v.name - vuln[:refs] = reflist.join(',') - ret[:vulns] << vuln - end - clean_nils(ret) - end - - def workspaces(token) - authenticate(token) - if(not db) - raise ::XMLRPC::FaultException.new(404, "database not loaded") - end - res = {} - res[:workspaces] = [] - @framework.db.workspaces.each do |j| - ws = {} - ws[:name] = j.name - ws[:created_at] = j.created_at.to_i - ws[:updated_at] = j.updated_at.to_i - res[:workspaces] << ws - end - res - end - - def current_workspace(token) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - { "workspace" => @framework.db.workspace.name } - - end - - def get_workspace(token,wspace) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - wspace = workspace(wspace) - ret = {} - ret[:workspace] = [] - if(wspace) - w = {} - w[:name] = wspace.name - w[:created_at] = wspace.created_at.to_i - w[:modified_at] = wspace.modified_at.to_i - ret[:workspace] << w - end - ret - end - - def set_workspace(token,wspace) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - workspace = @framework.db.find_workspace(wspace) - if(workspace) - @framework.db.workspace = workspace - return { 'result' => "success" } - end - { 'result' => 'failed' } - end - - def del_workspace(token,wspace) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - # Delete workspace - workspace = @framework.db.find_workspace(wspace) - if workspace.nil? - raise ::XMLRPC::FaultException.new(404, "Workspace not found: #{wspace}") - elsif workspace.default? - workspace.destroy - workspace = @framework.db.add_workspace(workspace.name) - else - # switch to the default workspace if we're about to delete the current one - @framework.db.workspace = @framework.db.default_workspace if @framework.db.workspace.name == workspace.name - # now destroy the named workspace - workspace.destroy - end - { 'result' => "success" } - end - - def add_workspace(token,wspace) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - wspace = @framework.db.add_workspace(wspace) - return { 'result' => 'success' } if(wspace) - { 'result' => 'failed' } - end - - def get_host(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - ret = {} - ret[:host] = [] - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - h = @framework.db.get_host(opts) - if(h) - host = {} - host[:created_at] = h.created_at.to_i - host[:address] = h.address.to_s - host[:address6] = h.address6.to_s - host[:mac] = h.mac.to_s - host[:name] = h.name.to_s - host[:state] = h.state.to_s - host[:os_name] = h.os_name.to_s - host[:os_flavor] = h.os_flavor.to_s - host[:os_sp] = h.os_sp.to_s - host[:os_lang] = h.os_lang.to_s - host[:updated_at] = h.updated_at.to_i - host[:purpose] = h.purpose.to_s - host[:info] = h.info.to_s - ret[:host] << host - end - ret - end - - def report_host(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - - res = @framework.db.report_host(opts) - return { :result => 'success' } if(res) - { :result => 'failed' } - - end - - def report_service(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - res = @framework.db.report_service(opts) - return { :result => 'success' } if(res) - { :result => 'failed' } - end - - def get_service(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - opts[:workspace] = wspace if opts[:workspace] - - ret = {} - ret[:service] = [] - - host = @framework.db.get_host(opts) - - services = [] - sret = nil - - if(host && opts[:proto] && opts[:port]) - sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port]) - elsif(opts[:proto] && opts[:port]) - conditions = {} - conditions[:state] = [ServiceState::Open] if opts[:up] - conditions[:proto] = opts[:proto] if opts[:proto] - conditions[:port] = opts[:port] if opts[:port] - conditions[:name] = opts[:names] if opts[:names] - sret = wspace.services.all(:conditions => conditions, :order => "hosts.address, port") - else - sret = host.services - end - return ret if sret == nil - services << sret if sret.class == Msf::DBManager::Service - services |= sret if sret.class == Array - - - services.each do |s| - service = {} - host = s.host - service[:host] = host.address || host.address6 || "unknown" - service[:created_at] = s[:created_at].to_i - service[:updated_at] = s[:updated_at].to_i - service[:port] = s[:port] - service[:proto] = s[:proto].to_s - service[:state] = s[:state].to_s - service[:name] = s[:name].to_s - service[:info] = s[:info].to_s - ret[:service] << service - end - ret - end - - def get_note(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - - ret = {} - ret[:note] = [] - - host = @framework.db.get_host(opts) - - return ret if( not host) - notes = [] - if(opts[:proto] && opts[:port]) - services = [] - nret = host.services.find_by_proto_and_port(opts[:proto], opts[:port]) - return ret if nret == nil - services << nret if nret.class == Msf::DBManager::Service - services |= nret if nret.class == Array - - services.each do |s| - nret = nil - if opts[:ntype] - nret = s.notes.find_by_ntype(opts[:ntype]) - else - nret = s.notes - end - next if nret == nil - notes << nret if nret.class == Msf::DBManager::Note - notes |= nret if nret.class == Array - end - else - notes = host.notes - end - notes.each do |n| - note = {} - host = n.host - note[:host] = host.address || host.address6 || "unknown" - if n.service - note[:port] = n.service.port - note[:proto] = n.service.proto - end - note[:created_at] = n[:created_at].to_i - note[:updated_at] = n[:updated_at].to_i - note[:ntype] = n[:ntype].to_s - note[:data] = n[:data] - note[:critical] = n[:critical].to_s - note[:seen] = n[:seen].to_s - ret[:note] << note - end - ret - end - - def get_client(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - ret = {} - ret[:client] = [] - c = @framework.db.get_client(opts) - if(c) - client = {} - host = c.host - client[:host] = host.address - client[:created_at] = c.created_at.to_i - client[:updated_at] = c.updated_at.to_i - client[:ua_string] = c.ua_string.to_s - client[:ua_name] = c.ua_name.to_s - client[:ua_ver] = c.ua_ver.to_s - ret[:client] << client - end - ret - end - - def report_client(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - res = @framework.db.report_client(opts) - return { :result => 'success' } if(res) - { :result => 'failed' } - end - - #DOC NOTE: :data and :ntype are REQUIRED - def report_note(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - if (opts[:host] or opts[:address]) and opts[:port] and opts[:proto] - addr = opts[:host] || opts[:address] - wspace = opts[:workspace] || @framework.db.workspace - host = wspace.hosts.find_by_address(addr) - service = host.services.find_by_proto_and_port(opts[:proto],opts[:port]) if host.services.count > 0 - opts[:service] = service if service - end - - res = @framework.db.report_note(opts) - return { :result => 'success' } if(res) - { :result => 'failed' } - end - - def notes(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) if opts[:workspace] - opts[:workspace] = wspace - - ret = {} - ret[:notes] = [] - hosts = [] - services = [] - notes = [] - - # Get Matching Hosts - if opts[:addresses] - conditions = {} - conditions[:address] = opts[:addresses] if opts[:addresses] - hosts = wspace.hosts.all(:conditions => conditions, :order => :address) - elsif opts[:host] || opts[:address] - host = @framework.db.get_host(opts) - hosts << host - end - - #Get Matching Services - if opts[:host] || opts[:address] || opts[:addresses] - hosts.each do |host| - sret = nil - if(opts[:proto] && opts[:port]) - sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port]) - else - sret = host.services - end - next if sret == nil - services << sret if sret.class == Msf::DBManager::Service - services |= sret if sret.class == Array - end - elsif opts[:port] && opts[:proto] - sret = wspace.services.find_by_proto_and_port(opts[:proto],opts[:port]) - services << sret if sret.class == Msf::DBManager::Service - services |= sret if sret.class == Array - end - - #get list of notes - if services.count > 0 - services.each do |s| - if opts[:ntype] - nret = s.notes.find_by_ntype(opts[:ntype]) - else - nret = s.notes - end - next if nret == nil - notes << nret if nret.class == Msf::DBManager::Note - notes |= nret if nret.class == Array - end - elsif hosts.count > 0 - hosts.each do |h| - if opts[:ntype] - nret = h.notes.find_by_ntype(opts[:ntype]) - else - nret = h.notes - end - next if nret == nil - notes << nret if nret.class == Msf::DBManager::Note - notes |= nret if nret.class == Array - end - else - nret = wspace.notes - notes << nret if nret.class == Msf::DBManager::Note - notes |= nret if nret.class == Array - end - - notes.each do |n| - note = {} - note[:time] = n.created_at.to_i - note[:host] = "" - note[:service] = "" - note[:host] = n.host.address || n.host.address6 if(n.host) - note[:service] = n.service.name || n.service.port if(n.service) - note[:type ] = n.ntype.to_s - note[:data] = n.data.inspect - ret[:notes] << note - end - ret - end - - def report_auth_info(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - res = @framework.db.report_auth_info(opts) - return { :result => 'success' } if(res) - { :result => 'failed' } - end - - def get_auth_info(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - ret = {} - ret[:auth_info] = [] - ai = @framework.db.get_auth_info(opts) - ai.each do |i| - info = {} - i.each do |k,v| - info[k.to_sym] = v - end - ret[:auth_info] << info - end - ret - end - - def get_ref(token,name) - authenticate(token) - return @framework.db.get_ref(name) - end - - def del_vuln(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - hosts = [] - services = [] - vulns = [] - - if opts[:host] or opts[:address] or opts[:addresses] - hosts = opts_to_hosts(opts) - end - - if opts[:port] or opts[:proto] - if opts[:host] or opts[:address] or opts[:addresses] - services = opts_to_services(hosts,opts) - else - services = opts_to_services([],opts) - end - end - - if opts[:port] or opts[:proto] - services.each do |s| - vret = nil - if opts[:name] - vret = s.vulns.find_by_name(opts[:name]) - else - vret = s.vulns - end - next if vret == nil - vulns << vret if vret.class == Msf::DBManager::Vuln - vulns |= vret if vret.class == Array - end - elsif opts[:address] or opts[:host] or opts[:addresses] - hosts.each do |h| - vret = nil - if opts[:name] - vret = h.vulns.find_by_name(opts[:name]) - else - vret = h.vulns - end - next if vret == nil - vulns << vret if vret.class == Msf::DBManager::Vuln - vulns |= vret if vret.class == Array - end - else - vret = nil - if opts[:name] - vret = wspace.vulns.find_by_name(opts[:name]) - else - vret = wspace.vulns - end - vulns << vret if vret.class == Msf::DBManager::Vuln - vulns |= vret if vret.class == Array - end - - deleted = [] - vulns.each do |v| - dent = {} - dent[:address] = v.host.address.to_s if v.host - dent[:port] = v.service.port if v.service - dent[:proto] = v.service.proto if v.service - dent[:name] = v.name - deleted << dent - v.destroy - end - - return { :result => 'success', :deleted => deleted } - end - - def del_note(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - hosts = [] - services = [] - notes = [] - - if opts[:host] or opts[:address] or opts[:addresses] - hosts = opts_to_hosts(opts) - end - - if opts[:port] or opts[:proto] - if opts[:host] or opts[:address] or opts[:addresses] - services = opts_to_services(hosts,opts) - else - services = opts_to_services([],opts) - end - end - - if opts[:port] or opts[:proto] - services.each do |s| - nret = nil - if opts[:ntype] - nret = s.notes.find_by_ntype(opts[:ntype]) - else - nret = s.notes - end - next if nret == nil - notes << nret if nret.class == Msf::DBManager::Note - notes |= nret if nret.class == Array - end - elsif opts[:address] or opts[:host] or opts[:addresses] - hosts.each do |h| - nret = nil - if opts[:ntype] - nret = h.notes.find_by_ntype(opts[:ntype]) - else - nret = h.notes - end - next if nret == nil - notes << nret if nret.class == Msf::DBManager::Note - notes |= nret if nret.class == Array - end - else - nret = nil - if opts[:ntype] - nret = wspace.notes.find_by_ntype(opts[:ntype]) - else - nret = wspace.notes - end - notes << nret if nret.class == Msf::DBManager::Note - notes |= nret if nret.class == Array - end - deleted = [] - notes.each do |n| - dent = {} - dent[:address] = n.host.address.to_s if n.host - dent[:port] = n.service.port if n.service - dent[:proto] = n.service.proto if n.service - dent[:ntype] = n.ntype - deleted << dent - n.destroy - end - - return { :result => 'success', :deleted => deleted } - end - - def del_service(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - hosts = [] - services = [] - if opts[:host] or opts[:address] - host = opts[:host] || opts[:address] - hent = wspace.hosts.find_by_address(host) - return { :result => 'failed' } if hent == nil or hent.class != Msf::DBManager::Host - hosts << hent - elsif opts[:addresses] - return { :result => 'failed' } if opts[:addresses].class != Array - conditions = { :address => opts[:addresses] } - hent = wspace.hosts.all(:conditions => conditions) - return { :result => 'failed' } if hent == nil - hosts |= hent if hent.class == Array - hosts << hent if hent.class == Msf::DBManager::Host - end - if opts[:addresses] or opts[:address] or opts[:host] - hosts.each do |h| - sret = nil - if opts[:port] or opts[:proto] - conditions = {} - conditions[:port] = opts[:port] if opts[:port] - conditions[:proto] = opts[:proto] if opts[:proto] - sret = h.services.all(:conditions => conditions) - next if sret == nil - services << sret if sret.class == Msf::DBManager::Service - services |= sret if sret.class == Array - else - services |= h.services - end - end - elsif opts[:port] or opts[:proto] - conditions = {} - conditions[:port] = opts[:port] if opts[:port] - conditions[:proto] = opts[:proto] if opts[:proto] - sret = wspace.services.all(:conditions => conditions) - services << sret if sret and sret.class == Msf::DBManager::Service - services |= sret if sret and sret.class == Array - end - - - - deleted = [] - services.each do |s| - dent = {} - dent[:address] = s.host.address.to_s - dent[:port] = s.port - dent[:proto] = s.proto - deleted << dent - s.destroy - end - - return { :result => 'success', :deleted => deleted } - end - - def del_host(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - hosts = [] - if opts[:host] or opts[:address] - host = opts[:host] || opts[:address] - hent = wspace.hosts.find_by_address(host) - return { :result => 'failed' } if hent == nil or hent.class != Msf::DBManager::Host - hosts << hent - elsif opts[:addresses] - return { :result => 'failed' } if opts[:addresses].class != Array - conditions = { :address => opts[:addresses] } - hent = wspace.hosts.all(:conditions => conditions) - return { :result => 'failed' } if hent == nil - hosts |= hent if hent.class == Array - hosts << hent if hent.class == Msf::DBManager::Host - end - deleted = [] - hosts.each do |h| - deleted << h.address.to_s - h.destroy - end - - return { :result => 'success', :deleted => deleted } - end - - - def report_vuln(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - res = @framework.db.report_vuln(opts) - return { :result => 'success' } if(res) - { :result => 'failed' } - end - - - def events(token,wspace = nil) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - wspace = workspace(wspace) - raise ::XMLRPC::FaultException.new(404, "unknown workspace") if(not wspace) - ret = {} - ret[:events] = [] - - @framework.db.events(wspace).each do |e| - event = {} - event[:host] = e.host.address || e.host.address6 if(e.host) - event[:created_at] = e.created_at.to_i - event[:updated_at] = e.updated_at.to_i - event[:name] = e.name - event[:critical] = e.critical if(e.critical) - event[:username] = e.username if(e.username) - event[:info] = e.info - ret[:events] << event - end - clean_nils(ret) - end - def report_event(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - res = @framework.db.report_event(opts) - return { :result => 'success' } if(res) - end - - #NOTE Path is required - #NOTE To match a service need host, port, proto - def report_loot(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - if opts[:host] && opts[:port] && opts[:proto] - opts[:service] = @framework.db.find_or_create_service(opts) - end - - res = @framework.db.report_loot(opts) - return { :result => 'success' } if(res) - end - - def loots(token,wspace=nil) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - wspace = workspace(wspace) - raise ::XMLRPC::FaultException.new(404, "unknown workspace") if(not wspace) - ret = {} - ret[:loots] = [] - @framework.db.loots(wspace).each do |l| - loot = {} - loot[:host] = l.host.address || l.host.address6 if(l.host) - loot[:service] = l.service.name || l.service.port if(l.service) - loot[:ltype] = l.ltype - loot[:content_type] = l.content_type - loot[:data] = l.data if (l.data) - loot[:created_at] = l.created_at.to_i - loot[:updated_at] = l.updated_at.to_i - loot[:name] = l.name if (l.name) - loot[:info] = l.info if (l.info) - loot[:path] = l.path - ret[:loots] << loot - end - ret - end - - # requires host, port, user, pass, ptype, and active - def report_cred(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - res = framework.db.find_or_create_cred(opts) - return { :result => 'success' } if(res) - { :result => 'failed' } - end - - #right now workspace is the only option supported - def creds(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - ret = {} - ret[:creds] = [] - @framework.db.creds(wspace).each do |c| - cred = {} - cred[:host] = c.service.host.address || c.service.host.address6 if(c.service.host) - cred[:time] = c.updated_at - cred[:port] = c.service.port - cred[:proto] = c.service.proto - cred[:sname] = c.service.name - cred[:type] = c.ptype - cred[:user] = c.user - cred[:pass] = c.pass - cred[:active] = c.active - ret[:creds] << cred - end - ret - end - - def import_data(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_msfe_xml(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_nexpose_simplexml(args={}) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_nexpose_rawxml(args={}) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_nmap_xml(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_nessus_nbe(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_nessus_xml(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_nessus_xml_v2(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_qualys_xml(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_ip_list(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_amap_log(args={}) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def import_amap_mlog(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - opts[:data] = Rex::Text.decode_base64(opts[:data]) - @framework.db.import(opts) - return { :result => 'success' } - end - - def get_vuln(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - opts = fix_options(xopts) - opts[:workspace] = workspace(opts[:workspace]) if opts[:workspace] - - ret = {} - ret[:vuln] = [] - - host = @framework.db.get_host(opts) - - return ret if( not host) - vulns = [] - - if(opts[:proto] && opts[:port]) - services = [] - sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port]) - return ret if sret == nil - services << sret if sret.class == Msf::DBManager::Service - services |= sret if sret.class == Array - - services.each do |s| - vulns |= s.vulns - end - else - vulns = host.vulns - end - - return ret if (not vulns) - - vulns.each do |v| - vuln= {} - host= v.host - vuln[:host] = host.address || host.address6 || "unknown" - if v.service - vuln[:port] = v.service.port - vuln[:proto] = v.service.proto - end - vuln[:created_at] = v[:created_at].to_i - vuln[:updated_at] = v[:updated_at].to_i - vuln[:name] = v[:name].to_s - vuln[:info] = v[:info].to_s - vuln[:refs] = [] - v.refs.each do |r| - vuln[:refs] << r.name - end - ret[:vuln] << vuln - end - ret - end - - def clients(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - hosts = [] - clients = [] - ret = {} - ret[:clients] = [] - - if opts[:host] or opts[:address] or opts[:addresses] - hosts = opts_to_hosts(opts) - else - hosts = wspace.hosts - end - - hosts.each do |h| - cret = nil - if opts[:ua_name] or opts[:ua_ver] - conditions = {} - conditions[:ua_name] = opts[:ua_name] if opts[:ua_name] - conditions[:ua_ver] = opts[:ua_ver] if opts[:ua_ver] - cret = h.clients.all(:conditions => conditions) - else - cret = h.clients - end - next if cret == nil - clients << cret if cret.class == Msf::DBManager::Client - clients |= cret if cret.class == Array - end - clients.each do |c| - client = {} - client[:host] = c.host.address.to_s if c.host - client[:ua_string] = c.ua_string - client[:ua_name] = c.ua_name - client[:ua_ver] = c.ua_ver - client[:created_at] = c.created_at.to_i - client[:updated_at] = c.updated_at.to_i - ret[:clients] << client - end - clean_nils(ret) - end - - def del_client(token,xopts) - authenticate(token) - raise ::XMLRPC::FaultException.new(404, "database not loaded") if(not db) - - opts = fix_options(xopts) - wspace = workspace(opts[:workspace]) - hosts = [] - clients = [] - - if opts[:host] or opts[:address] or opts[:addresses] - hosts = opts_to_hosts(opts) - else - hosts = wspace.hosts - end - - hosts.each do |h| - cret = nil - if opts[:ua_name] or opts[:ua_ver] - conditions = {} - conditions[:ua_name] = opts[:ua_name] if opts[:ua_name] - conditions[:ua_ver] = opts[:ua_ver] if opts[:ua_ver] - cret = h.clients.all(:conditions => conditions) - else - cret = h.clients - end - next if cret == nil - clients << cret if cret.class == Msf::DBManager::Client - clients |= cret if cret.class == Array - end - - deleted = [] - clients.each do |c| - dent = {} - dent[:address] = c.host.address.to_s - dent[:ua_string] = c.ua_string - deleted << dent - c.destroy - end - - return { :result => 'success', :deleted => deleted } - - end - - def driver(token,xopts) - authenticate(token) - opts = fix_options(xopts) - if opts[:driver] - if @framework.db.drivers.include?(opts[:driver]) - @framework.db.driver = opts[:driver] - return { :result => 'success' } - else - return { :result => 'failed' } - - end - else - return { :driver => @framework.db.driver.to_s } - end - return { :result => 'failed' } - end - - def connect(token,xopts) - authenticate(token) - opts = fix_options(xopts) - if(not @framework.db.driver and not opts[:driver]) - return { :result => 'failed' } - end - - if opts[:driver] - if @framework.db.drivers.include?(opts[:driver]) - @framework.db.driver = opts[:driver] - else - return { :result => 'failed' } - end - end - - driver = @framework.db.driver - - case driver - when 'postgresql' - opts['adapter'] = 'postgresql' - else - return { :result => 'failed' } - end - - if (not @framework.db.connect(opts)) - return { :result => 'failed' } - end - return { :result => 'success' } - - end - - def status(token) - authenticate(token) - if (not @framework.db.driver) - return {:driver => 'None' } - end - cdb = "" - if ActiveRecord::Base.connected? and ActiveRecord::Base.connection.active? - if ActiveRecord::Base.connection.respond_to? :current_database - cdb = ActiveRecord::Base.connection.current_database - else - cdb = ActiveRecord::Base.connection.instance_variable_get(:@config)[:database] - end - return {:driver => @framework.db.driver.to_s , :db => cdb } - else - return {:driver => @framework.db.driver.to_s} - end - return {:driver => 'None' } - end - - def disconnect(token) - authenticate(token) - if (@framework.db) - @framework.db.disconnect() - return { :result => 'success' } - else - return { :result => 'failed' } - end - end - - -end -end -end diff --git a/lib/msf/core/rpc/job.rb b/lib/msf/core/rpc/job.rb deleted file mode 100644 index ce3250f809..0000000000 --- a/lib/msf/core/rpc/job.rb +++ /dev/null @@ -1,49 +0,0 @@ -module Msf -module RPC -class Job < Base - - def list(token) - authenticate(token) - res = {} - res['jobs'] = {} - @framework.jobs.each do |j| - res['jobs'][j[0]] = j[1].name - end - res - end - - def stop(token,jid) - authenticate(token) - obj = @framework.jobs[jid.to_s] - if(not obj) - raise ::XMLRPC::FaultException.new(404, "no such job") - else - obj.stop - { "result" => "success" } - end - end - def info(token,jid) - authenticate(token) - obj = @framework.jobs[jid.to_s] - if(not obj) - raise ::XMLRPC::FaultException.new(404, "no such job") - else - info = { - "jid" => obj.jid, - "name" => obj.name, - "start_time" => obj.start_time.to_i - } - if obj.ctx && obj.ctx[0] - if obj.ctx[0].respond_to?(:get_resource) - info['uripath'] = obj.ctx[0].get_resource - end - if obj.ctx[0].respond_to?(:datastore) - info['datastore'] = obj.ctx[0].datastore - end - end - { "result" => "success" , "info" => info} - end - end -end -end -end diff --git a/lib/msf/core/rpc/module.rb b/lib/msf/core/rpc/module.rb deleted file mode 100644 index 8c5fe208e5..0000000000 --- a/lib/msf/core/rpc/module.rb +++ /dev/null @@ -1,333 +0,0 @@ -## -# $Id$ -## - -module Msf -module RPC -class Module < Base - - def exploits(token) - authenticate(token) - { "modules" => @framework.exploits.keys } - end - - def auxiliary(token) - authenticate(token) - { "modules" => @framework.auxiliary.keys } - end - - def payloads(token) - authenticate(token) - { "modules" => @framework.payloads.keys } - end - - def encoders(token) - authenticate(token) - { "modules" => @framework.encoders.keys } - end - - def nops(token) - authenticate(token) - { "modules" => @framework.nops.keys } - end - - def post(token) - authenticate(token) - { "modules" => @framework.post.keys } - end - - - def info(token, mtype, mname) - authenticate(token) - - m = _find_module(mtype,mname) - res = {} - - res['name'] = m.name - res['description'] = m.description - res['license'] = m.license - res['filepath'] = m.file_path - res['version'] = m.version - res['rank'] = m.rank.to_i - - res['references'] = [] - m.references.each do |r| - res['references'] << [r.ctx_id, r.ctx_val] - end - - res['authors'] = [] - m.each_author do |a| - res['authors'] << a.to_s - end - - if(m.type == "exploit") - res['targets'] = {} - m.targets.each_index do |i| - res['targets'][i] = m.targets[i].name - end - - if (m.default_target) - res['default_target'] = m.default_target - end - end - - if(m.type == "auxiliary") - res['actions'] = {} - m.actions.each_index do |i| - res['actions'][i] = m.actions[i].name - end - - if (m.default_action) - res['default_action'] = m.default_action - end - end - - res - end - - - def compatible_payloads(token, mname) - authenticate(token) - m = _find_module('exploit',mname) - if(not m) - raise ::XMLRPC::FaultException.new(404, "unknown module") - end - - res = {} - res['payloads'] = [] - m.compatible_payloads.each do |k| - res['payloads'] << k[0] - end - - res - end - - def compatible_sessions(token, mname) - authenticate(token) - m = _find_module('post',mname) - if(not m) - raise ::XMLRPC::FaultException.new(404, "unknown module") - end - - res = {} - res['sessions'] = m.compatible_sessions - - res - end - - def target_compatible_payloads(token, mname, target) - authenticate(token) - m = _find_module('exploit',mname) - if(not m) - raise ::XMLRPC::FaultException.new(404, "unknown module") - end - - res = {} - res['payloads'] = [] - m.datastore['TARGET'] = target.to_i - m.compatible_payloads.each do |k| - res['payloads'] << k[0] - end - - res - end - - def options(token, mtype, mname) - authenticate(token) - - m = _find_module(mtype,mname) - - res = {} - - m.options.each_key do |k| - o = m.options[k] - res[k] = { - 'type' => o.type, - 'required' => o.required, - 'advanced' => o.advanced, - 'evasion' => o.evasion, - 'desc' => o.desc - } - - if(not o.default.nil?) - res[k]['default'] = o.default - end - - if(o.enums.length > 1) - res[k]['enums'] = o.enums - end - end - - res - end - - def execute(token, mtype, mname, opts) - authenticate(token) - - mod = _find_module(mtype,mname) - case mtype - when 'exploit' - _run_exploit(mod, opts) - when 'auxiliary' - _run_auxiliary(mod, opts) - when 'payload' - _run_payload(mod, opts) - when 'post' - _run_post(mod, opts) - end - - end - - def encode(token, data, encoder, options) - authenticate(token) - buf = Rex::Text.decode_base64(data) - - # Load supported formats - supported_formats = Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats - - if (fmt = options['format']) - if not supported_formats.include?(fmt) - raise ::XMLRPC::FaultException.new(500, "failed to generate: invalid format: #{fmt}") - end - end - - badchars = '' - if options['badchars'] - badchars = Rex::Text.hex_to_raw(options['badchars']) - end - - plat = nil - if options['plat'] - plat = Msf::Module::PlatformList.transform(val) - end - arch = nil - if options['arch'] - arch = options['arch'] - end - - ecount = 1 - if options['ecount'] - ecount = options['ecount'].to_i - end - - exeopts = { - :inject => options['inject'], - :template => options['altexe'], - :template_path => options['exedir'] - } - - # If we were given addshellcode for a win32 payload, - # create a double-payload; one running in one thread, one running in the other - if options['addshellcode'] - buf = Msf::Util::EXE.win32_rwx_exec_thread(buf,0,'end') - file = ::File.new(options['addshellcode']) - file.binmode - buf << file.read - file.close - end - - enc = @framework.encoders.create(encoder) - - begin - # Imports options - enc.datastore.update(options) - - raw = buf.dup - - 1.upto(ecount) do |iteration| - # Encode it up - raw = enc.encode(raw, badchars, nil, plat) - end - - output = Msf::Util::EXE.to_executable_fmt(@framework, arch, plat, raw, fmt, exeopts) - - if not output - fmt ||= "ruby" - output = Msf::Simple::Buffer.transform(raw, fmt) - end - - # How to warn? - #if exeopts[:fellback] - # $stderr.puts(OutError + "Warning: Falling back to default template: #{exeopts[:fellback]}") - #end - - {"encoded" => Rex::Text.encode_base64(output.to_s)} - rescue => e - raise ::XMLRPC::FaultException.new(500, "#{enc.refname} failed: #{e} #{e.backtrace}") - end - end - -private - - def _find_module(mtype,mname) - mod = @framework.modules.create(mname) - - if(not mod) - raise ::XMLRPC::FaultException.new(404, "unknown module") - end - - mod - end - - def _run_exploit(mod, opts) - s = Msf::Simple::Exploit.exploit_simple(mod, { - 'Payload' => opts['PAYLOAD'], - 'Target' => opts['TARGET'], - 'RunAsJob' => true, - 'Options' => opts - }) - {"result" => "success"} - end - - def _run_auxiliary(mod, opts) - Msf::Simple::Auxiliary.run_simple(mod, { - 'Action' => opts['ACTION'], - 'RunAsJob' => true, - 'Options' => opts - }) - {"result" => "success"} - end - - def _run_payload(mod, opts) - badchars = [opts['BadChars'] || ''].pack("H*") - fmt = opts['Format'] || 'raw' - force = opts['ForceEncode'] || false - template = opts['Template'] || nil - plat = opts['Platform'] || nil - keep = opts['KeepTemplateWorking'] || false - force = opts['ForceEncode'] || false - sled_size = opts['NopSledSize'].to_i || 0 - iter = opts['Iterations'].to_i || 0 - - begin - res = Msf::Simple::Payload.generate_simple(mod, { - 'BadChars' => badchars, - 'Encoder' => opts['Encoder'], - 'Format' => fmt, - 'NoComment' => true, - 'NopSledSize' => sled_size, - 'Options' => opts, - 'ForceEncode' => force, - 'Template' => template, - 'Platform' => plat, - 'KeepTemplateWorking' => keep, - 'Iterations' => iter - }) - - {"result" => "success", "payload" => res.unpack("H*")[0]} - rescue ::Exception => e - raise ::XMLRPC::FaultException.new(500, "failed to generate: #{e.message}") - end - end - - def _run_post(mod, opts) - Msf::Simple::Post.run_simple(mod, { - 'RunAsJob' => true, - 'Options' => opts - }) - {"result" => "success"} - end -end -end -end - diff --git a/lib/msf/core/rpc/plugin.rb b/lib/msf/core/rpc/plugin.rb deleted file mode 100644 index 0c09eba1ea..0000000000 --- a/lib/msf/core/rpc/plugin.rb +++ /dev/null @@ -1,63 +0,0 @@ -module Msf -module RPC -class Plugin < Base - - def load(token,path,xopts = {}) - - authenticate(token) - opts = {} - - xopts.each do |k,v| - if k.class == String - opts[k.to_sym] = v - end - end - - if (path !~ /#{File::SEPARATOR}/) - plugin_file_name = path - - # If the plugin isn't in the user direcotry (~/.msf3/plugins/), use the base - path = Msf::Config.user_plugin_directory + File::SEPARATOR + plugin_file_name - if not File.exists?( path + ".rb" ) - # If the following "path" doesn't exist it will be caught when we attempt to load - path = Msf::Config.plugin_directory + File::SEPARATOR + plugin_file_name - end - end - - begin - if (inst = @framework.plugins.load(path, opts)) - return { "result" => "success" } - end - rescue ::Exception => e - elog("Error loading plugin #{path}: #{e}\n\n#{e.backtrace.join("\n")}", src = 'core', level = 0, from = caller) - return { "result" => "failure" } - end - - end - - def unload(token,name) - authenticate(token) - @framework.plugins.each { |plugin| - # Unload the plugin if it matches the name we're searching for - if (plugin.name == name) - @framework.plugins.unload(plugin) - return { "result" => "success" } - end - } - return { "result" => "failure" } - - end - - def loaded(token) - authenticate(token) - ret = {} - ret[:plugins] = [] - @framework.plugins.each do |plugin| - ret[:plugins] << plugin.name - end - ret - end - -end -end -end diff --git a/lib/msf/core/rpc/service.rb b/lib/msf/core/rpc/service.rb deleted file mode 100644 index 7647d677cb..0000000000 --- a/lib/msf/core/rpc/service.rb +++ /dev/null @@ -1,210 +0,0 @@ -require "xmlrpc/server" -require 'rex/service_manager' -require "rex" - - -module Msf -module RPC - - -module MonkeyPatcher - def initialize(*args) - - # Enable Bigint processing (required for big file sizes,etc) - if XMLRPC::Config.const_defined?(:ENABLE_BIGINT) - XMLRPC::Config.send(:remove_const, :ENABLE_BIGINT) - XMLRPC::Config.const_set(:ENABLE_BIGINT, true) - end - - # Enable nils in requests - if XMLRPC::Config.const_defined?(:ENABLE_NIL_CREATE) - XMLRPC::Config.send(:remove_const, :ENABLE_NIL_CREATE) - XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, true) - end - - # Enable nils in replies - if XMLRPC::Config.const_defined?(:ENABLE_NIL_PARSER) - XMLRPC::Config.send(:remove_const, :ENABLE_NIL_PARSER) - XMLRPC::Config.const_set(:ENABLE_NIL_PARSER, true) - end - - super(*args) - end -end - -class Service < ::XMLRPC::BasicServer - - include MonkeyPatcher - - attr_accessor :service, :state, :on_input, :on_output, :on_error - attr_accessor :dispatcher_timeout - - def initialize(srvhost, srvport, ssl=false, cert=nil, ckey=nil) - - self.dispatcher_timeout = 0 - - self.service = Rex::Socket::TcpServer.create( - 'LocalHost' => srvhost, - 'LocalPort' => srvport, - 'SSL' => ssl - ) - - self.service.on_client_connect_proc = Proc.new { |client| - on_client_connect(client) - } - self.service.on_client_data_proc = Proc.new { |client| - begin - Timeout.timeout(self.dispatcher_timeout) do - on_client_data(client) - end - rescue ::EOFError => e - raise e - rescue ::Exception => e - wlog("XMLRPC Server Error: #{client.inspect} #{e.class} #{e} #{e.backtrace}") - raise e - end - } - self.service.on_client_close_proc = Proc.new { |client| - on_client_close(client) - } - - self.state = {} - super() - end - - def start - self.state = {} - self.service.start - end - - def stop - self.state = {} - self.service.stop - self.service.close - end - - def wait - self.service.wait - end - - def on_client_close(c) - self.state.delete(c) - end - - def on_client_connect(c) - self.state[c] = "" - self.clean_state_table - end - - def on_client_data(c) - data = c.get_once(-1) - if(not data) - c.close - return - end - - if not self.state[c] - c.close - return - end - - self.state[c] << data - procxml(c) - end - - def clean_state_table - self.state.keys.each do |s| - self.state.delete(s) if s.closed? - end - end - - def procxml(c) - while(self.state[c].index("\x00")) - mesg,left = self.state[c].split("\x00", 2) - self.state[c] = left - begin - self.on_input.call(mesg) if self.on_input - - res = process(mesg) - - self.on_output.call(res) if self.on_output - - c.put(res+"\x00") - rescue ::Interrupt - raise $! - rescue ::Exception => e - self.on_error.call(e) if self.on_error - end - end - end - -end - -class WebService < ::XMLRPC::BasicServer - - include MonkeyPatcher - - attr_accessor :service, :state, :srvhost, :srvport, :uri - - - def initialize(port, host, uri = "/RPC2") - self.srvhost = host - self.srvport = port - self.uri = uri - self.service = nil - super() - end - - def start - self.state = {} - self.service = Rex::ServiceManager.start( - Rex::Proto::Http::Server, - self.srvport, - self.srvhost, - {} - ) - - uopts = { - 'Proc' => Proc.new { |cli, req| - on_request_uri(cli, req) - }, - 'Path' => self.uri - } - - self.service.add_resource(self.uri,uopts) - end - - def stop - self.state = {} - self.service.stop - end - - def wait - self.service.wait - end - - def on_client_close(c) - self.state.delete(c) - end - - def on_client_connect(c) - self.state[c] = "" - end - def on_request_uri(cli, req) - begin - res = Rex::Proto::Http::Response.new() - res["Content-Type"] = "text/xml" - res.body = process(req.body) - rescue XMLRPC::FaultException => e - res = Rex::Proto::Http::Response.new(e.faultCode,e.faultString) - rescue - res = Rex::Proto::Http::Response.new(404,"An Error Occured") - end - cli.send_response(res) - end - -end - -end -end - diff --git a/lib/msf/core/rpc/session.rb b/lib/msf/core/rpc/session.rb deleted file mode 100644 index 7dac89222c..0000000000 --- a/lib/msf/core/rpc/session.rb +++ /dev/null @@ -1,242 +0,0 @@ -require 'rex' -require 'rex/ui/text/output/buffer' - -module Msf -module RPC -class Session < Base - - - def list(token) - authenticate(token) - res = {} - @framework.sessions.each do |sess| - i,s = sess - res[s.sid] = { - 'type' => s.type.to_s, - 'tunnel_local'=> s.tunnel_local.to_s, - 'tunnel_peer' => s.tunnel_peer.to_s, - 'via_exploit' => s.via_exploit.to_s, - 'via_payload' => s.via_payload.to_s, - 'desc' => s.desc.to_s, - 'info' => s.info.to_s, - 'workspace' => s.workspace.to_s, - 'target_host' => s.target_host.to_s, - 'username' => s.username.to_s, - 'uuid' => s.uuid.to_s, - 'exploit_uuid' => s.exploit_uuid.to_s, - 'routes' => s.routes.join(",") - } - if(s.type.to_s == "meterpreter") - res[s.sid]['platform'] = s.platform.to_s - end - end - res - end - - def stop(token, sid) - authenticate(token) - s = @framework.sessions[sid.to_i] - if(not s) - raise ::XMLRPC::FaultException.new(404, "unknown session while stopping") - end - s.kill - { "result" => "success" } - end - - # Shell read is now a positon-aware reader of the shell's associated - # ring buffer. For more direct control of the pointer into a ring - # buffer, a client can instead use ring_read, and note the returned - # sequence number on their own (making multiple views into the same - # session possible, regardless of position in the stream) - def shell_read(token, sid, ptr=nil) - _valid_session(token,sid,"shell") - # @session_sequence tracks the pointer into the ring buffer - # data of sessions (by sid) in order to emulate the old behavior - # of shell_read - @session_sequence ||= {} - @session_sequence[sid] ||= 0 - ring_buffer = ring_read(token,sid,(ptr || @session_sequence[sid])) - if not (ring_buffer["seq"].nil? || ring_buffer["seq"].empty?) - @session_sequence[sid] = ring_buffer["seq"].to_i - end - return ring_buffer - end - - # shell_write is pretty much totally identical to ring_put - def shell_write(token, sid, data) - _valid_session(token,sid,"shell") - ring_put(token,sid,data) - end - - def shell_upgrade(token, sid, lhost, lport) - s = _valid_session(token,sid,"shell") - s.exploit_datastore['LHOST'] = lhost - s.exploit_datastore['LPORT'] = lport - s.execute_script('spawn_meterpreter', nil) - { "result" => "success" } - end - - def meterpreter_read(token, sid) - s = _valid_session(token,sid,"meterpreter") - - if not s.user_output.respond_to? :dump_buffer - s.init_ui(Rex::Ui::Text::Input::Buffer.new, Rex::Ui::Text::Output::Buffer.new) - end - - data = s.user_output.dump_buffer - { "data" => Rex::Text.encode_base64(data), "encoding" => "base64" } - end - - def ring_read(token, sid, ptr=nil) - authenticate(token) - s = _valid_session(token,sid,"ring") - begin - res = s.ring.read_data(ptr) - { "seq" => res[0].to_s, "data" =>(Rex::Text.encode_base64(res[1].to_s)), "encoding" => "base64"} - rescue ::Exception => e - raise ::XMLRPC::FaultException.new(500, "session disconnected: #{e.class} #{e}") - end - end - - def ring_put(token, sid, data) - authenticate(token) - s = _valid_session(token,sid,"ring") - buff = Rex::Text.decode_base64(data) - begin - res = s.shell_write(buff) - { "write_count" => res.to_s} - rescue ::Exception => e - raise ::XMLRPC::FaultException.new(500, "session disconnected: #{e.class} #{e}") - end - end - - def ring_last(token, sid) - authenticate(token) - s = _valid_session(token,sid,"ring") - { "seq" => s.ring.last_sequence.to_s } - end - - def ring_clear(token, sid) - authenticate(token) - s = _valid_session(token,sid,"ring") - res = s.ring.clear_data - if res.compact.empty? - { "result" => "success"} - else # Doesn't seem like this can fail. Maybe a race? - { "result" => "failure"} - end - end - - # - # Run a single meterpreter console command - # - def meterpreter_write(token, sid, data) - s = _valid_session(token,sid,"meterpreter") - - if not s.user_output.respond_to? :dump_buffer - s.init_ui(Rex::Ui::Text::Input::Buffer.new, Rex::Ui::Text::Output::Buffer.new) - end - - buff = Rex::Text.decode_base64(data) - - interacting = false - s.channels.each_value do |ch| - interacting ||= ch.respond_to?('interacting') && ch.interacting - end - if interacting - s.user_input.put(buff+"\n") - else - @framework.threads.spawn("MeterpreterRunSingle", false, s) { |sess| sess.console.run_single(buff) } - end - {} - end - - def meterpreter_session_detach(token,sid) - s = _valid_session(token,sid,"meterpreter") - s.channels.each_value do |ch| - if(ch.respond_to?('interacting') && ch.interacting) - ch.detach() - return { "result" => "success" } - end - end - { "result" => "failure" } - end - - def meterpreter_session_kill(token,sid) - s = _valid_session(token,sid,"meterpreter") - s.channels.each_value do |ch| - if(ch.respond_to?('interacting') && ch.interacting) - ch._close - return { "result" => "success" } - end - end - { "result" => "failure" } - end - - def meterpreter_tabs(token,sid, line) - s = _valid_session(token,sid,"meterpreter") - { "tabs" => s.console.tab_complete(line) } - end - - # runs a meterpreter command even if interacting with a shell or other channel - def meterpreter_run_single(token, sid, data) - s = _valid_session(token,sid,"meterpreter") - - if not s.user_output.respond_to? :dump_buffer - s.init_ui(Rex::Ui::Text::Input::Buffer.new, Rex::Ui::Text::Output::Buffer.new) - end - - @framework.threads.spawn("MeterpreterRunSingle", false, s) { |sess| sess.console.run_single(data) } - {} - end - - def meterpreter_script(token, sid, data) - meterpreter_run_single(token, sid, "run #{data}") - end - - def compatible_modules(token, sid) - authenticate(token) - ret = [] - - mtype = "post" - names = @framework.post.keys.map{ |x| "post/#{x}" } - names.each do |mname| - m = _find_module(mtype, mname) - next if not m.session_compatible?(sid) - ret << m.fullname - end - ret - end - -private - - def _find_module(mtype,mname) - mod = @framework.modules.create(mname) - - if(not mod) - raise ::XMLRPC::FaultException.new(404, "unknown module") - end - - mod - end - - def _valid_session(token,sid,type) - authenticate(token) - s = @framework.sessions[sid.to_i] - if(not s) - raise ::XMLRPC::FaultException.new(404, "unknown session while validating") - end - if type == "ring" - if not s.respond_to?(:ring) - raise ::XMLRPC::FaultException.new(403, "session #{s.type} does not support ring operations") - end - elsif(s.type != type) - raise ::XMLRPC::FaultException.new(403, "session is not "+type) - end - s - end - -end -end -end - diff --git a/lib/msf/core/rpc/v10/rpc_db.rb b/lib/msf/core/rpc/v10/rpc_db.rb index 9da4932529..828c2c2e45 100644 --- a/lib/msf/core/rpc/v10/rpc_db.rb +++ b/lib/msf/core/rpc/v10/rpc_db.rb @@ -100,7 +100,6 @@ public host = {} host[:created_at] = h.created_at.to_i host[:address] = h.address.to_s - host[:address6] = h.address6.to_s host[:mac] = h.mac.to_s host[:name] = h.name.to_s host[:state] = h.state.to_s @@ -135,7 +134,7 @@ public :limit => limit, :offset => offset).each do |s| service = {} host = s.host - service[:host] = host.address || host.address6 || "unknown" + service[:host] = host.address || "unknown" service[:created_at] = s[:created_at].to_i service[:updated_at] = s[:updated_at].to_i service[:port] = s[:port] @@ -172,7 +171,7 @@ public vuln[:proto] = nil end vuln[:time] = v.created_at.to_i - vuln[:host] = v.host.address || v.host.address6 || nil + vuln[:host] = v.host.address || nil vuln[:name] = v.name vuln[:refs] = reflist.join(',') ret[:vulns] << vuln @@ -261,7 +260,6 @@ public host = {} host[:created_at] = h.created_at.to_i host[:address] = h.address.to_s - host[:address6] = h.address6.to_s host[:mac] = h.mac.to_s host[:name] = h.name.to_s host[:state] = h.state.to_s @@ -324,7 +322,7 @@ public services.each do |s| service = {} host = s.host - service[:host] = host.address || host.address6 || "unknown" + service[:host] = host.address || "unknown" service[:created_at] = s[:created_at].to_i service[:updated_at] = s[:updated_at].to_i service[:port] = s[:port] @@ -371,7 +369,7 @@ public notes.each do |n| note = {} host = n.host - note[:host] = host.address || host.address6 || "unknown" + note[:host] = host.address || "unknown" if n.service note[:port] = n.service.port note[:proto] = n.service.proto @@ -449,7 +447,7 @@ public note[:time] = n.created_at.to_i note[:host] = "" note[:service] = "" - note[:host] = n.host.address || n.host.address6 if(n.host) + note[:host] = n.host.address if(n.host) note[:service] = n.service.name || n.service.port if(n.service) note[:type ] = n.ntype.to_s note[:data] = n.data.inspect @@ -718,7 +716,7 @@ public wspace.events.all(:limit => limit, :offset => offset).each do |e| event = {} - event[:host] = e.host.address || e.host.address6 if(e.host) + event[:host] = e.host.address if(e.host) event[:created_at] = e.created_at.to_i event[:updated_at] = e.updated_at.to_i event[:name] = e.name @@ -757,7 +755,7 @@ public ret[:loots] = [] wspace.loots.all(:limit => limit, :offset => offset).each do |l| loot = {} - loot[:host] = l.host.address || l.host.address6 if(l.host) + loot[:host] = l.host.address if(l.host) loot[:service] = l.service.name || n.service.port if(n.service) loot[:ltype] = l.ltype loot[:ctype] = l.ctype @@ -790,7 +788,7 @@ public DBManager::Cred.find(:all, :include => {:service => :host}, :conditions => ["hosts.workspace_id = ?", framework.db.workspace.id ], :limit => limit, :offset => offset).each do |c| cred = {} - cred[:host] = c.service.host.address || c.service.host.address6 if(c.service.host) + cred[:host] = c.service.host.address if(c.service.host) cred[:updated_at] = c.updated_at.to_i cred[:port] = c.service.port cred[:proto] = c.service.proto @@ -840,7 +838,7 @@ public vulns.each do |v| vuln= {} host= v.host - vuln[:host] = host.address || host.address6 || "unknown" + vuln[:host] = host.address || "unknown" if v.service vuln[:port] = v.service.port vuln[:proto] = v.service.proto diff --git a/lib/rex/socket.rb b/lib/rex/socket.rb index 1ed7ee2ff0..89e7651d3c 100644 --- a/lib/rex/socket.rb +++ b/lib/rex/socket.rb @@ -169,7 +169,7 @@ module Socket # def self.getaddress(addr, accept_ipv6 = true) begin - if dotted_ip?(addr) + if addr =~ MATCH_IPV4 or (accept_ipv6 and addr =~ MATCH_IPV6) return addr end @@ -205,12 +205,12 @@ module Socket # def self.getaddresses(addr, accept_ipv6 = true) begin - if dotted_ip?(addr) - return addr + if addr =~ MATCH_IPV4 or (accept_ipv6 and addr =~ MATCH_IPV6) + return [addr] end res = ::Socket.gethostbyname(addr) - return nil if not res + return [] if not res # Shift the first three elements out rname = res.shift @@ -223,12 +223,12 @@ module Socket end # Make sure we have at least one name - return nil if res.length == 0 + return [] if res.length == 0 # Return an array of all addresses res.map{ |addr| self.addr_ntoa(addr) } rescue ::ArgumentError # Win32 bug - nil + [] end end @@ -357,10 +357,10 @@ module Socket # IPv4 if (addr < 0x100000000 and not v6) - nboa.unpack('C4').join('.') + addr_ntoa(nboa) # IPv6 else - nboa.unpack('n8').map{ |c| "%.4x" % c }.join(":") + addr_ntoa(nboa) end end @@ -383,11 +383,32 @@ module Socket # IPv6 if (addr.length == 16) - return addr.unpack('n8').map{ |c| "%.4x" % c }.join(":") + return compress_address(addr.unpack('n8').map{ |c| "%x" % c }.join(":")) end raise RuntimeError, "Invalid address format" end + + # + # Implement zero compression for IPv6 addresses. + # Uses the compression method from Marco Ceresa's IPAddress GEM + # https://github.com/bluemonk/ipaddress/blob/master/lib/ipaddress/ipv6.rb + # + def self.compress_address(addr) + return addr unless is_ipv6?(addr) + addr = addr.dup + while true + break if addr.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::') + break if addr.sub!(/\b0:0:0:0:0:0:0\b/, ':') + break if addr.sub!(/\b0:0:0:0:0:0\b/, ':') + break if addr.sub!(/\b0:0:0:0:0\b/, ':') + break if addr.sub!(/\b0:0:0:0\b/, ':') + break if addr.sub!(/\b0:0:0\b/, ':') + break if addr.sub!(/\b0:0\b/, ':') + break + end + addr.sub(/:{3,}/, '::') + end # # Converts a network byte order address to an integer @@ -655,6 +676,7 @@ module Socket return [lsock, rsock] end + ## # diff --git a/lib/rex/socket/range_walker.rb b/lib/rex/socket/range_walker.rb index 2ddfdc0bb6..4685c4c55f 100644 --- a/lib/rex/socket/range_walker.rb +++ b/lib/rex/socket/range_walker.rb @@ -73,16 +73,19 @@ class RangeWalker else return false end + elsif arg.include?(":") - # Then it's IPv6 - # Can't really do much with IPv6 right now, just return it and - # hope for the best + # 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] + 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] } + 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})$/ # Then it's in the format of 1.2.3.4-5.6.7.8 # Note, this will /not/ deal with DNS names, or the fancy/obscure 10...1-10...2 diff --git a/modules/auxiliary/fuzzers/ftp/client_ftp.rb b/modules/auxiliary/fuzzers/ftp/client_ftp.rb index d9363423ff..39a3813c33 100644 --- a/modules/auxiliary/fuzzers/ftp/client_ftp.rb +++ b/modules/auxiliary/fuzzers/ftp/client_ftp.rb @@ -48,6 +48,13 @@ class Metasploit3 < Msf::Auxiliary OptBool.new('EXTRALINE', [ true, "Add extra CRLF's in response to LIST",true]) ], self.class) end + + + # Not compatible today + def support_ipv6? + false + end + #--------------------------------------------------------------------------------- def setup diff --git a/modules/auxiliary/scanner/http/httpbl_lookup.rb b/modules/auxiliary/scanner/http/httpbl_lookup.rb index 8474549d1a..430df3574b 100644 --- a/modules/auxiliary/scanner/http/httpbl_lookup.rb +++ b/modules/auxiliary/scanner/http/httpbl_lookup.rb @@ -40,7 +40,11 @@ class Metasploit3 < Msf::Auxiliary ], self.class) end - + # Not compatible today + def support_ipv6? + false + end + def resolve(ip) results = '' apikey = datastore['apikey'] diff --git a/modules/auxiliary/scanner/portscan/ack.rb b/modules/auxiliary/scanner/portscan/ack.rb index 52b1713d5b..f83b558d77 100644 --- a/modules/auxiliary/scanner/portscan/ack.rb +++ b/modules/auxiliary/scanner/portscan/ack.rb @@ -40,6 +40,11 @@ class Metasploit3 < Msf::Auxiliary deregister_options('FILTER','PCAPFILE') end + # No IPv6 support yet + def support_ipv6? + false + end + def run_batch_size datastore['BATCHSIZE'] || 256 end diff --git a/modules/auxiliary/scanner/portscan/ftpbounce.rb b/modules/auxiliary/scanner/portscan/ftpbounce.rb index 874d45bcbf..87f22d932f 100644 --- a/modules/auxiliary/scanner/portscan/ftpbounce.rb +++ b/modules/auxiliary/scanner/portscan/ftpbounce.rb @@ -41,6 +41,11 @@ class Metasploit3 < Msf::Auxiliary deregister_options('RHOST', 'RPORT') end + # No IPv6 support yet + def support_ipv6? + false + end + def run_host(ip) ports = Rex::Socket.portspec_crack(datastore['PORTS']) diff --git a/modules/auxiliary/scanner/portscan/syn.rb b/modules/auxiliary/scanner/portscan/syn.rb index 4400020163..42985dfd03 100644 --- a/modules/auxiliary/scanner/portscan/syn.rb +++ b/modules/auxiliary/scanner/portscan/syn.rb @@ -37,6 +37,11 @@ class Metasploit3 < Msf::Auxiliary deregister_options('FILTER','PCAPFILE') end + + # No IPv6 support yet + def support_ipv6? + false + end def run_batch_size datastore['BATCHSIZE'] || 256 diff --git a/modules/auxiliary/scanner/portscan/xmas.rb b/modules/auxiliary/scanner/portscan/xmas.rb index 1277bc1dc7..6aa4cb8650 100644 --- a/modules/auxiliary/scanner/portscan/xmas.rb +++ b/modules/auxiliary/scanner/portscan/xmas.rb @@ -40,6 +40,11 @@ class Metasploit3 < Msf::Auxiliary deregister_options('FILTER','PCAPFILE') end + # No IPv6 support yet + def support_ipv6? + false + end + def run_batch_size datastore['BATCHSIZE'] || 256 end diff --git a/modules/auxiliary/server/capture/http.rb b/modules/auxiliary/server/capture/http.rb index 3d3608df29..28df3f9e88 100644 --- a/modules/auxiliary/server/capture/http.rb +++ b/modules/auxiliary/server/capture/http.rb @@ -61,6 +61,11 @@ class Metasploit3 < Msf::Auxiliary ], self.class) end + # Not compatible today + def support_ipv6? + false + end + def run @formsdir = datastore['FORMSDIR'] @template = datastore['TEMPLATE'] diff --git a/msfrpc b/msfrpc index 40f5188ca0..b928975bf1 100755 --- a/msfrpc +++ b/msfrpc @@ -37,7 +37,7 @@ opts = { 'User' => 'msf', 'SSL' => true, 'ServerPort' => 55553, - 'Type' => 'Xml' + 'Type' => 'Msg' } # Parse command line arguments. @@ -53,8 +53,6 @@ arguments.parse(ARGV) { |opt, idx, val| opts['User'] = val when '-P' opts['Pass'] = val - when '-t' - opts['Type'] = (val =~ /xml/i) ? 'XML' : 'Msg' when "-h" print("\nUsage: #{File.basename(__FILE__)} \n" + arguments.usage) exit @@ -76,11 +74,7 @@ end $0 = "msfrpc" -if opts['Type'] == 'Msg' - require 'msf/core/rpc/v10/client' -else - require 'msf/core/rpc/client' -end +require 'msf/core/rpc/v10/client' require 'rex/ui' rpc = Msf::RPC::Client.new( diff --git a/msfrpcd b/msfrpcd index 714e086873..9207b77c7a 100755 --- a/msfrpcd +++ b/msfrpcd @@ -28,7 +28,6 @@ arguments = Rex::Parser::Arguments.new( "-p" => [ true, "Bind to this port instead of 55553" ], "-U" => [ true, "Specify the username to access msfrpcd" ], "-P" => [ true, "Specify the password to access msfrpcd" ], - "-t" => [ true, "Server type, [Basic|Web|Msg]" ], "-u" => [ true, "URI for Web server" ], "-S" => [ false, "Disable SSL on the RPC socket" ], "-f" => [ false, "Run the daemon in the foreground" ], @@ -40,7 +39,7 @@ opts = { 'SSL' => true, 'ServerHost' => '0.0.0.0', 'ServerPort' => 55553, - 'ServerType' => 'Basic' + 'ServerType' => 'Msg' } foreground = false @@ -62,8 +61,6 @@ arguments.parse(ARGV) { |opt, idx, val| opts['Pass'] = val when "-f" foreground = true - when "-t" - opts['ServerType'] = val when "-u" opts['URI'] = val when "-n" @@ -81,8 +78,7 @@ end $0 = "msfrpcd" -rpctype = 'XML' -rpctype = 'MSG' if opts['ServerType'].downcase == 'msg' +rpctype = 'MSG' $stderr.puts "[*] #{rpctype}RPC starting on #{opts['ServerHost']}:#{opts['ServerPort']} (#{opts['SSL'] ? "SSL" : "NO SSL"}):#{opts['ServerType']}..." diff --git a/plugins/xmlrpc.rb b/plugins/xmlrpc.rb deleted file mode 100644 index 52518cb899..0000000000 --- a/plugins/xmlrpc.rb +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env ruby -# -# $Id$ -# -# This plugin provides an msf daemon interface that spawns a listener on a -# defined port (default 55553) and gives each connecting client its own -# console interface. These consoles all share the same framework instance. -# Be aware that the console instance that spawns on the port is entirely -# unauthenticated, so realize that you have been warned. -# -# $Revision$ -# - -require "msf/core/rpc" -require "fileutils" - -module Msf - -### -# -# This class implements the msfd plugin interface. -# -### -class Plugin::XMLRPC < Msf::Plugin - - # - # The default local hostname that the server listens on. - # - DefaultHost = "127.0.0.1" - - # - # The default local port that the server listens on. - # - DefaultPort = 55553 - - # - # ServerPort - # - # The local port to listen on for connections. The default is 55553 - # - def initialize(framework, opts) - super - - host = opts['ServerHost'] || DefaultHost - port = opts['ServerPort'] || DefaultPort - ssl = (opts['SSL'] and opts['SSL'].to_s =~ /^[ty]/i) ? true : false - cert = opts['SSLCert'] - ckey = opts['SSLKey'] - - user = opts['User'] || "msf" - pass = opts['Pass'] || ::Rex::Text.rand_text_alphanumeric(8) - type = opts['ServerType'] || "Basic" - uri = opts['URI'] || "/RPC2" - - print_status("XMLRPC Service: #{host}:#{port} #{ssl ? " (SSL)" : ""}") - print_status("XMLRPC Username: #{user}") - print_status("XMLRPC Password: #{pass}") - print_status("XMLRPC Server Type: #{type}") - - @users = [ [user,pass] ] - if(type =~ /Web/i) - print_status("XMLRPC Web URI: #{uri}") - self.server = ::Msf::RPC::WebService.new(port,host,uri) - elsif(type =~ /Basic/i) - self.server = ::Msf::RPC::Service.new(host,port,ssl,cert,ckey) - else - print_status("Invalid server type #{type}, please choose Web or Basic") - end - - # If the run in foreground flag is not specified, then go ahead and fire - # it off in a worker thread. - if (opts['RunInForeground'] != true) - # Store a handle to the thread so we can kill it during - # cleanup when we get unloaded. - self.thread = Thread.new { - run - } - end - end - - # - # Returns 'xmlrpc' - # - def name - "xmlrpc" - end - - # - # Returns the plugin description. - # - def desc - "Provides a XMLRPC interface over a listening TCP port." - end - - # - # The meat of the plugin, sets up handlers for requests - # - def run - - # Initialize the list of authenticated sessions - @tokens = {} - - args = [framework,@tokens,@users] - - # Add handlers for every class - self.server.add_handler(::XMLRPC::iPIMethods("auth"), - ::Msf::RPC::Auth.new(*args) - ) - - # Note the extra argument for core as compared to the other - # handlers. This allows rpc clients access to the plugin so - # they can shutdown the server. - core_args = args + [self] - self.server.add_handler(::XMLRPC::iPIMethods("core"), - ::Msf::RPC::Core.new(*core_args) - ) - - self.server.add_handler(::XMLRPC::iPIMethods("session"), - ::Msf::RPC::Session.new(*args) - ) - - self.server.add_handler(::XMLRPC::iPIMethods("job"), - ::Msf::RPC::Job.new(*args) - ) - - self.server.add_handler(::XMLRPC::iPIMethods("module"), - ::Msf::RPC::Module.new(*args) - ) - - self.server.add_handler(::XMLRPC::iPIMethods("console"), - ::Msf::RPC::Console.new(*args) - ) - - self.server.add_handler(::XMLRPC::iPIMethods("db"), - ::Msf::RPC::Db.new(*args) - ) - - self.server.add_handler(::XMLRPC::iPIMethods("plugin"), - ::Msf::RPC::Plugin.new(*args) - ) - - # Set the default/catch-all handler - self.server.set_default_handler do |name, *args| - raise ::XMLRPC::FaultException.new(-99, "Method #{name} missing or wrong number of parameters!") - end - - # Start the actual service - self.server.start - - # Wait for the service to complete - self.server.wait - end - - # - # Closes the listener service. - # - def cleanup - self.server.stop if self.server - self.thread.kill if self.thread - self.server = nil - super - end - - def stop_rpc - print_line - print_status("XMLRPC Client requested server stop") - # Plugins aren't really meant to be able to unload themselves, so this - # is a bit of a corner case. Unloading ourselves ends up killing the - # thread that's doing the unloading so we need to fire off the unload - # in a seperate one. - Thread.new { - framework.plugins.unload(self) - } - nil - end - - # - # The XMLRPC instance. - # - attr_accessor :server - attr_accessor :thread - attr_accessor :users - attr_accessor :tokens - -end - -end -