Akamai has acquired Guardicore to extend its Zero Trust solutions and help stop ransomware. Read more

Blog

RSS

Catch Me if You Can—JavaScript Obfuscation

Written by

Or Katz

October 26, 2020

While conducting threat research on phishing evasion techniques, Akamai came across threat actors using obfuscation and encryption, making the malicious page harder to detect. The criminals were using JavaScript to pull this off.

JavaScript is a client-side scripting language used by nearly all internet websites. It is only natural this specific scripting language is used so intensively by internet scammers.

Due to its client-side nature, JavaScript gives those using it the ability to evade detection, by creating obfuscated code that doesn't reveal its true nature until it is executed by the victim's machine. This unfortunate, yet intended process, means that the true nature, impact, and functionality of the code isn't known until it is too late.

It is possible to know what the JavaScript code is doing before execution, but the level of effort needed to debug, as well as understand the flow and logic of the examined code, might be too high for some threat researchers and protection processes. Such efforts require a large amount of time, in addition to human and computational resources.

In an overwhelming environment of threats, such as phishing and web scamming, time and resources play a significant role in detection, mitigation, and prevention. Therefore, such evasion techniques are key, as they give the scammers the opportunity to stay under the radar and avoid being seen.

In this blog, we'll review some of the most prevalent evasion and obfuscation techniques being used in the wild based on numerous phishing websites Akamai has been able to track over the last few months.

Content escaping—URL Encoding

The most basic technique we were able to see being used in the wild is a phishing web page mainly composed of JavaScript objects. An example of this is shown in Figure 1. These objects, once executed, "unescape" the payloads that will be evaluated and rendered as HTML on the phishing website. The JavaScript functions being used are "unescape()",  and "eval()".

The "unescape()" function computes a new string in which hexadecimal escape sequences are replaced with the character it represents, and "eval()" takes the string and checks to see if it represents an expression. If it does, then eval() will execute that expression.

Fig. 1: An example for phishing page obfuscated with eval() and unescape() Fig. 1: An example for phishing page obfuscated with eval() and unescape()

This technique is not considered a highly sophisticated evasive technique. Yet, without rendering the page and evaluating the content, it will be hard to determine that the web page is malicious. Both the "eval()" and "unescape()" functions are being used by many benign websites, and are not enough on their own to indicate malicious activity. 

We can also see that the usage of the decodeURI() and decodeURIComponent() functions in the wild, as "unescape()" was deprecated in JavaScript version 1.5. 

In Figure 2, a custom function spotted in the wild takes base64 input and uses the array.prototype.map call to split the string to an Array, and use another custom function to run on each char adding '%' + '00', change "char" to ASCII and strip '00' again, to eventually run decodeURIComponent() on the entire output.

Fig. 2: An example for page obfuscated with decodeURIComponent() Fig. 2: An example for page obfuscated with decodeURIComponent()

Content escaping—Base64

Another common way to obfuscate content on a page is to use base64 encoding. Base64 encoding is often used on websites to transform binary data to an ASCII representation of the data. A legitimate and common use of base64 is to include embedded images content on an HTML page.

In the context of phishing and web scamming, base64 obfuscation is used to hide content as a base64-encoded data object. An example of this is seen in Figure 3, where we can see an HTML object being loaded from a "data:text/html;base64," data type, and rendered in HTML. The rendering is shown in Figure 4.

Fig. 3: Base64 decoded object Fig. 3: Base64 decoded object
Fig. 4: Rendered page out of base64 object Fig. 4: Rendered page out of base64 object

Another way to decode base64 spotted in the wild is to use the JavaScript function "atob()". An example of this is shown in Figure 5. 

Fig. 5: Base64 decoding - atob function Fig. 5: Base64 decoding - atob function

Content encryption—Javascript XOR decryption

Another technique we were able to see in the wild is a custom-made JavaScript function that executes XOR decryption for the given encrypted payload on the page. This isn't a new technique, but it certainly is interesting.

One notable observation about some of those XOR functions, such as the one presented in Figure 6, is that it is being customized each time it's used by changing function name, payload delimiter value, and encryption key padding. The usage of that kind of customization ensures it will be harder to detect the phishing or web scamming page via a static detection, such as text based signatures.

Fig. 6: customized XOR decryption functions     Fig. 6: customized XOR decryption functions

In some cases, we were able to see obfuscated source code that used both content escaping and XOR decryption to create an even more evasive combination not easily detected.

Content obfuscation—function and variable name

In order to make the JavaScript code hard to be read and debug, JavaScript functions and variables are being obfuscated by using hexadecimal patterns, overlapping naming conventions, usage of the same naming for variables and functions, and more.

Content obfuscation—dead code injection

By injecting code that will never meet the conditions to be executed, the JavaScript becomes hard to read and to debug, creating overhead for those that will try to understand code functionality and flow.

Content obfuscation—split and concatenation of string

By splitting and concatenating the code to be obfuscated into chunks of strings and executing all kinds of manipulations on those chunks - such as array value rotations - the results are code that becomes unreadable and evasive.

Anti debugging

In order to evade being detected and to make the challenge of understanding the executed code logic and functionality as hard as possible, evasive JavaScript might include all kinds of anti-debugging techniques.

When it comes to anti-debugging traps being used on the evasive code being executed, there are many techniques that can be used. Some of those techniques include overriding JavaScript functions that are frequently being used for debugging, or infinite debug breakpoint loops, which are activated only once debugger is running. Other techniques include using execution timer traps to detect code slowness, which is a result of debugging activity; and detection of code renaming by evaluating code integrity.      

Summary

Evasion and obfuscation techniques are used in a variety of legitimate use cases. For example, such measures can be used to stop someone from copying your client-side code. Therefore, the usage of evasive techniques shouldn't be considered as malicious by default.

We predict that the usage of evasive JavaScript techniques will become a trivial component in common scams, as JavaScript gives developers nearly infinite flexibility to customize code and introduce more advanced evasive techniques.

Enterprises need to make sure that websites are protected and guarded against malicious code injection, which will help protect applications and users alike. Likewise, they need to take care to layer their defenses in a way that protects users from scam sites that leverage these techniques



Written by

Or Katz

October 26, 2020