Land #3058 - Prevent jsobfu from generating reserved js keywords

bug/bundler_fix
sinn3r 2014-03-04 11:43:39 -06:00
commit e638c3d50a
No known key found for this signature in database
GPG Key ID: 2384DB4EF06F730B
2 changed files with 84 additions and 6 deletions

View File

@ -1,6 +1,7 @@
# -*- coding: binary -*-
require 'rex/text'
require 'rex/random_identifier_generator'
require 'rkelly'
module Rex
@ -47,6 +48,15 @@ module Exploitation
#
class JSObfu
# these keywords should never be used as a random var name
# source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
RESERVED_KEYWORDS = %w(
break case catch continue debugger default delete do else finally
for function if in instanceof new return switch this throw try
typeof var void while with class enum export extends import super
implements interface let package private protected public static yield
)
#
# Abstract Syntax Tree generated by RKelly::Parser#parse
#
@ -60,6 +70,11 @@ class JSObfu
@funcs = {}
@vars = {}
@debug = false
@rand_gen = Rex::RandomIdentifierGenerator.new(
:max_length => 15,
:first_char_set => Rex::Text::Alpha+"_$",
:char_set => Rex::Text::AlphaNumeric+"_$"
)
end
#
@ -107,8 +122,23 @@ class JSObfu
obfuscate_r(@ast)
end
# @return [String] a unique random var name that is not a reserved keyword
def random_var_name
loop do
text = random_string
unless @vars.has_value?(text) or RESERVED_KEYWORDS.include?(text)
return text
end
end
end
protected
# @return [String] a random string
def random_string
@rand_gen.generate
end
#
# Recursive method to obfuscate the given +ast+.
#
@ -152,14 +182,12 @@ protected
# Variables
when ::RKelly::Nodes::VarDeclNode
if @vars[node.name].nil?
#@vars[node.name] = "var_#{Rex::Text.rand_text_alpha(3+rand(12))}_#{node.name}"
@vars[node.name] = "#{Rex::Text.rand_text_alpha(3+rand(12))}"
@vars[node.name] = random_var_name
end
node.name = @vars[node.name]
when ::RKelly::Nodes::ParameterNode
if @vars[node.value].nil?
#@vars[node.value] = "param_#{Rex::Text.rand_text_alpha(3+rand(12))}_#{node.value}"
@vars[node.value] = "#{Rex::Text.rand_text_alpha(3+rand(12))}"
@vars[node.value] = random_var_name
end
node.value = @vars[node.value]
when ::RKelly::Nodes::ResolveNode
@ -181,8 +209,7 @@ protected
# Functions can also act as objects, so store them in the vars
# and the functions list so we can replace them in both places
if @funcs[node.value].nil? and not @funcs.values.include?(node.value)
#@funcs[node.value] = "func_#{Rex::Text.rand_text_alpha(3+rand(12))}_#{node.value}"
@funcs[node.value] = "#{Rex::Text.rand_text_alpha(3+rand(12))}"
@funcs[node.value] = random_var_name
if @vars[node.value].nil?
@vars[node.value] = @funcs[node.value]
end

View File

@ -0,0 +1,51 @@
require 'spec_helper'
require 'rex/exploitation/jsobfu'
describe Rex::Exploitation::JSObfu do
subject(:jsobfu) do
described_class.new("")
end
describe '#random_var_name' do
subject(:random_var_name) { jsobfu.random_var_name }
it { should be_a String }
it { should_not be_empty }
it 'is composed of _, $, alphanumeric chars' do
20.times { expect(jsobfu.random_var_name).to match(/\A[a-zA-Z0-9$_]+\Z/) }
end
it 'does not start with a number' do
20.times { expect(jsobfu.random_var_name).not_to match(/\A[0-9]/) }
end
context 'when a reserved word is generated' do
let(:reserved) { described_class::RESERVED_KEYWORDS.first }
let(:random) { 'abcdef' }
let(:generated) { [reserved, reserved, reserved, random] }
before do
jsobfu.stub(:random_string) { generated.shift }
end
it { should be random }
end
context 'when a non-unique random var is generated' do
let(:preexisting) { 'preexist' }
let(:random) { 'abcdef' }
let(:vars) { { 'jQuery' => preexisting } }
let(:generated) { [preexisting, preexisting, preexisting, random] }
before do
jsobfu.stub(:random_string) { generated.shift }
jsobfu.instance_variable_set("@vars", vars)
end
it { should be random }
end
end
end