Escape from Normality

Any good John Carpenter fan knows the only way you’ll escape from New York is if Snake Plissken is there to get you out. When it comes to web security, don’t bother waiting around for Kurt Russell’s help. You’re on your own.

Maybe you read a book on web security. Maybe you even remembered some of it. Maybe all you know is how to use escape characters in JavaScript Strings. In any case, maybe you should make sure the maximum security application you’ve created is as strong as you think it is.

The setup is simple: An app has a search box; it accepts queries via parameter “q” of a form, and rewrites the input box’s value with a one-line JavaScript call. Using JavaScript seems a little more complicated than updating the <input> field’s value directly, which would be as trivial as the following (with “abc” as the search term):

<input id="searchResult" type="text" name="q" value="abc">

It’s not necessarily a bad idea to update the element’s value with JavaScript. Building HTML on the server with string concatenation is a notorious vector for XSS. Writing the value with JavaScript might be more secure than rebuilding the HTML every time because the assignment avoids several encoding problems. This works if you’re keeping the HTML static and trading JSON messages with the server.

On the other hand, if you move the server-side string concatenation from the <input> field to a <script> tag, then you’ve shifted the problem without stepping towards a solution. The <input> field’s value was delimited with quotation marks (“). The JavaScript code uses apostrophes (‘) to delimit the string.

<script type='text/javascript'>
document.getElementById('searchResult').value = 'abc';
</script>

Rather than strip apostrophes from the search variable’s value, the developers have decided to escape them with backslashes. Here’s how it’s expected to work when a user searches for abc’.

document.getElementById('searchResult').value = 'abc\'';

Escaping the payload’s apostrophe preserves the original string delimiters, prevents the JavaScript syntax from being manipulated, and blocks HTML injection attacks. So it seems. What if the escape is escaped? Say, by throwing in a backslash of your own to search for something like abc\’.

document.getElementById('searchResult').value = 'abc\\'';

The developers caught the apostrophe, but missed the backslash. When JavaScript tokenizes the string it sees the escape working on the second backslash instead of the apostrophe. This corrupts the syntax, as follows:

//            ⬇ end of string token
value = 'abc\\'';
//             ⬆ dangling apostrophe


From here we just starting throwing HTML injection payloads against the app. JavaScript interprets \\ as a single backslash, accepts the apostrophe as the string terminator, and parses the rest of our payload.

http://web.site/search?q=abc\’;alert(9)//
document.getElementById('searchResult').value = 'abc\\';alert(9)//';

JavaScript’s semantics are lovely from the hacker’s perspective. Here’s an example payload using the String concatenation operator (+) to glue the alert function to the value:
http://web.site/search?q=abc\’%2balert(9)//

document.getElementById('searchResult').value = 'abc\\'+alert(9)//';

Or we could try a payload that uses the modulo operator (%) between the String and our alert.

abc\'%alert(9)//

Maybe the developers backlisted the alert function, e.g. a regex for alert\(, by checking for an opening parenthesis. Look up the function in the window object’s property list; this makes it look like a string:

abc\'%window["alert"](9)//

What happens if the developers blacklisted the word alert altogether? Build the string character by character:

abc\'window[String.fromCharCode(0x61,0x6c,0x65,0x72,0x74)](9)//

By now we’ve turned an evasion of an escaped apostrophe into an exercise in obfuscation and filter bypasses. (Check out the HIQR for more anti-regex patterns and JavaScript obfuscation techniques.)

Let’s do a quick recap of some security concepts. In this case, the clear mistake was forgetting all the permutations of escape sequences in a JavaScript string. Here’s an additional checklist:

  • Normalize the data, whether this entails character set conversion, character encoding, substitution, or removal.
  • Apply security checks, preferring inclusion lists over exclusion lists (it’s a lot easier to guess what’s safe than assume what’s dangerous).
  • In the design phase, be suspicious of string concatenation. Figure out if there’s a safer method to bind user-supplied data to HTML.
  • In the design phase, make sure your security check’s assumptions match the context where the data will be written.

Normalization is an important first step. Any time you transform data you should reapply security checks. Snake Plissken was never one for offering advice. Instead, think of The Hitchhiker’s Guide to the Galaxy and recall Trillian’s report as the Infinite Improbability Drive powers down (p. 61):

“…we have normality, I repeat we have normality….Anything you still can’t cope with is therefore your own problem.”

Good luck with normality, and trying to escape the right characters. Security isn’t certain, but one thing is, at least according to Queen. There’s “no escape from reality.”

(Updated January 2013 with shortcode formatting to make code examples more legible. Added reference to HIQR.)