Catch Me if You Can—JavaScript Obfuscation
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.
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.
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.
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.
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.
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