rex 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rex/arch/x86.rb +16 -0
  3. data/lib/rex/constants.rb +1 -0
  4. data/lib/rex/constants/windows.rb +147 -0
  5. data/lib/rex/encoder/xdr.rb +3 -2
  6. data/lib/rex/exceptions.rb +37 -5
  7. data/lib/rex/exploitation/cmdstager/bourne.rb +9 -1
  8. data/lib/rex/exploitation/cmdstager/tftp.rb +5 -5
  9. data/lib/rex/java.rb +3 -0
  10. data/lib/rex/java/serialization.rb +54 -0
  11. data/lib/rex/java/serialization/model.rb +20 -0
  12. data/lib/rex/java/serialization/model/annotation.rb +69 -0
  13. data/lib/rex/java/serialization/model/block_data.rb +70 -0
  14. data/lib/rex/java/serialization/model/block_data_long.rb +72 -0
  15. data/lib/rex/java/serialization/model/class_desc.rb +64 -0
  16. data/lib/rex/java/serialization/model/contents.rb +156 -0
  17. data/lib/rex/java/serialization/model/element.rb +44 -0
  18. data/lib/rex/java/serialization/model/end_block_data.rb +12 -0
  19. data/lib/rex/java/serialization/model/field.rb +172 -0
  20. data/lib/rex/java/serialization/model/long_utf.rb +48 -0
  21. data/lib/rex/java/serialization/model/new_array.rb +225 -0
  22. data/lib/rex/java/serialization/model/new_class_desc.rb +155 -0
  23. data/lib/rex/java/serialization/model/new_enum.rb +79 -0
  24. data/lib/rex/java/serialization/model/new_object.rb +223 -0
  25. data/lib/rex/java/serialization/model/null_reference.rb +12 -0
  26. data/lib/rex/java/serialization/model/reference.rb +61 -0
  27. data/lib/rex/java/serialization/model/reset.rb +12 -0
  28. data/lib/rex/java/serialization/model/stream.rb +123 -0
  29. data/lib/rex/java/serialization/model/utf.rb +69 -0
  30. data/lib/rex/mime/message.rb +9 -14
  31. data/lib/rex/payloads.rb +1 -0
  32. data/lib/rex/payloads/meterpreter.rb +2 -0
  33. data/lib/rex/payloads/meterpreter/patch.rb +136 -0
  34. data/lib/rex/payloads/win32/kernel/stager.rb +26 -25
  35. data/lib/rex/post/meterpreter/client.rb +50 -60
  36. data/lib/rex/post/meterpreter/client_core.rb +18 -25
  37. data/lib/rex/post/meterpreter/extensions/extapi/adsi/adsi.rb +102 -8
  38. data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +24 -14
  39. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +18 -0
  40. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +1 -0
  41. data/lib/rex/post/meterpreter/packet_dispatcher.rb +1 -1
  42. data/lib/rex/post/meterpreter/ui/console.rb +1 -1
  43. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +43 -1
  44. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +1 -1
  45. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +9 -0
  46. data/lib/rex/proto/dcerpc/svcctl.rb +2 -0
  47. data/lib/rex/proto/dcerpc/svcctl/packet.rb +304 -0
  48. data/lib/rex/proto/kademlia.rb +8 -0
  49. data/lib/rex/proto/kademlia/bootstrap_request.rb +19 -0
  50. data/lib/rex/proto/kademlia/bootstrap_response.rb +79 -0
  51. data/lib/rex/proto/kademlia/message.rb +72 -0
  52. data/lib/rex/proto/kademlia/ping.rb +19 -0
  53. data/lib/rex/proto/kademlia/pong.rb +41 -0
  54. data/lib/rex/proto/kademlia/util.rb +22 -0
  55. data/lib/rex/proto/natpmp/packet.rb +30 -2
  56. data/lib/rex/proto/quake.rb +3 -0
  57. data/lib/rex/proto/quake/message.rb +73 -0
  58. data/lib/rex/proto/smb/client.rb +1 -0
  59. data/lib/rex/proto/smb/simpleclient.rb +4 -0
  60. data/lib/rex/proto/sunrpc/client.rb +14 -3
  61. data/lib/rex/socket/comm/local.rb +10 -7
  62. data/lib/rex/socket/ssl_tcp_server.rb +79 -40
  63. data/lib/rex/ui/text/input/readline.rb +33 -6
  64. data/lib/rex/ui/text/output/file.rb +2 -2
  65. data/lib/rex/ui/text/output/stdio.rb +70 -14
  66. data/rex.gemspec +1 -1
  67. metadata +38 -3
@@ -0,0 +1,8 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/proto/kademlia/bootstrap_request'
4
+ require 'rex/proto/kademlia/bootstrap_response'
5
+ require 'rex/proto/kademlia/message'
6
+ require 'rex/proto/kademlia/ping'
7
+ require 'rex/proto/kademlia/pong'
8
+ require 'rex/proto/kademlia/util'
@@ -0,0 +1,19 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/proto/kademlia/message'
4
+
5
+ module Rex
6
+ module Proto
7
+ module Kademlia
8
+ # Opcode for a BOOTSTRAP request
9
+ BOOTSTRAP_REQUEST = 0x01
10
+
11
+ # A Kademlia bootstrap request message
12
+ class BootstrapRequest < Message
13
+ def initialize
14
+ super(BOOTSTRAP_REQUEST)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,79 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/proto/kademlia/message'
4
+ require 'rex/proto/kademlia/util'
5
+
6
+ module Rex
7
+ module Proto
8
+ module Kademlia
9
+ # Opcode for a bootstrap response
10
+ BOOTSTRAP_RESPONSE = 0x09
11
+
12
+ # A Kademlia bootstrap response message
13
+ class BootstrapResponse < Message
14
+ # @return [String] the ID of the peer that send the bootstrap response
15
+ attr_reader :peer_id
16
+ # @return [Integer] the TCP port that the responding peer is listening on
17
+ attr_reader :tcp_port
18
+ # @return [Integer] the version of this peer
19
+ attr_reader :version
20
+ # @return [Array<Hash<String, Object>>] the peer ID, IP address, UDP/TCP ports and version of each peer
21
+ attr_reader :peers
22
+
23
+ # Constructs a new bootstrap response
24
+ #
25
+ # @param peer_id [String] the ID of this peer
26
+ # @param tcp_port [Integer] the TCP port that this peer is listening on
27
+ # @param version [Integer] the version of this peer
28
+ # @param peers [Array<Hash<String, Object>>] the peer ID, IP address, UDP/TCP ports and version of each peer
29
+ def initialize(peer_id, tcp_port, version, peers)
30
+ @peer_id = peer_id
31
+ @tcp_port = tcp_port
32
+ @version = version
33
+ @peers = peers
34
+ end
35
+
36
+ # The minimum size of a peer in a KADEMLIA2_BOOTSTRAP_RES message:
37
+ # peer ID (16-bytes), IP (4 bytes), UDP port (2 bytes), TCP port (2 bytes)
38
+ # and version (1 byte)
39
+ BOOTSTRAP_PEER_SIZE = 25
40
+
41
+ # Builds a bootstrap response from given data
42
+ #
43
+ # @param data [String] the data to decode
44
+ # @return [BootstrapResponse] the bootstrap response if the data is valid, nil otherwise
45
+ def self.from_data(data)
46
+ message = Message.from_data(data)
47
+ # abort if this isn't a valid response
48
+ return unless message
49
+ return unless message.type == BOOTSTRAP_RESPONSE
50
+ return unless message.body.size >= 23
51
+ bootstrap_peer_id = Rex::Proto::Kademlia.decode_peer_id(message.body.slice!(0, 16))
52
+ bootstrap_tcp_port, bootstrap_version, num_peers = message.body.slice!(0, 5).unpack('vCv')
53
+ # protocol says there are no peers and the body confirms this, so just return with no peers
54
+ if num_peers == 0 && message.body.blank?
55
+ peers = []
56
+ else
57
+ peers_data = message.body
58
+ # peers data is too long/short, abort
59
+ return if peers_data.size % BOOTSTRAP_PEER_SIZE != 0
60
+ peers = []
61
+ until peers_data.blank?
62
+ peer_data = peers_data.slice!(0, BOOTSTRAP_PEER_SIZE)
63
+ peer_id = Rex::Proto::Kademlia.decode_peer_id(peer_data.slice!(0, 16))
64
+ ip, udp_port, tcp_port, version = peer_data.unpack('VvvC')
65
+ peers << {
66
+ id: peer_id,
67
+ ip: Rex::Socket.addr_itoa(ip),
68
+ tcp_port: tcp_port,
69
+ udp_port: udp_port,
70
+ version: version
71
+ }
72
+ end
73
+ end
74
+ BootstrapResponse.new(bootstrap_peer_id, bootstrap_tcp_port, bootstrap_version, peers)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,72 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ ##
6
+ #
7
+ # Minimal support for the newer Kademlia protocol, referred to here and often
8
+ # elsewhere as Kademlia2. It is unclear how this differs from the old protocol.
9
+ #
10
+ # Protocol details are hard to come by because most documentation is academic
11
+ # in nature and glosses over the low-level network details. The best
12
+ # documents I found on the protocol are:
13
+ #
14
+ # http://gbmaster.wordpress.com/2013/05/05/botnets-surrounding-us-an-initial-focus-on-kad/
15
+ # http://gbmaster.wordpress.com/2013/06/16/botnets-surrounding-us-sending-kademlia2_bootstrap_req-kademlia2_hello_req-and-their-strict-cousins/
16
+ # http://gbmaster.wordpress.com/2013/11/23/botnets-surrounding-us-performing-requests-sending-out-kademlia2_req-and-asking-contact-where-art-thou/
17
+ #
18
+ ##
19
+ module Kademlia
20
+ # A simple Kademlia message
21
+ class Message
22
+ # The header that non-compressed Kad messages use
23
+ STANDARD_PACKET = 0xE4
24
+ # The header that compressed Kad messages use, which is currently unsupported
25
+ COMPRESSED_PACKET = 0xE5
26
+
27
+ # @return [Integer] the message type
28
+ attr_reader :type
29
+ # @return [String] the message body
30
+ attr_reader :body
31
+
32
+ # Construct a new Message from the provided type and body
33
+ #
34
+ # @param type [String] the message type
35
+ # @param body [String] the message body
36
+ def initialize(type, body = '')
37
+ @type = type
38
+ @body = body
39
+ end
40
+
41
+ # Construct a new Message from the provided data
42
+ #
43
+ # @param data [String] the data to interpret as a Kademlia message
44
+ # @return [Message] the message if valid, nil otherwise
45
+ def self.from_data(data)
46
+ return if data.length < 2
47
+ header, type = data.unpack('CC')
48
+ if header == COMPRESSED_PACKET
49
+ fail NotImplementedError, "Unable to handle #{data.length}-byte compressed Kademlia message"
50
+ end
51
+ return if header != STANDARD_PACKET
52
+ Message.new(type, data[2, data.length])
53
+ end
54
+
55
+ # Get this Message as a String
56
+ #
57
+ # @return [String] the string representation of this Message
58
+ def to_str
59
+ [STANDARD_PACKET, @type].pack('CC') + @body
60
+ end
61
+
62
+ # Compares this Message and another Message for equality
63
+ #
64
+ # @param other [Message] the Message to compare
65
+ # @return [Boolean] true iff the two messages have equal types and bodies, false otherwise
66
+ def ==(other)
67
+ type == other.type && body == other.body
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/proto/kademlia/message'
4
+
5
+ module Rex
6
+ module Proto
7
+ module Kademlia
8
+ # Opcode for a PING request
9
+ PING = 0x60
10
+
11
+ # A Kademlia ping message.
12
+ class Ping < Message
13
+ def initialize
14
+ super(PING)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/proto/kademlia/message'
4
+
5
+ module Rex
6
+ module Proto
7
+ module Kademlia
8
+ # Opcode for a PING response
9
+ PONG = 0x61
10
+
11
+ # A Kademlia pong message.
12
+ class Pong < Message
13
+ # @return [Integer] the source port from which the PING was received
14
+ attr_reader :port
15
+
16
+ def initialize(port = nil)
17
+ super(PONG)
18
+ @port = port
19
+ end
20
+
21
+ # Builds a pong from given data
22
+ #
23
+ # @param data [String] the data to decode
24
+ # @return [Pong] the pong if the data is valid, nil otherwise
25
+ def self.from_data(data)
26
+ message = super(data)
27
+ return if message.type != PONG
28
+ return if message.body.size != 2
29
+ Pong.new(message.body.unpack('v')[0])
30
+ end
31
+
32
+ # Get this Pong as a String
33
+ #
34
+ # @return [String] the string representation of this Pong
35
+ def to_str
36
+ super + [@port].pack('v')
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Kademlia
6
+ # Decodes an on-the-wire representation of a Kademlia peer to its 16-character hex equivalent
7
+ #
8
+ # @param bytes [String] the on-the-wire representation of a Kademlia peer
9
+ # @return [String] the peer ID if valid, nil otherwise
10
+ def self.decode_peer_id(bytes)
11
+ peer_id = 0
12
+ return nil unless bytes.size == 16
13
+ bytes.unpack('VVVV').map { |p| peer_id = ((peer_id << 32) ^ p) }
14
+ peer_id.to_s(16).upcase
15
+ end
16
+
17
+ # TODO
18
+ # def encode_peer_id(id)
19
+ # end
20
+ end
21
+ end
22
+ end
@@ -3,8 +3,6 @@
3
3
  #
4
4
  # NAT-PMP protocol support
5
5
  #
6
- # by Jon Hart <jhart@spoofed.org>
7
- #
8
6
  ##
9
7
 
10
8
  module Rex
@@ -16,6 +14,20 @@ module NATPMP
16
14
  [ 0, 0 ].pack('nn')
17
15
  end
18
16
 
17
+ def get_external_address(udp_sock, host, port, timeout=1)
18
+ vprint_status("#{host}:#{port} - Probing NAT-PMP for external address")
19
+ udp_sock.sendto(external_address_request, host, port, 0)
20
+ external_address = nil
21
+ while (r = udp_sock.recvfrom(12, timeout) and r[1])
22
+ (ver, op, result, epoch, external_address) = parse_external_address_response(r[0])
23
+ if external_address
24
+ vprint_good("#{host}:#{port} - NAT-PMP external address is #{external_address}")
25
+ break
26
+ end
27
+ end
28
+ external_address
29
+ end
30
+
19
31
  # Parse a NAT-PMP external address response +resp+.
20
32
  # Returns the decoded parts of the response as an array.
21
33
  def parse_external_address_response(resp)
@@ -23,6 +35,21 @@ module NATPMP
23
35
  [ ver, op, result, epoch, Rex::Socket::addr_itoa(addr) ]
24
36
  end
25
37
 
38
+ def map_port(udp_sock, host, port, int_port, ext_port, protocol, lifetime, timeout=1)
39
+ vprint_status("#{host}:#{port} - Sending NAT-PMP mapping request")
40
+ # build the mapping request
41
+ req = map_port_request(int_port, ext_port,
42
+ Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), datastore['LIFETIME'])
43
+ # send it
44
+ udp_sock.sendto(req, host, datastore['RPORT'], 0)
45
+ # handle the reply
46
+ while (r = udp_sock.recvfrom(16, timeout) and r[1])
47
+ (_, _, result, _, _, actual_ext_port, _) = parse_map_port_response(r[0])
48
+ return (result == 0 ? actual_ext_port : nil)
49
+ end
50
+ nil
51
+ end
52
+
26
53
  # Return a NAT-PMP request to map remote port +rport+/+protocol+ to local port +lport+ for +lifetime+ ms
27
54
  def map_port_request(lport, rport, protocol, lifetime)
28
55
  [ Rex::Proto::NATPMP::Version, # version
@@ -39,6 +66,7 @@ module NATPMP
39
66
  def parse_map_port_response(resp)
40
67
  resp.unpack("CCnNnnN")
41
68
  end
69
+
42
70
  end
43
71
 
44
72
  end
@@ -0,0 +1,3 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/proto/quake/message'
@@ -0,0 +1,73 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ ##
6
+ #
7
+ # Quake 3 protocol, taken from ftp://ftp.idsoftware.com/idstuff/quake3/docs/server.txt
8
+ #
9
+ ##
10
+ module Quake
11
+ HEADER = 0xFFFFFFFF
12
+
13
+ def decode_message(message)
14
+ # minimum size is header (4) + <command> + <stuff>
15
+ return if message.length < 7
16
+ header = message.unpack('N')[0]
17
+ return if header != HEADER
18
+ message[4, message.length]
19
+ end
20
+
21
+ def encode_message(payload)
22
+ [HEADER].pack('N') + payload
23
+ end
24
+
25
+ def getstatus
26
+ encode_message('getstatus')
27
+ end
28
+
29
+ def getinfo
30
+ encode_message('getinfo')
31
+ end
32
+
33
+ def decode_infostring(infostring)
34
+ # decode an "infostring", which is just a (supposedly) quoted string of tokens separated
35
+ # by backslashes, generally terminated with a newline
36
+ token_re = /([^\\]+)\\([^\\]+)/
37
+ return nil unless infostring =~ token_re
38
+ # remove possibly present leading/trailing double quote
39
+ infostring.gsub!(/(?:^"|"$)/, '')
40
+ # remove the trailing \n, if present
41
+ infostring.gsub!(/\n$/, '')
42
+ # split on backslashes and group into key value pairs
43
+ infohash = {}
44
+ infostring.scan(token_re).each do |kv|
45
+ infohash[kv.first] = kv.last
46
+ end
47
+ infohash
48
+ end
49
+
50
+ def decode_response(message, type)
51
+ resp = decode_message(message)
52
+ if /^print\n(?<error>.*)\n?/m =~ resp
53
+ # XXX: is there a better exception to throw here?
54
+ fail ::ArgumentError, "#{type} error: #{error}"
55
+ # why doesn't this work?
56
+ # elsif /^#{type}Response\n(?<infostring>.*)/m =~ resp
57
+ elsif resp =~ /^#{type}Response\n(.*)/m
58
+ decode_infostring(Regexp.last_match(1))
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
64
+ def decode_status(message)
65
+ decode_response(message, 'status')
66
+ end
67
+
68
+ def decode_info(message)
69
+ decode_response(message, 'info')
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1872,6 +1872,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
1872
1872
 
1873
1873
  # Enumerates a specific path on the mounted tree
1874
1874
  def find_first(path)
1875
+ sid = nil
1875
1876
  files = { }
1876
1877
  parm = [
1877
1878
  26, # Search for ALL files
@@ -66,6 +66,10 @@ attr_accessor :socket, :client, :direct, :shares, :last_share
66
66
 
67
67
  self.client.spnopt = spnopt
68
68
 
69
+ # In case the user unsets the password option, we make sure this is
70
+ # always a string
71
+ pass ||= ''
72
+
69
73
  ok = self.client.session_setup(user, pass, domain)
70
74
  rescue ::Interrupt
71
75
  raise $!
@@ -6,10 +6,21 @@ module Rex
6
6
  module Proto
7
7
  module SunRPC
8
8
 
9
+ class RPCError < ::StandardError
10
+ def initialize(msg = 'RPC operation failed')
11
+ super
12
+ @msg = msg
13
+ end
14
+
15
+ def to_s
16
+ @msg
17
+ end
18
+ end
19
+
9
20
  class RPCTimeout < ::Interrupt
10
- def initialize(msg = 'Operation timed out.')
11
- @msg = msg
12
- end
21
+ def initialize(msg = 'Operation timed out.')
22
+ @msg = msg
23
+ end
13
24
 
14
25
  def to_s
15
26
  @msg