Symantec, India
Copyright © 2018 Virus Bulletin
The WebAssembly (Wasm) format is a way to run code, compiled in native languages such as C/C++, on web browsers. WebAssembly has better performance when running native code than other variations of compiled JavaScript such as asm.js (Assembly JS). WebAssembly is often used in developing web games. Recent versions of all popular browsers including Chrome, Firefox and Microsoft Edge support WebAssembly execution.
Though Wasm has been around for a few years, it rose to prominence more recently when it was used for cryptocurrency mining in browsers. This opened a Pandora's box of potential malicious uses of Wasm.
In this paper we will walk through some of the instances in which Wasm can be used maliciously, such as:
To add the cherry to the top of the cake, detection of Wasm is difficult as it is a compiled file, making string-based detection almost impossible. We will discuss some of the areas in which we expect the above methods to be used.
JavaScript [1] is a general-purpose programming language. It's a simple language with a huge ecosystem, and it is tightly integrated in the web. There is no way of moving away from JavaScript without breaking all of the existing web applications, which is not a situation any browser vendor wants. Furthermore, all browser technologies and security constraints are designed specifically for JavaScript.
Current JavaScript is quite fast, but there are a few mechanisms in JavaScript engines that limit its speed [2]:
Asm.js [3] is a subset of JavaScript, defined with the goal of being easily optimizable and used primarily as a compiler target from languages like C and C++. Asm.js code can produce executables that exhibit none of the drawbacks listed above. They can be compiled 'ahead of time' and are faster than JIT-compiled ones.
The web is not controlled by any single vendor, so every change must be a joint effort. It was a group of hardcore developers at Mozilla that developed asm.js. Meanwhile, Google developers worked on Native Client (NaCl) and Portable Native Client (PNaCl), a binary format for the web based on the LLVM compiler project. Although each of these solutions worked to some degree, they did not provide a satisfactory answer to all the above problems. It was from this experience that WebAssembly was born: a joint effort aimed at providing a cross-browser compiler target.
The continued evolution of asm.js is WebAssembly [4]. WebAssembly is intended to fill a role that JavaScript has been forced to occupy up to now: a low-level code representation that can serve as a compiler target.
WebAssembly provides a unified compilation target for languages such as C and C++ that do not map easily to JavaScript [5].
WebAssembly (Wasm) is a new type of code that can be run in modern web browsers and provides new features and major gains in performance. It is considered as a new binary format for the web [6, 7]. Generally, performance-critical functions can be implemented in Wasm and can be imported like a library into JavaScript.
Wasm was not created as a replacement for JavaScript, rather to complement and work alongside it. With the introduction of WebAssembly, the modern web browser's virtual machine is expected to run both JavaScript and Wasm.
All major browsers support Wasm. The benefits of WebAssembly include:
Tools like Emscripten [8, 9] can be used to compile code written in C/C++ into WebAssembly:
emcc hello.c -s WASM=1 -o hello.html
The options in the command are as follows:
-s WASM=1 – specifies that we want Wasm output. If we don't specify this, Emscripten will just output asm.js, as it does by default.
-o hello.html – specifies that we want Emscripten to generate an HTML page in which to run our code (and a filename to use), as well as the Wasm module and the JavaScript 'glue' code to compile and instantiate the Wasm so it can be used in the web environment.
There are future plans to get rid of the above JavaScript glue code to allow WebAssembly modules to be loaded like JavaScripts (<script type='module'>).
With the performance benefits and features that WebAssembly provides, it was only a matter of time until malware authors took notice. WebAssembly found its place in browser-based miners wherein it was used to mine cryptocurrency using the victim's computer resources (basically CPU cycles). The WebAssembly code used was developed using C implementation of the Cryptonight mining algorithm. The mining process occurred, mostly unknown to the victim.
The flow of the mining process is shown in Figure 4.
With knowledge of the above-mentioned technique, which is already in the wild, let's discuss other ways in which WebAssembly can be used maliciously.
A technical support scam (often abbreviated to tech support scam) refers to telephone fraud in which scammers claim to be providing a legitimate technical support service. It may begin with a cold call, usually from a legitimate-sounding third party like 'Microsoft' or 'Windows'. Remote desktop software is used to connect to the victim's computer, and the scammer then uses a variety of confidence tricks that employ various Windows components and utilities (such as the Event Viewer), third-party utilities (such as rogue security software), and reference sites like Wikipedia or summaries written by security companies to make the victim believe that the computer has issues that need to be fixed, before asking the victim to pay for 'support'. These scams usually target users, such as senior citizens, who are unfamiliar with the tools used in the process, especially when taken by surprise by a cold call.
In other cases, the scam is initiated with a browser pop-up that 'alerts' the victim to an apparent infection on their machine and urges them to call a tech support number. An example of a tech support scam browser pop-up can be seen in Figure 5.
The attacker wants victims to see the alerts in the browser and continues to bombard them with pop-ups about the apparent infection. When the victim calls the tech support number, the scammers either ask for money to address the 'problem' or simply install some software/backdoor on the victim's machine.
Sources of tech support scams may include the following:
For a long time, exploit kits were the preferred malware delivery vehicle for malware authors. However, the non-availability of newer browser and plug-in exploits coupled with hardening of operating systems, meant that exploit kits became increasingly less viable and malware authors were met with reduced infection rates. To keep the money flowing, redirection campaigns associated with exploit kits gradually shifted to delivering tech support scams to victims. This led to a heavy influx in tech support scams. Evidence of this can be found in reports presented by Microsoft [10] and the FBI's Internet Crime Complaint Center (IC3) [11].
When tech support scams first arrived on the scene, all the malicious and annoying web page behaviour was achieved through the use of JavaScript, which was unobfuscated and could easily be detected. However, as tech support scams began to emerge as a major force in the threat landscape, new anti-detection features were added. These started with the use of light obfuscation such as hex encoding, and went all the way to the use of packed encoding and even encryption algorithms like AES (Advanced Encryption Standard) [12, 13] (see Figure 6).
Now we have discussed both WebAssembly and tech support scams, let's take a dive into their fusion.
Tech support scams rely on JavaScript to achieve almost all of their objectives. WebAssembly allows the execution of JavaScript in its compiled binary form with fewer detection avenues. Thus, a combination of the two achieves the underlying objective of scaring the victim by presenting a scam which is entirely built on WebAssembly, leaving no traces.
A proof of concept for this combination can be found in Figure 7, which shows a snippet of C code which executes JavaScript code.
The Emscripten compiler provides a way to call JavaScript from C using EM_ASM() [14].
Code within the EM_ASM() tag will run as if it appeared directly in the generated code. That is, the JavaScript code is executed like a normal piece of JavaScript which is usually found on the web.
Walking through the JavaScript code, a pop-up warning the user that the system is infected is shown first, along with an image, as shown in Figure 8.
Moving forward, the scam checks for the following key presses:
Keycode | Key |
13 | ENTER |
27 | ESC |
18 | ALT |
123 | F12 |
85 | u |
9 | TAB |
115 | F4 |
116 | F5 |
112 | F1 |
114 | F3 |
17 | CTRL |
This prevents the user from escaping the scam by pressing keys like ESC or the CTRL+ALT+DELETE combination, or others as shown in the table.
The code also monitors mouse clicks and pops up the malicious alert each time the mouse is clicked.
In this scenario, only the code within the 'document.write()' tag is rendered in the browser, while the JavaScript code is loaded on the fly. The only visible trace of the C code is a Wasm file, seen in the browser cache, the content of which is shown in Figure 9. Thus, security products will only see the compiled Wasm file rather than the JavaScript source code. This is similar to seeing an executable file in a text editor, thus making detection difficult.
Keystroke logging, often referred to as keylogging or keyboard capturing, is the action of logging the keys struck on a keyboard, typically covertly, so that the person using the keyboard is unaware that their actions are being monitored. Data can then be retrieved by the person operating the logging program, better known as the keylogger [15].
Keyloggers are most often used for stealing passwords and other confidential information.
Keyloggers come in various forms including executable files, script files, etc., but the end objective is always to steal confidential data such as passwords, credit card details, etc.
Executable keylogger files land on the system via a variety of sources such as spam mails, social engineering scams, vulnerability exploitation, etc. Executable keyloggers can monitor keystrokes regardless of the running application – that is, keystrokes can be monitored whether the user is filling in a website form, typing in a Notepad file or any other actions carried out through the keyboard.
Script keyloggers are typically written in JavaScript, VB Script, etc. Script keyloggers are injected into compromised websites to steal passwords and other confidential information from website visitors. In the majority of cases, website owners and visitors are unaware of this keylogging activity. Script loggers are restricted to the website into which they are injected.
In this paper, we will discuss script keyloggers combined with WebAssembly. Since this kind of keylogger is written entirely in JavaScript, it is prone to string-based detection. With the following proof of concept, we will see how these detections can be bypassed.
In the code shown in Figure 10, there are four main functions:
In lines 43 and 57, we can see the 'change' eventListener being attached to the text fields for username and password. This event is fired when the user has finished entering the username/password. When this event is fired, the code in myFunction0() or myFunction1() is called respectively, thus capturing the credentials.
The rest of the code just builds the HTML front end for the user input form.
In this scenario, security products will only see the compiled Wasm file rather than the JavaScript source code, thus making detection difficult.
The output of the proof of concept can been seen in Figure 11.
This example shows that WebAssembly can be used in phishing campaigns to capture confidential information without leaving many traces for detection purposes.
As we have witnessed, WebAssembly can be used in a variety of ways to achieve nefarious goals. However, this is just the beginning. We firmly believe that, in the future, WebAssembly will leave its footprint in one or more of the following domains:
Thus, we can build a long redirection chain using WebAssembly: the compromised website loads the above Wasm, which leads to the custom phishing page where we steal confidential information using WebAssembly.
[1] https://www.quora.com/in/Will-WebAssembly-make-JavaScript-skills-more-or-less-valuable-in-the-future-WebAssembly-will-allow-performance-critical-stuff-to-be-done-using-WASM-while-all-the-rest-will-still-make-sense-to-be-done-in-Javascript.
[2] http://2ality.com/2013/02/asm-js.html.
[3] https://medium.com/javascript-scene/why-we-need-webassembly-an-interview-with-brendan-eich-7fb2a60b0723.
[4] https://brendaneich.com/2015/06/from-asm-js-to-webassembly/.
[5] https://auth0.com/blog/7-things-you-should-know-about-web-assembly/.
[7] https://developer.mozilla.org/en-US/docs/WebAssembly.
[8] https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Emscripten.
[9] http://kripken.github.io/emscripten-site/.
[10] https://cloudblogs.microsoft.com/microsoftsecure/2018/04/20/teaming-up-in-the-war-on-tech-support-scams/.
[11] https://www.ic3.gov/media/2018/180328.aspx.
[12] https://www.symantec.com/connect/blogs/tech-support-scams-increasing-complexity.
[13] https://www.symantec.com/blogs/threat-intelligence/tech-support-scams-aes.
[14] https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-call-javascript-from-native.