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,9 @@
1
+ module Rex
2
+ module Proto
3
+ module NTLM
4
+ module Exceptions
5
+ end
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,533 @@
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 module defines the message class , useful for easily handling type 1/2/3 ntlm messages
47
+
48
+ require 'rex/proto/ntlm/base'
49
+ require 'rex/proto/ntlm/constants'
50
+ require 'rex/proto/ntlm/crypt'
51
+
52
+
53
+ module Rex
54
+ module Proto
55
+ module NTLM
56
+ class Message < Rex::Proto::NTLM::Base::FieldSet
57
+
58
+ BASE = Rex::Proto::NTLM::Base
59
+ CONST = Rex::Proto::NTLM::Constants
60
+
61
+
62
+ class << Message
63
+ def parse(str)
64
+ m = Type0.new
65
+ m.parse(str)
66
+ case m.type
67
+ when 1
68
+ t = Type1.parse(str)
69
+ when 2
70
+ t = Type2.parse(str)
71
+ when 3
72
+ t = Type3.parse(str)
73
+ else
74
+ raise ArgumentError, "unknown type: #{m.type}"
75
+ end
76
+ t
77
+ end
78
+
79
+ def decode64(str)
80
+ parse(Rex::Text::decode_base64(str))
81
+ end
82
+ end#self
83
+
84
+ def has_flag?(flag)
85
+ (self[:flag].value & CONST::FLAGS[flag]) == CONST::FLAGS[flag]
86
+ end
87
+
88
+ def set_flag(flag)
89
+ self[:flag].value |= CONST::FLAGS[flag]
90
+ end
91
+
92
+ def dump_flags
93
+ CONST::FLAG_KEYS.each{ |k| print(k, "=", flag?(k), "\n") }
94
+ end
95
+
96
+ def serialize
97
+ deflag
98
+ super + security_buffers.map{|n, f| f.value}.join
99
+ end
100
+
101
+ def encode64
102
+ Rex::Text::encode_base64(serialize)
103
+ end
104
+
105
+ def decode64(str)
106
+ parse(Rex::Text::decode_base64(str))
107
+ end
108
+
109
+ alias head_size size
110
+
111
+ def data_size
112
+ security_buffers.inject(0){|sum, a| sum += a[1].data_size}
113
+ end
114
+
115
+ def size
116
+ head_size + data_size
117
+ end
118
+
119
+ private
120
+
121
+ def security_buffers
122
+ @alist.find_all{|n, f| f.instance_of?(BASE::SecurityBuffer)}
123
+ end
124
+
125
+ def deflag
126
+ security_buffers.inject(head_size){|cur, a|
127
+ a[1].offset = cur
128
+ cur += a[1].data_size
129
+ }
130
+ end
131
+
132
+ def data_edge
133
+ security_buffers.map{ |n, f| f.active ? f.offset : size}.min
134
+ end
135
+
136
+ # sub class definitions
137
+
138
+ Type0 = Message.define {
139
+ string :sign, {:size => 8, :value => CONST::SSP_SIGN}
140
+ int32LE :type, {:value => 0}
141
+ }
142
+
143
+ Type1 = Message.define {
144
+ string :sign, {:size => 8, :value => CONST::SSP_SIGN}
145
+ int32LE :type, {:value => 1}
146
+ int32LE :flag, {:value => CONST::DEFAULT_FLAGS[:TYPE1] }
147
+ security_buffer :domain, {:value => "", :active => false}
148
+ security_buffer :workstation, {:value => "", :active => false}
149
+ string :padding, {:size => 0, :value => "", :active => false }
150
+ }
151
+
152
+ class Type1
153
+ class << Type1
154
+ def parse(str)
155
+ t = new
156
+ t.parse(str)
157
+ t
158
+ end
159
+ end
160
+
161
+ def parse(str)
162
+ super(str)
163
+ enable(:domain) if has_flag?(:DOMAIN_SUPPLIED)
164
+ enable(:workstation) if has_flag?(:WORKSTATION_SUPPLIED)
165
+ super(str)
166
+ if ( (len = data_edge - head_size) > 0)
167
+ self.padding = "\0" * len
168
+ super(str)
169
+ end
170
+ end
171
+ end
172
+
173
+ Type2 = Message.define{
174
+ string :sign, {:size => 8, :value => CONST::SSP_SIGN}
175
+ int32LE :type, {:value => 2}
176
+ security_buffer :target_name, {:size => 0, :value => ""}
177
+ int32LE :flag, {:value => CONST::DEFAULT_FLAGS[:TYPE2]}
178
+ int64LE :challenge, {:value => 0}
179
+ int64LE :context, {:value => 0, :active => false}
180
+ security_buffer :target_info, {:value => "", :active => false}
181
+ string :padding, {:size => 0, :value => "", :active => false }
182
+ }
183
+
184
+ class Type2
185
+ class << Type2
186
+ def parse(str)
187
+ t = new
188
+ t.parse(str)
189
+ t
190
+ end
191
+ end
192
+
193
+ def parse(str)
194
+ super(str)
195
+ if has_flag?(:TARGET_INFO)
196
+ enable(:context)
197
+ enable(:target_info)
198
+ super(str)
199
+ end
200
+ if ( (len = data_edge - head_size) > 0)
201
+ self.padding = "\0" * len
202
+ super(str)
203
+ end
204
+ end
205
+
206
+ def response(arg, opt = {})
207
+ usr = arg[:user]
208
+ pwd = arg[:password]
209
+ if usr.nil? or pwd.nil?
210
+ raise ArgumentError, "user and password have to be supplied"
211
+ end
212
+
213
+ if opt[:workstation]
214
+ ws = opt[:workstation]
215
+ else
216
+ ws = ""
217
+ end
218
+
219
+ if opt[:client_challenge]
220
+ cc = opt[:client_challenge]
221
+ else
222
+ cc = rand(CONST::MAX64)
223
+ end
224
+ cc = Rex::Text::pack_int64le(cc) if cc.is_a?(Integer)
225
+ opt[:client_challenge] = cc
226
+
227
+ if has_flag?(:OEM) and opt[:unicode]
228
+ usr = Rex::Text::to_ascii(usr,'utf-16le')
229
+ pwd = Rex::Text::to_ascii(pwd,'utf-16le')
230
+ ws = Rex::Text::to_ascii(ws,'utf-16le')
231
+ opt[:unicode] = false
232
+ end
233
+
234
+ if has_flag?(:UNICODE) and !opt[:unicode]
235
+ usr = Rex::Text::to_unicode(usr,'utf-16le')
236
+ pwd = Rex::Text::to_unicode(pwd,'utf-16le')
237
+ ws = Rex::Text::to_unicode(ws,'utf-16le')
238
+ opt[:unicode] = true
239
+ end
240
+
241
+ tgt = self.target_name
242
+ ti = self.target_info
243
+
244
+ chal = self[:challenge].serialize
245
+
246
+ if opt[:ntlmv2]
247
+ ar = { :ntlmv2_hash => NTLM::ntlmv2_hash(usr, pwd, tgt, opt),
248
+ :challenge => chal, :target_info => ti}
249
+ lm_res = NTLM::lmv2_response(ar, opt)
250
+ ntlm_res = NTLM::ntlmv2_response(ar, opt)
251
+ elsif has_flag?(:NTLM2_KEY)
252
+ ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal}
253
+ lm_res, ntlm_res = NTLM::ntlm2_session(ar, opt)
254
+ else
255
+ lm_res = NTLM::lm_response(pwd, chal)
256
+ ntlm_res = NTLM::ntlm_response(pwd, chal)
257
+ end
258
+
259
+ Type3.create({
260
+ :lm_response => lm_res,
261
+ :ntlm_response => ntlm_res,
262
+ :domain => tgt,
263
+ :user => usr,
264
+ :workstation => ws,
265
+ :flag => self.flag
266
+ })
267
+ end
268
+ end
269
+
270
+
271
+ Type3 = Message.define{
272
+ string :sign, {:size => 8, :value => CONST::SSP_SIGN}
273
+ int32LE :type, {:value => 3}
274
+ security_buffer :lm_response, {:value => ""}
275
+ security_buffer :ntlm_response, {:value => ""}
276
+ security_buffer :domain, {:value => ""}
277
+ security_buffer :user, {:value => ""}
278
+ security_buffer :workstation, {:value => ""}
279
+ security_buffer :session_key, {:value => "", :active => false }
280
+ int64LE :flag, {:value => 0, :active => false }
281
+ }
282
+
283
+ class Type3
284
+ class << Type3
285
+ def parse(str)
286
+ t = new
287
+ t.parse(str)
288
+ t
289
+ end
290
+
291
+ def create(arg, opt ={})
292
+ t = new
293
+ t.lm_response = arg[:lm_response]
294
+ t.ntlm_response = arg[:ntlm_response]
295
+ t.domain = arg[:domain]
296
+ t.user = arg[:user]
297
+ t.workstation = arg[:workstation]
298
+
299
+ if arg[:session_key]
300
+ t.enable(:session_key)
301
+ t.session_key = arg[session_key]
302
+ end
303
+ if arg[:flag]
304
+ t.enable(:session_key)
305
+ t.enable(:flag)
306
+ t.flag = arg[:flag]
307
+ end
308
+ t
309
+ end
310
+ end#self
311
+ end
312
+
313
+ public
314
+ #those class method have been merged from lib/rex/smb/utils
315
+
316
+ #
317
+ # Process Type 3 NTLM Message (in Base64)
318
+ #
319
+ # from http://www.innovation.ch/personal/ronald/ntlm.html
320
+ #
321
+ # struct {
322
+ # byte protocol[8]; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
323
+ # byte type; // 0x03
324
+ # byte zero[3];
325
+ #
326
+ # short lm_resp_len; // LanManager response length (always 0x18)
327
+ # short lm_resp_len; // LanManager response length (always 0x18)
328
+ # short lm_resp_off; // LanManager response offset
329
+ # byte zero[2];
330
+ #
331
+ # short nt_resp_len; // NT response length (always 0x18)
332
+ # short nt_resp_len; // NT response length (always 0x18)
333
+ # short nt_resp_off; // NT response offset
334
+ # byte zero[2];
335
+ #
336
+ # short dom_len; // domain string length
337
+ # short dom_len; // domain string length
338
+ # short dom_off; // domain string offset (always 0x40)
339
+ # byte zero[2];
340
+ #
341
+ # short user_len; // username string length
342
+ # short user_len; // username string length
343
+ # short user_off; // username string offset
344
+ # byte zero[2];
345
+ #
346
+ # short host_len; // host string length
347
+ # short host_len; // host string length
348
+ # short host_off; // host string offset
349
+ # byte zero[6];
350
+ #
351
+ # short msg_len; // message length
352
+ # byte zero[2];
353
+ #
354
+ # short flags; // 0x8201
355
+ # byte zero[2];
356
+ #
357
+ # byte dom[*]; // domain string (unicode UTF-16LE)
358
+ # byte user[*]; // username string (unicode UTF-16LE)
359
+ # byte host[*]; // host string (unicode UTF-16LE)
360
+ # byte lm_resp[*]; // LanManager response
361
+ # byte nt_resp[*]; // NT response
362
+ # } type_3_message
363
+ #
364
+ def self.process_type3_message(message)
365
+ decode = Rex::Text.decode_base64(message.strip)
366
+ type = decode[8,1].unpack("C").first
367
+ if (type == 3)
368
+ lm_len = decode[12,2].unpack("v").first
369
+ lm_offset = decode[16,2].unpack("v").first
370
+ lm = decode[lm_offset, lm_len].unpack("H*").first
371
+
372
+ nt_len = decode[20,2].unpack("v").first
373
+ nt_offset = decode[24,2].unpack("v").first
374
+ nt = decode[nt_offset, nt_len].unpack("H*").first
375
+
376
+ dom_len = decode[28,2].unpack("v").first
377
+ dom_offset = decode[32,2].unpack("v").first
378
+ domain = decode[dom_offset, dom_len]
379
+
380
+ user_len = decode[36,2].unpack("v").first
381
+ user_offset = decode[40,2].unpack("v").first
382
+ user = decode[user_offset, user_len]
383
+
384
+ host_len = decode[44,2].unpack("v").first
385
+ host_offset = decode[48,2].unpack("v").first
386
+ host = decode[host_offset, host_len]
387
+
388
+ return domain, user, host, lm, nt
389
+ else
390
+ return "", "", "", "", ""
391
+ end
392
+ end
393
+
394
+
395
+
396
+ #
397
+ # Process Type 1 NTLM Messages, return a Base64 Type 2 Message
398
+ #
399
+ def self.process_type1_message(message, nonce = "\x11\x22\x33\x44\x55\x66\x77\x88", win_domain = 'DOMAIN',
400
+ win_name = 'SERVER', dns_name = 'server', dns_domain = 'example.com', downgrade = true)
401
+
402
+ dns_name = Rex::Text.to_unicode(dns_name + "." + dns_domain)
403
+ win_domain = Rex::Text.to_unicode(win_domain)
404
+ dns_domain = Rex::Text.to_unicode(dns_domain)
405
+ win_name = Rex::Text.to_unicode(win_name)
406
+ decode = Rex::Text.decode_base64(message.strip)
407
+
408
+ type = decode[8,1].unpack("C").first
409
+
410
+ if (type == 1)
411
+ # A type 1 message has been received, lets build a type 2 message response
412
+
413
+ reqflags = decode[12,4]
414
+ reqflags = reqflags.unpack("V").first
415
+
416
+ if (reqflags & CONST::REQUEST_TARGET) == CONST::REQUEST_TARGET
417
+
418
+ if (downgrade)
419
+ # At this time NTLMv2 and signing requirements are not supported
420
+ if (reqflags & CONST::NEGOTIATE_NTLM2_KEY) == CONST::NEGOTIATE_NTLM2_KEY
421
+ reqflags = reqflags - CONST::NEGOTIATE_NTLM2_KEY
422
+ end
423
+ if (reqflags & CONST::NEGOTIATE_ALWAYS_SIGN) == CONST::NEGOTIATE_ALWAYS_SIGN
424
+ reqflags = reqflags - CONST::NEGOTIATE_ALWAYS_SIGN
425
+ end
426
+ end
427
+
428
+ flags = reqflags + CONST::TARGET_TYPE_DOMAIN + CONST::TARGET_TYPE_SERVER
429
+ tid = true
430
+
431
+ tidoffset = 48 + win_domain.length
432
+ tidbuff =
433
+ [2].pack('v') + # tid type, win domain
434
+ [win_domain.length].pack('v') +
435
+ win_domain +
436
+ [1].pack('v') + # tid type, server name
437
+ [win_name.length].pack('v') +
438
+ win_name +
439
+ [4].pack('v') + # tid type, domain name
440
+ [dns_domain.length].pack('v') +
441
+ dns_domain +
442
+ [3].pack('v') + # tid type, dns_name
443
+ [dns_name.length].pack('v') +
444
+ dns_name
445
+ else
446
+ flags = CONST::NEGOTIATE_UNICODE + CONST::NEGOTIATE_NTLM
447
+ tid = false
448
+ end
449
+
450
+ type2msg = "NTLMSSP\0" + # protocol, 8 bytes
451
+ "\x02\x00\x00\x00" # type, 4 bytes
452
+
453
+ if (tid)
454
+ type2msg += # Target security info, 8 bytes. Filled if REQUEST_TARGET
455
+ [win_domain.length].pack('v') + # Length, 2 bytes
456
+ [win_domain.length].pack('v') # Allocated space, 2 bytes
457
+ end
458
+
459
+ type2msg +="\x30\x00\x00\x00" + # Offset, 4 bytes
460
+ [flags].pack('V') + # flags, 4 bytes
461
+ nonce + # the nonce, 8 bytes
462
+ "\x00" * 8 # Context (all 0s), 8 bytes
463
+
464
+ if (tid)
465
+ type2msg += # Target information security buffer. Filled if REQUEST_TARGET
466
+ [tidbuff.length].pack('v') + # Length, 2 bytes
467
+ [tidbuff.length].pack('v') + # Allocated space, 2 bytes
468
+ [tidoffset].pack('V') + # Offset, 4 bytes (usually \x48 + length of win_domain)
469
+ win_domain + # Target name data (domain in unicode if REQUEST_UNICODE)
470
+ # Target information data
471
+ tidbuff + # Type, 2 bytes
472
+ # Length, 2 bytes
473
+ # Data (in unicode if REQUEST_UNICODE)
474
+ "\x00\x00\x00\x00" # Terminator, 4 bytes, all \x00
475
+ end
476
+
477
+ type2msg = Rex::Text.encode_base64(type2msg).delete("\n") # base64 encode and remove the returns
478
+ else
479
+ # This is not a Type2 message
480
+ type2msg = ""
481
+ end
482
+
483
+ return type2msg
484
+ end
485
+
486
+ #
487
+ # Downgrading Type messages to LMv1/NTLMv1 and removing signing
488
+ #
489
+ def self.downgrade_type_message(message)
490
+ decode = Rex::Text.decode_base64(message.strip)
491
+
492
+ type = decode[8,1].unpack("C").first
493
+
494
+ if (type > 0 and type < 4)
495
+ reqflags = decode[12..15] if (type == 1 or type == 3)
496
+ reqflags = decode[20..23] if (type == 2)
497
+ reqflags = reqflags.unpack("V")
498
+
499
+ # Remove NEGOTIATE_NTLMV2_KEY and NEGOTIATE_ALWAYS_SIGN, this lowers the negotiation
500
+ # down to LMv1/NTLMv1.
501
+ if (reqflags & CONST::NEGOTIATE_NTLM2_KEY) == CONST::NEGOTIATE_NTLM2_KEY
502
+ reqflags = reqflags - CONST::NEGOTIATE_NTLM2_KEY
503
+ end
504
+ if (reqflags & CONST::NEGOTIATE_ALWAYS_SIGN) == CONST::NEGOTIATE_ALWAYS_SIGN
505
+ reqflags = reqflags - CONST::NEGOTIATE_ALWAYS_SIGN
506
+ end
507
+
508
+ # Return the flags back to the decode so we can base64 it again
509
+ flags = reqflags.to_s(16)
510
+ 0.upto(8) do |idx|
511
+ if (idx > flags.length)
512
+ flags.insert(0, "0")
513
+ end
514
+ end
515
+
516
+ idx = 0
517
+ 0.upto(3) do |cnt|
518
+ if (type == 2)
519
+ decode[23-cnt] = [flags[idx,1]].pack("C")
520
+ else
521
+ decode[15-cnt] = [flags[idx,1]].pack("C")
522
+ end
523
+ idx += 2
524
+ end
525
+
526
+ end
527
+ return Rex::Text.encode_base64(decode).delete("\n") # base64 encode and remove the returns
528
+ end
529
+
530
+ end
531
+ end
532
+ end
533
+ end