metasploit-framework/lib/msf/core/rpc/service.rb

211 lines
3.8 KiB
Ruby
Raw Normal View History

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