From a333632a693b0e10e5124d3763b10ec38240af5f Mon Sep 17 00:00:00 2001 From: sinn3r Date: Fri, 3 Apr 2015 11:30:23 -0500 Subject: [PATCH 1/3] Add standalone tool for jsobfu --- tools/jsobfu.rb | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100755 tools/jsobfu.rb diff --git a/tools/jsobfu.rb b/tools/jsobfu.rb new file mode 100755 index 0000000000..39797d0134 --- /dev/null +++ b/tools/jsobfu.rb @@ -0,0 +1,106 @@ +#!/usr/bin/env ruby + +msfbase = __FILE__ +while File.symlink?(msfbase) + msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) +end +$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', 'lib'))) +require 'msfenv' +require 'rex' +require 'msf/core' +require 'msf/base' +require 'optparse' + +module Jsobfu + class OptsConsole + def self.parse(args) + options = {} + parser = OptionParser.new do |opt| + opt.banner = "Usage: #{__FILE__} [options]" + opt.separator '' + opt.separator 'Specific options:' + + opt.on('-t', '--iteration ', "Number of times to obfuscate the JavaScript") do |v| + options[:iteration] = v + end + + opt.on('-i', '--input ', "The JavaScript file you want to obfuscate (default=1)") do |v| + options[:input] = v + end + + opt.on('-o', '--output ', "Save the obfuscated file as") do |v| + options[:output] = v + end + + opt.on_tail('-h', '--help', 'Show this message') do + $stdout.puts opt + exit + end + end + + parser.parse!(args) + + if options.empty? + raise OptionParser::MissingArgument, 'No options set, try -h for usage' + elsif options[:iteration] && options[:iteration] !~ /^\d+$/ + raise OptionParser::InvalidOption, "#{options[:format]} is not a number" + elsif !::File.exists?(options[:input].to_s) + raise OptionParser::InvalidOption, "Cannot find: #{options[:input]}" + end + + options[:iteration] = 1 unless options[:iteration] + + options + end + end + + class Driver + def initialize + begin + @opts = OptsConsole.parse(ARGV) + rescue OptionParser::ParseError => e + $stderr.puts "[x] #{e.message}" + exit + end + end + + def run + original_js = read_js(@opts[:input]) + js = ::Rex::Exploitation::JSObfu.new(original_js) + js.obfuscate(:iterations=>@opts[:iteration].to_i) + js = js.to_s + + output_stream = $stdout + output_stream.binmode + output_stream.write js + $stderr.puts + + if @opts[:output] + save_as(js, @opts[:output]) + end + end + + private + + def read_js(path) + js = ::File.open(path, 'rb') { |f| js = f.read } + js + end + + def save_as(js, outfile) + File.open(outfile, 'wb') do |f| + f.write(js) + end + + $stderr.puts + $stderr.puts "File saved as: #{outfile}" + end + + end +end + + +if __FILE__ == $PROGRAM_NAME + driver = Jsobfu::Driver.new + driver.run +end From c33a4a7fd9e3381ae69543620fedba7c9b6194c0 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Fri, 3 Apr 2015 15:27:35 -0500 Subject: [PATCH 2/3] rspec for jsobfu --- spec/tools/jsobfu_spec.rb | 73 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 spec/tools/jsobfu_spec.rb diff --git a/spec/tools/jsobfu_spec.rb b/spec/tools/jsobfu_spec.rb new file mode 100644 index 0000000000..c683c428df --- /dev/null +++ b/spec/tools/jsobfu_spec.rb @@ -0,0 +1,73 @@ +load Metasploit::Framework.root.join('tools/jsobfu.rb').to_path + +require 'stringio' + +describe Jsobfu do + + let(:fname) { + 'test.js' + } + + let(:js) { + %Q|alert("test");| + } + + describe Jsobfu::Driver do + + subject do + Jsobfu::Driver.new + end + + describe '#run' do + + def get_stdout(&block) + out = $stdout + $stdout = fake = StringIO.new + begin + yield + ensure + $stdout = out + end + fake.string + end + + let(:default_opts) { + { :input => fname, :iteration => 1 } + } + + before(:each) do + allow(Jsobfu::OptsConsole).to receive(:parse).with(any_args).and_return(default_opts) + allow(File).to receive(:open).with(fname, 'rb').and_yield(StringIO.new(js)) + end + + context 'when a javascript file is given' do + it 'returns the obfuscated version of the js code' do + output = get_stdout { subject.run } + expect(output).to include('String.fromCharCode') + end + end + + end + end + + + describe Jsobfu::OptsConsole do + subject do + Jsobfu::OptsConsole + end + + context 'when no options are given' do + it 'raises OptionParser::MissingArgument' do + expect{subject.parse([])}.to raise_error(OptionParser::MissingArgument) + end + end + + context 'when -t isn\'t a number' do + it 'raises OptionParser::MissingArgument' do + args = "-i #{fname} -t NaN".split + expect{subject.parse(args)}.to raise_error(OptionParser::InvalidOption) + end + end + end + +end From cb08e5b8da66e46f3cec9e488c7add12537a4f84 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 3 Apr 2015 16:00:28 -0500 Subject: [PATCH 3/3] Fix specs --- spec/tools/jsobfu_spec.rb | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/spec/tools/jsobfu_spec.rb b/spec/tools/jsobfu_spec.rb index c683c428df..5cfa463bd8 100644 --- a/spec/tools/jsobfu_spec.rb +++ b/spec/tools/jsobfu_spec.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + load Metasploit::Framework.root.join('tools/jsobfu.rb').to_path require 'stringio' @@ -19,18 +21,6 @@ describe Jsobfu do end describe '#run' do - - def get_stdout(&block) - out = $stdout - $stdout = fake = StringIO.new - begin - yield - ensure - $stdout = out - end - fake.string - end - let(:default_opts) { { :input => fname, :iteration => 1 } } @@ -38,15 +28,31 @@ describe Jsobfu do before(:each) do allow(Jsobfu::OptsConsole).to receive(:parse).with(any_args).and_return(default_opts) allow(File).to receive(:open).with(fname, 'rb').and_yield(StringIO.new(js)) + @out = $stdout + $stdout = StringIO.new + $stdout.string = '' + end + + after(:each) do + $stdout = @out end context 'when a javascript file is given' do - it 'returns the obfuscated version of the js code' do - output = get_stdout { subject.run } - expect(output).to include('String.fromCharCode') + it 'returns an String' do + subject.run + expect($stdout.string).to be_a(String) + end + + it 'returns a non empty String' do + subject.run + expect($stdout.string).not_to be_empty + end + + it 'returns an String different than the original' do + subject.run + expect($stdout.string).not_to eq(js) end end - end end