Class: Rex::Exploitation::JSObfu

Inherits:
Object
  • Object
show all
Defined in:
lib/rex/exploitation/jsobfu.rb

Overview

Obfuscate JavaScript by randomizing as much as possible and removing easily-signaturable string constants.

Example:

js = ::Rex::Exploitation::JSObfu.new %Q|
  var a = "0\\612\\063\\x34\\x35\\x36\\x37\\x38\\u0039";
  var b = { foo : "foo", bar : "bar" }
  alert(a);
  alert(b.foo);
|
js.obfuscate
puts js

Example Output:

var VwxvESbCgv = String.fromCharCode(0x30,0x31,062,063,064,53,0x36,067,070,0x39);
var ToWZPn = {
  "\146\157\x6f": (function () { var yDyv="o",YnCL="o",Qcsa="f"; return Qcsa+YnCL+yDyv })(),
  "\142ar": String.fromCharCode(0142,97,0162)
};
alert(VwxvESbCgv);
alert(ToWZPn.foo);

NOTE: Variables MUST be declared with a ‘var’ statement BEFORE first use (or not at all) for this to generate correct code! If variables are not declared they will not be randomized but the generated code will be correct.

Bad Example Javascript:

a = "asdf"; // this variable hasn't been declared and will not be randomized
var a;
alert(a); // real js engines will alert "asdf" here

Bad Example Obfuscated:

a = (function () { var hpHu="f",oyTm="asd"; return oyTm+hpHu })();
var zSrnHpEfJZtg;
alert(zSrnHpEfJZtg);

Notice that the first usage of a (before it was declared) is not randomized. Thus, the obfuscated version will alert ‘undefined’ instead of “asdf”.

Constant Summary collapse

RESERVED_KEYWORDS =

these keywords should never be used as a random var name source: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words

%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
)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(code) ⇒ JSObfu

Saves code for later obfuscation with #obfuscate



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rex/exploitation/jsobfu.rb', line 68

def initialize(code)
  @code = code
  @funcs = {}
  @vars  = {}
  @debug = false
  @rand_gen = Rex::RandomIdentifierGenerator.new(
    :max_length => 15,
    :first_char_set => Rex::Text::Alpha+"_$",
    :char_set => Rex::Text::AlphaNumeric+"_$"
  )
end

Instance Attribute Details

#astObject (readonly)

Abstract Syntax Tree generated by RKelly::Parser#parse



63
64
65
# File 'lib/rex/exploitation/jsobfu.rb', line 63

def ast
  @ast
end

Instance Method Details

#<<(str) ⇒ Object

Add str to the un-obfuscated code.

Calling this method after #obfuscate is undefined



85
86
87
# File 'lib/rex/exploitation/jsobfu.rb', line 85

def <<(str)
  @code << str
end

#obfuscateObject

Parse and obfuscate



120
121
122
123
# File 'lib/rex/exploitation/jsobfu.rb', line 120

def obfuscate
  parse
  obfuscate_r(@ast)
end

#random_var_nameString

Returns a unique random var name that is not a reserved keyword.

Returns:

  • (String)

    a unique random var name that is not a reserved keyword



126
127
128
129
130
131
132
133
# File 'lib/rex/exploitation/jsobfu.rb', line 126

def random_var_name
  loop do
    text = random_string
    unless @vars.has_value?(text) or RESERVED_KEYWORDS.include?(text)
      return text
    end
  end
end

#sym(lookup) ⇒ Object

Return the obfuscated name of a symbol

You MUST call #obfuscate before this method!



106
107
108
109
110
111
112
113
114
115
# File 'lib/rex/exploitation/jsobfu.rb', line 106

def sym(lookup)
  if @vars[lookup]
    ret = @vars[lookup]
  elsif @funcs[lookup]
    ret = @funcs[lookup]
  else
    ret = lookup
  end
  ret
end

#to_sObject

Return the (possibly obfuscated) code as a string.

If #obfuscate has not been called before this, returns the parsed, unobfuscated code. This can be useful for example to remove comments and standardize spacing.



96
97
98
99
# File 'lib/rex/exploitation/jsobfu.rb', line 96

def to_s
  parse if not @ast
  @ast.to_ecma
end