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

/lib/rex/socket/comm/local.rb

https://github.com/Jonono2/metasploit-framework
Ruby | 526 lines | 375 code | 86 blank | 65 comment | 79 complexity | 6c398ec2d4a01f979b47a55b16c77239 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-3.0, LGPL-2.1, GPL-2.0
  1. # -*- coding: binary -*-
  2. require 'singleton'
  3. require 'rex/socket'
  4. require 'rex/socket/tcp'
  5. require 'rex/socket/ssl_tcp'
  6. require 'rex/socket/ssl_tcp_server'
  7. require 'rex/socket/udp'
  8. require 'rex/socket/ip'
  9. require 'timeout'
  10. ###
  11. #
  12. # Local communication class factory.
  13. #
  14. ###
  15. class Rex::Socket::Comm::Local
  16. include Singleton
  17. include Rex::Socket::Comm
  18. #
  19. # Creates an instance of a socket using the supplied parameters.
  20. #
  21. def self.create(param)
  22. # Work around jRuby socket implementation issues
  23. if(RUBY_PLATFORM == 'java')
  24. return self.create_jruby(param)
  25. end
  26. case param.proto
  27. when 'tcp'
  28. return create_by_type(param, ::Socket::SOCK_STREAM, ::Socket::IPPROTO_TCP)
  29. when 'udp'
  30. return create_by_type(param, ::Socket::SOCK_DGRAM, ::Socket::IPPROTO_UDP)
  31. when 'ip'
  32. return create_ip(param)
  33. else
  34. raise Rex::UnsupportedProtocol.new(param.proto), caller
  35. end
  36. end
  37. #
  38. # Creates an instance of a socket using the supplied parameters.
  39. # Use various hacks to make this work with jRuby
  40. #
  41. def self.create_jruby(param)
  42. sock = nil
  43. # Notify handlers of the before socket create event.
  44. self.instance.notify_before_socket_create(self, param)
  45. case param.proto
  46. when 'tcp'
  47. if (param.server?)
  48. sock = TCPServer.new(param.localport, param.localhost)
  49. klass = Rex::Socket::TcpServer
  50. if (param.ssl)
  51. klass = Rex::Socket::SslTcpServer
  52. end
  53. sock.extend(klass)
  54. else
  55. sock = TCPSocket.new(param.peerhost, param.peerport)
  56. klass = Rex::Socket::Tcp
  57. if (param.ssl)
  58. klass = Rex::Socket::SslTcp
  59. end
  60. sock.extend(klass)
  61. end
  62. when 'udp'
  63. if (param.server?)
  64. sock = UDPServer.new(param.localport, param.localhost)
  65. klass = Rex::Socket::UdpServer
  66. sock.extend(klass)
  67. else
  68. sock = UDPSocket.new(param.peerhost, param.peerport)
  69. klass = Rex::Socket::Udp
  70. sock.extend(klass)
  71. end
  72. else
  73. raise Rex::UnsupportedProtocol.new(param.proto), caller
  74. end
  75. sock.initsock(param)
  76. self.instance.notify_socket_created(self, sock, param)
  77. return sock
  78. end
  79. #
  80. # Creates a raw IP socket using the supplied Parameter instance.
  81. # Special-cased because of how different it is from UDP/TCP
  82. #
  83. def self.create_ip(param)
  84. self.instance.notify_before_socket_create(self, param)
  85. sock = ::Socket.open(::Socket::PF_INET, ::Socket::SOCK_RAW, ::Socket::IPPROTO_RAW)
  86. sock.setsockopt(::Socket::IPPROTO_IP, ::Socket::IP_HDRINCL, 1)
  87. # Configure broadcast support
  88. sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_BROADCAST, true)
  89. if (param.bare? == false)
  90. sock.extend(::Rex::Socket::Ip)
  91. sock.initsock(param)
  92. end
  93. self.instance.notify_socket_created(self, sock, param)
  94. sock
  95. end
  96. #
  97. # Creates a socket using the supplied Parameter instance.
  98. #
  99. def self.create_by_type(param, type, proto = 0)
  100. # Whether to use IPv6 addressing
  101. usev6 = false
  102. # Detect IPv6 addresses and enable IPv6 accordingly
  103. if ( Rex::Socket.support_ipv6?())
  104. # Allow the caller to force IPv6
  105. if (param.v6)
  106. usev6 = true
  107. end
  108. # Force IPv6 mode for non-connected UDP sockets
  109. if (type == ::Socket::SOCK_DGRAM and not param.peerhost)
  110. # FreeBSD allows IPv6 socket creation, but throws an error on sendto()
  111. # Windows 7 SP1 and newer also fail to sendto with IPv6 udp sockets
  112. unless Rex::Compat.is_freebsd or Rex::Compat.is_windows
  113. usev6 = true
  114. end
  115. end
  116. local = Rex::Socket.resolv_nbo(param.localhost) if param.localhost
  117. peer = Rex::Socket.resolv_nbo(param.peerhost) if param.peerhost
  118. if (local and local.length == 16)
  119. usev6 = true
  120. end
  121. if (peer and peer.length == 16)
  122. usev6 = true
  123. end
  124. if (usev6)
  125. if (local and local.length == 4)
  126. if (local == "\x00\x00\x00\x00")
  127. param.localhost = '::'
  128. elsif (local == "\x7f\x00\x00\x01")
  129. param.localhost = '::1'
  130. else
  131. param.localhost = '::ffff:' + Rex::Socket.getaddress(param.localhost, true)
  132. end
  133. end
  134. if (peer and peer.length == 4)
  135. if (peer == "\x00\x00\x00\x00")
  136. param.peerhost = '::'
  137. elsif (peer == "\x7f\x00\x00\x01")
  138. param.peerhost = '::1'
  139. else
  140. param.peerhost = '::ffff:' + Rex::Socket.getaddress(param.peerhost, true)
  141. end
  142. end
  143. param.v6 = true
  144. end
  145. else
  146. # No IPv6 support
  147. param.v6 = false
  148. end
  149. # Notify handlers of the before socket create event.
  150. self.instance.notify_before_socket_create(self, param)
  151. # Create the socket
  152. sock = nil
  153. if (param.v6)
  154. sock = ::Socket.new(::Socket::AF_INET6, type, proto)
  155. else
  156. sock = ::Socket.new(::Socket::AF_INET, type, proto)
  157. end
  158. # Bind to a given local address and/or port if they are supplied
  159. if param.localport or param.localhost
  160. begin
  161. sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, true)
  162. sock.bind(Rex::Socket.to_sockaddr(param.localhost, param.localport))
  163. rescue ::Errno::EADDRNOTAVAIL,::Errno::EADDRINUSE
  164. sock.close
  165. raise Rex::AddressInUse.new(param.localhost, param.localport), caller
  166. end
  167. end
  168. # Configure broadcast support for all datagram sockets
  169. if (type == ::Socket::SOCK_DGRAM)
  170. sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_BROADCAST, true)
  171. end
  172. # If a server TCP instance is being created...
  173. if (param.server?)
  174. sock.listen(256)
  175. if (param.bare? == false)
  176. klass = Rex::Socket::TcpServer
  177. if (param.ssl)
  178. klass = Rex::Socket::SslTcpServer
  179. end
  180. sock.extend(klass)
  181. sock.initsock(param)
  182. end
  183. # Otherwise, if we're creating a client...
  184. else
  185. chain = []
  186. # If we were supplied with host information
  187. if (param.peerhost)
  188. # A flag that indicates whether we need to try multiple scopes
  189. retry_scopes = false
  190. # Always retry with link-local IPv6 addresses
  191. if Rex::Socket.is_ipv6?( param.peerhost ) and param.peerhost =~ /^fe80::/
  192. retry_scopes = true
  193. end
  194. # Prepare a list of scope IDs to try when connecting to
  195. # link-level addresses. Read from /proc if it is available,
  196. # otherwise increment through the first 255 IDs.
  197. @@ip6_lla_scopes ||= []
  198. if @@ip6_lla_scopes.length == 0 and retry_scopes
  199. # Linux specific interface lookup code
  200. if ::File.exists?( "/proc/self/net/igmp6" )
  201. ::File.open("/proc/self/net/igmp6") do |fd|
  202. fd.each_line do |line|
  203. line = line.strip
  204. tscope, tint, junk = line.split(/\s+/, 3)
  205. next if not tint
  206. # Specifying lo in any connect call results in the socket
  207. # being unusable, even if the correct interface is set.
  208. next if tint == "lo"
  209. @@ip6_lla_scopes << tscope
  210. end
  211. end
  212. else
  213. # Other Unix-like platforms should support a raw scope ID
  214. [*(1 .. 255)].map{ |x| @@ip6_lla_scopes << x.to_s }
  215. end
  216. end
  217. ip6_scope_idx = 0
  218. ip = param.peerhost
  219. port = param.peerport
  220. if param.proxies
  221. chain = param.proxies.dup
  222. chain.push(['host',param.peerhost,param.peerport])
  223. ip = chain[0][1]
  224. port = chain[0][2].to_i
  225. end
  226. begin
  227. begin
  228. Timeout.timeout(param.timeout) do
  229. sock.connect(Rex::Socket.to_sockaddr(ip, port))
  230. end
  231. rescue ::Timeout::Error
  232. raise ::Errno::ETIMEDOUT
  233. end
  234. rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL
  235. # Rescue errors caused by a bad Scope ID for a link-local address
  236. if retry_scopes and @@ip6_lla_scopes[ ip6_scope_idx ]
  237. ip = param.peerhost + "%" + @@ip6_lla_scopes[ ip6_scope_idx ]
  238. ip6_scope_idx += 1
  239. retry
  240. end
  241. sock.close
  242. raise Rex::HostUnreachable.new(param.peerhost, param.peerport), caller
  243. rescue ::Errno::EADDRNOTAVAIL,::Errno::EADDRINUSE
  244. sock.close
  245. raise Rex::AddressInUse.new(param.peerhost, param.peerport), caller
  246. rescue Errno::ETIMEDOUT
  247. sock.close
  248. raise Rex::ConnectionTimeout.new(param.peerhost, param.peerport), caller
  249. rescue ::Errno::ECONNRESET,::Errno::ECONNREFUSED,::Errno::ENOTCONN,::Errno::ECONNABORTED
  250. sock.close
  251. raise Rex::ConnectionRefused.new(param.peerhost, param.peerport), caller
  252. end
  253. end
  254. if (param.bare? == false)
  255. case param.proto
  256. when 'tcp'
  257. klass = Rex::Socket::Tcp
  258. sock.extend(klass)
  259. sock.initsock(param)
  260. when 'udp'
  261. sock.extend(Rex::Socket::Udp)
  262. sock.initsock(param)
  263. end
  264. end
  265. if chain.size > 1
  266. chain.each_with_index {
  267. |proxy, i|
  268. next_hop = chain[i + 1]
  269. if next_hop
  270. proxy(sock, proxy[0], next_hop[1], next_hop[2])
  271. end
  272. }
  273. end
  274. # Now extend the socket with SSL and perform the handshake
  275. if(param.bare? == false and param.ssl)
  276. klass = Rex::Socket::SslTcp
  277. sock.extend(klass)
  278. sock.initsock(param)
  279. end
  280. end
  281. # Notify handlers that a socket has been created.
  282. self.instance.notify_socket_created(self, sock, param)
  283. sock
  284. end
  285. def self.proxy(sock, type, host, port)
  286. case type.downcase
  287. when 'sapni'
  288. packet_type = 'NI_ROUTE'
  289. route_info_version = 2
  290. ni_version = 39
  291. num_of_entries = 2
  292. talk_mode = 1 # ref: http://help.sap.com/saphelp_dimp50/helpdata/En/f8/bb960899d743378ccb8372215bb767/content.htm
  293. num_rest_nodes = 1
  294. shost, sport = sock.peerinfo.split(":")
  295. first_route_item = [shost, 0, sport, 0, 0].pack("A*CA*cc")
  296. route_data = [first_route_item.length, first_route_item].pack("NA*")
  297. route_data << [host, 0, port.to_s, 0, 0].pack("A*CA*cc")
  298. ni_packet = [
  299. packet_type,
  300. 0,
  301. route_info_version,
  302. ni_version,
  303. num_of_entries,
  304. talk_mode,
  305. 0,
  306. 0,
  307. num_rest_nodes
  308. ].pack("A8c8")
  309. # Add the data block, according to sap documentation:
  310. # A 4-byte header precedes each data block. These 4 bytes give the
  311. # length of the data block (length without leading 4 bytes)
  312. # The data block (the route data)
  313. ni_packet << [route_data.length - 4].pack('N') + route_data
  314. # Now that we've built the whole packet, prepend its length before writing it to the wire
  315. ni_packet = [ni_packet.length].pack('N') + ni_packet
  316. size = sock.put(ni_packet)
  317. if size != ni_packet.length
  318. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
  319. end
  320. begin
  321. ret_len = sock.get_once(4, 30).unpack('N')[0]
  322. if ret_len and ret_len != 0
  323. ret = sock.get_once(ret_len, 30)
  324. end
  325. rescue IOError
  326. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
  327. end
  328. if ret and ret.length < 4
  329. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller
  330. end
  331. if ret =~ /NI_RTERR/
  332. case ret
  333. when /timed out/
  334. raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote host #{host} timed out")
  335. when /refused/
  336. raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote port #{port} closed")
  337. when /denied/
  338. raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} blocked by ACL")
  339. else
  340. raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed (Unknown fail)")
  341. end
  342. elsif ret =~ /NI_PONG/
  343. # success case
  344. # would like to print this "[*] remote native connection to #{host}:#{port} established\n"
  345. else
  346. raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed (Unknown fail)")
  347. end
  348. when 'http'
  349. setup = "CONNECT #{host}:#{port} HTTP/1.0\r\n\r\n"
  350. size = sock.put(setup)
  351. if (size != setup.length)
  352. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
  353. end
  354. begin
  355. ret = sock.get_once(39,30)
  356. rescue IOError
  357. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
  358. end
  359. if ret.nil?
  360. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
  361. end
  362. resp = Rex::Proto::Http::Response.new
  363. resp.update_cmd_parts(ret.split(/\r?\n/)[0])
  364. if resp.code != 200
  365. raise Rex::ConnectionProxyError.new(host, port, type, "The proxy returned a non-OK response"), caller
  366. end
  367. when 'socks4'
  368. setup = [4,1,port.to_i].pack('CCn') + Socket.gethostbyname(host)[3] + Rex::Text.rand_text_alpha(rand(8)+1) + "\x00"
  369. size = sock.put(setup)
  370. if (size != setup.length)
  371. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
  372. end
  373. begin
  374. ret = sock.get_once(8, 30)
  375. rescue IOError
  376. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
  377. end
  378. if (ret.nil? or ret.length < 8)
  379. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller
  380. end
  381. if ret[1,1] != "\x5a"
  382. raise Rex::ConnectionProxyError.new(host, port, type, "Proxy responded with error code #{ret[0,1].unpack("C")[0]}"), caller
  383. end
  384. when 'socks5'
  385. auth_methods = [5,1,0].pack('CCC')
  386. size = sock.put(auth_methods)
  387. if (size != auth_methods.length)
  388. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
  389. end
  390. ret = sock.get_once(2,30)
  391. if (ret[1,1] == "\xff")
  392. raise Rex::ConnectionProxyError.new(host, port, type, "The proxy requires authentication"), caller
  393. end
  394. if (Rex::Socket.is_ipv4?(host))
  395. addr = Rex::Socket.gethostbyname(host)[3]
  396. setup = [5,1,0,1].pack('C4') + addr + [port.to_i].pack('n')
  397. elsif (Rex::Socket.support_ipv6? and Rex::Socket.is_ipv6?(host))
  398. # IPv6 stuff all untested
  399. addr = Rex::Socket.gethostbyname(host)[3]
  400. setup = [5,1,0,4].pack('C4') + addr + [port.to_i].pack('n')
  401. else
  402. # Then it must be a domain name.
  403. # Unfortunately, it looks like the host has always been
  404. # resolved by the time it gets here, so this code never runs.
  405. setup = [5,1,0,3].pack('C4') + [host.length].pack('C') + host + [port.to_i].pack('n')
  406. end
  407. size = sock.put(setup)
  408. if (size != setup.length)
  409. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
  410. end
  411. begin
  412. response = sock.get_once(10, 30)
  413. rescue IOError
  414. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
  415. end
  416. if (response.nil? or response.length < 10)
  417. raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller
  418. end
  419. if response[1,1] != "\x00"
  420. raise Rex::ConnectionProxyError.new(host, port, type, "Proxy responded with error code #{response[1,1].unpack("C")[0]}"), caller
  421. end
  422. else
  423. raise RuntimeError, "The proxy type specified is not valid", caller
  424. end
  425. end
  426. ##
  427. #
  428. # Registration
  429. #
  430. ##
  431. def self.register_event_handler(handler) # :nodoc:
  432. self.instance.register_event_handler(handler)
  433. end
  434. def self.deregister_event_handler(handler) # :nodoc:
  435. self.instance.deregister_event_handler(handler)
  436. end
  437. def self.each_event_handler(handler) # :nodoc:
  438. self.instance.each_event_handler(handler)
  439. end
  440. end