Control Flow Integrity, a fun and innovative Javascript Evasion Technique

Pierluigi Paganini February 21, 2018

Javascript evasion technique – Security Expert Marco Ramilli detailed a fun and innovative way to evade reverse-engineering techniques based on Javascript technology.

Understanding the real code behind a Malware is a great opportunity for Malware analysts, it would increase the chances to understand what the sample really does. Unfortunately it is not always possible figuring out the “real code”, sometimes the Malware analyst needs to use tools like disassemblers or debuggers in order to guess the real Malware actions. However when the Sample is implemented by “interpreted code” such as (but not limited to): Java, Javascript, VBS and .NET there are several ways to get a closed look to the “code”.
Unfortunately attackers know what the analysis techniques are and often they implement evasive actions in order to reduce the analyst understanding or to make the overall analysis harder and harder. An evasive technique could be implemented to detect if the code runs over a VM or it could be implemented in order to run the code only on given environments or it could be implemented to avoid debugging connectors or again to evade reverse-engineering operations such as de-obfuscations techniques. Today “post” is about that, I’d like to focus my readers attention on a fun and innovative way to evade reverse-engineering techniques based on Javascript technology.
Javascript is getting day-by-day more important in term of attack vector, it is often used as a dropper stage and its implementation is widely influenced by many flavours and coding styles but as a bottom line, almost every Javascript Malware is obfuscated. The following image shows an example of obfuscated javascript payload (taken from one analysis of mine).

 

Example: Obfuscated Javascript

 

As a first step the Malware analyst would try to de-obfuscate such a code by getting into it. Starting from simple “cut and paste” to more powerful “substitution scripts” the analyst would try to rename functions and variables in order to split complexity and to make clear what code sections do. But in Javascript there is a nice way to get the callee function name which could be used to understand if a function name changed over the time. That function is the arguments.callee.caller. By using that function the attacker can create a stack trace where it saves the executed function chaining name list. The attacker would grab function names and use them as the key to dynamically decrypt specific and crafted Javascript code. Using this technique the Attacker would have an implicit control flow integrity because if a function is renamed or if the function order is slightly different from the designed one, the resulting “hash” would be different. If the hash is different the generated key would be different as well and it wont be able to decrypt and to launch specific encrypted code.
But lets take a closer look to what I meant. The following snip shows a clear (not obfuscated) example explaining this technique. I decided to show not obfuscated code up here just to make it simple.
var _ = require("underscore");
function keyCharAt(key, i) {
return key.charCodeAt( Math.floor(i % key.length) );
}
 
function xor_encrypt(key, data) {
return _.map(data, function(c, i) {
return c.charCodeAt(0) ^ keyCharAt(key, i);
});
}
 
function xor_decrypt(key, data) {
return _.map(data, function(c, i) {
return String.fromCharCode( c ^ keyCharAt(key, i) );
}).join("");
 
}
 
function cow001(){
eval(xor_decrypt(arguments.callee.name,[0,0,25,67,95,93,6,65,27,95,87,25,68,34,22,92,89,82,10,0,2,67,16,114,12,1,3,85,94,69,67,59,5,89,87,86,6,29,4,16,120,84,17,10,87,17,23,24]));
}
function pyth001(){
eval(xor_decrypt(arguments.callee.name,[19,22,3,88,0,1,25,89,66]));
}
 
function pippo(){
pyth001();
 
}
pippo();
Each internal stage evaluates ( eval() ) a content. On row 21 and 25 the function cow001 and pyth001 evaluates xor decrypted contents. The xor_decrypt function takes two arguments: decoding_key and the payload to be decrypted. Each internal stage function uses as decryption key the name of callee by using the arguments.callee.name function. If the function name is the “designed one” (the one that the attacker used to encrypt the payload) the encrypted content would be executed with no exceptions. On the other side if the function name is renamed (by meaning has been changed by the analyst for his convenience) the evaluation function would fail and potentially the attacker could trigger a different code path (by using a simple try and catch statement).
Before launching the Sample in the wild the attacker needs to prepare the “attack path” by developing the malicious Javascript and by obfuscating it. Once the obfuscation took place the attacker needs to use an additional script (such as the following one) to encrypt the payloads according to the obfuscated function names and to replace the newly encrypted payload to the final and encrypted Javascipt file replacing the encrypted payloads with the one encrypted having as a key the encrypted function names.
"use strict";   var _ = require("underscore");  
 function keyCharAt(key, i) { return key.charCodeAt( Math.floor(i % key.length) ); }   
function xor_encrypt(key, data) { return _.map(data, function(c, i) { return c.charCodeAt(0) ^ keyCharAt(key, i); }); }   
function xor_decrypt(key, data) 
{ return _.map(data, function(c, i) 
{ return String.fromCharCode( c ^ keyCharAt(key, i) ); }).join(""); }   

var final_payload = "console.log('Malicious Content Triggers Here !')"; 
var k_final = "cow001"; 
var encrypted_final = xor_encrypt(k_final,final_payload);
var decrypted_final = xor_decrypt(k_final, encrypted_final); console.log(encrypted_final.toString()); console.log(decrypted_final);   var _1_payload = "cow001();"; 
var k_1 = "pyth001"; 
var encrypted_1 = xor_encrypt(k_1,_1_payload); 
var decrypted_1 = xor_decrypt(k_1, encrypted_1); 

console.log(encrypted_1.toString()); 
console.log(decrypted_1);

The attacker is now able to write a Javascript code owning its own control flow. If the attacker iterates such a concept over and over again,  he would block or control the code execution by hitting a complete reverse-engineering evasion technique.

The original post published by Marco Ramilli on his blog at the following URL:

https://marcoramilli.blogspot.it/2018/02/control-flow-integrity-javascript.html

About the author: Marco Ramilli, Founder of Yoroi

I am a computer security scientist with an intensive hacking background. I do have a MD in computer engineering and a PhD on computer security from University of Bologna. During my PhD program I worked for US Government (@ National Institute of Standards and Technology, Security Division) where I did intensive researches in Malware evasion techniques and penetration testing of electronic voting systems.

 

I do have experience on security testing since I have been performing penetration testing on several US electronic voting systems. I’ve also been encharged of testing uVote voting system from the Italian Minister of homeland security. I met Palantir Technologies where I was introduced to the Intelligence Ecosystem. I decided to amplify my cyber security experiences by diving into SCADA security issues with some of the most biggest industrial aglomerates in Italy. I finally decided to found Yoroi: an innovative Managed Cyber Security Service Provider developing some of the most amazing cyber security defence center I’ve ever experienced ! Now I technically lead Yoroi defending our customers strongly believing in: Defence Belongs To Humans

[adrotate banner=”9″] [adrotate banner=”12″]

Edited by Pierluigi Paganini

(Security Affairs – Javascript Evasion Technique, malware)

[adrotate banner=”5″]

[adrotate banner=”13″



you might also like

leave a comment