Land #3058 - Prevent jsobfu from generating reserved js keywords
commit
e638c3d50a
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue