JavaScript – The language made for bugs

December 8, 2022

Ramp Up JavaScript

JavaScript is a programming language that can be used on both the client and server side for development. It is widely used on the Internet and is used on almost all web pages. In this article, we will discuss strange and interesting behaviours that JavaScript has built in and how they can be used by an attacker.

Function calls

In JavaScript, functions are first-class objects that refer to the Function object. Unlike other objects, the Function object can be called and return a value.

There are many different ways to call a function in JavaScript. We can call it directly, chain functions to call each other or call them from objects/prototypes.

In the payloads below, you can see some examples of how the alert() function can be called. An attacker can use these payloads to prove the existence of a Cross Site Scripting (XSS) vulnerability.

window.alert()
window['alert']()
alert()
alert``
onload=alert
\u0061lert()
globalThis.alert()
window?.alert()
eval?.('ale'+'rt('+')')
[1].find(alert)=alert,()
var x=x||alert;x()
alert(1),ErrExit
[][0]??alert()
null??alert()
undefined??alert()
x??alert();var x;

Newlines

JavaScript supports newlines that are not valid ASCII characters (\u2028 and \u2029). These two chars can be used just like any other newline char. To test this function, you can run the following commands below, copy the output and run it.

console.log('alert//\u2028(1)')
console.log('alert//\u2029(1)')

As a Proof of Concept, you can see that the code you executed is presented on a “single line” and that a comment (//) is in place. The JavaScript code still works without problems and this is because \u2028 and \u2029 are seen as a new line.

Comments

The most common JavaScript comments are the double forward slash (//) and multi-line comments (/**/), but JavaScript also supports two additional comments that are rarely mentioned. The <!-- and --> are both supported within JavaScript. These comments are built-in and are also supported in the backend when Node.js is running. The JavaScript code below is valid and uses all four comment methods.

Hoisting

In JavaScript, variables and functions can be used before they are declared, which can lead to many strange behaviours.

In the code snippet below, the function x is used in the if statement before it is declared, but because of the way JavaScript is hoisting, the function x is automatically declared in the hoisting process before the code is executed.

This behaviour causes the if statement to execute and print the text “Oh snap“.

JavaScript function hoisting

If you define variables directly in a function, the variable (x) will set its value (20) both inside and outside the function.

This behaviour is interesting from an attacker’s point of view: when the attacker can control a value set in a function, he can infect other code processes that use this variable.

Imagine that a developer creates two variables with the same name, one inside a function and one outside. The developer doesn’t realise that they are the same variable, so in reality, (s)he created a single variable that is being reused when the function is called. This is because (s)he had forgotten to declare the variable with var, let or const.

In this code, the variable str is first set to the value location.search and the variable name is set to the value returned by the ParamNames function (infected). When the ParamNames function is called, it uses the same variable name (str) that was used outside the function. This made the variable str update its value globally because the variable str wasn’t properly declared inside the function.

Error behaviour

JavaScript runs until an error occurs, as long as it is not a syntax error.

Imagine that you have found a Cross Site Scripting (XSS) vulnerability. The injection works, but you want to stop future code from running. You can trigger an error in JavaScript which will act as an “exit command“. This causes JavaScript to run the code (including your payload) and stop when it encounters the error.

Document Object Model (DOM) XSS methods

An input that is vulnerable to a DOM XSS gives an attacker a big advantage when exploiting an XSS. In a DOM XSS, the attacker sometimes only needs one character to exploit the vulnerability, the backslash character (\).

The backslash character can be used to write in Hex, Unicode and Octal encoded forms. In this case, the payload <h1>Hello</h1> can be written in all the different ways listed below:

1. <h1>Hello</h1>
2. \x3Ch1\x3EHello\x3C\x2Fh1\x3E
3. \u003Ch1\u003EHello\u003C\u002Fh1\u003E
4. \u{3C}h1\u{3E}Hello\u{3C}\u{2F}h1\u{3E}
5. \74\150\61\76Hello\74\57\150\61\76

This method can be used to exploit one of our vulnerable code snippet (#10).

Code Styles

JavaScript code can be written in many strange ways sometimes. Some code styles are nearly never used in development, but only in attack scenarios. These code styles are therefore a great advantage for an attacker…

Unicode

Instead of writing JavaScript as intended, you can also write characters [a-zA-Z] in Unicode encoded form. This will run the code without any problems.

1. var a; a == \u0061 // true
2. alert() == \u0061\u006c\u0065\u0072\u0074() // true

JSFuck

JavaScript can be written with only six characters ([]()+!): this method is called JsFuck. This code style can be used to bypass restricted filters, protections and/or to write stealth exploits/payloads.

(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]] === "ert" // true

JsFuck works when it’s mixed with regular JavaScript code style. Below is a payload that calls the alert() function from the object top.

top['al'+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]](1)

The payload used JsFuck to embed the string "ert" (with quotes) to the top object, resulting in the following payload: top['al'+"ert"](1)

Cross-Site Scripting exploitation

XSS is an underestimated vulnerability as it is often referred to as “the pop-up window alert(1)“. An XSS vulnerability should be exploited like any other vulnerability to show its full impact potential, with a takeover of a victim’s account, for example.

Session hijack

If the cookie has weak security, it is often very easy for an attacker to exploit XSS and take over the entire account from the victim. An attacker hijacks the session value(s) in the cookie and sends them to a server that (s)he owns.

Iframe exploit

When a session is used within cookies and use strong security, this is where creativity comes into play. A good technique would be to take advantage of iframes. If the iframe security policy is weak, you can use the XSS to embed an iframe that mirrors the original domain and hijack the data within the embedded iframe.

Keylogger

JavaScript can be used to write a keylogger that hijacks the victim’s keystrokes, making it possible to hijack credentials in clear text.

Keyloggers can be combined with other exploitation techniques, such as the iframe exploitation technique explained above. By combining these two techniques, it is possible to follow the victim and hijack all keystrokes from almost any endpoint.

XSS exploitation frameworks

Metasploit offers JavaScript exploitation modules, e.g. the JavaScript keylogger. This module is good to include in your report as a Proof of Concept when an XSS vulnerability is detected in an application.

Note that YesWeHack has recently released a tool called xsstools. This XSS development framework, written by our Tech Ambassador BitK, makes it easier to create XSS payloads. This tool is ideal for building a working Proof of Concept to demonstrate a real impact.

START HUNTING!🎯