Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

msfrpcd 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #!/usr/bin/env ruby
  2. # -*- coding: binary -*-
  3. #
  4. # $Id$
  5. #
  6. # This user interface listens on a port and provides clients that connect to
  7. # it with an RPC or JSON-RPC interface to the Metasploit Framework.
  8. #
  9. # $Revision$
  10. #
  11. RPC_TYPE = 'Msg'
  12. WS_TAG = 'msf-ws'
  13. WS_RPC_TAG = 'msf-json-rpc'
  14. WS_CONF = "#{WS_RPC_TAG}.ru"
  15. WS_ENV = 'production'
  16. def start_json_rpc_service(conf:, address:, port:, ssl:, ssl_key:, ssl_cert:,
  17. ssl_disable_verify:, daemonize:, log:, pid:)
  18. unless File.file?(conf)
  19. $stdout.puts "[-] No MSF JSON-RPC web service configuration found at #{conf}, not starting"
  20. return false
  21. end
  22. # check if MSF JSON-RPC web service is already started
  23. if File.file?(pid)
  24. ws_pid = Msf::Util::ServiceHelper.tail(pid)
  25. if ws_pid.nil? || !Msf::Util::ServiceHelper.process_active?(ws_pid.to_i)
  26. $stdout.puts "[-] MSF JSON-RPC web service PID file found, but no active process running as PID #{ws_pid}"
  27. $stdout.puts "[*] Deleting MSF JSON-RPC web service PID file #{pid}"
  28. File.delete(pid)
  29. else
  30. $stdout.puts "[*] MSF JSON-RPC web service is already running as PID #{ws_pid}"
  31. return false
  32. end
  33. end
  34. # attempt to start MSF JSON-RPC service
  35. thin_cmd = Msf::Util::ServiceHelper.thin_cmd(conf: conf,
  36. address: address,
  37. port: port,
  38. ssl: ssl,
  39. ssl_key: ssl_key,
  40. ssl_cert: ssl_cert,
  41. ssl_disable_verify: ssl_disable_verify,
  42. env: WS_ENV,
  43. daemonize: daemonize,
  44. log: log,
  45. pid: pid,
  46. tag: WS_RPC_TAG)
  47. Msf::Util::ServiceHelper.run_cmd("#{thin_cmd} start")
  48. end
  49. def stop_json_rpc_service(conf:, address:, port:, ssl:, ssl_key:, ssl_cert:,
  50. ssl_disable_verify:, daemonize:, log:, pid:)
  51. ws_pid = Msf::Util::ServiceHelper.tail(pid)
  52. $stdout.puts ''
  53. if ws_pid.nil? || !Msf::Util::ServiceHelper.process_active?(ws_pid.to_i)
  54. $stdout.puts '[*] MSF JSON-RPC web service is no longer running'
  55. if File.file?(pid)
  56. $stdout.puts "[*] Deleting MSF JSON-RPC web service PID file #{pid}"
  57. File.delete(pid)
  58. end
  59. else
  60. $stdout.puts "[*] Stopping MSF JSON-RPC web service PID #{ws_pid}"
  61. thin_cmd = Msf::Util::ServiceHelper.thin_cmd(conf: conf,
  62. address: address,
  63. port: port,
  64. ssl: ssl,
  65. ssl_key: ssl_key,
  66. ssl_cert: ssl_cert,
  67. ssl_disable_verify: ssl_disable_verify,
  68. env: WS_ENV,
  69. daemonize: daemonize,
  70. log: log,
  71. pid: pid,
  72. tag: WS_RPC_TAG)
  73. Msf::Util::ServiceHelper.run_cmd("#{thin_cmd} stop")
  74. end
  75. end
  76. def start_rpc_service(opts, frameworkOpts, foreground)
  77. # Fork into the background if requested
  78. begin
  79. if foreground
  80. $stdout.puts "[*] #{RPC_TYPE.upcase}RPC ready at #{Time.now}."
  81. else
  82. $stderr.puts "[*] #{RPC_TYPE.upcase}RPC backgrounding at #{Time.now}..."
  83. child_pid = Process.fork()
  84. if child_pid
  85. $stderr.puts "[*] #{RPC_TYPE.upcase}RPC background PID #{child_pid}"
  86. exit(0)
  87. end
  88. end
  89. rescue ::NotImplementedError
  90. $stderr.puts "[-] Background mode is not available on this platform"
  91. end
  92. # Create an instance of the framework
  93. $framework = Msf::Simple::Framework.create(frameworkOpts)
  94. # Run the plugin instance in the foreground.
  95. begin
  96. $framework.plugins.load("#{RPC_TYPE.downcase}rpc", opts).run
  97. rescue ::Interrupt
  98. $stderr.puts "[*] Shutting down"
  99. end
  100. end
  101. if $PROGRAM_NAME == __FILE__
  102. msfbase = __FILE__
  103. while File.symlink?(msfbase)
  104. msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
  105. end
  106. $:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib')))
  107. require 'msfenv'
  108. $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
  109. require 'msf/base'
  110. require 'msf/ui'
  111. require 'msf/util/service_helper'
  112. require 'msf/base/config'
  113. require 'rex/parser/arguments'
  114. ws_ssl_key_default = File.join(Msf::Config.get_config_root, "#{WS_TAG}-key.pem")
  115. ws_ssl_cert_default = File.join(Msf::Config.get_config_root, "#{WS_TAG}-cert.pem")
  116. ws_log = File.join(Msf::Config.get_config_root, 'logs', "#{WS_RPC_TAG}.log")
  117. ws_rpc_pid = File.join(Msf::Config.get_config_root, "#{WS_RPC_TAG}.pid")
  118. ws_ssl_key = ws_ssl_key_default
  119. ws_ssl_cert = ws_ssl_cert_default
  120. ssl_enable_verify = false
  121. foreground = false
  122. json_rpc = false
  123. frameworkOpts = {}
  124. opts = {
  125. 'RunInForeground' => true,
  126. 'SSL' => true,
  127. 'ServerHost' => '0.0.0.0',
  128. 'ServerPort' => 55553,
  129. 'ServerType' => RPC_TYPE,
  130. 'TokenTimeout' => 300,
  131. }
  132. # Declare the argument parser for msfrpcd
  133. arguments = Rex::Parser::Arguments.new(
  134. "-a" => [ true, "Bind to this IP address (default: #{opts['ServerHost']})" ],
  135. "-p" => [ true, "Bind to this port (default: #{opts['ServerPort']})" ],
  136. "-U" => [ true, "Specify the username to access msfrpcd" ],
  137. "-P" => [ true, "Specify the password to access msfrpcd" ],
  138. "-u" => [ true, "URI for Web server" ],
  139. "-t" => [ true, "Token Timeout seconds (default: #{opts['TokenTimeout']})" ],
  140. "-S" => [ false, "Disable SSL on the RPC socket" ],
  141. "-f" => [ false, "Run the daemon in the foreground" ],
  142. "-n" => [ false, "Disable database" ],
  143. "-j" => [ false, "(JSON-RPC) Start JSON-RPC server" ],
  144. "-k" => [ false, "(JSON-RPC) Path to private key (default: #{ws_ssl_key_default})" ],
  145. "-c" => [ false, "(JSON-RPC) Path to certificate (default: #{ws_ssl_cert_default})" ],
  146. "-v" => [ false, "(JSON-RPC) SSL enable verify (optional) client cert requests" ],
  147. "-h" => [ false, "Help banner" ])
  148. # Parse command line arguments.
  149. arguments.parse(ARGV) { |opt, idx, val|
  150. case opt
  151. when "-a"
  152. opts['ServerHost'] = val
  153. when "-S"
  154. opts['SSL'] = false
  155. when "-p"
  156. opts['ServerPort'] = val
  157. when '-U'
  158. opts['User'] = val
  159. when '-P'
  160. opts['Pass'] = val
  161. when "-t"
  162. opts['TokenTimeout'] = val.to_i
  163. when "-f"
  164. foreground = true
  165. when "-u"
  166. opts['URI'] = val
  167. when "-n"
  168. frameworkOpts['DisableDatabase'] = true
  169. when "-j"
  170. json_rpc = true
  171. when "-k"
  172. ws_ssl_key = val
  173. when "-c"
  174. ws_ssl_cert = val
  175. when "-v"
  176. ssl_enable_verify = true
  177. when "-h"
  178. print("\nUsage: #{File.basename(__FILE__)} <options>\n" + arguments.usage)
  179. exit
  180. end
  181. }
  182. $0 = "msfrpcd"
  183. begin
  184. if json_rpc
  185. if !File.file?(ws_ssl_key_default) || !File.file?(ws_ssl_cert_default)
  186. $stdout.puts "[-] It doesn't appear msfdb has been run; please run 'msfdb init' first."
  187. abort
  188. end
  189. $stderr.puts "[*] JSON-RPC starting on #{opts['ServerHost']}:#{opts['ServerPort']} (#{opts['SSL'] ? "SSL" : "NO SSL"})..."
  190. $stderr.puts "[*] URI: /api/v1/json-rpc"
  191. $stderr.puts "[*] JSON-RPC server log: #{ws_log}" unless foreground
  192. $stderr.puts "[*] JSON-RPC server PID file: #{ws_rpc_pid}" unless foreground
  193. ws_conf_full_path = File.expand_path(File.join(File.dirname(msfbase), WS_CONF))
  194. start_json_rpc_service(conf: ws_conf_full_path,
  195. address: opts['ServerHost'],
  196. port: opts['ServerPort'],
  197. ssl: opts['SSL'],
  198. ssl_key: ws_ssl_key,
  199. ssl_cert: ws_ssl_cert,
  200. ssl_disable_verify: !ssl_enable_verify,
  201. daemonize: !foreground,
  202. log: ws_log,
  203. pid: ws_rpc_pid)
  204. else
  205. unless opts['Pass']
  206. $stderr.puts "[-] Error: a password must be specified (-P)"
  207. exit(0)
  208. end
  209. $stderr.puts "[*] #{RPC_TYPE.upcase}RPC starting on #{opts['ServerHost']}:#{opts['ServerPort']} (#{opts['SSL'] ? "SSL" : "NO SSL"}):#{opts['ServerType']}..."
  210. $stderr.puts "[*] URI: #{opts['URI']}" if opts['URI']
  211. start_rpc_service(opts, frameworkOpts, foreground)
  212. end
  213. rescue ::Interrupt
  214. stop_json_rpc_service(conf: ws_conf_full_path,
  215. address: opts['ServerHost'],
  216. port: opts['ServerPort'],
  217. ssl: opts['SSL'],
  218. ssl_key: ws_ssl_key,
  219. ssl_cert: ws_ssl_cert,
  220. ssl_disable_verify: !ssl_enable_verify,
  221. daemonize: !foreground,
  222. log: ws_log,
  223. pid: ws_rpc_pid) if json_rpc
  224. end
  225. end