librex 0.0.6 → 0.0.7

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 (51) hide show
  1. data/README.md +3 -5
  2. data/Rakefile +26 -0
  3. data/lib/rex/compat.rb +1 -1
  4. data/lib/rex/exploitation/javascriptosdetect.rb +125 -62
  5. data/lib/rex/file.rb +15 -0
  6. data/lib/rex/io/stream.rb +1 -1
  7. data/lib/rex/parser/nmap_xml.rb +6 -0
  8. data/lib/rex/poly/block.rb +9 -0
  9. data/lib/rex/post/meterpreter/client.rb +0 -8
  10. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +6 -0
  11. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +1 -1
  12. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +49 -35
  13. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +26 -0
  14. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +9 -2
  15. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +630 -0
  16. data/lib/rex/post/meterpreter/packet.rb +3 -1
  17. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +143 -57
  18. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +6 -0
  19. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +9 -3
  20. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +6 -4
  21. data/lib/rex/proto.rb +1 -0
  22. data/lib/rex/proto/dhcp/server.rb +4 -2
  23. data/lib/rex/proto/http/packet.rb +5 -6
  24. data/lib/rex/proto/ntlm.rb +7 -0
  25. data/lib/rex/proto/ntlm.rb.ut.rb +177 -0
  26. data/lib/rex/proto/ntlm/base.rb +326 -0
  27. data/lib/rex/proto/ntlm/constants.rb +74 -0
  28. data/lib/rex/proto/ntlm/crypt.rb +340 -0
  29. data/lib/rex/proto/ntlm/exceptions.rb +9 -0
  30. data/lib/rex/proto/ntlm/message.rb +533 -0
  31. data/lib/rex/proto/ntlm/utils.rb +358 -0
  32. data/lib/rex/proto/smb/client.rb +548 -86
  33. data/lib/rex/proto/smb/client.rb.ut.rb +4 -4
  34. data/lib/rex/proto/smb/constants.rb +7 -24
  35. data/lib/rex/proto/smb/crypt.rb +12 -71
  36. data/lib/rex/proto/smb/exceptions.rb +12 -0
  37. data/lib/rex/proto/smb/simpleclient.rb +17 -5
  38. data/lib/rex/proto/smb/utils.rb +3 -460
  39. data/lib/rex/proto/tftp/server.rb +2 -2
  40. data/lib/rex/script/base.rb +2 -2
  41. data/lib/rex/socket.rb +12 -0
  42. data/lib/rex/socket.rb.ut.rb +31 -10
  43. data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +15 -5
  44. data/lib/rex/text.rb +55 -4
  45. data/lib/rex/ui/output.rb +0 -2
  46. data/lib/rex/ui/text/dispatcher_shell.rb +95 -10
  47. data/lib/rex/ui/text/output/buffer.rb +0 -4
  48. data/lib/rex/ui/text/shell.rb +8 -0
  49. data/lib/rex/ui/text/table.rb +21 -1
  50. metadata +15 -19
  51. data/lib/rex/proto/smb/crypt.rb.ut.rb +0 -20
@@ -50,7 +50,7 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
50
50
  assert_kind_of(Rex::Struct2::CStruct, ok)
51
51
 
52
52
  # puts "[*] Authenticating with NTLMv2..."
53
- ok = c.session_setup_ntlmv2($_REX_TEXT_SMB_USER, $_REX_TEXT_SMB_PASS)
53
+ ok = c.session_setup_with_ntlmssp($_REX_TEXT_SMB_USER, $_REX_TEXT_SMB_PASS)
54
54
  assert_kind_of(Rex::Struct2::CStruct, ok)
55
55
  assert_not_equal(c.auth_user_id, 0)
56
56
 
@@ -122,7 +122,7 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
122
122
  assert_kind_of(Rex::Struct2::CStruct, ok)
123
123
 
124
124
  # puts "[*] Authenticating with NTLMv2..."
125
- ok = c.session_setup_ntlmv2($_REX_TEXT_SMB_USER, $_REX_TEXT_SMB_PASS)
125
+ ok = c.session_setup_with_ntlmssp($_REX_TEXT_SMB_USER, $_REX_TEXT_SMB_PASS)
126
126
  assert_kind_of(Rex::Struct2::CStruct, ok)
127
127
  assert_not_equal(c.auth_user_id, 0)
128
128
 
@@ -171,11 +171,11 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
171
171
  assert_kind_of(Rex::Struct2::CStruct, ok)
172
172
 
173
173
  # puts "[*] Authenticating with NTLMv2..."
174
- ok = c.session_setup_ntlmv2
174
+ ok = c.session_setup_with_ntlmssp
175
175
  assert_kind_of(Rex::Struct2::CStruct, ok)
176
176
 
177
177
  # puts "[*] Authenticating with NTLMv1..."
178
- ok = c.session_setup_ntlmv1
178
+ ok = c.session_setup_no_ntlmssp
179
179
  assert_kind_of(Rex::Struct2::CStruct, ok)
180
180
 
181
181
  # puts "[*] Authenticating with clear text passwords..."
@@ -263,7 +263,11 @@ FILE_VOLUME_IS_COMPRESSED = 0x00008000
263
263
 
264
264
 
265
265
  # SMB Error Codes
266
- SMB_ERROR_BUFFER_OVERFLOW = 0x80000005
266
+ SMB_STATUS_SUCCESS = 0x00000000
267
+ SMB_ERROR_BUFFER_OVERFLOW = 0x80000005
268
+ SMB_STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016
269
+ SMB_STATUS_ACCESS_DENIED = 0xC0000022
270
+ SMB_STATUS_LOGON_FAILURE = 0xC000006D
267
271
 
268
272
  # SMB Dialect Compatibility
269
273
  DIALECT = {}
@@ -548,7 +552,7 @@ SMB_SETUP_NTLMV1_HDR_PKT = Rex::Struct2::CStructTemplate.new(
548
552
  SMB_SETUP_NTLMV1_PKT = self.make_nbs(SMB_SETUP_NTLMV1_HDR_PKT)
549
553
 
550
554
 
551
- # A SMB template for SMB Session Setup requests (NTLMV2)
555
+ # A SMB template for SMB Session Setup requests (When extended security is being used)
552
556
  SMB_SETUP_NTLMV2_HDR_PKT = Rex::Struct2::CStructTemplate.new(
553
557
  [ 'template', 'SMB', SMB_HDR ],
554
558
  [ 'uint8', 'AndX', 0 ],
@@ -569,7 +573,7 @@ SMB_SETUP_NTLMV2_HDR_PKT = Rex::Struct2::CStructTemplate.new(
569
573
  SMB_SETUP_NTLMV2_PKT = self.make_nbs(SMB_SETUP_NTLMV2_HDR_PKT)
570
574
 
571
575
 
572
- # A SMB template for SMB Session Setup responses (NTLMV2)
576
+ # A SMB template for SMB Session Setup responses (When extended security is being used)
573
577
  SMB_SETUP_NTLMV2_RES_HDR_PKT = Rex::Struct2::CStructTemplate.new(
574
578
  [ 'template', 'SMB', SMB_HDR ],
575
579
  [ 'uint8', 'AndX', 0 ],
@@ -1035,27 +1039,6 @@ SMB_SEARCH_HDR_PKT = Rex::Struct2::CStructTemplate.new(
1035
1039
  )
1036
1040
  SMB_SEARCH_PKT = self.make_nbs(SMB_SEARCH_HDR_PKT)
1037
1041
 
1038
- # NTLMSSP Message Flags
1039
- NEGOTIATE_UNICODE = 0x00000001 # Only set if Type 1 contains it - this or oem, not both
1040
- NEGOTIATE_OEM = 0x00000002 # Only set if Type 1 contains it - this or unicode, not both
1041
- REQUEST_TARGET = 0x00000004 # If set in Type 1, must return domain or server
1042
- NEGOTIATE_SIGN = 0x00000010 # Session signature required
1043
- NEGOTIATE_SEAL = 0x00000020 # Session seal required
1044
- NEGOTIATE_LMKEY = 0x00000080 # LM Session Key should be used for signing and sealing
1045
- NEGOTIATE_NTLM = 0x00000200 # NTLM auth is supported
1046
- NEGOTIATE_ANONYMOUS = 0x00000800 # Anonymous context used
1047
- NEGOTIATE_DOMAIN = 0x00001000 # Sent in Type1, client gives domain info
1048
- NEGOTIATE_WORKSTATION = 0x00002000 # Sent in Type1, client gives workstation info
1049
- NEGOTIATE_LOCAL_CALL = 0x00004000 # Server and client are on same machine
1050
- NEGOTIATE_ALWAYS_SIGN = 0x00008000 # Add signatures to packets
1051
- TARGET_TYPE_DOMAIN = 0x00010000 # If REQUEST_TARGET, we're adding the domain name
1052
- TARGET_TYPE_SERVER = 0x00020000 # If REQUEST_TARGET, we're adding the server name
1053
- TARGET_TYPE_SHARE = 0x00040000 # Supposed to denote "a share" but for a webserver?
1054
- NEGOTIATE_NTLM2_KEY = 0x00080000 # NTLMv2 Signature and Key exchanges
1055
- NEGOTIATE_TARGET_INFO = 0x00800000 # Server set when sending Target Information Block
1056
- NEGOTIATE_128 = 0x20000000 # 128-bit encryption supported
1057
- NEGOTIATE_KEY_EXCH = 0x40000000 # Client will supply encrypted master key in Session Key field of Type3 msg
1058
- NEGOTIATE_56 = 0x80000000 # 56-bit encryption supported
1059
1042
 
1060
1043
  end
1061
1044
  end
@@ -12,82 +12,23 @@ class Crypt
12
12
  @@loaded_openssl = true
13
13
  rescue ::Exception
14
14
  end
15
-
16
- begin
17
-
18
- def self.lanman_des(pass, chal)
19
- e_p24( [ e_p16( [ pass.upcase()[0,14] ].pack('a14') ) ].pack('a21'), chal)
20
- end
21
15
 
22
- def self.e_p16(pass)
23
- stat = "\x4b\x47\x53\x21\x40\x23\x24\x25"
24
- des_hash(stat, pass[0,7]) << des_hash(stat, pass[7,7])
25
- end
26
-
27
- def self.e_p24(pass, chal)
28
- des_hash(chal, pass[0,7]) << des_hash(chal, pass[7,7]) << des_hash(chal, pass[14,7])
29
- end
30
-
31
- def self.des_hash(data, ckey)
16
+ # Return a signed SMB packet
17
+ def self.sign_smb_packet(mackey, sequence_counter, data)
32
18
  raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
33
- cipher = OpenSSL::Cipher::Cipher.new('des-ecb')
34
- cipher.encrypt
35
- cipher.key = des_56_to_64(ckey)
36
- cipher.update(data)
37
- end
38
-
39
- def self.des_56_to_64(ckey56s)
40
- ckey64 = []
41
- ckey56 = ckey56s.unpack('C*')
42
- ckey64[0] = ckey56[0]
43
- ckey64[1] = ((ckey56[0] << 7) & 0xFF) | (ckey56[1] >> 1)
44
- ckey64[2] = ((ckey56[1] << 6) & 0xFF) | (ckey56[2] >> 2)
45
- ckey64[3] = ((ckey56[2] << 5) & 0xFF) | (ckey56[3] >> 3)
46
- ckey64[4] = ((ckey56[3] << 4) & 0xFF) | (ckey56[4] >> 4)
47
- ckey64[5] = ((ckey56[4] << 3) & 0xFF) | (ckey56[5] >> 5)
48
- ckey64[6] = ((ckey56[5] << 2) & 0xFF) | (ckey56[6] >> 6)
49
- ckey64[7] = (ckey56[6] << 1) & 0xFF
50
- ckey64.pack('C*')
19
+ seq = Rex::Text::pack_int64le(sequence_counter)
20
+ netbios_hdr = data.slice!(0,4)
21
+ data[14,8] = seq
22
+ signature = OpenSSL::Digest::MD5.digest(mackey + data)[0,8]
23
+ data[14,8] = signature
24
+ netbios_hdr + data
51
25
  end
52
26
 
53
- def self.ntlm_md4(pass, chal)
54
- e_p24( [ md4_hash(Rex::Text.to_unicode(pass)) ].pack('a21'), chal)
27
+ def self.is_signature_correct?(mackey, sequence_counter, data)
28
+ signature1 = data[18,8]
29
+ signature2 = sign_smb_packet(mackey, sequence_counter, data.dup)[18,8]
30
+ return signature1 == signature2
55
31
  end
56
-
57
- def self.md4_hash(data)
58
- raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
59
- digest = OpenSSL::Digest::MD4.digest(data)
60
- end
61
-
62
- def self.md5_hash(data)
63
- raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
64
- digest = OpenSSL::Digest::MD5.digest(data)
65
- end
66
-
67
- def self.lm2nt(pass, ntlm)
68
- res = nil
69
- Rex::Text.permute_case( pass.upcase ).each do |word|
70
- if(md4_hash(Rex::Text.to_unicode(word)) == ntlm)
71
- res = word
72
- break
73
- end
74
- end
75
- res
76
- end
77
-
78
- def self.lmchal2ntchal(pass, ntlm, challenge)
79
- res = nil
80
- Rex::Text.permute_case( pass.upcase ).each do |word|
81
- if(ntlm_md4(word,challenge) == ntlm)
82
- res = word
83
- break
84
- end
85
- end
86
- res
87
- end
88
-
89
- rescue LoadError
90
- end
91
32
 
92
33
  end
93
34
  end
@@ -829,6 +829,18 @@ class NTLM2MissingChallenge < Error
829
829
  end
830
830
  end
831
831
 
832
+ class SigningError < Error
833
+ def to_s
834
+ "Unable to handle signing in this situation"
835
+ end
836
+ end
837
+
838
+ class IncorrectSigningError < Error
839
+ def to_s
840
+ "The signature sent by the server is not correct"
841
+ end
842
+ end
843
+
832
844
  class SimpleClientError < Error
833
845
  attr_accessor :source, :fatal
834
846
  end
@@ -179,14 +179,24 @@ attr_accessor :socket, :client, :direct, :shares, :last_share
179
179
  self.shares = { }
180
180
  end
181
181
 
182
- def login(name = '', user = '', pass = '', domain = '')
182
+ def login( name = '', user = '', pass = '', domain = '',
183
+ verify_signature = false, usentlmv2 = false, usentlm2_session = true,
184
+ send_lm = true, use_lanman_key = false, send_ntlm = true,
185
+ native_os = 'Windows 2000 2195', native_lm = 'Windows 2000 5.0')
183
186
 
184
187
  begin
185
188
 
186
189
  if (self.direct != true)
187
190
  self.client.session_request(name)
188
191
  end
189
-
192
+ self.client.native_os = native_os
193
+ self.client.native_lm = native_lm
194
+ self.client.verify_signature = verify_signature
195
+ self.client.use_ntlmv2 = usentlmv2
196
+ self.client.usentlm2_session = usentlm2_session
197
+ self.client.send_lm = send_lm
198
+ self.client.use_lanman_key = use_lanman_key
199
+ self.client.send_ntlm = send_ntlm
190
200
  self.client.negotiate
191
201
  ok = self.client.session_setup(user, pass, domain)
192
202
  rescue ::Interrupt
@@ -233,7 +243,7 @@ attr_accessor :socket, :client, :direct, :shares, :last_share
233
243
 
234
244
  def login_split_next_ntlm1(user, domain, hash_lm, hash_nt)
235
245
  begin
236
- ok = self.client.session_setup_ntlmv1_prehash(user, domain, hash_lm, hash_nt)
246
+ ok = self.client.session_setup_no_ntlmssp_prehash(user, domain, hash_lm, hash_nt)
237
247
  rescue ::Interrupt
238
248
  raise $!
239
249
  rescue ::Exception => e
@@ -261,14 +271,16 @@ attr_accessor :socket, :client, :direct, :shares, :last_share
261
271
  self.shares.delete(share)
262
272
  end
263
273
 
264
- def open(path, perm)
274
+
275
+ def open(path, perm, chunk_size = 48000)
265
276
  mode = UTILS.open_mode_to_mode(perm)
266
277
  access = UTILS.open_mode_to_access(perm)
267
278
 
268
279
  ok = self.client.open(path, mode, access)
269
280
  file_id = ok['Payload'].v['FileID']
270
-
271
281
  fh = OpenFile.new(self.client, path, self.client.last_tree_id, file_id)
282
+ fh.chunk_size = chunk_size
283
+ fh
272
284
  end
273
285
 
274
286
  def delete(*args)
@@ -96,468 +96,11 @@ CONST = Rex::Proto::SMB::Constants
96
96
  return decoded
97
97
  end
98
98
 
99
- #
100
- # Prepends an ASN1 formatted length field to a piece of data
101
- #
102
- def self.asn1encode(str = '')
103
- res = ''
104
-
105
- # If the high bit of the first byte is 1, it contains the number of
106
- # length bytes that follow
107
-
108
- case str.length
109
- when 0 .. 0x7F
110
- res = [str.length].pack('C') + str
111
- when 0x80 .. 0xFF
112
- res = [0x81, str.length].pack('CC') + str
113
- when 0x100 .. 0xFFFF
114
- res = [0x82, str.length].pack('Cn') + str
115
- when 0x10000 .. 0xffffff
116
- res = [0x83, str.length >> 16, str.length & 0xFFFF].pack('CCn') + str
117
- when 0x1000000 .. 0xffffffff
118
- res = [0x84, str.length].pack('CN') + str
119
- else
120
- raise "ASN1 str too long"
121
- end
122
- return res
99
+ # Determine whether the password is a known hash format
100
+ def self.is_pass_ntlm_hash?(str)
101
+ str.downcase =~ /^[0-9a-f]{32}:[0-9a-f]{32}$/
123
102
  end
124
-
125
- def self.make_ntlmv2_secblob_init(domain = 'WORKGROUP', name = 'WORKSTATION', flags=0x80201)
126
- blob =
127
- "\x60" + self.asn1encode(
128
- "\x06" + self.asn1encode(
129
- "\x2b\x06\x01\x05\x05\x02"
130
- ) +
131
- "\xa0" + self.asn1encode(
132
- "\x30" + self.asn1encode(
133
- "\xa0" + self.asn1encode(
134
- "\x30" + self.asn1encode(
135
- "\x06" + self.asn1encode(
136
- "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
137
- )
138
- )
139
- ) +
140
- "\xa2" + self.asn1encode(
141
- "\x04" + self.asn1encode(
142
- "NTLMSSP\x00" +
143
- [1, flags].pack('VV') +
144
-
145
- [
146
- domain.length, #length
147
- domain.length, #max length
148
- 32
149
- ].pack('vvV') +
150
-
151
- [
152
- name.length, #length
153
- name.length, #max length
154
- domain.length + 32
155
- ].pack('vvV') +
156
-
157
- domain + name
158
- )
159
- )
160
- )
161
- )
162
- )
163
-
164
- return blob
165
- end
166
-
167
- def self.make_ntlmv2_secblob_auth(domain, name, user, lmv2, ntlm, flags = 0x080201)
168
-
169
- lmv2 ||= "\x00" * 24
170
- ntlm ||= "\x00" * 24
171
-
172
- domain_uni = Rex::Text.to_unicode(domain)
173
- user_uni = Rex::Text.to_unicode(user)
174
- name_uni = Rex::Text.to_unicode(name)
175
- session = ''
176
-
177
- ptr = 64
178
- blob =
179
- "\xa1" + self.asn1encode(
180
- "\x30" + self.asn1encode(
181
- "\xa2" + self.asn1encode(
182
- "\x04" + self.asn1encode(
183
-
184
- "NTLMSSP\x00" +
185
- [ 3 ].pack('V') +
186
-
187
- [ # Lan Manager Response
188
- lmv2.length,
189
- lmv2.length,
190
- (ptr)
191
- ].pack('vvV') +
192
-
193
- [ # NTLM Manager Response
194
- ntlm.length,
195
- ntlm.length,
196
- (ptr += lmv2.length)
197
- ].pack('vvV') +
198
-
199
- [ # Domain Name
200
- domain_uni.length,
201
- domain_uni.length,
202
- (ptr += ntlm.length)
203
- ].pack('vvV') +
204
-
205
- [ # Username
206
- user_uni.length,
207
- user_uni.length,
208
- (ptr += domain_uni.length)
209
- ].pack('vvV') +
210
-
211
- [ # Hostname
212
- name_uni.length,
213
- name_uni.length,
214
- (ptr += user_uni.length)
215
- ].pack('vvV') +
216
-
217
- [ # Session Key (none)
218
- session.length,
219
- session.length,
220
- (ptr += name_uni.length)
221
- ].pack('vvV') +
222
-
223
- [ flags ].pack('V') +
224
-
225
- lmv2 +
226
- ntlm +
227
- domain_uni +
228
- user_uni +
229
- name_uni +
230
- session + "\x00"
231
- )
232
- )
233
- )
234
- )
235
- return blob
236
- end
237
-
238
-
239
- def self.make_negotiate_secblob_resp(account, domain)
240
- blob =
241
- "\x60" + self.asn1encode(
242
- "\x06" + self.asn1encode(
243
- "\x2b\x06\x01\x05\x05\x02"
244
- ) +
245
- "\xa0" + self.asn1encode(
246
- "\x30" + self.asn1encode(
247
- "\xa0" + self.asn1encode(
248
- "\x30" + self.asn1encode(
249
- "\x06" + self.asn1encode(
250
- "\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"
251
- ) +
252
- "\x06" + self.asn1encode(
253
- "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
254
- ) +
255
- "\x06" + self.asn1encode(
256
- "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x03"
257
- ) +
258
- "\x06" + self.asn1encode(
259
- "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
260
- )
261
- )
262
- ) +
263
- "\xa3" + self.asn1encode(
264
- "\x30" + self.asn1encode(
265
- "\xa0" + self.asn1encode(
266
- "\x1b" + self.asn1encode(
267
- account + '@' + domain
268
- )
269
- )
270
- )
271
- )
272
- )
273
- )
274
- )
275
103
 
276
- return blob
277
- end
278
-
279
- def self.make_ntlmv2_secblob_chall(win_domain, dns_domain, win_name, dns_name, chall, flags)
280
-
281
- win_domain = Rex::Text.to_unicode(win_domain)
282
- dns_domain = Rex::Text.to_unicode(dns_domain)
283
- win_name = Rex::Text.to_unicode(win_name)
284
- dns_name = Rex::Text.to_unicode(dns_name)
285
-
286
- addr_list = ''
287
- addr_list << [2, win_domain.length].pack('vv') + win_domain
288
- addr_list << [1, win_name.length].pack('vv') + win_name
289
- addr_list << [4, dns_domain.length].pack('vv') + dns_domain
290
- addr_list << [3, dns_name.length].pack('vv') + dns_name
291
- addr_list << [5, dns_domain.length].pack('vv') + dns_domain
292
- addr_list << [0, 0].pack('vv')
293
-
294
- ptr = 0
295
- blob =
296
- "\xa1" + self.asn1encode(
297
- "\x30" + self.asn1encode(
298
- "\xa0" + self.asn1encode(
299
- "\x0a" + self.asn1encode(
300
- "\x01"
301
- )
302
- ) +
303
- "\xa1" + self.asn1encode(
304
- "\x06" + self.asn1encode(
305
- "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
306
- )
307
- ) +
308
- "\xa2" + self.asn1encode(
309
- "\x04" + self.asn1encode(
310
- "NTLMSSP\x00" +
311
- [2].pack('V') +
312
- [
313
- win_domain.length, # length
314
- win_domain.length, # max length
315
- (ptr += 48)
316
- ].pack('vvV') +
317
- [ flags ].pack('V') +
318
- chall +
319
- "\x00\x00\x00\x00\x00\x00\x00\x00" +
320
- [
321
- addr_list.length, # length
322
- addr_list.length, # max length
323
- (ptr += win_domain.length)
324
- ].pack('vvV') +
325
- win_domain +
326
- addr_list
327
- )
328
- )
329
- )
330
- )
331
-
332
- return blob
333
- end
334
-
335
- def self.make_ntlmv2_secblob_success
336
- blob =
337
- "\xa1" + self.asn1encode(
338
- "\x30" + self.asn1encode(
339
- "\xa0" + self.asn1encode(
340
- "\x0a" + self.asn1encode(
341
- "\x00"
342
- )
343
- )
344
- )
345
- )
346
- return blob
347
- end
348
-
349
- #
350
- # Process Type 3 NTLM Message (in Base64)
351
- #
352
- # from http://www.innovation.ch/personal/ronald/ntlm.html
353
- #
354
- # struct {
355
- # byte protocol[8]; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
356
- # byte type; // 0x03
357
- # byte zero[3];
358
- #
359
- # short lm_resp_len; // LanManager response length (always 0x18)
360
- # short lm_resp_len; // LanManager response length (always 0x18)
361
- # short lm_resp_off; // LanManager response offset
362
- # byte zero[2];
363
- #
364
- # short nt_resp_len; // NT response length (always 0x18)
365
- # short nt_resp_len; // NT response length (always 0x18)
366
- # short nt_resp_off; // NT response offset
367
- # byte zero[2];
368
- #
369
- # short dom_len; // domain string length
370
- # short dom_len; // domain string length
371
- # short dom_off; // domain string offset (always 0x40)
372
- # byte zero[2];
373
- #
374
- # short user_len; // username string length
375
- # short user_len; // username string length
376
- # short user_off; // username string offset
377
- # byte zero[2];
378
- #
379
- # short host_len; // host string length
380
- # short host_len; // host string length
381
- # short host_off; // host string offset
382
- # byte zero[6];
383
- #
384
- # short msg_len; // message length
385
- # byte zero[2];
386
- #
387
- # short flags; // 0x8201
388
- # byte zero[2];
389
- #
390
- # byte dom[*]; // domain string (unicode UTF-16LE)
391
- # byte user[*]; // username string (unicode UTF-16LE)
392
- # byte host[*]; // host string (unicode UTF-16LE)
393
- # byte lm_resp[*]; // LanManager response
394
- # byte nt_resp[*]; // NT response
395
- # } type_3_message
396
- #
397
- def self.process_type3_message(message)
398
- decode = Rex::Text.decode_base64(message.strip)
399
- type = decode[8,1].unpack("C").first
400
- if (type == 3)
401
- lm_len = decode[12,2].unpack("v").first
402
- lm_offset = decode[16,2].unpack("v").first
403
- lm = decode[lm_offset, lm_len].unpack("H*").first
404
-
405
- nt_len = decode[20,2].unpack("v").first
406
- nt_offset = decode[24,2].unpack("v").first
407
- nt = decode[nt_offset, nt_len].unpack("H*").first
408
-
409
- dom_len = decode[28,2].unpack("v").first
410
- dom_offset = decode[32,2].unpack("v").first
411
- domain = decode[dom_offset, dom_len]
412
-
413
- user_len = decode[36,2].unpack("v").first
414
- user_offset = decode[40,2].unpack("v").first
415
- user = decode[user_offset, user_len]
416
-
417
- host_len = decode[44,2].unpack("v").first
418
- host_offset = decode[48,2].unpack("v").first
419
- host = decode[host_offset, host_len]
420
-
421
- return domain, user, host, lm, nt
422
- else
423
- return "", "", "", "", ""
424
- end
425
- end
426
-
427
- #
428
- # Process Type 1 NTLM Messages, return a Base64 Type 2 Message
429
- #
430
- def self.process_type1_message(message, nonce = "\x11\x22\x33\x44\x55\x66\x77\x88", win_domain = 'DOMAIN',
431
- win_name = 'SERVER', dns_name = 'server', dns_domain = 'example.com', downgrade = true)
432
-
433
- dns_name = Rex::Text.to_unicode(dns_name + "." + dns_domain)
434
- win_domain = Rex::Text.to_unicode(win_domain)
435
- dns_domain = Rex::Text.to_unicode(dns_domain)
436
- win_name = Rex::Text.to_unicode(win_name)
437
- decode = Rex::Text.decode_base64(message.strip)
438
-
439
- type = decode[8,1].unpack("C").first
440
-
441
- if (type == 1)
442
- # A type 1 message has been received, lets build a type 2 message response
443
-
444
- reqflags = decode[12,4]
445
- reqflags = reqflags.unpack("V").first
446
-
447
- if (reqflags & CONST::REQUEST_TARGET) == CONST::REQUEST_TARGET
448
-
449
- if (downgrade)
450
- # At this time NTLMv2 and signing requirements are not supported
451
- if (reqflags & CONST::NEGOTIATE_NTLM2_KEY) == CONST::NEGOTIATE_NTLM2_KEY
452
- reqflags = reqflags - CONST::NEGOTIATE_NTLM2_KEY
453
- end
454
- if (reqflags & CONST::NEGOTIATE_ALWAYS_SIGN) == CONST::NEGOTIATE_ALWAYS_SIGN
455
- reqflags = reqflags - CONST::NEGOTIATE_ALWAYS_SIGN
456
- end
457
- end
458
-
459
- flags = reqflags + CONST::TARGET_TYPE_DOMAIN + CONST::TARGET_TYPE_SERVER
460
- tid = true
461
-
462
- tidoffset = 48 + win_domain.length
463
- tidbuff =
464
- [2].pack('v') + # tid type, win domain
465
- [win_domain.length].pack('v') +
466
- win_domain +
467
- [1].pack('v') + # tid type, server name
468
- [win_name.length].pack('v') +
469
- win_name +
470
- [4].pack('v') + # tid type, domain name
471
- [dns_domain.length].pack('v') +
472
- dns_domain +
473
- [3].pack('v') + # tid type, dns_name
474
- [dns_name.length].pack('v') +
475
- dns_name
476
- else
477
- flags = CONST::NEGOTIATE_UNICODE + CONST::NEGOTIATE_NTLM
478
- tid = false
479
- end
480
-
481
- type2msg = "NTLMSSP\0" + # protocol, 8 bytes
482
- "\x02\x00\x00\x00" # type, 4 bytes
483
-
484
- if (tid)
485
- type2msg += # Target security info, 8 bytes. Filled if REQUEST_TARGET
486
- [win_domain.length].pack('v') + # Length, 2 bytes
487
- [win_domain.length].pack('v') # Allocated space, 2 bytes
488
- end
489
-
490
- type2msg +="\x30\x00\x00\x00" + # Offset, 4 bytes
491
- [flags].pack('V') + # flags, 4 bytes
492
- nonce + # the nonce, 8 bytes
493
- "\x00" * 8 # Context (all 0s), 8 bytes
494
-
495
- if (tid)
496
- type2msg += # Target information security buffer. Filled if REQUEST_TARGET
497
- [tidbuff.length].pack('v') + # Length, 2 bytes
498
- [tidbuff.length].pack('v') + # Allocated space, 2 bytes
499
- [tidoffset].pack('V') + # Offset, 4 bytes (usually \x48 + length of win_domain)
500
- win_domain + # Target name data (domain in unicode if REQUEST_UNICODE)
501
- # Target information data
502
- tidbuff + # Type, 2 bytes
503
- # Length, 2 bytes
504
- # Data (in unicode if REQUEST_UNICODE)
505
- "\x00\x00\x00\x00" # Terminator, 4 bytes, all \x00
506
- end
507
-
508
- type2msg = Rex::Text.encode_base64(type2msg).delete("\n") # base64 encode and remove the returns
509
- else
510
- # This is not a Type2 message
511
- type2msg = ""
512
- end
513
-
514
- return type2msg
515
- end
516
-
517
- #
518
- # Downgrading Type messages to LMv1/NTLMv1 and removing signing
519
- #
520
- def self.downgrade_type_message(message)
521
- decode = Rex::Text.decode_base64(message.strip)
522
-
523
- type = decode[8,1].unpack("C").first
524
-
525
- if (type > 0 and type < 4)
526
- reqflags = decode[12..15] if (type == 1 or type == 3)
527
- reqflags = decode[20..23] if (type == 2)
528
- reqflags = reqflags.unpack("V")
529
-
530
- # Remove NEGOTIATE_NTLMV2_KEY and NEGOTIATE_ALWAYS_SIGN, this lowers the negotiation
531
- # down to LMv1/NTLMv1.
532
- if (reqflags & CONST::NEGOTIATE_NTLM2_KEY) == CONST::NEGOTIATE_NTLM2_KEY
533
- reqflags = reqflags - CONST::NEGOTIATE_NTLM2_KEY
534
- end
535
- if (reqflags & CONST::NEGOTIATE_ALWAYS_SIGN) == CONST::NEGOTIATE_ALWAYS_SIGN
536
- reqflags = reqflags - CONST::NEGOTIATE_ALWAYS_SIGN
537
- end
538
-
539
- # Return the flags back to the decode so we can base64 it again
540
- flags = reqflags.to_s(16)
541
- 0.upto(8) do |idx|
542
- if (idx > flags.length)
543
- flags.insert(0, "0")
544
- end
545
- end
546
-
547
- idx = 0
548
- 0.upto(3) do |cnt|
549
- if (type == 2)
550
- decode[23-cnt] = [flags[idx,1]].pack("C")
551
- else
552
- decode[15-cnt] = [flags[idx,1]].pack("C")
553
- end
554
- idx += 2
555
- end
556
-
557
- end
558
- return Rex::Text.encode_base64(decode).delete("\n") # base64 encode and remove the returns
559
- end
560
-
561
104
  end
562
105
  end
563
106
  end