rex-exploitation 0.1.0
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 +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
|