PageRenderTime 28ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/rex/post/meterpreter/packet_dispatcher.rb

https://bitbucket.org/cfield/metasploit-framework
Ruby | 544 lines | 300 code | 95 blank | 149 comment | 45 complexity | 908c0a7aed894df186a3c84da79ed2b6 MD5 | raw file
  1. #!/usr/bin/env ruby
  2. # -*- coding: binary -*-
  3. require 'rex/post/meterpreter/packet_response_waiter'
  4. require 'rex/logging'
  5. require 'rex/exceptions'
  6. module Rex
  7. module Post
  8. module Meterpreter
  9. ###
  10. #
  11. # Exception thrown when a request fails.
  12. #
  13. ###
  14. class RequestError < ArgumentError
  15. def initialize(method, einfo, ecode=nil)
  16. @method = method
  17. @result = einfo
  18. @code = ecode || einfo
  19. end
  20. def to_s
  21. "#{@method}: Operation failed: #{@result}"
  22. end
  23. # The method that failed.
  24. attr_reader :method
  25. # The error result that occurred, typically a windows error message.
  26. attr_reader :result
  27. # The error result that occurred, typically a windows error code.
  28. attr_reader :code
  29. end
  30. ###
  31. #
  32. # Handles packet transmission, reception, and correlation,
  33. # and processing
  34. #
  35. ###
  36. module PacketDispatcher
  37. PacketTimeout = 600
  38. ##
  39. #
  40. # Synchronization
  41. #
  42. ##
  43. attr_accessor :comm_mutex
  44. ##
  45. #
  46. #
  47. # Passive Dispatching
  48. #
  49. ##
  50. attr_accessor :passive_service, :send_queue, :recv_queue
  51. def initialize_passive_dispatcher
  52. self.send_queue = []
  53. self.recv_queue = []
  54. self.waiters = []
  55. self.alive = true
  56. self.passive_service = self.passive_dispatcher
  57. self.passive_service.remove_resource("/" + self.conn_id + "/")
  58. self.passive_service.add_resource("/" + self.conn_id + "/",
  59. 'Proc' => Proc.new { |cli, req| on_passive_request(cli, req) },
  60. 'VirtualDirectory' => true
  61. )
  62. end
  63. def shutdown_passive_dispatcher
  64. return if not self.passive_service
  65. self.passive_service.remove_resource("/" + self.conn_id + "/")
  66. self.alive = false
  67. self.send_queue = []
  68. self.recv_queue = []
  69. self.waiters = []
  70. self.passive_service = nil
  71. end
  72. def on_passive_request(cli, req)
  73. begin
  74. resp = Rex::Proto::Http::Response.new(200, "OK")
  75. resp['Content-Type'] = 'application/octet-stream'
  76. resp['Connection'] = 'close'
  77. # If the first 4 bytes are "RECV", return the oldest packet from the outbound queue
  78. if req.body[0,4] == "RECV"
  79. rpkt = send_queue.pop
  80. resp.body = rpkt || ''
  81. begin
  82. cli.send_response(resp)
  83. rescue ::Exception => e
  84. send_queue.unshift(rpkt) if rpkt
  85. elog("Exception sending a reply to the reader request: #{cli.inspect} #{e.class} #{e} #{e.backtrace}")
  86. end
  87. else
  88. resp.body = ""
  89. if req.body and req.body.length > 0
  90. packet = Packet.new(0)
  91. packet.from_r(req.body)
  92. dispatch_inbound_packet(packet)
  93. end
  94. cli.send_response(resp)
  95. end
  96. # Force a closure for older WinInet implementations
  97. self.passive_service.close_client( cli )
  98. rescue ::Exception => e
  99. elog("Exception handling request: #{cli.inspect} #{req.inspect} #{e.class} #{e} #{e.backtrace}")
  100. end
  101. end
  102. ##
  103. #
  104. # Transmission
  105. #
  106. ##
  107. #
  108. # Sends a packet without waiting for a response.
  109. #
  110. def send_packet(packet, completion_routine = nil, completion_param = nil)
  111. if (completion_routine)
  112. add_response_waiter(packet, completion_routine, completion_param)
  113. end
  114. bytes = 0
  115. raw = packet.to_r
  116. err = nil
  117. # Short-circuit send when using a passive dispatcher
  118. if self.passive_service
  119. send_queue.push(raw)
  120. return raw.size # Lie!
  121. end
  122. if (raw)
  123. # This mutex is used to lock out new commands during an
  124. # active migration.
  125. self.comm_mutex.synchronize do
  126. begin
  127. bytes = self.sock.write(raw)
  128. rescue ::Exception => e
  129. err = e
  130. end
  131. end
  132. if bytes.to_i == 0
  133. # Mark the session itself as dead
  134. self.alive = false
  135. # Indicate that the dispatcher should shut down too
  136. @finish = true
  137. # Reraise the error to the top-level caller
  138. raise err if err
  139. end
  140. end
  141. return bytes
  142. end
  143. #
  144. # Sends a packet and waits for a timeout for the given time interval.
  145. #
  146. def send_request(packet, t = self.response_timeout)
  147. if not t
  148. send_packet(packet)
  149. return nil
  150. end
  151. response = send_packet_wait_response(packet, t)
  152. if (response == nil)
  153. raise TimeoutError.new("Send timed out")
  154. elsif (response.result != 0)
  155. einfo = lookup_error(response.result)
  156. e = RequestError.new(packet.method, einfo, response.result)
  157. e.set_backtrace(caller)
  158. raise e
  159. end
  160. return response
  161. end
  162. #
  163. # Transmits a packet and waits for a response.
  164. #
  165. def send_packet_wait_response(packet, t)
  166. # First, add the waiter association for the supplied packet
  167. waiter = add_response_waiter(packet)
  168. # Transmit the packet
  169. if (send_packet(packet).to_i <= 0)
  170. # Remove the waiter if we failed to send the packet.
  171. remove_response_waiter(waiter)
  172. return nil
  173. end
  174. # Wait for the supplied time interval
  175. waiter.wait(t)
  176. # Remove the waiter from the list of waiters in case it wasn't
  177. # removed
  178. remove_response_waiter(waiter)
  179. # Return the response packet, if any
  180. return waiter.response
  181. end
  182. ##
  183. #
  184. # Reception
  185. #
  186. ##
  187. #
  188. # Monitors the PacketDispatcher's sock for data in its own
  189. # thread context and parsers all inbound packets.
  190. #
  191. def monitor_socket
  192. # Skip if we are using a passive dispatcher
  193. return if self.passive_service
  194. self.comm_mutex = ::Mutex.new
  195. self.waiters = []
  196. @pqueue = []
  197. @finish = false
  198. @last_recvd = Time.now
  199. @ping_sent = false
  200. self.alive = true
  201. # Spawn a thread for receiving packets
  202. self.receiver_thread = Rex::ThreadFactory.spawn("MeterpreterReceiver", false) do
  203. while (self.alive)
  204. begin
  205. rv = Rex::ThreadSafe.select([ self.sock.fd ], nil, nil, 0.25)
  206. ping_time = 60
  207. # If there's nothing to read, and it's been awhile since we
  208. # saw a packet, we need to send a ping. We wait
  209. # ping_time*2 seconds before deciding a session is dead.
  210. if (not rv and self.send_keepalives and Time.now - @last_recvd > ping_time)
  211. # If the queue is empty and we've already sent a
  212. # keepalive without getting a reply, then this
  213. # session is hosed, and we should give up on it.
  214. if @ping_sent and @pqueue.empty? and (Time.now - @last_recvd > ping_time * 2)
  215. dlog("No response to ping, session #{self.sid} is dead", LEV_3)
  216. self.alive = false
  217. @finish = true
  218. break
  219. end
  220. # Let the packet queue processor finish up before
  221. # we send a ping.
  222. if not @ping_sent and @pqueue.empty?
  223. # Our 'ping' is actually just a check for eof on
  224. # channel id 0. This method has no side effects
  225. # and always returns an answer (regardless of the
  226. # existence of chan 0), which is all that's
  227. # needed for a liveness check. The answer itself
  228. # is unimportant and is ignored.
  229. pkt = Packet.create_request('core_channel_eof')
  230. pkt.add_tlv(TLV_TYPE_CHANNEL_ID, 0)
  231. waiter = Proc.new { |response, param|
  232. @ping_sent = false
  233. @last_recvd = Time.now
  234. }
  235. send_packet(pkt, waiter)
  236. @ping_sent = true
  237. end
  238. next
  239. end
  240. next if not rv
  241. packet = receive_packet
  242. @pqueue << packet if packet
  243. @last_recvd = Time.now
  244. rescue ::Exception
  245. dlog("Exception caught in monitor_socket: #{$!}", 'meterpreter', LEV_1)
  246. @finish = true
  247. self.alive = false
  248. break
  249. end
  250. end
  251. end
  252. # Spawn a new thread that monitors the socket
  253. self.dispatcher_thread = Rex::ThreadFactory.spawn("MeterpreterDispatcher", false) do
  254. begin
  255. # Whether we're finished or not is determined by the receiver
  256. # thread above.
  257. while(not @finish)
  258. if(@pqueue.empty?)
  259. ::IO.select(nil, nil, nil, 0.10)
  260. next
  261. end
  262. incomplete = []
  263. backlog = []
  264. while(@pqueue.length > 0)
  265. backlog << @pqueue.shift
  266. end
  267. #
  268. # Prioritize message processing here
  269. # 1. Close should always be processed at the end
  270. # 2. Command responses always before channel data
  271. #
  272. tmp_command = []
  273. tmp_channel = []
  274. tmp_close = []
  275. backlog.each do |pkt|
  276. if(pkt.response?)
  277. tmp_command << pkt
  278. next
  279. end
  280. if(pkt.method == "core_channel_close")
  281. tmp_close << pkt
  282. next
  283. end
  284. tmp_channel << pkt
  285. end
  286. backlog = []
  287. backlog.push(*tmp_command)
  288. backlog.push(*tmp_channel)
  289. backlog.push(*tmp_close)
  290. #
  291. # Process the message queue
  292. #
  293. backlog.each do |pkt|
  294. begin
  295. if ! dispatch_inbound_packet(pkt)
  296. # Only requeue packets newer than the timeout
  297. if (::Time.now.to_i - pkt.created_at.to_i < PacketTimeout)
  298. incomplete << pkt
  299. end
  300. end
  301. rescue ::Exception => e
  302. dlog("Dispatching exception with packet #{pkt}: #{e} #{e.backtrace}", 'meterpreter', LEV_1)
  303. end
  304. end
  305. # If the backlog and incomplete arrays are the same, it means
  306. # dispatch_inbound_packet wasn't able to handle any of the
  307. # packets. When that's the case, we can get into a situation
  308. # where @pqueue is not empty and, since nothing else bounds this
  309. # loop, we spin CPU trying to handle packets that can't be
  310. # handled. Sleep here to treat that situation as though the
  311. # queue is empty.
  312. if (backlog.length > 0 && backlog.length == incomplete.length)
  313. ::IO.select(nil, nil, nil, 0.10)
  314. end
  315. @pqueue.unshift(*incomplete)
  316. if(@pqueue.length > 100)
  317. dlog("Backlog has grown to over 100 in monitor_socket, dropping older packets: #{@pqueue[0 .. 25].map{|x| x.inspect}.join(" - ")}", 'meterpreter', LEV_1)
  318. @pqueue = @pqueue[25 .. 100]
  319. end
  320. end
  321. rescue ::Exception => e
  322. dlog("Exception caught in monitor_socket dispatcher: #{e.class} #{e} #{e.backtrace}", 'meterpreter', LEV_1)
  323. ensure
  324. self.receiver_thread.kill if self.receiver_thread
  325. end
  326. end
  327. end
  328. #
  329. # Parses data from the dispatcher's sock and returns a Packet context
  330. # once a full packet has been received.
  331. #
  332. def receive_packet
  333. return parser.recv(self.sock)
  334. end
  335. #
  336. # Stop the monitor
  337. #
  338. def monitor_stop
  339. if(self.receiver_thread)
  340. self.receiver_thread.kill
  341. self.receiver_thread = nil
  342. end
  343. if(self.dispatcher_thread)
  344. self.dispatcher_thread.kill
  345. self.dispatcher_thread = nil
  346. end
  347. end
  348. ##
  349. #
  350. # Waiter registration
  351. #
  352. ##
  353. #
  354. # Adds a waiter association with the supplied request packet.
  355. #
  356. def add_response_waiter(request, completion_routine = nil, completion_param = nil)
  357. waiter = PacketResponseWaiter.new(request.rid, completion_routine, completion_param)
  358. self.waiters << waiter
  359. return waiter
  360. end
  361. #
  362. # Notifies a whomever is waiting for a the supplied response,
  363. # if anyone.
  364. #
  365. def notify_response_waiter(response)
  366. self.waiters.each() { |waiter|
  367. if (waiter.waiting_for?(response))
  368. waiter.notify(response)
  369. remove_response_waiter(waiter)
  370. break
  371. end
  372. }
  373. end
  374. #
  375. # Removes a waiter from the list of waiters.
  376. #
  377. def remove_response_waiter(waiter)
  378. self.waiters.delete(waiter)
  379. end
  380. ##
  381. #
  382. # Dispatching
  383. #
  384. ##
  385. #
  386. # Initializes the inbound handlers.
  387. #
  388. def initialize_inbound_handlers
  389. @inbound_handlers = []
  390. end
  391. #
  392. # Dispatches and processes an inbound packet. If the packet is a
  393. # response that has an associated waiter, the waiter is notified.
  394. # Otherwise, the packet is passed onto any registered dispatch
  395. # handlers until one returns success.
  396. #
  397. def dispatch_inbound_packet(packet, client = nil)
  398. handled = false
  399. # If no client context was provided, return self as PacketDispatcher
  400. # is a mixin for the Client instance
  401. if (client == nil)
  402. client = self
  403. end
  404. # If the packet is a response, try to notify any potential
  405. # waiters
  406. if ((resp = packet.response?))
  407. if (notify_response_waiter(packet))
  408. return true
  409. end
  410. end
  411. # Enumerate all of the inbound packet handlers until one handles
  412. # the packet
  413. @inbound_handlers.each { |handler|
  414. handled = nil
  415. begin
  416. if ! resp
  417. handled = handler.request_handler(client, packet)
  418. else
  419. handled = handler.response_handler(client, packet)
  420. end
  421. rescue ::Exception => e
  422. dlog("Exception caught in dispatch_inbound_packet: handler=#{handler} #{e.class} #{e} #{e.backtrace}", 'meterpreter', LEV_1)
  423. return true
  424. end
  425. if (handled)
  426. break
  427. end
  428. }
  429. return handled
  430. end
  431. #
  432. # Registers an inbound packet handler that implements the
  433. # InboundPacketHandler interface.
  434. #
  435. def register_inbound_handler(handler)
  436. @inbound_handlers << handler
  437. end
  438. #
  439. # Deregisters a previously registered inbound packet handler.
  440. #
  441. def deregister_inbound_handler(handler)
  442. @inbound_handlers.delete(handler)
  443. end
  444. protected
  445. attr_accessor :receiver_thread # :nodoc:
  446. attr_accessor :dispatcher_thread # :nodoc:
  447. attr_accessor :waiters # :nodoc:
  448. end
  449. end; end; end