Merge pull request #28 from bcook-r7/land-5287-rpc-fixes

More #5287 RPC API fixes
bug/bundler_fix
sinn3r 2015-05-04 14:46:37 -05:00
commit 0b4260ab89
3 changed files with 84 additions and 117 deletions

View File

@ -12,7 +12,7 @@ private
end
def find_workspace(wspace = nil)
if(wspace and wspace != "")
if wspace and wspace != ""
return self.framework.db.find_workspace(wspace) || error(500, "Invalid workspace")
end
self.framework.db.workspace
@ -104,6 +104,39 @@ private
return opts, opts[:workspace]
end
def get_notes(xopts)
::ActiveRecord::Base.connection_pool.with_connection {
opts, wspace = init_db_opts_workspace(xopts)
notes = []
host = self.framework.db.get_host(opts)
return notes if not host
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 == ::Mdm::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 == ::Mdm::Note
notes |= nret if nret.class == Array
end
else
notes = host.notes
end
notes
}
end
public
@ -416,7 +449,7 @@ public
wspace.vulns.includes(:service).where(conditions).offset(offset).limit(limit).each do |v|
vuln = {}
reflist = v.refs.map { |r| r.name }
if(v.service)
if v.service
vuln[:port] = v.service.port
vuln[:proto] = v.service.proto
else
@ -495,7 +528,7 @@ public
wspace = find_workspace(wspace)
ret = {}
ret[:workspace] = []
if(wspace)
if wspace
w = {}
w[:name] = wspace.name
w[:id] = wspace.id
@ -524,7 +557,7 @@ public
::ActiveRecord::Base.connection_pool.with_connection {
db_check
workspace = find_workspace(wspace)
if(workspace)
if workspace
self.framework.db.workspace = workspace
return { 'result' => "success" }
end
@ -580,7 +613,7 @@ public
::ActiveRecord::Base.connection_pool.with_connection {
db_check
wspace = self.framework.db.add_workspace(wspace)
return { 'result' => 'success' } if(wspace)
return { 'result' => 'success' } if wspace
{ 'result' => 'failed' }
}
end
@ -620,7 +653,7 @@ public
ret[:host] = []
opts = fix_options(xopts)
h = self.framework.db.get_host(opts)
if(h)
if h
host = {}
host[:created_at] = h.created_at.to_i
host[:address] = h.address.to_s
@ -669,7 +702,7 @@ public
opts, wspace = init_db_opts_workspace(xopts)
res = self.framework.db.report_host(opts)
return { :result => 'success' } if(res)
return { :result => 'success' } if res
{ :result => 'failed' }
}
end
@ -695,7 +728,7 @@ public
::ActiveRecord::Base.connection_pool.with_connection {
opts, wspace = init_db_opts_workspace(xopts)
res = self.framework.db.report_service(opts)
return { :result => 'success' } if(res)
return { :result => 'success' } if res
{ :result => 'failed' }
}
end
@ -735,9 +768,9 @@ public
services = []
sret = nil
if(host && opts[:proto] && opts[:port])
if host && opts[:proto] && opts[:port]
sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
elsif(opts[:proto] && opts[:port])
elsif opts[:proto] && opts[:port]
conditions = {}
conditions[:state] = [Msf::ServiceState::Open] if opts[:up]
conditions[:proto] = opts[:proto] if opts[:proto]
@ -769,10 +802,12 @@ public
}
end
# Returns a note.
#
# @param [Hash] xopts Options.
# @option xopts [String] :addr Host address.
# @option xopts [String] :address Same as :addr.
# @option xopts [String] :host Same as :address.
# @option xopts [String] :proto Protocol.
# @option xopts [Fixnum] :port Port.
# @option xopts [String] :ntype Note type.
@ -794,37 +829,11 @@ public
# @example Here's how you would use this from the client:
# rpc.call('db.get_note', {:proto => 'tcp', :port => 80})
def rpc_get_note(xopts)
::ActiveRecord::Base.connection_pool.with_connection {
opts, wspace = init_db_opts_workspace(xopts)
ret = {}
ret[:note] = []
host = self.framework.db.get_host(opts)
notes = get_notes(xopts)
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 == ::Mdm::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 == ::Mdm::Note
notes |= nret if nret.class == Array
end
else
notes = host.notes
end
notes.each do |n|
note = {}
host = n.host
@ -842,7 +851,6 @@ public
ret[:note] << note
end
ret
}
end
@ -872,7 +880,7 @@ public
ret = {}
ret[:client] = []
c = self.framework.db.get_client(opts)
if(c)
if c
client = {}
host = c.host
client[:host] = host.address
@ -909,7 +917,7 @@ public
::ActiveRecord::Base.connection_pool.with_connection {
opts, wspace = init_db_opts_workspace(xopts)
res = self.framework.db.report_client(opts)
return { :result => 'success' } if(res)
return { :result => 'success' } if res
{ :result => 'failed' }
}
end
@ -944,12 +952,16 @@ public
addr = opts[:host] || opts[:address]
wspace = opts[:workspace] || self.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
if host && host.services.count > 0
service = host.services.find_by_proto_and_port(opts[:proto],opts[:port])
if service
opts[:service] = service
end
end
end
res = self.framework.db.report_note(opts)
return { :result => 'success' } if(res)
return { :result => 'success' } if res
{ :result => 'failed' }
}
end
@ -997,8 +1009,8 @@ public
note[:time] = n.created_at.to_i
note[:host] = ""
note[:service] = ""
note[:host] = n.host.address if(n.host)
note[:service] = n.service.name || n.service.port if(n.service)
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
ret[:notes] << note
@ -1058,14 +1070,14 @@ public
vulns = []
if opts[:host] or opts[:address] or opts[:addresses]
hosts = opts_to_hosts(opts)
hosts = opts_to_hosts(xopts)
end
if opts[:port] or opts[:proto]
if opts[:host] or opts[:address] or opts[:addresses]
services = opts_to_services(hosts,opts)
services = opts_to_services(hosts,xopts)
else
services = opts_to_services([],opts)
services = opts_to_services([],xopts)
end
end
@ -1144,58 +1156,8 @@ public
# @example Here's how you would use this from the client:
# rpc.call('db.del_note', {:workspace=>'default', :host=>ip, :port=>443, :proto=>'tcp'})
def rpc_del_note(xopts)
::ActiveRecord::Base.connection_pool.with_connection {
opts, wspace = init_db_opts_workspace(xopts)
hosts = []
services = []
notes = []
notes = get_notes(xopts)
if opts[:host] or opts[:address] or opts[:addresses]
hosts = opts_to_hosts(xopts)
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 == ::Mdm::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 == ::Mdm::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 == ::Mdm::Note
notes |= nret if nret.class == Array
end
deleted = []
notes.each do |n|
dent = {}
@ -1208,7 +1170,6 @@ public
end
return { :result => 'success', :deleted => deleted }
}
end
@ -1360,7 +1321,7 @@ public
opts = fix_options(xopts)
opts[:workspace] = find_workspace(opts[:workspace]) if opts[:workspace]
res = self.framework.db.report_vuln(opts)
return { :result => 'success' } if(res)
return { :result => 'success' } if res
{ :result => 'failed' }
}
end
@ -1398,12 +1359,12 @@ public
wspace.events.offset(offset).limit(limit).each do |e|
event = {}
event[:host] = e.host.address 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
event[:critical] = e.critical if(e.critical)
event[:username] = e.username if(e.username)
event[:critical] = e.critical if e.critical
event[:username] = e.username if e.username
event[:info] = e.info
ret[:events] << event
end
@ -1430,7 +1391,7 @@ public
::ActiveRecord::Base.connection_pool.with_connection {
opts, wspace = init_db_opts_workspace(xopts)
res = self.framework.db.report_event(opts)
{ :result => 'success' } if(res)
{ :result => 'success' } if res
}
end
@ -1465,7 +1426,7 @@ public
end
res = self.framework.db.report_loot(opts)
{ :result => 'success' } if(res)
{ :result => 'success' } if res
}
end
@ -1503,8 +1464,8 @@ public
ret[:loots] = []
wspace.loots.offset(offset).limit(limit).each do |l|
loot = {}
loot[:host] = l.host.address if(l.host)
loot[:service] = l.service.name || l.service.port if(l.service)
loot[:host] = l.host.address if l.host
loot[:service] = l.service.name || l.service.port if l.service
loot[:ltype] = l.ltype
loot[:ctype] = l.content_type
loot[:data] = l.data
@ -1605,10 +1566,10 @@ public
host = self.framework.db.get_host(opts)
return ret if( not host)
return ret if not host
vulns = []
if(opts[:proto] && opts[:port])
if opts[:proto] && opts[:port]
services = []
sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
return ret if sret == nil
@ -1725,7 +1686,7 @@ public
clients = []
if opts[:host] or opts[:address] or opts[:addresses]
hosts = opts_to_hosts(opts)
hosts = opts_to_hosts(xopts)
else
hosts = wspace.hosts
end
@ -1800,7 +1761,7 @@ public
# rpc.call('db.connect', {:driver=>'postgresql'})
def rpc_connect(xopts)
opts = fix_options(xopts)
if(not self.framework.db.driver and not opts[:driver])
if not self.framework.db.driver and not opts[:driver]
return { :result => 'failed' }
end

10
msfrpcd
View File

@ -30,9 +30,10 @@ arguments = Rex::Parser::Arguments.new(
"-U" => [ true, "Specify the username to access msfrpcd" ],
"-P" => [ true, "Specify the password to access msfrpcd" ],
"-u" => [ true, "URI for Web server" ],
"-S" => [ false, "Disable SSL on the RPC socket" ],
"-t" => [ true, "Token Timeout (default 300 seconds" ],
"-S" => [ false, "Disable SSL on the RPC socket" ],
"-f" => [ false, "Run the daemon in the foreground" ],
"-n" => [ false, "Disable database" ],
"-n" => [ false, "Disable database" ],
"-h" => [ false, "Help banner" ])
opts = {
@ -40,7 +41,8 @@ opts = {
'SSL' => true,
'ServerHost' => '0.0.0.0',
'ServerPort' => 55553,
'ServerType' => 'Msg'
'ServerType' => 'Msg',
'TokenTimeout' => 300,
}
foreground = false
@ -60,6 +62,8 @@ arguments.parse(ARGV) { |opt, idx, val|
opts['User'] = val
when '-P'
opts['Pass'] = val
when "-t"
opts['TokenTimeout'] = val.to_i
when "-f"
foreground = true
when "-u"

View File

@ -45,6 +45,7 @@ class Plugin::MSGRPC < Msf::Plugin
user = opts['User'] || "msf"
pass = opts['Pass'] || ::Rex::Text.rand_text_alphanumeric(8)
uri = opts['URI'] || "/api"
timeout = opts['TokenTimeout'] || 300
print_status("MSGRPC Service: #{host}:#{port} #{ssl ? " (SSL)" : ""}")
print_status("MSGRPC Username: #{user}")
@ -56,7 +57,8 @@ class Plugin::MSGRPC < Msf::Plugin
:ssl => ssl,
:cert => cert,
:uri => uri,
:tokens => { }
:tokens => { },
:token_timeout => timeout
})
self.server.add_user(user, pass)