Mayall: A Framework for Desktop JavaScript Auditing and Post-Exploitation Analysis

Writing desktop applications in JavaScript offers developers the opportunity to write cross-platform applications with cutting edge capabilities. However in doing so, they are potentially submitting their code to a number of unsanctioned modifications from malicious actors. Electron is one such JavaScript application framework which facilitates this multi-platform out-the-box paradigm and is based upon the Node.js JavaScript runtime --- an increasingly popular server-side technology. In bringing this technology to the client-side environment, previously unrealized risks are exposed to users due to the powerful system programming interface that Node.js exposes. In a concerted effort to highlight previously unexposed risks in these rapidly expanding frameworks, this paper presents the Mayall Framework, an extensible toolkit aimed at JavaScript security auditing and post-exploitation analysis. The paper also exposes fifteen highly popular Electron applications and demonstrates that two thirds of applications were found to be using known vulnerable elements with high CVSS scores. Moreover, this paper discloses a wide-reaching and overlooked vulnerability within the Electron Framework which is a direct byproduct of shipping the runtime unaltered with each application, allowing malicious actors to modify source code and inject covert malware inside verified and signed applications without restriction. Finally, a number of injection vectors are explored and appropriate remediations are proposed.


Introduction
Application designers often seek to produce high quality, cross platform applications in order to maximize their customer base. This introduces a number of difficulties regarding code reuse, with applications having to be modified, re-written or recompiled for each individual operating system.
Enter the explosion of new, fashionable languages and their counterpart interpreters and compilers. Such 'write once, run everywhere' languages, with their multi-platform out-the-box paradigm, attempt to revolutionize the way in which native applications are developed. These languages, such as Go and Node.js, have garnered rapid popularity through their inherent power and ease of development [1]. In the case of Node.js, this rapid rate of expansion brought with it a staggering number of modules and frameworks, along with an ever growing list of security issues.
Electron is one such framework aiming to bring this JavaScript runtime to the native operating system, unifying web technologies and distilling them into what is effectively a native executable. In doing so, developers are not only potentially opening themselves up to traditional web exploits such as Single-Origin Policy misconfiguration [2] -albeit this time in the much more dangerous context of the operating system -but also exploits that are unique to the framework in question.
Frameworks such as Electron, NW.js and to some extent, the Chrome Embedded Framework, are rapidly expanding and as such, it is important to address the security surrounding these products. There has been an increasing number of recent discoveries and events which bring into question the level of focus on the security surrounding the modules available on npm, the de facto standard for Node.js package management. As Electron is beginning to emerge as the clear winner of the two Node.js based frameworks, this paper will focus predominantly on the security surrounding Electron and the increasingly popular applications which are built upon it.

arXiv:1811.05945v2 [cs.CR] 15 Nov 2018
When contemporary frameworks grow at such exponential rates, including adoption from major players such as Microsoft [3], NVIDIA [4] and Slack [5], it is crucial that the security awareness surrounding the product does not go amiss. This reliance on the Node.js JavaScript runtime and the package manager that is used so prolifically with it compounds the security issues, as it adds additional levels of complexity which each require individual consideration with regards to security. There is comparatively little in the way of security research for Node.js and its accompanying frameworks when set side by side with other native programming languages, and what has been implemented in the way of security fixes is often reactive, rather than proactive. This is especially true with regards to the debacle over the kik module in March 2016, where an author unpublished a package which many other packages depended on [6].
This crucial oversight, highlights a clear need to analyze the platform for other potential issues, and to consider remediations for them before they occur. By investigating the method by which dependencies are handled and the way in which code is executed, the Mayall framework 1 presented in this paper allows developers to do just that. This paper explores the current state of security surrounding the Electron framework and the underlying Node.js constructs and demonstrates real world risks associated with this through the introduction of a post-exploitation framework built in Node.js, leveraging the modular structure of the language. The contributions from this paper are threefold: 1. An exploit which can take advantage of popular Electron based applications such Slack, Discord, etc. 2. An investigation of issues inherent of the Electron Framework.
3. An Open Source Extensible Security framework for analyzing Node.js applications.
The remainder of the paper is organized as follows: In section 2, an assessment of the current state of JavaScript security is performed and categories of vulnerabilities, language constructs and application management are discussed. This current review is taken further in section 3 where we expose the vulnerabilities of fifteen popular applications built with Electron, moreover we present a proof of concept exploit which allows us to take advantage of Electron based applications. The results from the audit are presented in section 4 and a discussion on how to remediate the risks from exploitation is proposed in section 5.

Background and related work
JavaScript security is a long discussed and multi-faceted affair; this is no different within the context of the Electron and Node.js runtimes. Now that the JavaScript language can be run natively, outwith the context of the browser, additional security concerns are brought to the fore. This is compounded by the rapid growth experienced by both JavaScript and Node.js over the past few years; JavaScript has consistently been top of the most popular technologies in the Developer Survey Results produced by [7].
This section explores the current security themes that are directly affecting the Node.js landscape. Specific examples are drawn upon where applicable to highlight the relevance of these themes when applied to Node.js. Whilst on the surface it may appear that some of these examples are self contained and acutely specific, the general risks discussed can be applied to Node.js and its desktop application counterpart, Electron. It is therefore important to discuss these precursor attacks that have direct relevance to these new languages and frameworks going forward. 1 Named after the astronomical body, Mayall's Object, which consists of two colliding galaxies, the framework's primary aim is to inject a module into the original application and modify its execution.

Web based JavaScript
When looking at traditional web-only based applications written in JavaScript, there are a series of recurring patterns that introduce a possibility for security vulnerabilities. For example, contained within JavaScript are a set of functions which allow for dynamic parsing and production of JavaScript code, the primary of which is eval(). One particular study by Richards textitet al. took a large sample of the top 10,000 websites and discovered that 89% of them used JavaScript. Furthermore, they discovered that "over 82% of the top 100 pages use eval, and 50% of the remaining 10,000 pages do as well" [8]. The primary issue that occurs with the use of eval is when arbitrary and unsanitized user data is passed to the function. When this occurs, it is possible for an attacker to execute the string they provide to the web application as JavaScript code. Whilst static code analysis often highlights security issues within an application, this becomes more challenging when dynamic elements such as eval are introduced. One method of analyzing such code is to perform an automatic transformation of "many common uses of eval into other language constructs with the use of a dataflow analyzer" [9]. These transformations are able to make some headway towards restoring the effectiveness of static code analysis on JavaScript applications. This is as a direct result of reducing the number of malleable and untrusted variables within the code, which subsequently reduces the number of mechanisms available to exploit such code.
While eval() is arguably the most relevant security risk when applied to modern cross-platform JavaScript applications due to it's alarming prevalence in Node.js, there still remain a large number of additional JavaScript vulnerabilities that apply to both web and desktop JavaScript, the most common of which is cross-site scripting (XSS) [10]. Marked as third in the OWASP Top 10 vulnerabilities list, XSS works similarly to injection vulnerabilities (such as those described above) in that it arises from a mishandling of user input and can result in arbitrary JavaScript execution within the web application [11]. Furthermore, JavaScript is used in the development of browser add-ons i.e. Web Extensions in Mozilla Firefox. Such vulnerabilities have the potential to allow for the development of malicious extensions, posing a security risk [12].

Node.js
Node.js is a JavaScript runtime that is built upon the V8 JavaScript engine developed by Google. Its primary aim is to provide a highly scalable environment on which JavaScript code can be run, allowing it to be deployed on desktop and server-side environments. Its focus is driven towards asynchronicity and concurrency in handling a large volume of connections whilst preventing thread-locks within the application [13]. It can be reasoned that Node.js is more akin to a standard library than a web framework and is comparable to PHP, Ruby or Python rather than the frameworks that run atop these platforms such as Laravel, Ruby on Rails and Flask. This is an idea bolstered by Eloff et al. and his analysis of Node.js as a baseline platform for web services [14].
Its adoption by commercial players such as Uber [15] and Netflix, [16] amongst others has helped to springboard the language towards success.
As it aims to be a powerful programming language in its own right, this requires it to contain a number of libraries and Application Programming Interfaces (APIs) that allow it to perform "low level networking, basic HTTP server functionality, file system operations, compression and many other common tasks" [17] [18]. As a result of this, the exec() command was introduced to the Node.js specification in order to expose shell interaction functionality on the operating system level. Similar to the way eval() works, data that is provided to exec() is interpreted as a command, however it is passed to the operating system shell rather than the JavaScript engine [19].

Electron
The Electron framework is an open source library designed for cross-platform application development in web based languages HTML, CSS and JavaScript [20]. It combines Chromium and Node.js into a single package so that traditional back-end and front-end code can be run within a single runtime environment.
A basic Electron application consists of three components: the package.json file, the Electron executable binary and the JavaScript source code.

Node Security
The tendency for writing insecure eval statements is not a scenario that is just limited to the web -desktop JavaScript is also affected by this [19]. As we see an increase in desktop JavaScript applications being shipped (examples include the increasingly popular Slack and Discord [5]), the programming paradigms that were popular on the web, are also unsurprisingly popular on desktop frameworks. The transference of such insecure coding practices are dangerously widespread as Staicu et al. show [19]. The study was carried out across a sample set of 235,850 Node.js modules. Their results demonstrate that approximately 20% of these modules made use of the potentially unsafe eval() and exec() API calls directly or indirectly after all the first and second level dependencies were accounted for. A reasonable majority of these modules did not directly call these APIs however, with only 3% and 4% of the sample calling the exec() and eval() APIs directlythe remainder were run within the module dependent code [19].
Whilst popular belief may lead to the conclusion that these insecure modules are unpopular, this hypothesis is challenged by the discovery that the contrary is true and that in fact "various vulnerable modules and injection modules are highly popular, exposing millions of users to the risk of injections" [19].
The immediacy of these findings does not present itself until it is noted that the sandboxes present in the web browsing environments (such as Chrome and Firefox) are not present within the Electron framework [21] and that any application running on Node.js has full system access equivalent to the account that is running the process.

The npm Registry and Module Security
When the number of external includes present in an application increases, so does the potential for unchecked vulnerabilities and the level of trust placed in unknown module authors. This idea is backed up by research into remote inclusions which put forward the important notion that "whenever developers of a web application decide to include a library from a third-party provider, they allow the latter to execute code with the same level of privilege as their own code" [22]. The package management system that is used for Node.js is known as npm and is where the vast majority of Node modules reside. Additionally, as part of the module install process, npm exposes the functionality to run additional scripts on the target machine [23]. These so-called preinstall and postinstall scripts have historically been a cause for concern within the npm registry and Node.js landscape. These script hooks introduce a new danger to the npm and Node.js environment as the scripts will run on the host with the same privileges as the user installing the module.

Typosquatting
Tschacher et al. brings to light the dangers of typosquatting within package managers in his dissertation he explores the malicious module that was released into the npm registry by a malware author on 26th January, 2015 [24] [25]. The module in question was known as rimrafall and contained "a preinstall hook that executed the command rm -rf / * " [26] [17]. As a result of this pre-install hook, any unsuspecting user that entered npm install rimrafall in a terminal prompt would end up with all their files being deleted from the machine. Whilst this module was removed from the registry less than two hours after being published, it does highlight the risks present in blindly requiring 2 numerous modules into a project. The primary goal of this module appeared to be to highlight that "npm install can be as dangerous as curl dangerous.com | sh" [27].
Whilst Lift Security provide tools to actively monitor modules that are required as well as systematically audit the most popular modules present on npm [26], the fact still exists that malicious modules can be introduced to the npm registry. Although methods exist to prevent scripts from running on install, the majority of users simply do not apply these checks when requiring modules into their codebase [24].
This lack of concern and consideration employed by some developers is evidenced in research performed on the effectiveness of typosquatting in a wide range of package managers for a multitude of different languages. 214 different packages were uploaded to the respective registries with typos in their names, each of which acquired 92 installations on average per package [24]. Whilst this may not sound like much, "the most installed package (urllib2) received 3929 unique installations in almost 2 weeks" and "the most installed package per day was bs4 with 366 unique daily installations on average" [24].
What is more alarming is the origin where these downloads occurred, as well as the prevalence of installs that were run with administrative privileges. It was found that 43.6% of module downloads and inclusions were run with administrative rights [24], thereby giving the accompanying install hooks administrative access on the machines where they were installed. In addition to the checking of administrative rights, [24] performed reverse DNS lookups with the installed module and discovered that his module had been installed on a surprising number of government and educational domains.

Trojan Modules
In addition to the direct installs of first level dependencies and the evident risks associated with directly installing unchecked code, there exists a risk of hidden malware further down the dependency tree. If a malicious author can influence code that is included in a numerous amount of other modules, the infection rate will be vastly increased. This exact scenario has occurred in the past on a variety of modules, however [22] points to a specific instance with popular jQuery plugin, qTip2. Nikiforakis et al. state that "The qTip2 library was modified, and the malicious version was distributed for 33 days" [22]. The compromised code made frequent callbacks to a specific IP address located in Russia and transmitted data including "[the] site's hostname, [the browser's] user agent, and the referer" [28].
These types of risk are not exclusive to WordPress and the web environment, this threat has presented itself in the npm registry. An npm developer encountered legal issues with Kik Interactive Inc. -developers of Kik Messenger -when he published a module under the name 'kik'. The npm developer was unable to come to an agreement with the company and after a fall out with the npm registry over the use of 'kik' as his module name, the developer took the decision to remove all 273 packages that he authored from the registry. As a result of this, thousands of Node.js applicationsincluding the widely used babel 3 library -started issuing dependency errors and failed to execute [29].
In addition to the breaking changes that were made due to the unpublishing from the npm registry, the removal of these modules presented an even greater threat. Every single module name-space that had been removed had now become available for any developer to claim control over. This allowed any actor, either benevolent or malicious, to potentially inject code into thousands of Node projects requiring any of the widely used modules that he had authored [6]. npm responded reflexively by blocking the registration of any of the removed modules as well as applying the same 2 Similar to a Python import statement, a require statement is the equivalent method by which external JavaScript modules are imported to a JavaScript application. 3 Babel (https://babeljs.io/) is a JavaScript compiler used by Facebook, CloudFlare and Netflix, amongst others. tactic to any future removed application, but not before a vast number of modules dropped from the registry had already been claimed by other developers.

Developer Attitudes
As with a lot of systems, updating is often an easy way to ensure that applications are free from vulnerabilities. However this is a major issue with the npm repository. As a result of the codebase being highly distributed over an exceedingly large number of developers, high code quality and a guarantee of constant security updates is not always available. Whilst auditing the top npm packages, [19] discovered a number of vulnerabilities within modules which they responsibly disclosed to the developers. They stated that "most of the developers acknowledge the problem, and they want to fix it. However, over the course of several months, only three of the 20 vulnerabilities have been completely fixed. The majority of issues are still pending, showing the lack of maintenance for many of the modules involved.". This lack of maintained code is not the only issue present in the Electron and Node.js landscape; the prevalence of version pinning also prevents a large majority of applications from being updated even after vulnerabilities are patched. This has become the mainstream method of dependency management after GitHub actively recommended "[setting] a fixed version number (1.1.0 instead of 1.1.0) to ensure that all upgrades of Electron are a manual operation made by the developer" [30]. This prevents applications suffering when breaking changes are introduced into the Electron framework, however it does place the onus on the developers to pay attention to updates and manually push these security fixes to the end users.
The following section expands on the work done by previous researchers, with a sharper focus on desktop applications written in JavaScript and JavaScript based frameworks, by presenting a framework centered around the security of Node.js and it's counterpart front-end, Electron. The framework is highly extensible and allows for the use of cross-platform payloads for remote execution of malicious code, taking advantage of the lack of code signing enforcement either remotely or locally.

Design and Implementation
This section aims to highlight the stages of development of the framework. The framework provides two algorithms presented in subsections 3.2 and 3.3 respectively. Both aim at assisting a security analyst during an audit with automated JavaScript vulnerability scanning. Additional security vulnerabilities are brought to the fore in subsection 3.4 with regards to how Electron handles updating application bundles and an exploit is demonstrated in subsubsection 3.4.3. This notion of exploit development is expanded further with the production of a fully functional 'backdoor module' in subsection 3.5 which discusses the methods by which Node.js malware can be introduced into a system and is rounded out in subsection 3.6 with the amalgamation of the produced tools into one cohesive framework that can be used for JavaScript security analysis.

Application Auditing
Due to the high prevalence of insecure modules present within the npm repository, it is deemed appropriate to perform an analysis of modules in use by some of the most popular Electron based applications. Electron applications are bundled into what is known as an asar archive, which is a concatenation of all files in the source code folder, similar to a tar archive. Electron can then access files from this archive during execution of the application. The asar package can be installed globally onto a system by using npm and the command npm install -g asar, after which point the asar command can be called directly from a terminal prompt. The asar archiving process does not contain any encryption or obfuscation and the tool is freely available and open source. As a result of this, it is possible to issue the command asar e app.asar app to retrieve the entire source code folder for an application, complete with formatting, comments and module dependencies as written by the developer. It is the latter which is of interest during this phase of the investigation as attempts will be made to discover if any of the modules contain vulnerabilities. Modules that have been required by either the application author directly (henceforth referred to as primary modules) or any of its dependencies (henceforth referred to as tertiary modules) are located in the node_modules folder within the decompressed asar archive. Each of these modules contains an individual package.json file which is specific to that module. This file contains details such as the name, version and author of the module, but also additional information such as the repository url for that module. Of the modules surveyed, only a negligible amount of modules did not provide a GitHub repository location and it was therefore very easy to further analyze these modules through commits and issues present on the respective repositories.

appScanner.js
An algorithm was developed to assist in the version analysis of all imported modules, as the number of tertiary modules can be vastly larger than the number of primary modules, thereby creating excessive amounts of workload for a manual audit, as shown in section 4. By interfacing with the GitHub API, it was possible to pinpoint the individual git commit which corresponded to the release number inside a module's package.json file. This was done by querying the repository listed within the package.json file for tagged commits with the version number of the module. Following this, a comparison of the returned commit to the latest commit on the master branch was made and a count was returned of the number of commits the master branch was ahead of the imported module. Modules that were a substantial number of commits behind the master branch -above or equal to 150 -were considered to be suspect packages and could help an analyst look in the right places for existing bugs and vulnerabilities which would affect an application.
Although being a large number of commits behind the master branch may at first seem alarming, a lack of pulled commits may themselves not necessarily indicate a directly actionable exploit or vulnerability -this idea is discussed in more detail later in subsubsection 5.2.1. If an application has not been updated to the latest build, it may be to prevent breaking changes rather than a lack of concern for updating.

nspCheck.js
While checking how far a module is behind the master branch helps to give indicators to the security status of an application, a git commit record does not immediately indicate security flaws within the respective modules without additional analysis. To this end, another algorithm was developed allowing immediate highlighting of known and reported security vulnerabilities within a module.
The Node Security Platform maintains a list of security advisories along with a corresponding API. By comparing the installed module versions against this NSP database, immediate security vulnerabilities can be flagged to developers. By querying this API and parsing the response data into an easily human readable format, the algorithm makes strides towards building a toolkit for security researchers and analysts assessing overall Node.js security within a network.
When auditing for vulnerabilities, it does not suffice to simply check the package.json for the main application. Although a developer may require only modules that are up-to-date, they are not directly responsible for the management of multi-level dependencies, with this responsibility falling to the module author. As a result of this, vulnerabilities can be introduced despite a developer including only up to date version numbers. This is demonstrated in Theorem 1 and Figure 1, where it can be seen that whilst the developer has required up-to-date module versions, those modules in turn could depend on vulnerable code which is subsequently imported into the application. Theorem 1. Let A be the main source code, where B, C = 1 st are level dependencies and D, E, F = 2 nd are level dependencies. Let X n be the module version, where n = 1 indicates the most recent version and n = 0 represent outdated versions. Let X r be the set of requirements for a module.
This demonstrates that a single pinned version requirement further down a dependency tree can result in the inclusion of outdated modules, despite the developer updating all of their primary dependencies. Nested dependencies can introduce vulnerabilities through version pinning. Arrows represent dependency calls, while the red and green sections represent vulnerable and patched module versions respectively. Although an alarming percentage of the applications tested did contain known vulnerable elements (Table 1), there still were a number of large name, well known applications which passed this scan with no vulnerabilities being detected. With this in mind, it was necessary to widen the scope to audit other aspects of the application processes, one of which was updating.

Malicious Update Process
Updating Electron applications is typically managed via the Squirrel Framework which is provided to Electron developers as an interface through the autoUpdater module shipped with Electron. The update process is not uniform across platforms with the Windows process requiring additional steps in order to produce the update packages.

Update Electron Packages
When Electron applications are updated on macOS, the only step that is taken is to recompile the entire application and push it to an update server. This update server is then polled at application startup by Electron applications running the autoUpdater code. For Windows, it is possible to create delta packages which contain the changes made since the last version.
The update server follows a specific directory layout where the platform specific updates are stored in sub-folders for that platform. The Windows subdirectory contains a RELEASES file which contains a list of packages available on the server in the format 'SHA1_checksum filename size_in_bytes'. This RELEASES file is queried by the remote applications at startup to determine if an update is available. If one of the entries in the RELEASES file contains an application with a greater version number than the one provided by the application, the update process will automatically download and update to the latest version without any user input required. Automatic updates on Windows will occur so long as code signing has not previously been put in place and the version number is higher than the current version performing the update check.
On the other hand, macOS applications will not automatically update unless the update package is signed with a valid code signature. For this reason, a proof of concept was built on the Windows platform to eliminate additional overheads which are outwith the scope of this study, namely code signature bypasses.

Enumerating Update Endpoints
As a result of requiring no user input, it may be possible to covertly install malicious updates without user interaction. In order to demonstrate the vulnerability, a freely available application built on the Electron Framework was downloaded and it's contents extracted with asar e app.asar app. The code in the resultant app folder was then examined and additional code was inserted. The added code resulted in the writing of a new file to the user's home folder on launch.
Due to the lack of code signing in effect on the application, and the lack of a secure HTTPS connection to the update server, it was possible to man-in-the-middle (MITM) the entire update process. When the application was launched, the connection request to the remote update server was intercepted and handled by a rogue update server that mimicked the responses that the application was expecting.
In order to build this rogue server, the update endpoints needed to be determined. This was achieved by setting an HTTP server handling all requests from the application. By modifying the hosts file to redirect the target application to localhost, all URL endpoints could be enumerated by the rogue server. It was subsequently possible to recreate the folder structure required for a Windows update and have the rogue server resolve the requests made by the insecure application.

Building Malicious Updates
The Windows update process involves downloading a delta package (a package containing the changes made since the last version) or, if one is unavailable, a complete package from the server. The package system in use is based on the Windows NuGet Package Manager and application updates are provided to the Squirrel Framework as .nupkg files.
A .nupkg file is compressed in the same way as a .zip folder and contains the source code for the application along with associated metadata such as version numbers. By unzipping the full nupkg file for the most recent version of the application and modifying the metadata and source code, a fully functional update could be created and served by the rogue server.
As a result of these steps, the application automatically updated on launch to the 'most recent version' as supplied to it by the rogue server, thereby writing a file to the user's home folder. As a presumed formality, the application presented the user with a dialog box informing that an update was available and asked the user if they would like to update now or later. However, this dialog box only appeared after the automatic update had already been installed and it was irrelevant whether the user clicked 'Install' or 'Later'. If the user clicked 'Install', the application would open a web page in the user's default browser showing the patch notes for the version just installed. To alleviate suspicion from a user, this webpage (http://1clipboard.io/update) was cloned and served to the user through the malicious server. socket.write(stdout); 7 }); 8 }); 9 }).listen(conn_port); 10 }

Malicious Exploit Design
While injecting via an update is a viable infection method if the application does not correctly implement code signing, there remain a number of applications which do code sign and thus this method may sometimes be impractical. Despite the fact that code signing is in place during the update process, this security check is not enforced at application runtime and code signing is disregarded. To this end, if it is possible to gain access to a machine -through a social engineering or phishing attack for example -it would be possible to modify the application source code to inject malicious content. This is possible as the Electron executable does not check the code integrity of the application on runtime.

Malicious Exploit Design -A Dropper Module
Before the injection of an application is demonstrated, it is necessary to generate a payload that is able to communicate with and receive commands from a remote Command and Control (C2) server as demonstrated in Listing 1 representing the target code, and Listing 2 representing the pseudo code for the C2 Server. As Node.js is the underlying language that Electron is based on, the basic module was built in Node.js without Electron in mind -Electron is primarily used as the visual bolt-on to a Node.js application, exposing the Graphical User Interface (GUI) and other interaction methods to an end-user and Node modules can still be run underneath Electron.
In order to receive commands, a websocket functionality was introduced, opening a port on the target machine on which mayall.js listen for commands. This can be seen where the payload waits for data tagged with the string 'exec', the contents of which it executes in an exec command, writing the results back out to the socket. Once the module is running on a target machine, it is then possible to connect with a networking tool such as netcat.

Covertly Embedding Modules
Running a node module outright from the command line, although effective in demonstrating Node.js capabilities, is not going to have a high conversion rate from payloads delivered to remote shells returned. In order to have a greater activation rate from the Mayall payload, it was deemed necessary to embed it within applications that a user trusts and installed themselves. An additional benefit of embedding an application with the Mayall malware (rather than running it directly) is that any firewall notifications will be requested on behalf of that injected application. For instance, if Mayall is injected into Slack -a popular team communication product -any initial firewall request by Mayall to open ports will appear to come from Slack and not the malicious module. Furthermore, once this request has been accepted once, it will continue to be allowed to run on future execution of Slack.
The mayall.js payload is developed further to allow agnostic infection across multiple operating systems and applications. A list of popular Electron applications is compiled and shipped alongside the module, complete with an automatic injector. Figure 2 demonstrates the method by which the payload embeds itself within an application, starting with an initial operating system detection. After determining the platform it is ran inside (exposed through Node.js' process.platform variable) the injector is subsequently handed off to the appropriate dropper module. This module will search the typical installation locations for Electron applications for the system type and inject mayall malware into any applications that it discovered. This is achieved by first extracting the asar archive associated with the application and executing a read of the .main field from the package.json file located within the archive. This field details the entry point of the application. If a valid file is discovered, the dropper downloaded the mayall module into the node_modules folder in the extracted archive. This is followed by a pre-pending of the entry file with a require statement for the newly downloaded module, causing it to be loaded into memory when the application next executes. Once in place, the injector then repackages the asar archive and cleans up any files that were left behind as a result of the execution.
As with many modern day applications, developers of Electron applications exhibit a tendency to have their applications launch on boot. As a result of this software design trait, persistence is gained when Mayall is injected into an application which exhibits this behavior -examples include the highly popular Slack, Discord and Tidal Music applications (Figure 3).

Executing JavaScript Natively on a Target Machine
As this injection module is written in Node.js, it may be assumed that the Node.js is a necessary installation prerequisite for executing a successful attack. However this is not the case. If Electron applications are the target then it is possible to use operating specific scripts (for example, batch files on Windows or bash scripts on *nix systems) to identify these applications. Once identified, the injector module can be executed with the Node.js binaries that are provided alongside the Electron executables. As aforementioned, the Electron application does not concern itself with the integrity of the code that is being run and as such it would be possible to decouple the main application code from the Electron application and instead run the malicious code against this decoupled binary including a cleanup and replacement of the old code base. The Node.js binary can often be found in unexpected locations. NVIDIA is one such example. When installing the appropriate drivers for an NVIDIA graphics card, a web helper is also installed for the NVIDIA GeForce Experience companion application. This applications handles driver updates, game optimisation and the ability to record and stream gameplay through ShadowPlay. Additionally, this application is installed by default when drivers are installed for the graphics card.
Contained within this package is a binary titled NVIDIA Web Helper.exe which upon further inspection is a Node.js executable which has been resigned by NVIDIA. This provides a binary upon which malicious code can be run with the added bonus of being signed by NVIDIA, therein bypassing certain security features provided by Windows -namely application white-listing [4].

A Framework for Post-Exploitation
In a concerted effort to raise awareness and kickstart the introduction of actionable change in the JavaScript security landscape, the Mayall Framework will be released as an open source tool for the open source community, allowing security researchers to efficiently and effectively drill down on the security issues plaguing modern JavaScript applications, in a similar vein to other frameworks such as MetaSploit and PowerShell Empire.

Results
This section presents the findings of the investigation carried out on the different applications.

Scanning Module
The scanning module produced in subsection 3.2 was run against a number of the most popular applications written in the Electron framework, the results of which can be seen in Table 2.
This shows how many modules are included directly by the developer, followed by the subsequent total number of modules that are imported to the application through the full dependency tree. The commits column shows the number of commits behind the master branches in the associated GitHub repositories, as well as the number of commits each module is behind on average. In addition, the number of application dependencies were compared to the number of modules explicitly included by the developers. The results (Figure 4) shows that a linear regression exists between the number of direct imports and the total number of dependencies. This demonstrates that a relatively low number of direct imports can result in mass inclusions of additional dependent modules, vastly increasing the code base with an approximate fivefold increase in total modules against primary imports. In addition to the GitHub upstream checker, the same applications were audited against the Node Security Platform and the list of advisories that NSP maintain on npm modules. Table 1 (previously shown in subsection 3.3) details the number of unique advisories found along with the highest CVSS score found.

Update Injection and Malicious Modules
By producing a malicious update package and placing it on a server which responded to URL requests from Electron applications, it was possible to inject an application which had not taken basic security measures to ensure server authenticity. If the malicious update claimed a high version number (such as v.50 when the current version is v.0.8.1) future updates would also be blocked as the application would opt out of downgrading its version number. Once injected (either through update hijacking or script running), it is possible to exfiltrate data through the execution of commands on the remote system.

Current Remediations
A number of suggestions have been made to combat the risk of uncontrolled JavaScript in web and client-side applications, however a lot of these struggle to find their place in the full-stack JavaScript development environment [31] [32]. For example [22] recommends sandboxing remote code as well as manually importing remote includes by writing the required code directly into the main source. While sandboxing has been a long discussed issue on the Electron GitHub repository and work was done by developers of the Brave Browser to reintroduce the Chrome Sandbox in their forked version of Electron [33], there is still a lot of discussion and work to be done in order to merge these changes back into the upstream Electron repository [34]. With regards to minimizing external includes, the issue lies with the Node.js model of programming where small modular includes are a major part of the language style. Whilst it would be possible to rewrite code from external modules directly into the source code, it is not the widely accepted or adopted method of Node.js application development. In addition to this, there are occasions where this is simply infeasible and could end up causing more harm than good -for instance, with regards to cryptography and authentication modules. By analyzing how other languages and frameworks handle code integrity, the immaturity of some elements of Node.js and Electron become clear. [35] poses multiple solutions for ensuring software integrity including the introduction of 'file system integrity checkers', 'code signing' and 'visualization' in the event of attempted malicious code execution. Whilst some of these elements may be in the process of implementation, these measures simply haven't been effectively implemented in Electron. There have been a number of methods proposed by which arbitrary code execution could be mitigated in both the context of secure application development and in application runtime monitoring and threat modelling. One such method is presented by [19] who proposed a tool that reduced the impact and effectiveness that vulnerable call sites (such as eval and exec) have on a system. Whilst this research study discusses "[their] runtime mechanism effectively prevents 100% of the attacks", they also highlight that "developers who both use and maintain JavaScript libraries are reluctant to use analysis tools and are not always willing to fix their code". This reluctance to employ third-party security tools suggests the need to push greater security measures into the frameworks and runtimes themselves, rather than placing the onus on either the developer or the user to enforce good security practices at runtime. Another solution to protect against malicious modules is based around runtime modification and surrounds itself with the idea of threat modeling. [36] investigates the process of creating "access control policies on interactions between libraries and their environment", giving modules only the access that they require based on a model of 'least-privilege'. Whilst this is a potentially feasible implementation when dealing with server-side JavaScript, this policy enforcement can not be guaranteed when applied to Electron, as an attacker could have full control over the source code and execution of the application.

Git Commit Divergence
As briefly mentioned in subsection 3.2, whilst a notable divergence in commits from the master branch may not necessarily indicate the certainty of a security risk, it is still enough to raise concern. This disparity in module update mentality when compared to the urgency and immediacy of updates seen elsewhere (operating systems, etc.) may have been caused in part by this notion of version pinning, combined with the prolific lack of code maintenance -an issue that was also noted by [19] in subsection 2.5. Whilst version pinning will prevent unwanted change (be it breaking API changes or malicious trojan inserts), it may also simultaneously prevent security updates from being patched into a system. This was the case when modules in the test sample were found to contain known vulnerabilities when cross-referenced against the Node Security Platform Advisories List [37]. By modifying the appScanner.js tool to additionally search for key phrases such as 'security', 'urgent' or 'vulnerability' within the commit messages or issues that are present between the current version and the version in use, it should be possible to create more meaningful data that developers will be able to respond to quickly. The primary risk with this method is centered around the list of search terms that commits and issues are compared against. Each developer and repository has their own type and there is a risk that tag names will be missed if they are stylized differently (for example a tag with the name 'Type: Bug' instead of just 'Bug'). If crucial tags are missed, then vulnerabilities could slip through the net, giving developers a false sense of security that their applications are secure. The Node Security Platform is making strong steps towards providing a searchable database of known security vulnerabilities, however more work is required to ensure that module maintainers are submitting these vulnerabilities to the database as they patch, in order to provide a central queryable database for all developers.

Update Process
Evergreen applications are gaining greater traction as part of the software development life cycle. Evergreen here refers to the process of automatic self-updating and is adopted by widely used applications such as Chrome and Spotify as well as the majority of applications built on Electron. As a result of this well documented methodology, it is easy to configure an update server which applications can poll at regular intervals as part of this self-updating process. Consequently, it has also proved trivial for an attacker to configure a rogue server that mimics expected application endpoints if developers have not taken basic measures to protect the security of this process.
Whilst TLS encrypted communication and application code signing is not an issue caused directly by Electron, steps could be taken to enforce these more secure practices. For example, macOS applications can not be automatically updated unless a valid code signature is provided. Whilst this is a security feature present in macOS, this ideology could be transferred from the operating system paradigm into the cross-platform Electron Framework. By rejecting all application updates that do not have valid code signatures, developers will be forced to move towards code signing in order to release a popular and relevant application. Although this may seem like a drastic measure, Google are performing similar measures with regards to their "Not Secure" stance on web pages that do not employ HTTPS [38]. In addition to this, the introduction of code signing across the board may help to unify the fragmented update process currently in place. By calling for a redesign of the process, it may also be beneficial to reassess the packaging process so that the entire procedure can be made simpler for developers, potentially with the introduction of certificate acquisition scripts which are a practice currently recommended by [39] with regards to TLS. This can also bring Linux autoUpdating inline with macOS and Windows, a platform which is currently unsupported by the Squirrel updater.

Application Signing Against Runtime
While the Program Files directory in Windows requires administrative privileges to write to, the majority of Electron applications are installed in AppData/Local on Windows which does not require any special permissions. This places application source code in an unprotected environment and is free to be modified by any process. In order to protect the system from any malicious activity caused by a change in source code, code integrity checking mechanisms must be implemented at the execution stage of an application. This is a process that is not only confined to Windows, as macOS also suffers the same issue. By running simple scripts with the same privilege of the current user, all Electron applications can be injected with malware, potentially without any knowledge of this from the user. If Electron were to implement rigid code signing policies, any malicious changes made to the source code of such applications would result in a non-execution of the application at launch. Unfortunately, this change to the framework would create massive breaking changes. If the next version of Electron was to implement this type of code signing, there may not be anything stopping an attacker from replacing the Electron binary with a downgraded version which does not check for code signatures. As a result, application breaking code changes may be required in order to make downgrading a time inefficient attack for an adversary.

Secure TLS Connections
One major oversight was the lack of transport layer security implementations that allowed for malicious update injections due to the absence of cryptography on all connections to the update server. As Electron allowed updates to occur over HTTP, it was trivial to execute a man in the middle attack and perform arbitrary remote code execution on the target machine. If Electron were to prevent such connections from occurring, it would prove much more difficult to inject applications in this way. In addition to this, Electron should issue warnings to developers concerning the downloading of resources over HTTP and begin deprecation of this plaintext transport mechanism. At the time of writing, there are no less than 142 individual security advisories on the Node Security Platform for applications which download resources over HTTP, leaving themselves vulnerable to MITM attacks, potential code injection and arbitrary execution. This downloading of binary resources through insecure means opens applications up to the types of attack that have been demonstrated throughout this paper as an attacker will be able to replace the resource being downloaded with their own malicious versions.

Repackaging binaries
The practice of shipping JavaScript applications is becoming widespread, however the act of resigning a Node.js binary and shipping it as part of a wider product has not been properly observed or documented in the wild until it was discovered in an NVIDIA package by [4]. By providing the Node.js binary to vast swathes of users, one of the main barriers to entry for JavaScript malware is removed. One potential explanation as to why JavaScript malware has only seen a slow uptick in recent years could be due to the lack of an available runtime to execute it against. As more applications are beginning to ship with Node.js included either through Electron or as a directly repackaged binary, it may be the case that a notable increase in JavaScript malware is observed. The ability to be able to produce truly cross-platform malware that can run on both servers and clients across all major operating systems could have potentially catastrophic outcomes.

Developer Involvement with the Node Security Platform
Although it may be easy for security researchers to pin the blame on the insecure practices of developers, this is neither helpful nor constructive. In order to remediate the risks associated with the use of known vulnerable modules, more awareness of the dangers and available scanning tools must be made available to developers. The npm package manager has the ability to issue warnings at the terminal prompt whenever vulnerable or deprecated modules are npm installed, however these warnings do not flag up for every vulnerability listed in the NSP Advisories List.
It is proposed that npm issue a warning detailing the risks of installing these modules and have developers explicitly accept these risks before the installation continues. In addition to this, it may be beneficial to warn developers of out of date, dangerous modules at runtime, each time the application is tested or executed. This upfront alerting mechanism may influence developers to start taking measures to secure their applications before deployment.

Conclusions
In this manuscript a fully-functional framework is presented, demonstrating a technique to successfully inject user-installed applications with malicious Mayall modules. The framework presented was made of two primary modules: the injector and the command and control server, as well as the vulnerability scanning algorithms. By using the Electron runtime as a standalone executable, the injector was able to execute on the remote host using the Electron and Node APIs bundled within the Electron binary. Furthermore, by providing the ability to pass eval and exec parameters to the payload from a remote server, execution is possible not only within the Electron and Node.js runtimes, but also from the native operating system shell.
The findings drawn from this manuscript signify the need for increased awareness and action surrounding JavaScript security. As Node.js inevitably continues to grow, the awareness of risks associated with running untrusted code need to grow alongside it. Unlike other popular programming languages (such as Python), Electron applications are not compiled directly into native executables for that operating system (in the same way py2exe would for Python) and are rather executed via the generic runtime environment that is distributed alongside the application. This introduces potential and previously unseen risks -as demonstrated by NVIDIA's packaging and release of their rebranded and signed Node.js binary -as it provides attackers with a new increasingly available toolset with inbuilt system interfacing capabilities. Moreover, this study demonstrated lack of accountability that an Electron binary held for its associated code base. The ability to entirely rewrite sections of an application without throwing alerts or warnings is a major risk that could be easily leveraged by an attacker under the appropriate circumstances.

Future Work
In order to be an extensible framework (similar to Powershell Empire and MetaSploit), the source code will be made available online for other researchers to contribute. By leveraging the module dependency nature of Node.js, we plan on building extensions as standalone modules which are required by the core framework. Moreover, we plan to port popular penetration testing tools such as Mimikatz onto the Mayall framework.
Author Contributions: Adam Rapley carried out the investigation, and wrote the first draft of the paper. Colin McLean, Lynsay A. Shepherd, and Xavier Bellekens supervised the project, and wrote the paper.