JavaScript for hackers

By garethheyes

Introduction

I love to use JavaScript in unexpected ways, to create code that looks like it shouldn't work but does, or produces some unexpected behavior. This may sound trivial, but the results I've found lead to some very useful techniques. Each of the techniques described can be used for XSS filter evasion, which was my original intention when developing them. However, learning such JavaScript can dramatically increase your knowledge of the language, helping you become better at cleaning up input, and increase web application security.

So read on and enjoy my weird and wonderful JavaScript hacks.

RegExp replace can execute code

When using regular expressions with replace the second argument supports a function assignment. In Opera it seems you can use this argument to execute code. For example, check out the code snippet below:

'XSS'.replace(/XSS/g,alert)

This results in alert('XSS'); this works because the match from the RegExp is passed to the alert function as an argument. Normally you would use a function to perform another routine on the matched text, like so:

'somestring'.replace(/some/,function($1){//do something with some})

But as you can see in the first example in this section, instead of a user defined function we are executing a native alert call, and the arguments are passed to the native call from the regular expression. It's a cool trick and could be used to evade some XSS filters, for example if you inject a string then proceed with a dot you can then call any function you like.

To see how this is used in a XSS context, imagine we have an unfiltered " in the string in which an injection occurs, such as a JavaScript event or a script tag. First we inject our payload alert(1), then we break out of the quotes - " - and continue our regular expression:

.replace(/.+/,eval)//

Notice I use eval here to execute any code I like and the regular expression matches everything so that the full payload is passed to eval.

If I put all the code together and show you the output of the page it is easier to understand what is going on:

Page output:

<script>somevariableUnfiltered="YOUR INPUT"</script>

The above code is common in analytics scripts where your search string is stored by an advertising company. You often don't see these scripts but if you view the source of a web page you'll find that they are a regular occurrence; forums are another place where they are prevalent. "YOUR INPUT" is the string you have control of; this is also referred to as DOM based XSS if the input isn't filtered correctly.

Input:

alert(1)".replace(/.+/,eval)//

Resulting output:

<script>somevariableUnfiltered="alert(1)".replace(/.+/,eval)//"</script>

Notice the single line comment used to remove the trailing quote.

Unicode escapes

Although it's not possible to use parentheses when escaping unicode characters, you can escape the name of the function being called, for example:

\u0061\u006c\u0065\u0072\u0074(1)

This calls alert(1); \u indicates it's a unicode escape and the hex number after specifies the character. \u0061 is "a" and so on.

Mixing and matching unicode escapes is possible with normal characters; the example below demonstrates this:

\u0061lert(1)

You can also include them in strings and even evaluate them using eval. Unicode escapes are different to normal hex or octal escapes because they can be included in a string, or a reference to a function, variable or object.

The example below shows how to use unicode escapes that are evaluated and split into separate parts:

eval('\\u'+'0061'+'lert(1)')

By avoiding normal function names like alert, we can fool XSS filters into injecting our code. This very example was used to bypass PHPIDS (an open source IDS system), which resulted in the rules subsequently being made much stronger. If you are considering decoding JavaScript for malware analysis at runtime you need to consider the possible ways that multiple levels of encoding can work; as you can see from this example it won't be a easy task.

JavaScript parser engine

JavaScript is a very dynamic language. It can execute a surprising amount of code that at first glance doesn't look valid, however once you know how the parsers work, you begin to understand the logic behind it.

JavaScript doesn't know the result of a function until it is executed, and obviously it has to call the function to return the variable type. This leads to an interesting quirk - for example, if the returning function doesn't return a valid value for the code block, a syntax error will occur after the execution of the function.

What does this mean in English? Well, code speaks louder than words - check this example out

+alert(1)--

The alert function executes and returns undefined but by that time it is too late - the decrement operator is expecting a number and therefore raises an error.

Here's a few more valid examples that don't raise errors but are interesting nevertheless.

+alert(1)
1/alert(1)
alert(1)>>>/abc/

You might think the above examples are pointless but in fact they offer great insight into how Javascript works. Once you understand the small details the bigger picture becomes clear and the way that your code executes can help you understand how the parser works. I find these sort of examples useful when tracking down syntax errors and DOM based XSS, and exploiting XSS Filters.

Throw, Delete what?

You can use the delete operator in ways that you wouldn't at first expect, which results in some pretty wacky syntax. Lets see what happens if we combine the throw, delete, not and typeof operators?

throw delete~typeof~alert(1)

Even though you'd think it couldn't possibly work, it's possible to call delete on a function call and it still executes:

delete alert(1)

Here are a few more examples

delete~[a=alert]/delete a(1)
delete [a=alert],delete a(1)

At first glance you'd think that they would raise a syntax error but when examining the code further it sorta makes sense. The parser finds a variable assignment first within a array, performs the assignment and then deletes the array. Likewise the delete is performed after a function call because it needs to know the result of the function before it can delete the returned object, even if it is null.

Again these examples have been used to defeat XSS filters because they are often trying to match valid syntax and they don't expect the obscure nature of the code. You should consider such examples when programming your application data validation.

Global objects are statements

In certain instances of XSS filter evasion, it can be useful to send English-like text hidden within a vector. Clever systems like PHPIDS use English and vector comparisons to determine if a request is an attack or not, so it is a useful way to test these systems.

Using global objects/functions on their own can produce English-like code blocks. In fact, on the sla.ckers security forum we had a little game to produce English-like sentences in JavaScript. To get an idea of how it works, check out the following example:

stop, open, print && alert(1)

I coined the name Javascriptlish because it's possible to produce some crazy looking code:

javascript : /is/^{ a : ' weird ' }[' & wonderful ']/" language "
the_fun: ['never '] + stop['s']

We use the regular expression /is/ with the operator ^ and then create a object { a : 'weird'} (which has a property a and an assignment of weird.) Then we look for a property ' & wonderful ' within the object we just created, which is then divided by a string of language.

Next we use a label called the_fun and an array with never , use a global function called stop and check for a property of s ... all of which is valid syntax.

Getters/Setters fun

When Firefox added the custom syntax for setters it enabled some interesting XSS vectors that didn't use parentheses. Opera doesn't support a custom syntax yet - this is good from a security point of view but not from a JavaScript hacker's perspective.

Opera does however support the standard defineSetter syntax. This enables us to call functions via assignments, which still has some use for XSS filter evasion:

defineSetter('x',alert); x=1;

In case you're not aware of setters/getters, the example above creates a setter for the global variable x. A setter is called whenever a variable is set with something and the argument is supplied from whatever has been assigned. The second argument is the function to be called on assignment, which is alert. Then, when x is assigned the value of 1, the alert function is called with 1 as the argument.

Location allows url encoding

The location object allows url encoding within the JavaScript code. This allows you to further obfuscate XSS vectors by double encoding them.

location='javascript:%61%6c%65%72%74%28%31%29'

Combining them with unicode escapes can hide strings quite nicely:

location='javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c %75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(1)'

The first example works because the URL bar in Opera accepts urlencoded strings - you can hide JavaScript syntax by url encoding it. This is useful because when it is passed within a XSS vector you can double url encode it to help further with filter evasion.

The second example combines the first technique with the unicode escape technique mentioned previously. So when you decode the string it results in the unicode representation of alert which is \u0061\u006c\u0065\u0072\u0074.

This article is licensed under a Creative Commons Attribution, Non Commercial - Share Alike 2.5 license.

Comments

The forum archive of this article is still available on My Opera.

No new comments accepted.