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 +5 -13
- data/lib/rex.rb +2 -1
- data/lib/rex/arch.rb +1 -1
- data/lib/rex/arch/x86.rb +7 -5
- data/lib/rex/elfparsey/elf.rb +1 -1
- data/lib/rex/elfparsey/elfbase.rb +9 -0
- data/lib/rex/encoder/nonalpha.rb +4 -4
- data/lib/rex/exploitation/js/detect.rb +4 -2
- data/lib/rex/exploitation/jsobfu.rb +5 -501
- data/lib/rex/image_source/image_source.rb +6 -2
- data/lib/rex/mime/header.rb +3 -2
- data/lib/rex/mime/message.rb +1 -2
- data/lib/rex/parser/nexpose_raw_nokogiri.rb +1 -1
- data/lib/rex/post/meterpreter/client.rb +1 -1
- data/lib/rex/proto/dhcp/constants.rb +2 -0
- data/lib/rex/proto/dhcp/server.rb +20 -13
- data/lib/rex/proto/http/handler/proc.rb +1 -1
- data/lib/rex/proto/http/packet.rb +1 -1
- data/lib/rex/proto/http/{header.rb → packet/header.rb} +0 -0
- data/lib/rex/socket/parameters.rb +3 -3
- data/lib/rex/socket/ssl_tcp.rb +46 -6
- data/rex.gemspec +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
NDQ2YzQwN2FiNzY1Y2M0YjY3YzE0NTU1NDc1OWZjZDNlZDc4MDliZA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 79a1308c4fbc5e37cc531c402b45228f0480314a
|
4
|
+
data.tar.gz: 55b5f247534fdac3322b929d4c46e4846c9ec9bb
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
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-
|
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,
|
data/lib/rex/arch.rb
CHANGED
data/lib/rex/arch/x86.rb
CHANGED
@@ -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
|
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
|
-
#
|
265
|
-
|
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
|
-
#
|
284
|
-
|
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
|
|
data/lib/rex/elfparsey/elf.rb
CHANGED
@@ -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 &&
|
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.
|
data/lib/rex/encoder/nonalpha.rb
CHANGED
@@ -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
|
31
|
+
if tablelen > 255 || block == 0x7B
|
32
32
|
raise RuntimeError, "BadChar"
|
33
33
|
end
|
34
34
|
|
35
|
-
if (block >= 0x41
|
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,
|
19
|
-
# os_flavor - OS flavor as a string
|
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 '
|
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
|
-
#
|
38
|
-
#
|
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
|
-
|
33
|
-
|
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
|
data/lib/rex/mime/header.rb
CHANGED
data/lib/rex/mime/message.rb
CHANGED
@@ -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=([
|
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]["
|
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
|
251
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
252
252
|
ctx.key = key
|
253
253
|
ctx.cert = cert
|
254
254
|
|
@@ -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,
|
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
|
-
|
205
|
+
_hwtype = buf[1,1]
|
202
206
|
hwlen = buf[2,1].unpack("C").first
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
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
|
-
|
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)
|
File without changes
|
@@ -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 (
|
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
|
|
data/lib/rex/socket/ssl_tcp.rb
CHANGED
@@ -56,18 +56,55 @@ begin
|
|
56
56
|
def initsock(params = nil)
|
57
57
|
super
|
58
58
|
|
59
|
-
|
60
|
-
|
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
|
-
|
66
|
+
versions = [:SSLv2]
|
64
67
|
when 'SSL23', :SSLv23
|
65
|
-
|
68
|
+
versions = [:SSLv23]
|
69
|
+
when 'SSL3', :SSLv3
|
70
|
+
versions = [:SSLv3]
|
66
71
|
when 'TLS1', :TLSv1
|
67
|
-
|
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
|
data/rex.gemspec
CHANGED
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.
|
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-
|
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: []
|