rex 2.0.8 → 2.0.9

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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rex.rb +1 -0
  3. data/lib/rex/arch.rb +5 -0
  4. data/lib/rex/arch/x86.rb +19 -5
  5. data/lib/rex/arch/zarch.rb +17 -0
  6. data/lib/rex/compat.rb +5 -4
  7. data/lib/rex/constants.rb +3 -1
  8. data/lib/rex/encoder/alpha2/alpha_mixed.rb +70 -9
  9. data/lib/rex/encoder/alpha2/alpha_upper.rb +67 -8
  10. data/lib/rex/exploitation/cmdstager.rb +1 -0
  11. data/lib/rex/exploitation/cmdstager/certutil.rb +115 -0
  12. data/lib/rex/exploitation/cmdstager/echo.rb +6 -3
  13. data/lib/rex/exploitation/egghunter.rb +1 -1
  14. data/lib/rex/google/geolocation.rb +68 -0
  15. data/lib/rex/io/bidirectional_pipe.rb +0 -4
  16. data/lib/rex/java/serialization.rb +2 -0
  17. data/lib/rex/java/serialization/decode_error.rb +11 -0
  18. data/lib/rex/java/serialization/encode_error.rb +11 -0
  19. data/lib/rex/java/serialization/model.rb +2 -0
  20. data/lib/rex/java/serialization/model/annotation.rb +3 -3
  21. data/lib/rex/java/serialization/model/block_data.rb +3 -3
  22. data/lib/rex/java/serialization/model/block_data_long.rb +3 -3
  23. data/lib/rex/java/serialization/model/class_desc.rb +6 -6
  24. data/lib/rex/java/serialization/model/contents.rb +17 -10
  25. data/lib/rex/java/serialization/model/field.rb +12 -11
  26. data/lib/rex/java/serialization/model/long_utf.rb +3 -3
  27. data/lib/rex/java/serialization/model/new_array.rb +22 -23
  28. data/lib/rex/java/serialization/model/new_class.rb +57 -0
  29. data/lib/rex/java/serialization/model/new_class_desc.rb +15 -16
  30. data/lib/rex/java/serialization/model/new_enum.rb +5 -5
  31. data/lib/rex/java/serialization/model/new_object.rb +22 -17
  32. data/lib/rex/java/serialization/model/proxy_class_desc.rb +109 -0
  33. data/lib/rex/java/serialization/model/reference.rb +4 -4
  34. data/lib/rex/java/serialization/model/stream.rb +7 -7
  35. data/lib/rex/java/serialization/model/utf.rb +3 -3
  36. data/lib/rex/json_hash_file.rb +94 -0
  37. data/lib/rex/logging/log_sink.rb +1 -0
  38. data/lib/rex/logging/sinks/timestamp_flatfile.rb +21 -0
  39. data/lib/rex/parser/appscan_nokogiri.rb +13 -23
  40. data/lib/rex/parser/fs/ntfs.rb +10 -5
  41. data/lib/rex/parser/nmap_nokogiri.rb +3 -1
  42. data/lib/rex/parser/openvas_nokogiri.rb +70 -73
  43. data/lib/rex/parser/winscp.rb +108 -0
  44. data/lib/rex/parser/x509_certificate.rb +92 -0
  45. data/lib/rex/payloads.rb +0 -1
  46. data/lib/rex/payloads/meterpreter/config.rb +154 -0
  47. data/lib/rex/payloads/meterpreter/uri_checksum.rb +136 -0
  48. data/lib/rex/post/meterpreter.rb +1 -1
  49. data/lib/rex/post/meterpreter/client.rb +26 -3
  50. data/lib/rex/post/meterpreter/client_core.rb +387 -75
  51. data/lib/rex/post/meterpreter/extensions/android/android.rb +127 -37
  52. data/lib/rex/post/meterpreter/extensions/android/tlv.rb +46 -25
  53. data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +4 -0
  54. data/lib/rex/post/meterpreter/extensions/extapi/ntds/ntds.rb +39 -0
  55. data/lib/rex/post/meterpreter/extensions/extapi/pageant/pageant.rb +44 -0
  56. data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +9 -0
  57. data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +16 -1
  58. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +1 -1
  59. data/lib/rex/post/meterpreter/extensions/python/python.rb +114 -0
  60. data/lib/rex/post/meterpreter/extensions/python/tlv.rb +21 -0
  61. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +17 -14
  62. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +33 -12
  63. data/lib/rex/post/meterpreter/extensions/stdapi/fs/mount.rb +57 -0
  64. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3 -3
  65. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +3 -1
  66. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +2 -0
  67. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -3
  68. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +29 -6
  69. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +5 -1
  70. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +18 -6
  71. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +2 -2
  72. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +34 -36
  73. data/lib/rex/post/meterpreter/packet.rb +29 -0
  74. data/lib/rex/post/meterpreter/packet_dispatcher.rb +20 -7
  75. data/lib/rex/post/meterpreter/ui/console.rb +1 -0
  76. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +230 -72
  77. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +544 -34
  78. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +188 -57
  79. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +115 -93
  80. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +1 -1
  81. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +1 -1
  82. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +49 -15
  83. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +11 -2
  84. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/python.rb +187 -0
  85. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +324 -133
  86. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +52 -2
  87. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +68 -65
  88. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +9 -1
  89. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +113 -118
  90. data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +3 -0
  91. data/lib/rex/powershell.rb +62 -0
  92. data/lib/rex/powershell/command.rb +359 -0
  93. data/lib/rex/{exploitation/powershell → powershell}/function.rb +0 -2
  94. data/lib/rex/{exploitation/powershell → powershell}/obfu.rb +0 -2
  95. data/lib/rex/{exploitation/powershell → powershell}/output.rb +11 -5
  96. data/lib/rex/{exploitation/powershell → powershell}/param.rb +0 -2
  97. data/lib/rex/powershell/parser.rb +182 -0
  98. data/lib/rex/powershell/payload.rb +78 -0
  99. data/lib/rex/{exploitation/powershell → powershell}/psh_methods.rb +16 -2
  100. data/lib/rex/{exploitation/powershell → powershell}/script.rb +2 -4
  101. data/lib/rex/proto/dcerpc/client.rb +6 -6
  102. data/lib/rex/proto/dcerpc/exceptions.rb +26 -0
  103. data/lib/rex/proto/http/client.rb +3 -3
  104. data/lib/rex/proto/http/client_request.rb +0 -5
  105. data/lib/rex/proto/http/response.rb +86 -0
  106. data/lib/rex/proto/ipmi/utils.rb +30 -26
  107. data/lib/rex/proto/kerberos/client.rb +1 -1
  108. data/lib/rex/proto/kerberos/model/kdc_request.rb +2 -2
  109. data/lib/rex/proto/rfb/client.rb +8 -3
  110. data/lib/rex/proto/rfb/constants.rb +1 -1
  111. data/lib/rex/proto/rmi.rb +2 -0
  112. data/lib/rex/proto/rmi/decode_error.rb +10 -0
  113. data/lib/rex/proto/rmi/exception.rb +10 -0
  114. data/lib/rex/proto/rmi/model.rb +5 -0
  115. data/lib/rex/proto/rmi/model/call.rb +4 -4
  116. data/lib/rex/proto/rmi/model/call_data.rb +137 -0
  117. data/lib/rex/proto/rmi/model/dgc_ack.rb +2 -2
  118. data/lib/rex/proto/rmi/model/element.rb +26 -11
  119. data/lib/rex/proto/rmi/model/output_header.rb +4 -4
  120. data/lib/rex/proto/rmi/model/ping.rb +2 -2
  121. data/lib/rex/proto/rmi/model/ping_ack.rb +2 -2
  122. data/lib/rex/proto/rmi/model/protocol_ack.rb +2 -2
  123. data/lib/rex/proto/rmi/model/return_data.rb +5 -5
  124. data/lib/rex/proto/rmi/model/return_value.rb +124 -0
  125. data/lib/rex/proto/rmi/model/unique_identifier.rb +77 -0
  126. data/lib/rex/proto/steam.rb +3 -0
  127. data/lib/rex/proto/steam/message.rb +125 -0
  128. data/lib/rex/proto/tftp/client.rb +35 -14
  129. data/lib/rex/random_identifier_generator.rb +2 -0
  130. data/lib/rex/ropbuilder.rb +1 -1
  131. data/lib/rex/socket/parameters.rb +9 -0
  132. data/lib/rex/socket/ssl_tcp.rb +25 -41
  133. data/lib/rex/socket/ssl_tcp_server.rb +10 -21
  134. data/lib/rex/sslscan/result.rb +20 -1
  135. data/lib/rex/text.rb +241 -55
  136. data/lib/rex/ui/output.rb +0 -3
  137. data/lib/rex/ui/subscriber.rb +0 -10
  138. data/lib/rex/ui/text/color.rb +9 -0
  139. data/lib/rex/ui/text/dispatcher_shell.rb +1 -0
  140. data/lib/rex/ui/text/output.rb +15 -4
  141. data/lib/rex/ui/text/output/file.rb +1 -0
  142. data/lib/rex/ui/text/output/stdio.rb +0 -16
  143. data/lib/rex/ui/text/shell.rb +3 -0
  144. data/lib/rex/ui/text/table.rb +85 -19
  145. data/lib/rex/user_agent.rb +118 -0
  146. data/rex.gemspec +2 -2
  147. metadata +41 -14
  148. data/lib/rex/exploitation/powershell.rb +0 -62
  149. data/lib/rex/exploitation/powershell/parser.rb +0 -183
  150. data/lib/rex/payloads/meterpreter.rb +0 -2
  151. data/lib/rex/payloads/meterpreter/patch.rb +0 -136
@@ -15,6 +15,12 @@ module Parser
15
15
  attrs = normalize_attrs(attrs)
16
16
  block = @block
17
17
  @state[:current_tag][name] = true
18
+
19
+ unless @text.nil?
20
+ @state[:text_backup] = @text
21
+ @text = nil
22
+ end
23
+
18
24
  case name
19
25
  when "host"
20
26
  @state[:has_text] = true
@@ -25,97 +31,90 @@ module Parser
25
31
  def end_element(name=nil)
26
32
  block = @block
27
33
  case name
28
- when "name"
29
- return if not in_tag("result")
30
- @state[:has_text] = true
31
- @state[:vuln_name] = @text.strip if @text
32
- @text = nil
33
- when "description"
34
+ when 'name'
35
+ if in_tag('result')
36
+ @state[:has_text] = true
37
+ @state[:vuln_name] = @text.strip if @text
38
+ end
39
+ when 'description'
34
40
  @state[:has_text] = true
35
41
  @state[:vuln_desc] = @text.strip if @text
36
- @text = nil
37
- when "bid"
38
- return if not in_tag("result")
39
- return if not in_tag("nvt")
40
- @state[:has_text] = true
41
- @state[:bid] = @text.strip if @text
42
- @text = nil
43
- when "cve"
44
- return if not in_tag("result")
45
- return if not in_tag("nvt")
46
- @state[:has_text] = true
47
- @state[:cves] = @text.strip if @text
48
- @text = nil
49
- when "risk_factor"
50
- return if not in_tag("result")
51
- return if not in_tag("nvt")
52
-
53
- #we do this to clean out the buffer so to speak
54
- #if we don't set text to nil now, the text will show up later
55
- @state[:has_text] = true
56
- @text = nil
57
- when "cvss_base"
58
- return if not in_tag("result")
59
- return if not in_tag("nvt")
60
- @state[:has_text] = true
61
- @text = nil
62
- when "subnet"
63
- @state[:has_text] = true
64
- @text = nil
65
- when "result"
66
- return if not in_tag("results")
67
- record_vuln
68
- when "threat"
69
- return if not in_tag("ports")
70
- return if not in_tag("port")
71
- @state[:has_text] = true
72
-
73
- if not @text.index('(')
74
- @state[:name] = nil
75
- @state[:port] = nil
76
- @state[:proto] = nil
77
- @text = nil
78
- return
42
+ when 'bid'
43
+ if in_tag('result') && in_tag('nvt')
44
+ @state[:has_text] = true
45
+ @state[:bid] = @text.strip if @text
79
46
  end
80
-
81
- @state[:name] = @text.split(' ')[0] if @text
82
- @state[:port] = @text.split('(')[1].split('/')[0] if @text
83
- @state[:proto] = @text.split('(')[1].split('/')[1].split(')')[0] if @text
84
-
85
- @text = nil
86
- when "host"
47
+ when 'cve'
48
+ if in_tag('result') && in_tag('nvt')
49
+ @state[:has_text] = true
50
+ @state[:cves] = @text.strip if @text
51
+ end
52
+ when 'risk_factor'
53
+ if in_tag('result') && in_tag('nvt')
54
+ #we do this to clean out the buffer so to speak
55
+ #if we don't set text to nil now, the text will show up later
56
+ @state[:has_text] = true
57
+ end
58
+ when 'cvss_base'
59
+ if in_tag('result') && in_tag('nvt')
60
+ @state[:has_text] = true
61
+ end
62
+ when 'subnet'
63
+ @state[:has_text] = true
64
+ when 'result'
65
+ record_vuln if in_tag('results')
66
+ when 'threat'
67
+ @state[:has_text] = true if in_tag('ports') && in_tag('port')
68
+ when 'host'
87
69
  if in_tag('result')
88
70
  @state[:has_text] = true
89
71
  @state[:host] = @text.strip if @text
90
- @text = nil
91
- elsif in_tag('ports')
92
- return if not in_tag('port')
72
+ elsif in_tag('ports') && in_tag('port')
93
73
  @state[:has_text] = true
94
74
  @state[:host] = @text.strip if @text
95
- @text = nil
96
75
  end
97
- when "port"
76
+ when 'port'
98
77
  if in_tag('result')
99
78
  @state[:has_text] = true
100
- if not @text.index('(')
79
+ if @text && @text.index('(')
80
+ @state[:proto] = @text.split('(')[1].split('/')[1].gsub(/\)/, '')
81
+ @state[:port] = @text.split('(')[1].split('/')[0].gsub(/\)/, '')
82
+ elsif @text && @text.index('/')
83
+ @state[:proto] = @text.split('/')[1].strip
84
+ @state[:port] = @text.split('/')[0].strip
85
+ else
86
+ @state[:proto] = nil
87
+ @state[:port] = nil
88
+ end
89
+
90
+ if @state[:port] && @state[:port] == 'general'
101
91
  @state[:proto] = nil
102
92
  @state[:port] = nil
103
- @text = nil
104
- return
105
93
  end
106
- @state[:proto] = @text.split('(')[0].strip if @text
107
- @state[:port] = @text.split('(')[1].split('/')[0].gsub(/\)/, '') if @text
108
- @text = nil
109
94
  elsif in_tag('ports')
110
- record_service
95
+ if @text && @text.index('(')
96
+ @state[:name] = @text.split(' ')[0]
97
+ @state[:port] = @text.split('(')[1].split('/')[0]
98
+ @state[:proto] = @text.split('(')[1].split('/')[1].split(')')[0]
99
+ record_service unless @state[:name].nil?
100
+ elsif @text && @text.index('/')
101
+ @state[:port] = @text.split('/')[0]
102
+ @state[:proto] = @text.split('/')[1]
103
+ record_service unless @state[:port] == 'general'
104
+ end
111
105
  end
112
- when "name"
113
- return if not in_tag("result")
106
+ when 'name'
107
+ return if not in_tag('result')
114
108
  @state[:has_text] = true
115
- @text = nil
109
+ end
110
+
111
+ if @state[:text_backup]
112
+ @text = @state[:text_backup]
113
+ @state[:text_backup] = nil
116
114
  else
117
115
  @text = nil
118
116
  end
117
+
119
118
  @state[:current_tag].delete name
120
119
  end
121
120
 
@@ -153,8 +152,6 @@ module Parser
153
152
  end
154
153
 
155
154
  def record_service
156
- return if not @state[:name]
157
-
158
155
  service_info = {}
159
156
  service_info[:host] = @state[:host]
160
157
  service_info[:name] = @state[:name]
@@ -0,0 +1,108 @@
1
+ require 'rex/parser/ini'
2
+
3
+ module Rex
4
+ module Parser
5
+ module WinSCP
6
+ PWDALG_SIMPLE_MAGIC = 0xA3
7
+ PWDALG_SIMPLE_FLAG = 0xFF
8
+
9
+ def read_and_parse_ini(filename)
10
+ file = File.read(filename)
11
+ return if file.to_s.empty?
12
+ parse_ini(file)
13
+ end
14
+
15
+ def parse_protocol(fsprotocol)
16
+ return 'Unknown' if fsprotocol.nil?
17
+
18
+ case fsprotocol
19
+ when 5 then 'FTP'
20
+ when 0 then 'SSH'
21
+ else
22
+ 'Unknown'
23
+ end
24
+ end
25
+
26
+ def parse_ini(file)
27
+ results = []
28
+ raise RuntimeError, 'No data to parse' if file.nil? || file.empty?
29
+
30
+ ini = Rex::Parser::Ini.from_s(file)
31
+
32
+ if ini['Configuration\\Security']
33
+ # if a Master Password is in use we give up
34
+ if ini['Configuration\\Security']['UseMasterPassword'].to_i == 1
35
+ raise RuntimeError, 'Master Password Set, unable to recover saved passwords!'
36
+ end
37
+ end
38
+
39
+ # Runs through each group in the ini file looking for all of the Sessions
40
+ ini.each_key do |group|
41
+ if group.include?('Sessions') && ini[group].has_key?('Password')
42
+ # Decrypt our password, and report on results
43
+ encrypted_password = ini[group]['Password']
44
+ user = ini[group]['UserName']
45
+ host = ini[group]['HostName']
46
+ sname = parse_protocol(ini[group]['FSProtocol'].to_i)
47
+ plaintext = decrypt_password(encrypted_password, "#{user}#{host}")
48
+
49
+ results << {
50
+ hostname: host,
51
+ password: plaintext,
52
+ portnumber: ini[group]['PortNumber'] || 22,
53
+ username: user,
54
+ protocol: sname
55
+ }
56
+ end
57
+ end
58
+
59
+ results
60
+ end
61
+
62
+ # Decrypts the next character in the password sequence
63
+ def decrypt_next_char(pwd)
64
+ if pwd.nil? || pwd.length <= 0
65
+ return 0, pwd
66
+ end
67
+
68
+ # Takes the first char from the encrypted password and then left shifts the returned index by 4 bits
69
+ a = pwd[0].hex << 4
70
+
71
+ # Takes the second char from the encrypted password
72
+ b = pwd[1].hex
73
+
74
+ # Adds the two results, XORs against 0xA3, NOTs it and then ANDs it with 0xFF
75
+ result = ~((a + b) ^ PWDALG_SIMPLE_MAGIC) & PWDALG_SIMPLE_FLAG
76
+
77
+ # Strips the first two chars off and returns our result
78
+ return result, pwd[2..-1]
79
+ end
80
+
81
+ def decrypt_password(pwd, key)
82
+ flag, pwd = decrypt_next_char(pwd)
83
+
84
+ if flag == PWDALG_SIMPLE_FLAG
85
+ _, pwd = decrypt_next_char(pwd)
86
+ length, pwd = decrypt_next_char(pwd)
87
+ else
88
+ length = flag
89
+ end
90
+
91
+ del, pwd = decrypt_next_char(pwd)
92
+ pwd = pwd[del*2..-1]
93
+
94
+ result = ""
95
+ length.times do
96
+ r, pwd = decrypt_next_char(pwd)
97
+ result << r.chr
98
+ end
99
+
100
+ if flag == PWDALG_SIMPLE_FLAG
101
+ result = result[key.length..-1]
102
+ end
103
+
104
+ result
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,92 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'openssl'
4
+
5
+ module Rex
6
+ module Parser
7
+
8
+ ###
9
+ #
10
+ # This class parses the contents of a PEM-encoded X509 certificate file containing
11
+ # a private key, a public key, and any appended glue certificates.
12
+ #
13
+ ###
14
+ class X509Certificate
15
+
16
+ #
17
+ # Parse a certificate in unified PEM format that contains a private key and
18
+ # one or more certificates. The first certificate is the primary, while any
19
+ # additional certificates are treated as intermediary certificates. This emulates
20
+ # the behavior of web servers like nginx.
21
+ #
22
+ # @param [String] ssl_cert
23
+ # @return [String, String, Array]
24
+ def self.parse_pem(ssl_cert)
25
+ cert = nil
26
+ key = nil
27
+ chain = nil
28
+
29
+ certs = []
30
+ ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
31
+ if pem =~ /PRIVATE KEY/
32
+ key = OpenSSL::PKey::RSA.new(pem)
33
+ elsif pem =~ /CERTIFICATE/
34
+ certs << OpenSSL::X509::Certificate.new(pem)
35
+ end
36
+ end
37
+
38
+ cert = certs.shift
39
+ if certs.length > 0
40
+ chain = certs
41
+ end
42
+
43
+ [key, cert, chain]
44
+ end
45
+
46
+ #
47
+ # Parse a certificate in unified PEM format from a file
48
+ #
49
+ # @param [String] ssl_cert_file
50
+ # @return [String, String, Array]
51
+ def self.parse_pem_file(ssl_cert_file)
52
+ data = ''
53
+ ::File.open(ssl_cert_file, 'rb') do |fd|
54
+ data << fd.read(fd.stat.size)
55
+ end
56
+ parse_pem(data)
57
+ end
58
+
59
+ #
60
+ # Parse a certificate in unified PEM format and retrieve
61
+ # the SHA1 hash.
62
+ #
63
+ # @param [String] ssl_cert
64
+ # @return [String]
65
+ def self.get_cert_hash(ssl_cert)
66
+ hcert = parse_pem(ssl_cert)
67
+
68
+ unless hcert and hcert[0] and hcert[1]
69
+ raise ArgumentError, "Could not parse a private key and certificate"
70
+ end
71
+
72
+ Rex::Text.sha1_raw(hcert[1].to_der)
73
+ end
74
+
75
+ #
76
+ # Parse a file that contains a certificate in unified PEM
77
+ # format and retrieve the SHA1 hash.
78
+ #
79
+ # @param [String] ssl_cert_file
80
+ # @return [String]
81
+ def self.get_cert_file_hash(ssl_cert_file)
82
+ data = ''
83
+ ::File.open(ssl_cert_file, 'rb') do |fd|
84
+ data << fd.read(fd.stat.size)
85
+ end
86
+ get_cert_hash(data)
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+ end
data/lib/rex/payloads.rb CHANGED
@@ -1,3 +1,2 @@
1
1
  # -*- coding: binary -*-
2
2
  require 'rex/payloads/win32'
3
- require 'rex/payloads/meterpreter'
@@ -0,0 +1,154 @@
1
+ # -*- coding: binary -*-
2
+ require 'msf/core/payload/uuid'
3
+ require 'msf/core/payload/windows'
4
+ require 'msf/core/reflective_dll_loader'
5
+ require 'rex/parser/x509_certificate'
6
+
7
+ class Rex::Payloads::Meterpreter::Config
8
+
9
+ include Msf::ReflectiveDLLLoader
10
+
11
+ URL_SIZE = 512
12
+ UA_SIZE = 256
13
+ PROXY_HOST_SIZE = 128
14
+ PROXY_USER_SIZE = 64
15
+ PROXY_PASS_SIZE = 64
16
+ CERT_HASH_SIZE = 20
17
+
18
+ def initialize(opts={})
19
+ @opts = opts
20
+ if opts[:ascii_str] == true
21
+ @to_str = self.method(:to_ascii)
22
+ else
23
+ @to_str = self.method(:to_wchar_t)
24
+ end
25
+ end
26
+
27
+ def to_b
28
+ config_block
29
+ end
30
+
31
+ private
32
+
33
+ def is_x86?
34
+ @opts[:arch] == ARCH_X86
35
+ end
36
+
37
+ def to_str(item, size)
38
+ @to_str.call(item, size)
39
+ end
40
+
41
+ def to_wchar_t(item, size)
42
+ to_ascii(item, size).unpack('C*').pack('v*')
43
+ end
44
+
45
+ def to_ascii(item, size)
46
+ item.to_s.ljust(size, "\x00")
47
+ end
48
+
49
+ def session_block(opts)
50
+ uuid = opts[:uuid].to_raw
51
+ exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]
52
+
53
+ session_data = [
54
+ 0, # comms socket, patched in by the stager
55
+ exit_func, # exit function identifer
56
+ opts[:expiration], # Session expiry
57
+ uuid # the UUID
58
+ ]
59
+
60
+ session_data.pack('VVVA*')
61
+ end
62
+
63
+ def transport_block(opts)
64
+ # Build the URL from the given parameters, and pad it out to the
65
+ # correct size
66
+ lhost = opts[:lhost]
67
+ if lhost && opts[:scheme].start_with?('http') && Rex::Socket.is_ipv6?(lhost)
68
+ lhost = "[#{lhost}]"
69
+ end
70
+
71
+ url = "#{opts[:scheme]}://#{lhost}:#{opts[:lport]}"
72
+ url << "#{opts[:uri]}/" if opts[:uri]
73
+ url << "?#{opts[:scope_id]}" if opts[:scope_id]
74
+
75
+ # if the transport URI is for a HTTP payload we need to add a stack
76
+ # of other stuff
77
+ pack = 'A*VVV'
78
+ transport_data = [
79
+ to_str(url, URL_SIZE), # transport URL
80
+ opts[:comm_timeout], # communications timeout
81
+ opts[:retry_total], # retry total time
82
+ opts[:retry_wait] # retry wait time
83
+ ]
84
+
85
+ if url.start_with?('http')
86
+ proxy_host = ''
87
+ if opts[:proxy_host] && opts[:proxy_port]
88
+ prefix = 'http://'
89
+ prefix = 'socks=' if opts[:proxy_type].downcase == 'socks'
90
+ proxy_host = "#{prefix}#{opts[:proxy_host]}:#{opts[:proxy_port]}"
91
+ end
92
+ proxy_host = to_str(proxy_host || '', PROXY_HOST_SIZE)
93
+ proxy_user = to_str(opts[:proxy_user] || '', PROXY_USER_SIZE)
94
+ proxy_pass = to_str(opts[:proxy_pass] || '', PROXY_PASS_SIZE)
95
+ ua = to_str(opts[:ua] || '', UA_SIZE)
96
+
97
+ cert_hash = "\x00" * CERT_HASH_SIZE
98
+ cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash]
99
+
100
+ # add the HTTP specific stuff
101
+ transport_data << proxy_host # Proxy host name
102
+ transport_data << proxy_user # Proxy user name
103
+ transport_data << proxy_pass # Proxy password
104
+ transport_data << ua # HTTP user agent
105
+ transport_data << cert_hash # SSL cert hash for verification
106
+
107
+ # update the packing spec
108
+ pack << 'A*A*A*A*A*'
109
+ end
110
+
111
+ # return the packed transport information
112
+ transport_data.pack(pack)
113
+ end
114
+
115
+ def extension_block(ext_name, file_extension)
116
+ ext_name = ext_name.strip.downcase
117
+ ext, o = load_rdi_dll(MetasploitPayloads.meterpreter_path("ext_server_#{ext_name}",
118
+ file_extension))
119
+
120
+ extension_data = [ ext.length, ext ].pack('VA*')
121
+ end
122
+
123
+ def config_block
124
+ # start with the session information
125
+ config = session_block(@opts)
126
+
127
+ # then load up the transport configurations
128
+ (@opts[:transports] || []).each do |t|
129
+ config << transport_block(t)
130
+ end
131
+
132
+ # terminate the transports with NULL (wchar)
133
+ config << "\x00\x00"
134
+
135
+ # configure the extensions - this will have to change when posix comes
136
+ # into play.
137
+ file_extension = 'x86.dll'
138
+ file_extension = 'x64.dll' unless is_x86?
139
+
140
+ (@opts[:extensions] || []).each do |e|
141
+ config << extension_block(e, file_extension)
142
+ end
143
+
144
+ # terminate the extensions with a 0 size
145
+ if is_x86?
146
+ config << [0].pack('V')
147
+ else
148
+ config << [0].pack('Q<')
149
+ end
150
+
151
+ # and we're done
152
+ config
153
+ end
154
+ end