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
@@ -0,0 +1,326 @@
1
+ #
2
+ # An NTLM Authentication Library for Ruby
3
+ #
4
+ # This code is a derivative of "dbf2.rb" written by yrock
5
+ # and Minero Aoki. You can find original code here:
6
+ # http://jp.rubyist.net/magazine/?0013-CodeReview
7
+ # -------------------------------------------------------------
8
+ # Copyright (c) 2005,2006 yrock
9
+ #
10
+ # This program is free software.
11
+ # You can distribute/modify this program under the terms of the
12
+ # Ruby License.
13
+ #
14
+ # 2011-02-23 refactored by Alexandre Maloteaux for Metasploit Project
15
+ # -------------------------------------------------------------
16
+ #
17
+ # 2006-02-11 refactored by Minero Aoki
18
+ # -------------------------------------------------------------
19
+ #
20
+ # All protocol information used to write this code stems from
21
+ # "The NTLM Authentication Protocol" by Eric Glass. The author
22
+ # would thank to him for this tremendous work and making it
23
+ # available on the net.
24
+ # http://davenport.sourceforge.net/ntlm.html
25
+ # -------------------------------------------------------------
26
+ # Copyright (c) 2003 Eric Glass
27
+ #
28
+ # Permission to use, copy, modify, and distribute this document
29
+ # for any purpose and without any fee is hereby granted,
30
+ # provided that the above copyright notice and this list of
31
+ # conditions appear in all copies.
32
+ # -------------------------------------------------------------
33
+ #
34
+ # The author also looked Mozilla-Firefox-1.0.7 source code,
35
+ # namely, security/manager/ssl/src/nsNTLMAuthModule.cpp and
36
+ # Jonathan Bastien-Filiatrault's libntlm-ruby.
37
+ # "http://x2a.org/websvn/filedetails.php?
38
+ # repname=libntlm-ruby&path=%2Ftrunk%2Fntlm.rb&sc=1"
39
+ # The latter has a minor bug in its separate_keys function.
40
+ # The third key has to begin from the 14th character of the
41
+ # input string instead of 13th:)
42
+ #--
43
+ # $Id: ntlm.rb 11678 2011-01-30 19:26:35Z hdm $
44
+ #++
45
+
46
+ #this class defines the base type needed for other modules like message and crypt
47
+
48
+ require 'rex/proto/ntlm/constants'
49
+
50
+ module Rex
51
+ module Proto
52
+ module NTLM
53
+ class Base
54
+
55
+ CONST = Rex::Proto::NTLM::Constants
56
+
57
+ # base classes for primitives
58
+ class Field
59
+ attr_accessor :active, :value
60
+
61
+ def initialize(opts)
62
+ @value = opts[:value]
63
+ @active = opts[:active].nil? ? true : opts[:active]
64
+ end
65
+
66
+ def size
67
+ @active ? @size : 0
68
+ end
69
+ end
70
+
71
+ class String < Field
72
+ def initialize(opts)
73
+ super(opts)
74
+ @size = opts[:size]
75
+ end
76
+
77
+ def parse(str, offset=0)
78
+ if @active and str.size >= offset + @size
79
+ @value = str[offset, @size]
80
+ @size
81
+ else
82
+ 0
83
+ end
84
+ end
85
+
86
+ def serialize
87
+ if @active
88
+ @value
89
+ else
90
+ ""
91
+ end
92
+ end
93
+
94
+ def value=(val)
95
+ @value = val
96
+ @size = @value.nil? ? 0 : @value.size
97
+ @active = (@size > 0)
98
+ end
99
+ end
100
+
101
+ class Int16LE < Field
102
+ def initialize(opt)
103
+ super(opt)
104
+ @size = 2
105
+ end
106
+
107
+ def parse(str, offset=0)
108
+ if @active and str.size >= offset + @size
109
+ @value = str[offset, @size].unpack("v")[0]
110
+ @size
111
+ else
112
+ 0
113
+ end
114
+ end
115
+
116
+ def serialize
117
+ [@value].pack("v")
118
+ end
119
+ end
120
+
121
+ class Int32LE < Field
122
+ def initialize(opt)
123
+ super(opt)
124
+ @size = 4
125
+ end
126
+
127
+ def parse(str, offset=0)
128
+ if @active and str.size >= offset + @size
129
+ @value = str.slice(offset, @size).unpack("V")[0]
130
+ @size
131
+ else
132
+ 0
133
+ end
134
+ end
135
+
136
+ def serialize
137
+ [@value].pack("V") if @active
138
+ end
139
+ end
140
+
141
+ class Int64LE < Field
142
+ def initialize(opt)
143
+ super(opt)
144
+ @size = 8
145
+ end
146
+
147
+ def parse(str, offset=0)
148
+ if @active and str.size >= offset + @size
149
+ d, u = str.slice(offset, @size).unpack("V2")
150
+ @value = (u * 0x100000000 + d)
151
+ @size
152
+ else
153
+ 0
154
+ end
155
+ end
156
+
157
+ def serialize
158
+ [@value & 0x00000000ffffffff, @value >> 32].pack("V2") if @active
159
+ end
160
+ end
161
+
162
+ # base class of data structure
163
+ class FieldSet
164
+ class << FieldSet
165
+ def define(&block)
166
+ c = Class.new(self)
167
+ def c.inherited(subclass)
168
+ proto = @proto
169
+ subclass.instance_eval {
170
+ @proto = proto
171
+ }
172
+ end
173
+ c.module_eval(&block)
174
+ c
175
+ end
176
+
177
+ def string(name, opts)
178
+ add_field(name, String, opts)
179
+ end
180
+
181
+ def int16LE(name, opts)
182
+ add_field(name, Int16LE, opts)
183
+ end
184
+
185
+ def int32LE(name, opts)
186
+ add_field(name, Int32LE, opts)
187
+ end
188
+
189
+ def int64LE(name, opts)
190
+ add_field(name, Int64LE, opts)
191
+ end
192
+
193
+ def security_buffer(name, opts)
194
+ add_field(name, SecurityBuffer, opts)
195
+ end
196
+
197
+ def prototypes
198
+ @proto
199
+ end
200
+
201
+ def names
202
+ @proto.map{|n, t, o| n}
203
+ end
204
+
205
+ def types
206
+ @proto.map{|n, t, o| t}
207
+ end
208
+
209
+ def opts
210
+ @proto.map{|n, t, o| o}
211
+ end
212
+
213
+ private
214
+
215
+ def add_field(name, type, opts)
216
+ (@proto ||= []).push [name, type, opts]
217
+ define_accessor name
218
+ end
219
+
220
+ def define_accessor(name)
221
+ module_eval(<<-End, __FILE__, __LINE__ + 1)
222
+ def #{name}
223
+ self['#{name}'].value
224
+ end
225
+
226
+ def #{name}=(val)
227
+ self['#{name}'].value = val
228
+ end
229
+ End
230
+ end
231
+ end #self
232
+
233
+ def initialize
234
+ @alist = self.class.prototypes.map{ |n, t, o| [n, t.new(o)] }
235
+ end
236
+
237
+ def serialize
238
+ @alist.map{|n, f| f.serialize }.join
239
+ end
240
+
241
+ def parse(str, offset=0)
242
+ @alist.inject(offset){|cur, a| cur += a[1].parse(str, cur)}
243
+ end
244
+
245
+ def size
246
+ @alist.inject(0){|sum, a| sum += a[1].size}
247
+ end
248
+
249
+ def [](name)
250
+ a = @alist.assoc(name.to_s.intern)
251
+ raise ArgumentError, "no such field: #{name}" unless a
252
+ a[1]
253
+ end
254
+
255
+ def []=(name, val)
256
+ a = @alist.assoc(name.to_s.intern)
257
+ raise ArgumentError, "no such field: #{name}" unless a
258
+ a[1] = val
259
+ end
260
+
261
+ def enable(name)
262
+ self[name].active = true
263
+ end
264
+
265
+ def disable(name)
266
+ self[name].active = false
267
+ end
268
+ end
269
+
270
+ Blob = FieldSet.define {
271
+ int32LE :blob_signature, {:value => CONST::BLOB_SIGN}
272
+ int32LE :reserved, {:value => 0}
273
+ int64LE :timestamp, {:value => 0}
274
+ string :challenge, {:value => "", :size => 8}
275
+ int32LE :unknown1, {:value => 0}
276
+ string :target_info, {:value => "", :size => 0}
277
+ int32LE :unknown2, {:value => 0}
278
+ }
279
+
280
+ SecurityBuffer = FieldSet.define {
281
+ int16LE :length, {:value => 0}
282
+ int16LE :allocated, {:value => 0}
283
+ int32LE :offset, {:value => 0}
284
+ }
285
+
286
+
287
+ class SecurityBuffer
288
+ attr_accessor :active
289
+ def initialize(opts)
290
+ super()
291
+ @value = opts[:value]
292
+ @active = opts[:active].nil? ? true : opts[:active]
293
+ @size = 8
294
+ end
295
+
296
+ def parse(str, offset=0)
297
+ if @active and str.size >= offset + @size
298
+ super(str, offset)
299
+ @value = str[self.offset, self.length]
300
+ @size
301
+ else
302
+ 0
303
+ end
304
+ end
305
+
306
+ def serialize
307
+ super if @active
308
+ end
309
+
310
+ def value
311
+ @value
312
+ end
313
+
314
+ def value=(val)
315
+ @value = val
316
+ self.length = self.allocated = val.size
317
+ end
318
+
319
+ def data_size
320
+ @active ? @value.size : 0
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
@@ -0,0 +1,74 @@
1
+ module Rex
2
+ module Proto
3
+ module NTLM
4
+ class Constants
5
+
6
+ SSP_SIGN = "NTLMSSP\0"
7
+ BLOB_SIGN = 0x00000101
8
+ LM_MAGIC = "KGS!@\#$%"
9
+ TIME_OFFSET = 11644473600
10
+ MAX64 = 0xffffffffffffffff
11
+
12
+ FLAGS = {
13
+ :UNICODE => 0x00000001,
14
+ :OEM => 0x00000002,
15
+ :REQUEST_TARGET => 0x00000004,
16
+ #:UNKNOWN => 0x00000008,
17
+ :SIGN => 0x00000010,
18
+ :SEAL => 0x00000020,
19
+ #:UNKNOWN => 0x00000040,
20
+ :NETWARE => 0x00000100,
21
+ :NTLM => 0x00000200,
22
+ #:UNKNOWN => 0x00000400,
23
+ #:UNKNOWN => 0x00000800,
24
+ :DOMAIN_SUPPLIED => 0x00001000,
25
+ :WORKSTATION_SUPPLIED => 0x00002000,
26
+ :LOCAL_CALL => 0x00004000,
27
+ :ALWAYS_SIGN => 0x00008000,
28
+ :TARGET_TYPE_DOMAIN => 0x00010000,
29
+ :TARGET_INFO => 0x00800000,
30
+ :NTLM2_KEY => 0x00080000,
31
+ :KEY128 => 0x20000000,
32
+ :KEY56 => 0x80000000
33
+ }
34
+
35
+ FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] }
36
+
37
+ DEFAULT_FLAGS = {
38
+ :TYPE1 => FLAGS[:UNICODE] | FLAGS[:OEM] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY],
39
+ :TYPE2 => FLAGS[:UNICODE],
40
+ :TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY]
41
+ }
42
+
43
+ # NTLM Response Type
44
+ NTLM_V1_RESPONSE = 1
45
+ NTLM_V2_RESPONSE = 2
46
+ NTLM_2_SESSION_RESPONSE = 3
47
+
48
+ #the same flags but merged from lib/rex/proto/smb/constants and keeped for compatibility
49
+ # NTLMSSP Message Flags
50
+ NEGOTIATE_UNICODE = 0x00000001 # Only set if Type 1 contains it - this or oem, not both
51
+ NEGOTIATE_OEM = 0x00000002 # Only set if Type 1 contains it - this or unicode, not both
52
+ REQUEST_TARGET = 0x00000004 # If set in Type 1, must return domain or server
53
+ NEGOTIATE_SIGN = 0x00000010 # Session signature required
54
+ NEGOTIATE_SEAL = 0x00000020 # Session seal required
55
+ NEGOTIATE_LMKEY = 0x00000080 # LM Session Key should be used for signing and sealing
56
+ NEGOTIATE_NTLM = 0x00000200 # NTLM auth is supported
57
+ NEGOTIATE_ANONYMOUS = 0x00000800 # Anonymous context used
58
+ NEGOTIATE_DOMAIN = 0x00001000 # Sent in Type1, client gives domain info
59
+ NEGOTIATE_WORKSTATION = 0x00002000 # Sent in Type1, client gives workstation info
60
+ NEGOTIATE_LOCAL_CALL = 0x00004000 # Server and client are on same machine
61
+ NEGOTIATE_ALWAYS_SIGN = 0x00008000 # Add signatures to packets
62
+ TARGET_TYPE_DOMAIN = 0x00010000 # If REQUEST_TARGET, we're adding the domain name
63
+ TARGET_TYPE_SERVER = 0x00020000 # If REQUEST_TARGET, we're adding the server name
64
+ TARGET_TYPE_SHARE = 0x00040000 # Supposed to denote "a share" but for a webserver?
65
+ NEGOTIATE_NTLM2_KEY = 0x00080000 # NTLMv2 Signature and Key exchanges
66
+ NEGOTIATE_TARGET_INFO = 0x00800000 # Server set when sending Target Information Block
67
+ NEGOTIATE_128 = 0x20000000 # 128-bit encryption supported
68
+ NEGOTIATE_KEY_EXCH = 0x40000000 # Client will supply encrypted master key in Session Key field of Type3 msg
69
+ NEGOTIATE_56 = 0x80000000 # 56-bit encryption supported
70
+
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,340 @@
1
+ #
2
+ # An NTLM Authentication Library for Ruby
3
+ #
4
+ # This code is a derivative of "dbf2.rb" written by yrock
5
+ # and Minero Aoki. You can find original code here:
6
+ # http://jp.rubyist.net/magazine/?0013-CodeReview
7
+ # -------------------------------------------------------------
8
+ # Copyright (c) 2005,2006 yrock
9
+ #
10
+ # This program is free software.
11
+ # You can distribute/modify this program under the terms of the
12
+ # Ruby License.
13
+ #
14
+ # 2011-03-08 improved through a code merge with Metasploit's SMB::Crypt
15
+ # -------------------------------------------------------------
16
+ #
17
+ # 2011-02-23 refactored and improved by Alexandre Maloteaux for Metasploit Project
18
+ # -------------------------------------------------------------
19
+ #
20
+ # 2006-02-11 refactored by Minero Aoki
21
+ # -------------------------------------------------------------
22
+ #
23
+ # All protocol information used to write this code stems from
24
+ # "The NTLM Authentication Protocol" by Eric Glass. The author
25
+ # would thank to him for this tremendous work and making it
26
+ # available on the net.
27
+ # http://davenport.sourceforge.net/ntlm.html
28
+ # -------------------------------------------------------------
29
+ # Copyright (c) 2003 Eric Glass
30
+ #
31
+ # Permission to use, copy, modify, and distribute this document
32
+ # for any purpose and without any fee is hereby granted,
33
+ # provided that the above copyright notice and this list of
34
+ # conditions appear in all copies.
35
+ # -------------------------------------------------------------
36
+ #
37
+ # The author also looked Mozilla-Firefox-1.0.7 source code,
38
+ # namely, security/manager/ssl/src/nsNTLMAuthModule.cpp and
39
+ # Jonathan Bastien-Filiatrault's libntlm-ruby.
40
+ # "http://x2a.org/websvn/filedetails.php?
41
+ # repname=libntlm-ruby&path=%2Ftrunk%2Fntlm.rb&sc=1"
42
+ # The latter has a minor bug in its separate_keys function.
43
+ # The third key has to begin from the 14th character of the
44
+ # input string instead of 13th:)
45
+ #--
46
+ # $Id: ntlm.rb 11678 2011-01-30 19:26:35Z hdm $
47
+ #++
48
+
49
+
50
+ require 'rex/proto/ntlm/constants'
51
+ require 'rex/proto/ntlm/base'
52
+
53
+ module Rex
54
+ module Proto
55
+ module NTLM
56
+ class Crypt
57
+
58
+ CONST = Rex::Proto::NTLM::Constants
59
+ BASE = Rex::Proto::NTLM::Base
60
+
61
+ @@loaded_openssl = false
62
+
63
+ begin
64
+ require 'openssl'
65
+ require 'openssl/digest'
66
+ @@loaded_openssl = true
67
+ rescue ::Exception
68
+ end
69
+
70
+ def self.gen_keys(str)
71
+ str.scan(/.{7}/).map{ |key| des_56_to_64(key) }
72
+ end
73
+
74
+ def self.des_56_to_64(ckey56s)
75
+ ckey64 = []
76
+ ckey56 = ckey56s.unpack('C*')
77
+ ckey64[0] = ckey56[0]
78
+ ckey64[1] = ((ckey56[0] << 7) & 0xFF) | (ckey56[1] >> 1)
79
+ ckey64[2] = ((ckey56[1] << 6) & 0xFF) | (ckey56[2] >> 2)
80
+ ckey64[3] = ((ckey56[2] << 5) & 0xFF) | (ckey56[3] >> 3)
81
+ ckey64[4] = ((ckey56[3] << 4) & 0xFF) | (ckey56[4] >> 4)
82
+ ckey64[5] = ((ckey56[4] << 3) & 0xFF) | (ckey56[5] >> 5)
83
+ ckey64[6] = ((ckey56[5] << 2) & 0xFF) | (ckey56[6] >> 6)
84
+ ckey64[7] = (ckey56[6] << 1) & 0xFF
85
+ ckey64.pack('C*')
86
+ end
87
+
88
+ def self.apply_des(plain, keys)
89
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
90
+ dec = OpenSSL::Cipher::DES.new
91
+ keys.map do |k|
92
+ dec.key = k
93
+ dec.encrypt.update(plain)
94
+ end
95
+ end
96
+
97
+ def self.lm_hash(password, half = false)
98
+ size = half ? 7 : 14
99
+ keys = gen_keys(password.upcase.ljust(size, "\0"))
100
+ apply_des(CONST::LM_MAGIC, keys).join
101
+ end
102
+
103
+ def self.ntlm_hash(password, opt = {})
104
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
105
+ pwd = password.dup
106
+ unless opt[:unicode]
107
+ pwd = Rex::Text.to_unicode(pwd)
108
+ end
109
+ OpenSSL::Digest::MD4.digest(pwd)
110
+ end
111
+
112
+ # This hash is used for lmv2/ntlmv2 response calculation
113
+ def self.ntlmv2_hash(user, password, domain, opt={})
114
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
115
+
116
+ if opt[:pass_is_hash]
117
+ ntlmhash = password
118
+ else
119
+ ntlmhash = ntlm_hash(password, opt)
120
+ end
121
+
122
+ # With Win 7 and maybe other OSs we sometimes get the domain not uppercased
123
+ userdomain = user.upcase + domain
124
+ unless opt[:unicode]
125
+ userdomain = Rex::Text.to_unicode(userdomain)
126
+ end
127
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmhash, userdomain)
128
+ end
129
+
130
+ # Create the LANMAN response
131
+ def self.lm_response(arg, half = false)
132
+ begin
133
+ hash = arg[:lm_hash]
134
+ chal = arg[:challenge]
135
+ rescue
136
+ raise ArgumentError
137
+ end
138
+ chal = BASE::pack_int64le(chal) if chal.is_a?(Integer)
139
+ if half then size = 7 else size = 21 end
140
+ keys = gen_keys hash.ljust(size, "\0")
141
+ apply_des(chal, keys).join
142
+ end
143
+
144
+ # Synonym of lm_response for old compatibility with lib/rex/proto/smb/crypt
145
+ def self.lanman_des(password, challenge)
146
+ lm_response({
147
+ :lm_hash => self.lm_hash(password),
148
+ :challenge => challenge
149
+ })
150
+ end
151
+
152
+ def self.ntlm_response(arg)
153
+ hash = arg[:ntlm_hash]
154
+ chal = arg[:challenge]
155
+ chal = BASE::pack_int64le(chal) if chal.is_a?(::Integer)
156
+ keys = gen_keys(hash.ljust(21, "\0"))
157
+ apply_des(chal, keys).join
158
+ end
159
+
160
+ #synonym of ntlm_response for old compatibility with lib/rex/proto/smb/crypt
161
+ def self.ntlm_md4(password, challenge)
162
+ ntlm_response({
163
+ :ntlm_hash => self.ntlm_hash(password),
164
+ :challenge => challenge
165
+ })
166
+ end
167
+
168
+ def self.ntlmv2_response(arg, opt = {})
169
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
170
+
171
+ key, chal = arg[:ntlmv2_hash], arg[:challenge]
172
+ if not (key and chal)
173
+ raise ArgumentError , 'ntlmv2_hash and challenge are mandatory'
174
+ end
175
+
176
+ chal = BASE::pack_int64le(chal) if chal.is_a?(::Integer)
177
+ bb = nil
178
+
179
+ if opt[:nt_client_challenge]
180
+ if opt[:nt_client_challenge].to_s.length <= 24
181
+ raise ArgumentError,"nt_client_challenge is not in a correct format "
182
+ end
183
+ bb = opt[:nt_client_challenge]
184
+ else
185
+ if not arg[:target_info]
186
+ raise ArgumentError, "target_info is mandatory in this case"
187
+ end
188
+
189
+ ti = arg[:target_info]
190
+ cc = opt[:client_challenge] || rand(CONST::MAX64)
191
+ cc = BASE::pack_int64le(cc) if cc.is_a?(::Integer)
192
+
193
+ ts = opt[:timestamp] || Time.now.to_i
194
+
195
+ # Convert the unix timestamp to windows format
196
+ # epoch -> milsec from Jan 1, 1601
197
+ ts = 10000000 * (ts + CONST::TIME_OFFSET)
198
+
199
+ blob = BASE::Blob.new
200
+ blob.timestamp = ts
201
+ blob.challenge = cc
202
+ blob.target_info = ti
203
+
204
+ bb = blob.serialize
205
+ end
206
+
207
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, chal + bb) + bb
208
+
209
+ end
210
+
211
+ def self.lmv2_response(arg, opt = {})
212
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
213
+ key = arg[:ntlmv2_hash]
214
+ chal = arg[:challenge]
215
+
216
+ chal = BASE::pack_int64le(chal) if chal.is_a?(::Integer)
217
+ cc = opt[:client_challenge] || rand(CONST::MAX64)
218
+ cc = BASE::pack_int64le(cc) if cc.is_a?(::Integer)
219
+
220
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, chal + cc) + cc
221
+ end
222
+
223
+ def self.ntlm2_session(arg, opt = {})
224
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
225
+ passwd_hash,chal = arg[:ntlm_hash],arg[:challenge]
226
+ if not (passwd_hash and chal)
227
+ raise RuntimeError, "ntlm_hash and challenge are required"
228
+ end
229
+
230
+ cc = opt[:client_challenge] || rand(CONST::MAX64)
231
+ cc = BASE::pack_int64le(cc) if cc.is_a?(Integer)
232
+
233
+ keys = gen_keys(passwd_hash.ljust(21, "\0"))
234
+ session_hash = OpenSSL::Digest::MD5.digest(chal + cc)[0,8]
235
+ response = apply_des(session_hash, keys).join
236
+ [cc.ljust(24, "\0"), response]
237
+ end
238
+
239
+ #
240
+ # Signing method added for metasploit project
241
+ #
242
+
243
+ # Used when only the LMv1 response is provided (i.e., with Win9x clients)
244
+ def self.lmv1_user_session_key(pass, opt = {})
245
+ if opt[:pass_is_hash]
246
+ usk = pass[0,8]
247
+ else
248
+ usk = self.lm_hash(pass.upcase[0,7],true)
249
+ end
250
+ usk.ljust(16,"\x00")
251
+ end
252
+
253
+ # This variant is used when the client sends the NTLMv1 response
254
+ def self.ntlmv1_user_session_key(pass, opt = {})
255
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
256
+
257
+ if opt[:pass_is_hash]
258
+ usk = pass
259
+ else
260
+ usk = self.ntlm_hash(pass)
261
+ end
262
+ OpenSSL::Digest::MD4.digest(usk)
263
+ end
264
+
265
+ # Used when NTLMv1 authentication is employed with NTLM2 session security
266
+ def self.ntlm2_session_user_session_key(pass, srv_chall, cli_chall, opt = {})
267
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
268
+
269
+ ntlm_key = self.ntlmv1_user_session_key(pass, opt )
270
+ session_chal = srv_chall + cli_chall
271
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlm_key, session_chal)
272
+ end
273
+
274
+ # Used when the LMv2 response is sent
275
+ def self.lmv2_user_session_key(user, pass, domain, srv_chall, cli_chall, opt = {})
276
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
277
+
278
+ ntlmv2_key = self.ntlmv2_hash(user, pass, domain, opt)
279
+ hash1 = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_key, srv_chall + cli_chall)
280
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_key, hash1)
281
+ end
282
+
283
+ # Used when the NTLMv2 response is sent
284
+ class << self; alias_method :ntlmv2_user_session_key, :lmv2_user_session_key; end
285
+
286
+ # Used when LanMan Key flag is set
287
+ def self.lanman_session_key(pass, srvchall, opt = {})
288
+ if opt[:pass_is_hash]
289
+ halfhash = pass[0,8]
290
+ else
291
+ halfhash = lm_hash(pass.upcase[0,7],true)
292
+ end
293
+ plain = self.lm_response({
294
+ :lm_hash => halfhash[0,7],
295
+ :challenge => srvchall
296
+ }, true )
297
+ key = halfhash + ["bdbdbdbdbdbd"].pack("H*")
298
+ keys = self.gen_keys(key)
299
+ apply_des(plain, keys).join
300
+ end
301
+
302
+ def self.encrypt_sessionkey(session_key, user_session_key)
303
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
304
+ cipher = OpenSSL::Cipher::Cipher.new('rc4')
305
+ cipher.encrypt
306
+ cipher.key = user_session_key
307
+ cipher.update(session_key)
308
+ end
309
+
310
+ def self.decrypt_sessionkey(encrypted_session_key, user_session_key)
311
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
312
+ cipher = OpenSSL::Cipher::Cipher.new('rc4')
313
+ cipher.decrypt
314
+ cipher.key = user_session_key
315
+ cipher.update(encrypted_session_key)
316
+ end
317
+
318
+ def self.make_weak_sessionkey(session_key,key_size,lanman_key = false)
319
+ case key_size
320
+ when 40
321
+ if lanman_key
322
+ return session_key[0,5] + "\xe5\x38\xb0"
323
+ else
324
+ return session_key[0,5]
325
+ end
326
+ when 56
327
+ if lanman_key
328
+ return session_key[0,7] + "\xa0"
329
+ else
330
+ return session_key[0,7]
331
+ end
332
+ else #128
333
+ return session_key[0,16]
334
+ end
335
+ end
336
+
337
+ end
338
+ end
339
+ end
340
+ end