rex-exploitation 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/README.md +33 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/data/exploits/cmdstager/debug_asm +91 -0
- data/data/exploits/cmdstager/debug_write +819 -0
- data/data/exploits/cmdstager/vbs_b64 +40 -0
- data/data/exploits/cmdstager/vbs_b64_adodb +50 -0
- data/data/exploits/cmdstager/vbs_b64_noquot +49 -0
- data/data/exploits/cmdstager/vbs_b64_sleep +41 -0
- data/data/js/detect/ie_addons.js +89 -0
- data/data/js/detect/misc_addons.js +157 -0
- data/data/js/detect/os.js +831 -0
- data/data/js/memory/explib2/lib/explib2.js +426 -0
- data/data/js/memory/explib2/payload/drop_exec.js +33 -0
- data/data/js/memory/explib2/payload/exec.js +10 -0
- data/data/js/memory/heap_spray.js +17 -0
- data/data/js/memory/heaplib2.js +192 -0
- data/data/js/memory/mstime_malloc.js +31 -0
- data/data/js/memory/property_spray.js +38 -0
- data/data/js/network/ajax_download.js +18 -0
- data/data/js/network/ajax_post.js +18 -0
- data/data/js/network/xhr_shim.js +15 -0
- data/data/js/utils/base64.js +126 -0
- data/data/ropdb/flash.xml +80 -0
- data/data/ropdb/hxds.xml +66 -0
- data/data/ropdb/java.xml +33 -0
- data/data/ropdb/msvcrt.xml +71 -0
- data/data/ropdb/reader.xml +132 -0
- data/data/ropdb/samba.xml +436 -0
- data/data/ropdb/stagefright.xml +225 -0
- data/lib/rex/exploitation.rb +7 -0
- data/lib/rex/exploitation/cmdstager.rb +11 -0
- data/lib/rex/exploitation/cmdstager/base.rb +189 -0
- data/lib/rex/exploitation/cmdstager/bourne.rb +118 -0
- data/lib/rex/exploitation/cmdstager/certutil.rb +114 -0
- data/lib/rex/exploitation/cmdstager/debug_asm.rb +139 -0
- data/lib/rex/exploitation/cmdstager/debug_write.rb +133 -0
- data/lib/rex/exploitation/cmdstager/echo.rb +166 -0
- data/lib/rex/exploitation/cmdstager/printf.rb +121 -0
- data/lib/rex/exploitation/cmdstager/tftp.rb +70 -0
- data/lib/rex/exploitation/cmdstager/vbs.rb +125 -0
- data/lib/rex/exploitation/egghunter.rb +423 -0
- data/lib/rex/exploitation/encryptjs.rb +79 -0
- data/lib/rex/exploitation/heaplib.js.b64 +331 -0
- data/lib/rex/exploitation/heaplib.rb +107 -0
- data/lib/rex/exploitation/js.rb +6 -0
- data/lib/rex/exploitation/js/detect.rb +70 -0
- data/lib/rex/exploitation/js/memory.rb +80 -0
- data/lib/rex/exploitation/js/network.rb +83 -0
- data/lib/rex/exploitation/js/utils.rb +32 -0
- data/lib/rex/exploitation/jsobfu.rb +17 -0
- data/lib/rex/exploitation/obfuscatejs.rb +336 -0
- data/lib/rex/exploitation/omelet.rb +321 -0
- data/lib/rex/exploitation/opcodedb.rb +819 -0
- data/lib/rex/exploitation/ropdb.rb +190 -0
- data/lib/rex/exploitation/seh.rb +93 -0
- data/lib/rex/exploitation/version.rb +5 -0
- data/rex-exploitation.gemspec +35 -0
- metadata +298 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/text'
|
4
|
+
require 'rex/exploitation/jsobfu'
|
5
|
+
|
6
|
+
module Rex
|
7
|
+
module Exploitation
|
8
|
+
module Js
|
9
|
+
|
10
|
+
|
11
|
+
class Detect
|
12
|
+
|
13
|
+
#
|
14
|
+
# Provides several javascript functions for determining the OS and browser versions of a client.
|
15
|
+
#
|
16
|
+
# getVersion(): returns an object with the following properties
|
17
|
+
# os_name - OS name such as "Windows 8", "Linux", "Mac OS X"
|
18
|
+
# os_flavor - OS flavor as a string such as "Home", "Enterprise", etc
|
19
|
+
# os_sp - OS service pack (e.g.: "SP2", will be empty on non-Windows)
|
20
|
+
# os_lang - OS language (e.g.: "en-us")
|
21
|
+
# os_vendor - A company or organization name such as Microsoft, Ubuntu, Apple, etc
|
22
|
+
# os_device - A specific piece of hardware such as iPad, iPhone, etc
|
23
|
+
# ua_name - Client name, one of the Msf::HttpClients constants
|
24
|
+
# ua_version - Client version as a string (e.g.: "3.5.1", "6.0;SP2")
|
25
|
+
# arch - Architecture, one of the ARCH_* constants
|
26
|
+
#
|
27
|
+
# The following functions work on the version returned in obj.ua_version
|
28
|
+
#
|
29
|
+
# ua_ver_cmp(a, b): returns -1, 0, or 1 based on whether a < b, a == b, or a > b respectively
|
30
|
+
# ua_ver_lt(a, b): returns true if a < b
|
31
|
+
# ua_ver_gt(a, b): returns true if a > b
|
32
|
+
# ua_ver_eq(a, b): returns true if a == b
|
33
|
+
#
|
34
|
+
def self.os(custom_js = '')
|
35
|
+
js = custom_js
|
36
|
+
js << ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "detect", "os.js"))
|
37
|
+
|
38
|
+
Rex::Exploitation::JSObfu.new(js)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
#
|
43
|
+
# Provides javascript functions to determine IE addon information.
|
44
|
+
#
|
45
|
+
# getMsOfficeVersion(): Returns the version for Microsoft Office
|
46
|
+
#
|
47
|
+
def self.ie_addons(custom_js = '')
|
48
|
+
js = custom_js
|
49
|
+
js << ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "detect", "ie_addons.js"))
|
50
|
+
|
51
|
+
Rex::Exploitation::JSObfu.new(js)
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Provides javascript functions that work for all browsers to determine addon information
|
56
|
+
#
|
57
|
+
# getJavaVersion(): Returns the Java version
|
58
|
+
# hasSilverlight(): Returns whether Silverlight is enabled or not
|
59
|
+
#
|
60
|
+
def self.misc_addons(custom_js = '')
|
61
|
+
js = custom_js
|
62
|
+
js << ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "detect", "misc_addons.js"))
|
63
|
+
|
64
|
+
Rex::Exploitation::JSObfu.new(js)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
|
4
|
+
module Rex
|
5
|
+
module Exploitation
|
6
|
+
module Js
|
7
|
+
|
8
|
+
#
|
9
|
+
# Provides meomry manipulative functions in JavaScript
|
10
|
+
#
|
11
|
+
class Memory
|
12
|
+
|
13
|
+
def self.mstime_malloc
|
14
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "mstime_malloc.js"))
|
15
|
+
js = js.gsub(/W00TA/, Rex::Text.rand_text_hex(6))
|
16
|
+
js = js.gsub(/W00TB/, Rex::Text.rand_text_hex(5))
|
17
|
+
|
18
|
+
::Rex::Exploitation::ObfuscateJS.new(js,
|
19
|
+
{
|
20
|
+
'Symbols' => {
|
21
|
+
'Variables' => %w{ buf eleId acTag }
|
22
|
+
}
|
23
|
+
}).obfuscate
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.heaplib2(custom_js='', opts={})
|
27
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "heaplib2.js"))
|
28
|
+
|
29
|
+
unless custom_js.to_s.strip.empty?
|
30
|
+
js << custom_js
|
31
|
+
end
|
32
|
+
|
33
|
+
js = ::Rex::Exploitation::JSObfu.new js
|
34
|
+
js.obfuscate
|
35
|
+
return js
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.property_spray
|
39
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "property_spray.js"))
|
40
|
+
|
41
|
+
::Rex::Exploitation::ObfuscateJS.new(js,
|
42
|
+
{
|
43
|
+
'Symbols' => {
|
44
|
+
'Variables' => %w{ sym_div_container data junk obj }
|
45
|
+
}
|
46
|
+
}).obfuscate
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.heap_spray
|
50
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "heap_spray.js"))
|
51
|
+
|
52
|
+
::Rex::Exploitation::ObfuscateJS.new(js,
|
53
|
+
{
|
54
|
+
'Symbols' => {
|
55
|
+
'Variables' => %w{ index heapSprayAddr_hi heapSprayAddr_lo retSlide heapBlockCnt }
|
56
|
+
}
|
57
|
+
}).obfuscate
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.explib2
|
61
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "explib2", "lib", "explib2.js"))
|
62
|
+
|
63
|
+
::Rex::Exploitation::ObfuscateJS.obfuscate(js)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.explib2_payload(payload="exec")
|
67
|
+
case payload
|
68
|
+
when "drop_exec"
|
69
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "explib2", "payload", "drop_exec.js"))
|
70
|
+
else # "exec"
|
71
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "explib2", "payload", "exec.js"))
|
72
|
+
end
|
73
|
+
|
74
|
+
::Rex::Exploitation::ObfuscateJS.obfuscate(js)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
|
4
|
+
module Rex
|
5
|
+
module Exploitation
|
6
|
+
module Js
|
7
|
+
|
8
|
+
#
|
9
|
+
# Provides networking functions in JavaScript
|
10
|
+
#
|
11
|
+
class Network
|
12
|
+
|
13
|
+
# @param [Hash] opts the options hash
|
14
|
+
# @option opts [Boolean] :obfuscate toggles js obfuscation. defaults to true.
|
15
|
+
# @option opts [Boolean] :inject_xhr_shim automatically stubs XHR to use ActiveXObject when needed.
|
16
|
+
# defaults to true.
|
17
|
+
# @return [String] javascript code to perform a synchronous ajax request to the remote
|
18
|
+
# and returns the response
|
19
|
+
def self.ajax_download(opts={})
|
20
|
+
should_obfuscate = opts.fetch(:obfuscate, true)
|
21
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "network", "ajax_download.js"))
|
22
|
+
|
23
|
+
if should_obfuscate
|
24
|
+
js = ::Rex::Exploitation::ObfuscateJS.new(js,
|
25
|
+
{
|
26
|
+
'Symbols' => {
|
27
|
+
'Variables' => %w{ xmlHttp oArg }
|
28
|
+
}
|
29
|
+
}).obfuscate
|
30
|
+
end
|
31
|
+
|
32
|
+
xhr_shim(opts) + js
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [Hash] opts the options hash
|
36
|
+
# @option opts [Boolean] :obfuscate toggles js obfuscation. defaults to true.
|
37
|
+
# @option opts [Boolean] :inject_xhr_shim automatically stubs XHR to use ActiveXObject when needed.
|
38
|
+
# defaults to true.
|
39
|
+
# @return [String] javascript code to perform a synchronous or asynchronous ajax request to
|
40
|
+
# the remote with the data specified.
|
41
|
+
def self.ajax_post(opts={})
|
42
|
+
should_obfuscate = opts.fetch(:obfuscate, true)
|
43
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "network", "ajax_post.js"))
|
44
|
+
|
45
|
+
if should_obfuscate
|
46
|
+
js = ::Rex::Exploitation::ObfuscateJS.new(js,
|
47
|
+
{
|
48
|
+
'Symbols' => {
|
49
|
+
'Variables' => %w{ xmlHttp cb path data }
|
50
|
+
}
|
51
|
+
}).obfuscate
|
52
|
+
end
|
53
|
+
|
54
|
+
xhr_shim(opts) + js
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param [Hash] opts the options hash
|
58
|
+
# @option opts [Boolean] :obfuscate toggles js obfuscation. defaults to true.
|
59
|
+
# @option opts [Boolean] :inject_xhr_shim false causes this method to return ''. defaults to true.
|
60
|
+
# @return [String] javascript code that adds XMLHttpRequest to the global scope if it
|
61
|
+
# does not exist (e.g. on IE6, where you have to use the ActiveXObject constructor)
|
62
|
+
def self.xhr_shim(opts={})
|
63
|
+
return '' unless opts.fetch(:inject_xhr_shim, true)
|
64
|
+
|
65
|
+
should_obfuscate = opts.fetch(:obfuscate, true)
|
66
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "network", "xhr_shim.js"))
|
67
|
+
|
68
|
+
if should_obfuscate
|
69
|
+
js = ::Rex::Exploitation::ObfuscateJS.new(js,
|
70
|
+
{
|
71
|
+
'Symbols' => {
|
72
|
+
'Variables' => %w{ activeObjs idx }
|
73
|
+
}
|
74
|
+
}
|
75
|
+
).obfuscate
|
76
|
+
end
|
77
|
+
js
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/text'
|
4
|
+
require 'rex/exploitation/jsobfu'
|
5
|
+
|
6
|
+
module Rex
|
7
|
+
module Exploitation
|
8
|
+
module Js
|
9
|
+
|
10
|
+
#
|
11
|
+
# Javascript utilities
|
12
|
+
#
|
13
|
+
class Utils
|
14
|
+
|
15
|
+
def self.base64
|
16
|
+
js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "utils", "base64.js"))
|
17
|
+
|
18
|
+
opts = {
|
19
|
+
'Symbols' => {
|
20
|
+
'Variables' => %w{ Base64 encoding result _keyStr encoded_data utftext input_idx
|
21
|
+
input output chr chr1 chr2 chr3 enc1 enc2 enc3 enc4 },
|
22
|
+
'Methods' => %w{ _utf8_encode _utf8_decode encode decode }
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
::Rex::Exploitation::ObfuscateJS.new(js, opts).to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'jsobfu'
|
4
|
+
|
5
|
+
module Rex
|
6
|
+
module Exploitation
|
7
|
+
|
8
|
+
#
|
9
|
+
# Simple wrapper class that makes the JSObfu functionality
|
10
|
+
# from the gem available under the Rex namespace.
|
11
|
+
#
|
12
|
+
class JSObfu < ::JSObfu
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,336 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
require 'rex/text'
|
3
|
+
module Rex
|
4
|
+
module Exploitation
|
5
|
+
|
6
|
+
#
|
7
|
+
# Obfuscates javascript in various ways
|
8
|
+
#
|
9
|
+
class ObfuscateJS
|
10
|
+
attr_reader :opts
|
11
|
+
|
12
|
+
#
|
13
|
+
# Obfuscates a javascript string.
|
14
|
+
#
|
15
|
+
# Options are 'Symbols', described below, and 'Strings', a boolean
|
16
|
+
# which specifies whether strings within the javascript should be
|
17
|
+
# mucked with (defaults to false).
|
18
|
+
#
|
19
|
+
# The 'Symbols' argument should have the following format:
|
20
|
+
#
|
21
|
+
# {
|
22
|
+
# 'Variables' => [ 'var1', ... ],
|
23
|
+
# 'Methods' => [ 'method1', ... ],
|
24
|
+
# 'Namespaces' => [ 'n', ... ],
|
25
|
+
# 'Classes' => [ { 'Namespace' => 'n', 'Class' => 'y'}, ... ]
|
26
|
+
# }
|
27
|
+
#
|
28
|
+
# Make sure you order your methods, classes, and namespaces by most
|
29
|
+
# specific to least specific to prevent partial substitution. For
|
30
|
+
# instance, if you have two methods (joe and joeBob), you should place
|
31
|
+
# joeBob before joe because it is more specific and will be globally
|
32
|
+
# replaced before joe is replaced.
|
33
|
+
#
|
34
|
+
# A simple example follows:
|
35
|
+
#
|
36
|
+
# <code>
|
37
|
+
# js = ObfuscateJS.new <<ENDJS
|
38
|
+
# function say_hi() {
|
39
|
+
# var foo = "Hello, world";
|
40
|
+
# document.writeln(foo);
|
41
|
+
# }
|
42
|
+
# ENDJS
|
43
|
+
# js.obfuscate(
|
44
|
+
# 'Symbols' => {
|
45
|
+
# 'Variables' => [ 'foo' ],
|
46
|
+
# 'Methods' => [ 'say_hi' ]
|
47
|
+
# }
|
48
|
+
# 'Strings' => true
|
49
|
+
# )
|
50
|
+
# </code>
|
51
|
+
#
|
52
|
+
# which should generate something like the following:
|
53
|
+
#
|
54
|
+
# <code>
|
55
|
+
# function oJaDYRzFOyJVQCOHk() { var cLprVG = "\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64"; document.writeln(cLprVG); }
|
56
|
+
# </code>
|
57
|
+
#
|
58
|
+
# String obfuscation tries to deal with escaped quotes within strings but
|
59
|
+
# won't catch things like
|
60
|
+
# "\\"
|
61
|
+
# so be careful.
|
62
|
+
#
|
63
|
+
def self.obfuscate(js, opts = {})
|
64
|
+
ObfuscateJS.new(js).obfuscate(opts)
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Initialize an instance of the obfuscator
|
69
|
+
#
|
70
|
+
def initialize(js = "", opts = {})
|
71
|
+
@js = js
|
72
|
+
@dynsym = {}
|
73
|
+
@opts = {
|
74
|
+
'Symbols' => {
|
75
|
+
'Variables'=>[],
|
76
|
+
'Methods'=>[],
|
77
|
+
'Namespaces'=>[],
|
78
|
+
'Classes'=>[]
|
79
|
+
},
|
80
|
+
'Strings'=>false
|
81
|
+
}
|
82
|
+
@done = false
|
83
|
+
update_opts(opts) if (opts.length > 0)
|
84
|
+
end
|
85
|
+
|
86
|
+
def update_opts(opts)
|
87
|
+
if (opts.nil? or opts.length < 1)
|
88
|
+
return
|
89
|
+
end
|
90
|
+
if (@opts['Symbols'] && opts['Symbols'])
|
91
|
+
['Variables', 'Methods', 'Namespaces', 'Classes'].each { |k|
|
92
|
+
if (@opts['Symbols'][k] && opts['Symbols'][k])
|
93
|
+
opts['Symbols'][k].each { |s|
|
94
|
+
if (not @opts['Symbols'][k].include? s)
|
95
|
+
@opts['Symbols'][k].push(s)
|
96
|
+
end
|
97
|
+
}
|
98
|
+
elsif (opts['Symbols'][k])
|
99
|
+
@opts['Symbols'][k] = opts['Symbols'][k]
|
100
|
+
end
|
101
|
+
}
|
102
|
+
elsif opts['Symbols']
|
103
|
+
@opts['Symbols'] = opts['Symbols']
|
104
|
+
end
|
105
|
+
@opts['Strings'] ||= opts['Strings']
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Returns the dynamic symbol associated with the supplied symbol name
|
110
|
+
#
|
111
|
+
# If obfuscation has not yet been performed (i.e. obfuscate() has not been
|
112
|
+
# called), then this method simply returns its argument
|
113
|
+
#
|
114
|
+
def sym(name)
|
115
|
+
@dynsym[name] || name
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Obfuscates the javascript string passed to the constructor
|
120
|
+
#
|
121
|
+
def obfuscate(opts = {})
|
122
|
+
#return @js if (@done)
|
123
|
+
@done = true
|
124
|
+
|
125
|
+
update_opts(opts)
|
126
|
+
|
127
|
+
if (@opts['Strings'])
|
128
|
+
obfuscate_strings()
|
129
|
+
|
130
|
+
# Full space randomization does not work for javascript -- despite
|
131
|
+
# claims that space is irrelavent, newlines break things. Instead,
|
132
|
+
# use only space (0x20) and tab (0x09).
|
133
|
+
|
134
|
+
#@js.gsub!(/[\x09\x20]+/) { |s|
|
135
|
+
# len = rand(50)+2
|
136
|
+
# set = "\x09\x20"
|
137
|
+
# buf = ''
|
138
|
+
# while (buf.length < len)
|
139
|
+
# buf << set[rand(set.length)].chr
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# buf
|
143
|
+
#}
|
144
|
+
end
|
145
|
+
|
146
|
+
# Remove our comments
|
147
|
+
remove_comments
|
148
|
+
|
149
|
+
# Globally replace symbols
|
150
|
+
replace_symbols(@opts['Symbols']) if @opts['Symbols']
|
151
|
+
|
152
|
+
return @js
|
153
|
+
end
|
154
|
+
|
155
|
+
#
|
156
|
+
# Returns the replaced javascript string
|
157
|
+
#
|
158
|
+
def to_s
|
159
|
+
@js
|
160
|
+
end
|
161
|
+
alias :to_str :to_s
|
162
|
+
|
163
|
+
def <<(str)
|
164
|
+
@js << str
|
165
|
+
end
|
166
|
+
def +(str)
|
167
|
+
@js + str
|
168
|
+
end
|
169
|
+
|
170
|
+
protected
|
171
|
+
attr_accessor :done
|
172
|
+
|
173
|
+
#
|
174
|
+
# Get rid of both single-line C++ style comments and multiline C style comments.
|
175
|
+
#
|
176
|
+
# Note: embedded comments (e.g.: "/*/**/*/") will break this,
|
177
|
+
# but they also break real javascript engines so I don't care.
|
178
|
+
#
|
179
|
+
def remove_comments
|
180
|
+
@js.gsub!(%r{\s+//.*$}, '')
|
181
|
+
@js.gsub!(%r{/\*.*?\*/}m, '')
|
182
|
+
end
|
183
|
+
|
184
|
+
# Replace method, class, and namespace symbols found in the javascript
|
185
|
+
# string
|
186
|
+
def replace_symbols(symbols)
|
187
|
+
taken = { }
|
188
|
+
|
189
|
+
# Generate random symbol names
|
190
|
+
[ 'Variables', 'Methods', 'Classes', 'Namespaces' ].each { |symtype|
|
191
|
+
next if symbols[symtype].nil?
|
192
|
+
symbols[symtype].each { |sym|
|
193
|
+
dyn = Rex::Text.rand_text_alpha(rand(32)+1) until dyn and not taken.key?(dyn)
|
194
|
+
|
195
|
+
taken[dyn] = true
|
196
|
+
|
197
|
+
if symtype == 'Classes'
|
198
|
+
full_sym = sym['Namespace'] + "." + sym['Class']
|
199
|
+
@dynsym[full_sym] = dyn
|
200
|
+
|
201
|
+
@js.gsub!(/#{full_sym}/) { |m|
|
202
|
+
sym['Namespace'] + "." + dyn
|
203
|
+
}
|
204
|
+
else
|
205
|
+
@dynsym[sym] = dyn
|
206
|
+
|
207
|
+
@js.gsub!(/#{sym}/, dyn)
|
208
|
+
end
|
209
|
+
}
|
210
|
+
}
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# Change each string into some javascript that will generate that string
|
215
|
+
#
|
216
|
+
# There are a couple of caveats to using string obfuscation:
|
217
|
+
# * it tries to deal with escaped quotes within strings but won't catch
|
218
|
+
# things like: "\\"
|
219
|
+
# * depending on the random choices, this can easily balloon a short
|
220
|
+
# string up to hundreds of kilobytes if called multiple times.
|
221
|
+
# so be careful.
|
222
|
+
#
|
223
|
+
def obfuscate_strings()
|
224
|
+
@js.gsub!(/".*?[^\\]"|'.*?[^\\]'/) { |str|
|
225
|
+
buf = ''
|
226
|
+
quote = str[0,1]
|
227
|
+
# Pull the quotes off either end
|
228
|
+
str = str[1, str.length-2]
|
229
|
+
case (rand(2))
|
230
|
+
# Disable hex encoding for now. It's just too big a hassle.
|
231
|
+
#when 0
|
232
|
+
# # This is where we can run into trouble with generating
|
233
|
+
# # incorrect code. If we hex encode a string twice, the second
|
234
|
+
# # encoding will generate the first instead of the original
|
235
|
+
# # string.
|
236
|
+
# if str =~ /\\x/
|
237
|
+
# # Always have to remove spaces from strings so the space
|
238
|
+
# # randomization doesn't mess with them.
|
239
|
+
# buf = quote + str.gsub(/ /, '\x20') + quote
|
240
|
+
# else
|
241
|
+
# buf = '"' + Rex::Text.to_hex(str) + '"'
|
242
|
+
# end
|
243
|
+
when 0
|
244
|
+
#
|
245
|
+
# Escape sequences when naively encoded for unescape become a
|
246
|
+
# literal backslash instead of the intended meaning. To avoid
|
247
|
+
# that problem, we scan the string for escapes and leave them
|
248
|
+
# unmolested.
|
249
|
+
#
|
250
|
+
buf << 'unescape("'
|
251
|
+
bytes = str.unpack("C*")
|
252
|
+
c = 0
|
253
|
+
while bytes[c]
|
254
|
+
if bytes[c].chr == "\\"
|
255
|
+
# XXX This is pretty slow.
|
256
|
+
esc_len = parse_escape(bytes, c)
|
257
|
+
buf << bytes[c, esc_len].map{|a| a.chr}.join
|
258
|
+
c += esc_len
|
259
|
+
next
|
260
|
+
end
|
261
|
+
buf << "%%%0.2x"%(bytes[c])
|
262
|
+
# Break the string into smaller strings
|
263
|
+
if bytes[c+1] and rand(10) == 0
|
264
|
+
buf << '" + "'
|
265
|
+
end
|
266
|
+
c += 1
|
267
|
+
end
|
268
|
+
buf << '")'
|
269
|
+
when 1
|
270
|
+
buf = "String.fromCharCode( "
|
271
|
+
bytes = str.unpack("C*")
|
272
|
+
c = 0
|
273
|
+
while bytes[c]
|
274
|
+
if bytes[c].chr == "\\"
|
275
|
+
case bytes[c+1].chr
|
276
|
+
# For chars that contain their non-escaped selves, step
|
277
|
+
# past the backslash and let the rand() below decide
|
278
|
+
# how to represent the character.
|
279
|
+
when '"'; c += 1
|
280
|
+
when "'"; c += 1
|
281
|
+
when "\\"; c += 1
|
282
|
+
# For others, just take the hex representation out of
|
283
|
+
# laziness.
|
284
|
+
when "n"; buf << "0x0a"; c += 2; next
|
285
|
+
when "t"; buf << "0x09"; c += 2; next
|
286
|
+
# Lastly, if it's a hex, unicode, or octal escape,
|
287
|
+
# leave it, and anything after it, alone. At some
|
288
|
+
# point we may want to parse up to the end of the
|
289
|
+
# escapes and encode subsequent non-escape characters.
|
290
|
+
# Since this is the lazy way to do it, spaces after an
|
291
|
+
# escape sequence will get away unmodified. To prevent
|
292
|
+
# the space randomizer from hosing the string, convert
|
293
|
+
# spaces specifically.
|
294
|
+
else
|
295
|
+
buf = buf[0,buf.length-1] + " )"
|
296
|
+
buf << ' + ("' + bytes[c, bytes.length].map{|a| a==0x20 ? '\x20' : a.chr}.join + '" '
|
297
|
+
break
|
298
|
+
end
|
299
|
+
end
|
300
|
+
case (rand(3))
|
301
|
+
when 0
|
302
|
+
buf << " %i,"%(bytes[c])
|
303
|
+
when 1
|
304
|
+
buf << " 0%o,"%(bytes[c])
|
305
|
+
when 2
|
306
|
+
buf << " 0x%0.2x,"%(bytes[c])
|
307
|
+
end
|
308
|
+
c += 1
|
309
|
+
end
|
310
|
+
# Strip off the last comma
|
311
|
+
buf = buf[0,buf.length-1] + " )"
|
312
|
+
end
|
313
|
+
buf
|
314
|
+
}
|
315
|
+
@js
|
316
|
+
end
|
317
|
+
|
318
|
+
def parse_escape(bytes, offset)
|
319
|
+
esc_len = 0
|
320
|
+
if bytes[offset].chr == "\\"
|
321
|
+
case bytes[offset+1].chr
|
322
|
+
when "u"; esc_len = 6 # unicode \u1234
|
323
|
+
when "x"; esc_len = 4 # hex, \x41
|
324
|
+
when /[0-9]/ # octal, \123, \0
|
325
|
+
oct = bytes[offset+1, 4].map{|a|a.chr}.join
|
326
|
+
oct =~ /([0-9]+)/
|
327
|
+
esc_len = 1 + $1.length
|
328
|
+
else; esc_len = 2 # \" \n, etc.
|
329
|
+
end
|
330
|
+
end
|
331
|
+
esc_len
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|
336
|
+
end
|