211 lines
3.8 KiB
Ruby
211 lines
3.8 KiB
Ruby
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
|
|
|