rex 2.0.3 → 2.0.4

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.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MDQwMjkwNWY0OTJlZGI3NDkyYjg2NWE0MzQ1ODE2MGU5NWFjNGRiYw==
5
- data.tar.gz: !binary |-
6
- NDQ2YzQwN2FiNzY1Y2M0YjY3YzE0NTU1NDc1OWZjZDNlZDc4MDliZA==
2
+ SHA1:
3
+ metadata.gz: 79a1308c4fbc5e37cc531c402b45228f0480314a
4
+ data.tar.gz: 55b5f247534fdac3322b929d4c46e4846c9ec9bb
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ZTk4N2VhZWJlNzkyZjhmYTA2MWM0NTM0NzU2MTc1MjgzZTRjYzY5ZTJhNGZi
10
- NDFiOGIzNjIwZGQwZjVkYTk4MmU3YzEzYTA4MDgxNmFiY2YyYTFlNjA3M2U1
11
- ZGI3YmY0MjRiMjc2ODk1MzAxYTRkNTIzYjFjNGVlOGJjYjc2NzI=
12
- data.tar.gz: !binary |-
13
- NDM1MjdjM2MyNjZjMWM3MmQ4M2JmMWJlZmU0Nzg5MDdmYjc1NDIzZmJjZTcx
14
- NjI3MjUzOTY1NWZkNmMwYzNiN2JjZDRhODU5MDBhMWM0Nzk3ZjhkMDY5M2M3
15
- MWY3MWM3YTcwM2Y2ZDQ0NWMxMDg0Mjc2N2RhZjg0ZWQ5MWJjNTA=
6
+ metadata.gz: 49e7741c0bc14e27943de1291b38e69300173bdffd3a1598372d5db5d1338040201ef011e67680bf42ba611948dd18cc5ad0627388a80d1079ef58c80088bd3e
7
+ data.tar.gz: 10161b1c288d4c7aab84399ad7f66048ef276d7225b4a701b8ac8eac784ada87786499137dad1fed0f652c4dea529b65c7678f7e2b0b958be5e29dc232da480b
data/lib/rex.rb CHANGED
@@ -1,8 +1,9 @@
1
+ # -*- coding: binary -*-
1
2
  =begin
2
3
 
3
4
  The Metasploit Rex library is provided under the 3-clause BSD license.
4
5
 
5
- Copyright (c) 2005-2010, Rapid7, Inc.
6
+ Copyright (c) 2005-2014, Rapid7, Inc.
6
7
  All rights reserved.
7
8
 
8
9
  Redistribution and use in source and binary forms, with or without modification,
@@ -48,7 +48,7 @@ module Arch
48
48
  case arch
49
49
  when ARCH_X86
50
50
  [addr].pack('V')
51
- when ARCH_X86_64
51
+ when ARCH_X86_64, ARCH_X64
52
52
  [addr].pack('Q<')
53
53
  when ARCH_MIPS # ambiguous
54
54
  [addr].pack('N')
@@ -244,7 +244,7 @@ module X86
244
244
  _check_reg(dst)
245
245
 
246
246
  # If the value is 0 try xor/sub dst, dst (2 bytes)
247
- if(val == 0)
247
+ if val == 0
248
248
  opcodes = Rex::Text.remove_badchars("\x29\x2b\x31\x33", badchars)
249
249
  if !opcodes.empty?
250
250
  return opcodes[rand(opcodes.length)].chr + encode_modrm(dst, dst)
@@ -261,8 +261,9 @@ module X86
261
261
 
262
262
  # try clear dst, mov BYTE dst (4 bytes)
263
263
  begin
264
- # break if val == 0
265
- return _check_badchars(clear(dst, badchars) + mov_byte(dst, val), badchars)
264
+ unless val == 0 # clear tries to set(dst, 0, badchars), entering an infinite recursion
265
+ return _check_badchars(clear(dst, badchars) + mov_byte(dst, val), badchars)
266
+ end
266
267
  rescue ::ArgumentError, ::RuntimeError, ::RangeError
267
268
  end
268
269
 
@@ -280,8 +281,9 @@ module X86
280
281
 
281
282
  # try clear dst, mov WORD dst (6 bytes)
282
283
  begin
283
- # break if val == 0
284
- return _check_badchars(clear(dst, badchars) + mov_word(dst, val), badchars)
284
+ unless val == 0 # clear tries to set(dst, 0, badchars), entering an infinite recursion
285
+ return _check_badchars(clear(dst, badchars) + mov_word(dst, val), badchars)
286
+ end
285
287
  rescue ::ArgumentError, ::RuntimeError, ::RangeError
286
288
  end
287
289
 
@@ -34,7 +34,7 @@ class Elf < ElfBase
34
34
  isource.read(offset, PROGRAM_HEADER_SIZE), ei_data
35
35
  )
36
36
 
37
- if program_header[-1].p_type == PT_LOAD && base_addr == 0
37
+ if program_header[-1].p_type == PT_LOAD && program_header[-1].p_flags & PF_EXEC > 0
38
38
  base_addr = program_header[-1].p_vaddr
39
39
  end
40
40
 
@@ -214,6 +214,15 @@ class ElfBase
214
214
  [ 'uint32n', 'p_align', 0 ]
215
215
  )
216
216
 
217
+ # p_flags This member tells which permissions should have the segment
218
+
219
+ # Flags
220
+
221
+ PF_EXEC = 1
222
+ PF_WRITE = 2
223
+ PF_READ = 4
224
+
225
+
217
226
  #
218
227
  # p_type This member tells what kind of segment this array element
219
228
  # describes or how to interpret the array element's information.
@@ -7,7 +7,7 @@ module Encoder
7
7
 
8
8
  class NonAlpha
9
9
 
10
- def NonAlpha.gen_decoder()
10
+ def NonAlpha.gen_decoder
11
11
  decoder =
12
12
  "\x66\xB9\xFF\xFF" +
13
13
  "\xEB\x19" + # Jmp to table
@@ -28,13 +28,13 @@ class NonAlpha
28
28
  end
29
29
 
30
30
  def NonAlpha.encode_byte(block, table, tablelen)
31
- if (tablelen > 255) or (block == 0x7B)
31
+ if tablelen > 255 || block == 0x7B
32
32
  raise RuntimeError, "BadChar"
33
33
  end
34
34
 
35
- if (block >= 0x41 and block <= 0x5A) or (block >= 0x61 and block <= 0x7A)
35
+ if (block >= 0x41 && block <= 0x5A) || (block >= 0x61 && block <= 0x7A)
36
36
  # gen offset, return magic
37
- offset = 0x7b - block;
37
+ offset = 0x7b - block
38
38
  table += offset.chr
39
39
  tablelen = tablelen + 1
40
40
  block = 0x7B
@@ -15,10 +15,12 @@ class Detect
15
15
  # Provides several javascript functions for determining the OS and browser versions of a client.
16
16
  #
17
17
  # getVersion(): returns an object with the following properties
18
- # os_name - OS name, one of the Msf::OperatingSystems constants
19
- # os_flavor - OS flavor as a string (e.g.: "XP", "2000")
18
+ # os_name - OS name such as "Windows 8", "Linux", "Mac OS X"
19
+ # os_flavor - OS flavor as a string such as "Home", "Enterprise", etc
20
20
  # os_sp - OS service pack (e.g.: "SP2", will be empty on non-Windows)
21
21
  # os_lang - OS language (e.g.: "en-us")
22
+ # os_vendor - A company or organization name such as Microsoft, Ubuntu, Apple, etc
23
+ # os_device - A specific piece of hardware such as iPad, iPhone, etc
22
24
  # ua_name - Client name, one of the Msf::HttpClients constants
23
25
  # ua_version - Client version as a string (e.g.: "3.5.1", "6.0;SP2")
24
26
  # arch - Architecture, one of the ARCH_* constants
@@ -1,513 +1,17 @@
1
1
  # -*- coding: binary -*-
2
2
 
3
- require 'rex/text'
4
- require 'rex/random_identifier_generator'
5
- require 'rkelly'
3
+ require 'jsobfu'
6
4
 
7
5
  module Rex
8
6
  module Exploitation
9
7
 
10
-
11
- #
12
- # Obfuscate JavaScript by randomizing as much as possible and removing
13
- # easily-signaturable string constants.
14
- #
15
- # Example:
16
- # js = ::Rex::Exploitation::JSObfu.new %Q|
17
- # var a = "0\\612\\063\\x34\\x35\\x36\\x37\\x38\\u0039";
18
- # var b = { foo : "foo", bar : "bar" }
19
- # alert(a);
20
- # alert(b.foo);
21
- # |
22
- # js.obfuscate
23
- # puts js
24
- # Example Output:
25
- # var VwxvESbCgv = String.fromCharCode(0x30,0x31,062,063,064,53,0x36,067,070,0x39);
26
- # var ToWZPn = {
27
- # "\146\157\x6f": (function () { var yDyv="o",YnCL="o",Qcsa="f"; return Qcsa+YnCL+yDyv })(),
28
- # "\142ar": String.fromCharCode(0142,97,0162)
29
- # };
30
- # alert(VwxvESbCgv);
31
- # alert(ToWZPn.foo);
32
- #
33
- # NOTE: Variables MUST be declared with a 'var' statement BEFORE first use (or
34
- # not at all) for this to generate correct code! If variables are not declared
35
- # they will not be randomized but the generated code will be correct.
36
8
  #
37
- # Bad Example Javascript:
38
- # a = "asdf"; // this variable hasn't been declared and will not be randomized
39
- # var a;
40
- # alert(a); // real js engines will alert "asdf" here
41
- # Bad Example Obfuscated:
42
- # a = (function () { var hpHu="f",oyTm="asd"; return oyTm+hpHu })();
43
- # var zSrnHpEfJZtg;
44
- # alert(zSrnHpEfJZtg);
45
- # Notice that the first usage of +a+ (before it was declared) is not
46
- # randomized. Thus, the obfuscated version will alert 'undefined' instead of
47
- # "asdf".
9
+ # Simple wrapper class that makes the JSObfu functionality
10
+ # from the gem available under the Rex namespace.
48
11
  #
49
- class JSObfu
50
-
51
- # these keywords should never be used as a random var name
52
- # source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
53
- RESERVED_KEYWORDS = %w(
54
- break case catch continue debugger default delete do else finally
55
- for function if in instanceof new return switch this throw try
56
- typeof var void while with class enum export extends import super
57
- implements interface let package private protected public static yield
58
- )
59
-
60
- #
61
- # Abstract Syntax Tree generated by RKelly::Parser#parse
62
- #
63
- attr_reader :ast
64
-
65
- #
66
- # Saves +code+ for later obfuscation with #obfuscate
67
- #
68
- def initialize(code)
69
- @code = code
70
- @funcs = {}
71
- @vars = {}
72
- @debug = false
73
- @rand_gen = Rex::RandomIdentifierGenerator.new(
74
- :max_length => 15,
75
- :first_char_set => Rex::Text::Alpha+"_$",
76
- :char_set => Rex::Text::AlphaNumeric+"_$"
77
- )
78
- end
79
-
80
- #
81
- # Add +str+ to the un-obfuscated code.
82
- #
83
- # Calling this method after #obfuscate is undefined
84
- #
85
- def <<(str)
86
- @code << str
87
- end
88
-
89
- #
90
- # Return the (possibly obfuscated) code as a string.
91
- #
92
- # If #obfuscate has not been called before this, returns the parsed,
93
- # unobfuscated code. This can be useful for example to remove comments and
94
- # standardize spacing.
95
- #
96
- def to_s
97
- parse if not @ast
98
- @ast.to_ecma
99
- end
100
-
101
- #
102
- # Return the obfuscated name of a symbol
103
- #
104
- # You MUST call #obfuscate before this method!
105
- #
106
- def sym(lookup)
107
- if @vars[lookup]
108
- ret = @vars[lookup]
109
- elsif @funcs[lookup]
110
- ret = @funcs[lookup]
111
- else
112
- ret = lookup
113
- end
114
- ret
115
- end
116
-
117
- #
118
- # Parse and obfuscate
119
- #
120
- def obfuscate
121
- parse
122
- obfuscate_r(@ast)
123
- end
124
-
125
- # @return [String] a unique random var name that is not a reserved keyword
126
- def random_var_name
127
- loop do
128
- text = random_string
129
- unless @vars.has_value?(text) or RESERVED_KEYWORDS.include?(text)
130
- return text
131
- end
132
- end
133
- end
134
-
135
- protected
136
-
137
- # @return [String] a random string
138
- def random_string
139
- @rand_gen.generate
140
- end
141
-
142
- #
143
- # Recursive method to obfuscate the given +ast+.
144
- #
145
- # +ast+ should be the result of RKelly::Parser#parse
146
- #
147
- def obfuscate_r(ast)
148
- ast.each do |node|
149
- #if node.respond_to? :value and node.value.kind_of? String and node.value =~ /bodyOnLoad/i
150
- # $stdout.puts("bodyOnLoad: #{node.class}: #{node.value}")
151
- #end
152
-
153
- case node
154
- when nil
155
- nil
156
-
157
- when ::RKelly::Nodes::SourceElementsNode
158
- # Recurse
159
- obfuscate_r(node.value)
160
-
161
- #when ::RKelly::Nodes::ObjectLiteralNode
162
- # TODO
163
- #$stdout.puts(node.methods - Object.new.methods)
164
- #$stdout.puts(node.value.inspect)
165
-
166
- when ::RKelly::Nodes::PropertyNode
167
- # Property names must be bare words or string literals NOT
168
- # expressions! Can't use transform_string() here
169
- if node.name =~ /^[a-zA-Z_][a-zA-Z0-9_]*$/
170
- n = '"'
171
- node.name.unpack("C*") { |c|
172
- case rand(3)
173
- when 0; n << "\\x%02x"%(c)
174
- when 1; n << "\\#{c.to_s 8}"
175
- when 2; n << [c].pack("C")
176
- end
177
- }
178
- n << '"'
179
- node.instance_variable_set(:@name, n)
180
- end
181
-
182
- # Variables
183
- when ::RKelly::Nodes::VarDeclNode
184
- if @vars[node.name].nil?
185
- @vars[node.name] = random_var_name
186
- end
187
- node.name = @vars[node.name]
188
- when ::RKelly::Nodes::ParameterNode
189
- if @vars[node.value].nil?
190
- @vars[node.value] = random_var_name
191
- end
192
- node.value = @vars[node.value]
193
- when ::RKelly::Nodes::ResolveNode
194
- #$stdout.puts("Resolve bodyOnload: #{@vars[node.value]}") if "bodyOnLoad" == node.value
195
- node.value = @vars[node.value] if @vars[node.value]
196
- when ::RKelly::Nodes::DotAccessorNode
197
- case node.value
198
- when ::RKelly::Nodes::ResolveNode
199
- if @vars[node.value.value]
200
- node.value.value = @vars[node.value.value]
201
- end
202
- #else
203
- # $stderr.puts("Non-resolve node as target of dotaccessor: #{node.value.class}")
204
- end
205
-
206
- # Functions
207
- when ::RKelly::Nodes::FunctionDeclNode
208
- #$stdout.puts("FunctionDecl: #{node.value}")
209
- # Functions can also act as objects, so store them in the vars
210
- # and the functions list so we can replace them in both places
211
- if @funcs[node.value].nil? and not @funcs.values.include?(node.value)
212
- @funcs[node.value] = random_var_name
213
- if @vars[node.value].nil?
214
- @vars[node.value] = @funcs[node.value]
215
- end
216
- node.value = @funcs[node.value]
217
- end
218
- when ::RKelly::Nodes::FunctionCallNode
219
- # The value of a FunctionCallNode is some sort of accessor node or a ResolveNode
220
- # so this is basically useless
221
- #$stdout.puts("Function call: #{node.name} => #{@funcs[node.name]}")
222
- #node.value = @funcs[node.value] if @funcs[node.value]
223
-
224
- # Transformers
225
- when ::RKelly::Nodes::NumberNode
226
- node.value = transform_number(node.value)
227
- when ::RKelly::Nodes::StringNode
228
- node.value = transform_string(node.value)
229
- else
230
- #$stderr.puts "#{node.class}: #{node.value}"
231
- #$stderr.puts "#{node.class}"
232
- end
233
-
234
- #unless node.kind_of? ::RKelly::Nodes::SourceElementsNode
235
- # $stderr.puts "#{node.class}: #{node.value}"
236
- #end
237
- end
238
-
239
- nil
240
- end
241
-
242
- #
243
- # Generate an Abstract Syntax Tree (#ast) for later obfuscation
244
- #
245
- def parse
246
- parser = RKelly::Parser.new
247
- @ast = parser.parse(@code)
248
- end
249
-
250
- #
251
- # Convert a number to a random base (decimal, octal, or hexedecimal).
252
- #
253
- # Given 10 as input, the possible return values are:
254
- # "10"
255
- # "0xa"
256
- # "012"
257
- #
258
- def rand_base(num)
259
- case rand(3)
260
- when 0; num.to_s
261
- when 1; "0%o" % num
262
- when 2; "0x%x" % num
263
- end
264
- end
265
-
266
- #
267
- # Return a mathematical expression that will evaluate to the given number
268
- # +num+.
269
- #
270
- # +num+ can be a float or an int, but should never be negative.
271
- #
272
- def transform_number(num)
273
- case num
274
- when Fixnum
275
- if num == 0
276
- r = rand(10) + 1
277
- transformed = "('#{Rex::Text.rand_text_alpha(r)}'.length - #{r})"
278
- elsif num > 0 and num < 10
279
- # use a random string.length for small numbers
280
- transformed = "'#{Rex::Text.rand_text_alpha(num)}'.length"
281
- else
282
- transformed = "("
283
- divisor = rand(num) + 1
284
- a = num / divisor.to_i
285
- b = num - (a * divisor)
286
- # recurse half the time for a
287
- a = (rand(2) == 0) ? transform_number(a) : rand_base(a)
288
- # recurse half the time for divisor
289
- divisor = (rand(2) == 0) ? transform_number(divisor) : rand_base(divisor)
290
- transformed << "#{a}*#{divisor}"
291
- transformed << "+#{b}"
292
- transformed << ")"
293
- end
294
- when Float
295
- transformed = "(#{num - num.floor} + #{rand_base(num.floor)})"
296
- end
297
-
298
- #puts("#{num} == #{transformed}")
299
-
300
- transformed
301
- end
302
-
303
- #
304
- # Convert a javascript string into something that will generate that string.
305
- #
306
- # Randomly calls one of the +transform_string_*+ methods
307
- #
308
- def transform_string(str)
309
- quote = str[0,1]
310
- # pull off the quotes
311
- str = str[1,str.length - 2]
312
- return quote*2 if str.length == 0
313
-
314
- case rand(2)
315
- when 0
316
- transformed = transform_string_split_concat(str, quote)
317
- when 1
318
- transformed = transform_string_fromCharCode(str)
319
- #when 2
320
- # # Currently no-op
321
- # transformed = transform_string_unescape(str)
322
- end
323
-
324
- #$stderr.puts "Obfuscating str: #{str.ljust 30} #{transformed}"
325
- transformed
326
- end
327
-
328
- #
329
- # Split a javascript string, +str+, without breaking escape sequences.
330
- #
331
- # The maximum length of each piece of the string is half the total length
332
- # of the string, ensuring we (almost) always split into at least two
333
- # pieces. This won't always be true when given a string like "AA\x41",
334
- # where escape sequences artificially increase the total length (escape
335
- # sequences are considered a single character).
336
- #
337
- # Returns an array of two-element arrays. The zeroeth element is a
338
- # randomly generated variable name, the first is a piece of the string
339
- # contained in +quote+s.
340
- #
341
- # See #escape_length
342
- #
343
- def safe_split(str, quote)
344
- parts = []
345
- max_len = str.length / 2
346
- while str.length > 0
347
- len = 0
348
- loop do
349
- e_len = escape_length(str[len..-1])
350
- e_len = 1 if e_len.nil?
351
- len += e_len
352
- # if we've reached the end of the string, bail
353
- break unless str[len]
354
- break if len > max_len
355
- # randomize the length of each part
356
- break if (rand(4) == 0)
357
- end
358
-
359
- part = str.slice!(0, len)
360
-
361
- var = Rex::Text.rand_text_alpha(4)
362
- parts.push( [ var, "#{quote}#{part}#{quote}" ] )
363
- end
364
-
365
- parts
366
- end
367
-
368
- #
369
- # Stolen from obfuscatejs.rb
370
- #
371
- # Determines the length of an escape sequence
372
- #
373
- def escape_length(str)
374
- esc_len = nil
375
- if str[0,1] == "\\"
376
- case str[1,1]
377
- when "u"; esc_len = 6 # unicode \u1234
378
- when "x"; esc_len = 4 # hex, \x41
379
- when /[0-7]/ # octal, \123, \0
380
- str[1,3] =~ /([0-7]{1,3})/
381
- if $1.to_i(8) > 255
382
- str[1,3] =~ /([0-7]{1,2})/
383
- end
384
- esc_len = 1 + $1.length
385
- else; esc_len = 2 # \" \n, etc.
386
- end
387
- end
388
- esc_len
389
- end
390
-
391
- #
392
- # Split a javascript string, +str+, into multiple randomly-ordered parts
393
- # and return an anonymous javascript function that joins them in the
394
- # correct order. This method can be called safely on strings containing
395
- # escape sequences. See #safe_split.
396
- #
397
- def transform_string_split_concat(str, quote)
398
- parts = safe_split(str, quote)
399
- func = "(function () { var "
400
- ret = "; return "
401
- parts.sort { |a,b| rand }.each do |part|
402
- func << "#{part[0]}=#{part[1]},"
403
- end
404
- func.chop!
405
-
406
- ret << parts.map{|part| part[0]}.join("+")
407
- final = func + ret + " })()"
408
-
409
- final
410
- end
411
-
412
-
413
- # TODO
414
- #def transform_string_unescape(str)
415
- # str
416
- #end
417
-
418
- #
419
- # Return a call to String.fromCharCode() with each char of the input as arguments
420
- #
421
- # Example:
422
- # input : "A\n"
423
- # output: String.fromCharCode(0x41, 10)
424
- #
425
- def transform_string_fromCharCode(str)
426
- buf = "String.fromCharCode("
427
- bytes = str.unpack("C*")
428
- len = 0
429
- while str.length > 0
430
- if str[0,1] == "\\"
431
- str.slice!(0,1)
432
- # then this is an escape sequence and we need to deal with all
433
- # the special cases
434
- case str[0,1]
435
- # For chars that contain their non-escaped selves, step past
436
- # the backslash and let the rand_base() below decide how to
437
- # represent the character.
438
- when '"', "'", "\\", " "
439
- char = str.slice!(0,1).unpack("C").first
440
- # For symbolic escapes, use the known value
441
- when "n"; char = 0x0a; str.slice!(0,1)
442
- when "t"; char = 0x09; str.slice!(0,1)
443
- # Lastly, if it's a hex, unicode, or octal escape, pull out the
444
- # real value and use that
445
- when "x"
446
- # Strip the x
447
- str.slice!(0,1)
448
- char = str.slice!(0,2).to_i 16
449
- when "u"
450
- # This can potentially lose information in the case of
451
- # characters like \u0041, but since regular ascii is stored
452
- # as unicode internally, String.fromCharCode(0x41) will be
453
- # represented as 00 41 in memory anyway, so it shouldn't
454
- # matter.
455
- str.slice!(0,1)
456
- char = str.slice!(0,4).to_i 16
457
- when /[0-7]/
458
- # Octals are a bit harder since they are variable width and
459
- # don't necessarily mean what you might think. For example,
460
- # "\61" == "1" and "\610" == "10". 610 is a valid octal
461
- # number, but not a valid ascii character. Javascript will
462
- # interpreter as much as it can as a char and use the rest
463
- # as a literal. Boo.
464
- str =~ /([0-7]{1,3})/
465
- char = $1.to_i 8
466
- if char > 255
467
- str =~ /([0-7]{1,2})/
468
- char = $1.to_i 8
469
- end
470
- str.slice!(0,$1.length)
471
- end
472
- else
473
- char = str.slice!(0,1).unpack("C").first
474
- end
475
- buf << "#{rand_base(char)},"
476
- end
477
- # Strip off the last comma
478
- buf = buf[0,buf.length-1] + ")"
479
- transformed = buf
480
-
481
- transformed
482
- end
483
-
12
+ class JSObfu < ::JSObfu
484
13
 
485
14
  end
486
- end
487
- end
488
-
489
-
490
- =begin
491
- if __FILE__ == $0
492
- if ARGV[0]
493
- code = File.read(ARGV[0])
494
- else
495
- #require 'rex/exploitation/javascriptosdetect'
496
- #code = Rex::Exploitation::JavascriptOSDetect.new.to_s
497
- code = <<-EOS
498
- // Should alert "0123456789"
499
- var a = "0\\612\\063\\x34\\x35\\x36\\x37\\x38\\u0039";
500
- var a,b=2,c=3;
501
- alert(a);
502
- // should alert "asdfjkl;"
503
- var d = (function() { var foo = "jkl;", blah = "asdf"; return blah + foo; })();
504
- alert(d);
505
- EOS
506
- end
507
- js = Rex::Exploitation::JSObfu.new(code)
508
- js.obfuscate
509
- puts js.to_s
510
15
 
511
16
  end
512
-
513
- =end
17
+ end
@@ -29,8 +29,12 @@ class ImageSource
29
29
  # FIXME, make me better
30
30
  string = ''
31
31
  loop do
32
- char = read(offset, 1)
33
- break if char == "\x00"
32
+ begin
33
+ char = read(offset, 1)
34
+ rescue RangeError
35
+ break
36
+ end
37
+ break if char.nil? || char == "\x00"
34
38
  offset += 1
35
39
  string << char
36
40
  end
@@ -25,8 +25,9 @@ class Header
25
25
  next
26
26
  end
27
27
 
28
- var,val = line.split(':')
29
- next if not val
28
+ var, val = line.split(':', 2)
29
+ next if val.nil?
30
+
30
31
  self.headers << [ var.to_s.strip, val.to_s.strip ]
31
32
  prev = self.headers.length - 1
32
33
  end
@@ -24,9 +24,8 @@ class Message
24
24
  self.header.parse(head)
25
25
  ctype = self.header.find('Content-Type')
26
26
 
27
- if ctype and ctype[1] and ctype[1] =~ /multipart\/mixed;\s*boundary=([^\s]+)/
27
+ if ctype and ctype[1] and ctype[1] =~ /multipart\/mixed;\s*boundary="?([A-Za-z0-9'\(\)\+\_,\-\.\/:=\?^\s]+)"?/
28
28
  self.bound = $1
29
-
30
29
  chunks = body.to_s.split(/--#{self.bound}(--)?\r?\n/)
31
30
  self.content = chunks.shift.to_s.gsub(/\s+$/, '')
32
31
  self.content << "\r\n" if not self.content.empty?
@@ -504,7 +504,7 @@ module Rex
504
504
  }
505
505
  }
506
506
  note[:data][:vendor] = @report_data[:os]["os_vendor"] if @report_data[:os]["os_vendor"]
507
- note[:data][:product] = @report_data[:os]["os_product"] if @report_data[:os]["os_prduct"]
507
+ note[:data][:product] = @report_data[:os]["os_product"] if @report_data[:os]["os_product"]
508
508
  note[:data][:version] = @report_data[:os]["os_version"] if @report_data[:os]["os_version"]
509
509
  note[:data][:arch] = @report_data[:os]["os_arch"] if @report_data[:os]["os_arch"]
510
510
  db_report(:note, note)
@@ -248,7 +248,7 @@ class Client
248
248
  cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
249
249
  cert.sign(key, OpenSSL::Digest::SHA1.new)
250
250
 
251
- ctx = OpenSSL::SSL::SSLContext.new(:SSLv3)
251
+ ctx = OpenSSL::SSL::SSLContext.new
252
252
  ctx.key = key
253
253
  ctx.cert = cert
254
254
 
@@ -19,8 +19,10 @@ OpDHCPServer = 0x36
19
19
  OpLeaseTime = 0x33
20
20
  OpSubnetMask = 1
21
21
  OpRouter = 3
22
+ OpDomainName = 15
22
23
  OpDns = 6
23
24
  OpHostname = 0x0c
25
+ OpURL = 0x72
24
26
  OpEnd = 0xff
25
27
 
26
28
  PXEMagic = "\xF1\x00\x74\x7E"
@@ -94,6 +94,9 @@ class Server
94
94
  self.pxealtconfigfile = "update0"
95
95
  self.pxepathprefix = ""
96
96
  self.pxereboottime = 2000
97
+
98
+ self.domain_name = hash['DOMAINNAME'] || nil
99
+ self.url = hash['URL'] if hash.include?('URL')
97
100
  end
98
101
 
99
102
  def report(&block)
@@ -126,7 +129,7 @@ class Server
126
129
  allowed_options = [
127
130
  :serveOnce, :pxealtconfigfile, :servePXE, :relayip, :leasetime, :dnsserv,
128
131
  :pxeconfigfile, :pxepathprefix, :pxereboottime, :router,
129
- :give_hostname, :served_hostname, :served_over, :serveOnlyPXE
132
+ :give_hostname, :served_hostname, :served_over, :serveOnlyPXE, :domain_name, :url
130
133
  ]
131
134
 
132
135
  opts.each_pair { |k,v|
@@ -151,10 +154,11 @@ class Server
151
154
  end
152
155
 
153
156
  attr_accessor :listen_host, :listen_port, :context, :leasetime, :relayip, :router, :dnsserv
157
+ attr_accessor :domain_name
154
158
  attr_accessor :sock, :thread, :myfilename, :ipstring, :served, :serveOnce
155
159
  attr_accessor :current_ip, :start_ip, :end_ip, :broadcasta, :netmaskn
156
160
  attr_accessor :servePXE, :pxeconfigfile, :pxealtconfigfile, :pxepathprefix, :pxereboottime, :serveOnlyPXE
157
- attr_accessor :give_hostname, :served_hostname, :served_over, :reporter
161
+ attr_accessor :give_hostname, :served_hostname, :served_over, :reporter, :url
158
162
 
159
163
  protected
160
164
 
@@ -166,7 +170,7 @@ protected
166
170
  wds = []
167
171
  eds = [@sock]
168
172
 
169
- r,w,e = ::IO.select(rds,wds,eds,1)
173
+ r,_,_ = ::IO.select(rds,wds,eds,1)
170
174
 
171
175
  if (r != nil and r[0] == self.sock)
172
176
  buf,host,port = self.sock.recvfrom(65535)
@@ -198,19 +202,19 @@ protected
198
202
  end
199
203
 
200
204
  # parse out the members
201
- hwtype = buf[1,1]
205
+ _hwtype = buf[1,1]
202
206
  hwlen = buf[2,1].unpack("C").first
203
- hops = buf[3,1]
204
- txid = buf[4..7]
205
- elapsed = buf[8..9]
206
- flags = buf[10..11]
207
+ _hops = buf[3,1]
208
+ _txid = buf[4..7]
209
+ _elapsed = buf[8..9]
210
+ _flags = buf[10..11]
207
211
  clientip = buf[12..15]
208
- givenip = buf[16..19]
209
- nextip = buf[20..23]
210
- relayip = buf[24..27]
211
- clienthwaddr = buf[28..(27+hwlen)]
212
+ _givenip = buf[16..19]
213
+ _nextip = buf[20..23]
214
+ _relayip = buf[24..27]
215
+ _clienthwaddr = buf[28..(27+hwlen)]
212
216
  servhostname = buf[44..107]
213
- filename = buf[108..235]
217
+ _filename = buf[108..235]
214
218
  magic = buf[236..239]
215
219
 
216
220
  if (magic != DHCPMagic)
@@ -293,6 +297,8 @@ protected
293
297
  pkt << dhcpoption(OpSubnetMask, self.netmaskn)
294
298
  pkt << dhcpoption(OpRouter, self.router)
295
299
  pkt << dhcpoption(OpDns, self.dnsserv)
300
+ pkt << dhcpoption(OpDomainName, self.domain_name)
301
+
296
302
  if self.servePXE # PXE options
297
303
  pkt << dhcpoption(OpPXEMagic, PXEMagic)
298
304
  # We already got this one, serve localboot file
@@ -317,6 +323,7 @@ protected
317
323
  pkt << dhcpoption(OpHostname, send_hostname)
318
324
  end
319
325
  end
326
+ pkt << dhcpoption(OpURL, self.url) if self.url
320
327
  pkt << dhcpoption(OpEnd)
321
328
 
322
329
  pkt << ("\x00" * 32) #padding
@@ -36,7 +36,7 @@ class Handler::Proc < Handler
36
36
  def on_request(cli, req)
37
37
  begin
38
38
  procedure.call(cli, req)
39
- rescue Errno::EPIPE
39
+ rescue Errno::EPIPE, ::Errno::ECONNRESET, ::Errno::ENOTCONN, ::Errno::ECONNABORTED
40
40
  elog("Proc::on_request: Client closed connection prematurely", LogSource)
41
41
  rescue
42
42
  elog("Proc::on_request: #{$!.class}: #{$!}\n\n#{$@.join("\n")}", LogSource)
@@ -32,7 +32,7 @@ class Packet
32
32
  Completed = 3
33
33
  end
34
34
 
35
- require 'rex/proto/http/header'
35
+ require 'rex/proto/http/packet/header'
36
36
 
37
37
  #
38
38
  # Initializes an instance of an HTTP packet.
@@ -56,7 +56,7 @@ class Rex::Socket::Parameters
56
56
  # @option hash [Bool] 'Bool' Create a bare socket
57
57
  # @option hash [Bool] 'Server' Whether or not this should be a server
58
58
  # @option hash [Bool] 'SSL' Whether or not SSL should be used
59
- # @option hash [String] 'SSLVersion' Specify SSL2, SSL3, or TLS1 (SSL3 is
59
+ # @option hash [String] 'SSLVersion' Specify Auto, SSL2, SSL3, or TLS1 (Auto is
60
60
  # default)
61
61
  # @option hash [String] 'SSLCert' A file containing an SSL certificate (for
62
62
  # server sockets)
@@ -117,7 +117,7 @@ class Rex::Socket::Parameters
117
117
  self.ssl = false
118
118
  end
119
119
 
120
- supported_ssl_versions = ['SSL2', 'SSL23', 'TLS1', 'SSL3', :SSLv2, :SSLv3, :SSLv23, :TLSv1]
120
+ supported_ssl_versions = ['Auto', 'SSL2', 'SSL23', 'TLS1', 'SSL3', :Auto, :SSLv2, :SSLv3, :SSLv23, :TLSv1]
121
121
  if (hash['SSLVersion'] and supported_ssl_versions.include? hash['SSLVersion'])
122
122
  self.ssl_version = hash['SSLVersion']
123
123
  end
@@ -324,7 +324,7 @@ class Rex::Socket::Parameters
324
324
  # @return [Bool]
325
325
  attr_accessor :ssl
326
326
 
327
- # What version of SSL to use (SSL2, SSL3, SSL23, TLS1)
327
+ # What version of SSL to use (Auto, SSL2, SSL3, SSL23, TLS1)
328
328
  # @return [String,Symbol]
329
329
  attr_accessor :ssl_version
330
330
 
@@ -56,18 +56,55 @@ begin
56
56
  def initsock(params = nil)
57
57
  super
58
58
 
59
- version = :SSLv3
60
- if(params)
59
+ # The autonegotiation preference for SSL/TLS versions
60
+ versions = [:TLSv1, :SSLv3, :SSLv23, :SSLv2]
61
+
62
+ # Limit this to a specific SSL/TLS version if specified
63
+ if params
61
64
  case params.ssl_version
62
65
  when 'SSL2', :SSLv2
63
- version = :SSLv2
66
+ versions = [:SSLv2]
64
67
  when 'SSL23', :SSLv23
65
- version = :SSLv23
68
+ versions = [:SSLv23]
69
+ when 'SSL3', :SSLv3
70
+ versions = [:SSLv3]
66
71
  when 'TLS1', :TLSv1
67
- version = :TLSv1
72
+ versions = [:TLSv1]
73
+ else
74
+ # Leave the version list as-is (Auto)
68
75
  end
69
76
  end
70
77
 
78
+ # Limit our versions to those supported by the linked OpenSSL library
79
+ versions = versions.select {|v| OpenSSL::SSL::SSLContext::METHODS.include? v }
80
+
81
+ # Raise an error if no selected versions are supported
82
+ if versions.length == 0
83
+ raise ArgumentError, 'The system OpenSSL does not support the requested SSL/TLS version'
84
+ end
85
+
86
+ last_error = nil
87
+
88
+ # Iterate through SSL/TLS versions until we successfully negotiate
89
+ versions.each do |version|
90
+ begin
91
+ # Try intializing the socket with this SSL/TLS version
92
+ # This will throw an exception if it fails
93
+ initsock_with_ssl_version(params, version)
94
+
95
+ # Success! Record what method was used and return
96
+ self.ssl_negotiated_version = version
97
+ return
98
+ rescue OpenSSL::SSL::SSLError => e
99
+ last_error = e
100
+ end
101
+ end
102
+
103
+ # No SSL/TLS versions succeeded, raise the last error
104
+ raise last_error
105
+ end
106
+
107
+ def initsock_with_ssl_version(params, version)
71
108
  # Build the SSL connection
72
109
  self.sslctx = OpenSSL::SSL::SSLContext.new(version)
73
110
 
@@ -84,7 +121,9 @@ begin
84
121
  # Could also do this as graceful faildown in case a passed verify_mode is not supported
85
122
  self.sslctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
86
123
  end
124
+
87
125
  self.sslctx.options = OpenSSL::SSL::OP_ALL
126
+
88
127
  if params.ssl_cipher
89
128
  self.sslctx.ciphers = params.ssl_cipher
90
129
  end
@@ -101,7 +140,6 @@ begin
101
140
  # XXX - enabling this causes infinite recursion, so disable for now
102
141
  # self.sslsock.sync_close = true
103
142
 
104
-
105
143
  # Force a negotiation timeout
106
144
  begin
107
145
  Timeout.timeout(params.timeout) do
@@ -327,11 +365,13 @@ begin
327
365
  end
328
366
 
329
367
  attr_reader :peer_verified # :nodoc:
368
+ attr_reader :ssl_negotiated_version # :nodoc:
330
369
  attr_accessor :sslsock, :sslctx # :nodoc:
331
370
 
332
371
  protected
333
372
 
334
373
  attr_writer :peer_verified # :nodoc:
374
+ attr_writer :ssl_negotiated_version # :nodoc:
335
375
 
336
376
 
337
377
  rescue LoadError
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  APP_NAME = "rex"
4
- VERSION = "2.0.3"
4
+ VERSION = "2.0.4"
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = APP_NAME
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rex
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - HD Moore
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-09-07 00:00:00.000000000 Z
12
+ date: 2014-10-15 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Rex provides a variety of classes useful for security testing and exploit
15
15
  development.
@@ -371,8 +371,8 @@ files:
371
371
  - lib/rex/proto/http/handler.rb
372
372
  - lib/rex/proto/http/handler/erb.rb
373
373
  - lib/rex/proto/http/handler/proc.rb
374
- - lib/rex/proto/http/header.rb
375
374
  - lib/rex/proto/http/packet.rb
375
+ - lib/rex/proto/http/packet/header.rb
376
376
  - lib/rex/proto/http/request.rb
377
377
  - lib/rex/proto/http/response.rb
378
378
  - lib/rex/proto/http/server.rb
@@ -521,12 +521,12 @@ require_paths:
521
521
  - lib
522
522
  required_ruby_version: !ruby/object:Gem::Requirement
523
523
  requirements:
524
- - - ! '>='
524
+ - - ">="
525
525
  - !ruby/object:Gem::Version
526
526
  version: 1.9.3
527
527
  required_rubygems_version: !ruby/object:Gem::Requirement
528
528
  requirements:
529
- - - ! '>='
529
+ - - ">="
530
530
  - !ruby/object:Gem::Version
531
531
  version: '0'
532
532
  requirements: []