搜文章
推荐 原创 视频 Java开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发
Lambda在线 > 合天智汇 > xssgame通关攻略

xssgame通关攻略

合天智汇 2018-06-29
xssgame通关攻略

15

0x00前言
xssgame通关攻略

前两天打sctf的时候有一道题是考的AngularJS的xss,当时看了队友写的write up也没搞太懂,深感自己xss方面太过薄弱,然后看到队友write up中提到了这个xssgame,刷了下感觉题目的质量还是很不错的,循序渐进,而且对于像我这样的小白可以学到不少知识 这套题目一共8关 题目地址:(需科学上网食用) http://www.xssgame.com/ 



0x01:第一关  
xssgame通关攻略

xssgame通关攻略

这可以说是很贴心了,题目直接说了用户的输入会没有任何过滤直接输出到页面上 那么我们直接<script>alert(/xss/)</script>就可以了 


xssgame通关攻略


0x02:第二关
xssgame通关攻略

xssgame通关攻略

题目说明中说到,每比特用户的输入都被转义了 那么我们还是输入<script>alert(/xss/)</script>试试 


xssgame通关攻略

xssgame通关攻略

从上图我们可以看到,我们的输入被输出到页面上了,但是并没有产生xss弹窗 这时,我们可以按f12,来查看我们点击按钮后到底发生了什么

xssgame通关攻略

点击?timer=......,然后查看Response 


xssgame通关攻略

我们可以看到'<'符号和'>'符号都被转义为实体符号了 

xssgame通关攻略

但是如果我们注意,就会发现我们输入的数据,在onload事件里面,那么我们就可以不使用<script>标签就可以达到弹窗的效果了 我们直接插入'+alert(/xss/)+' 这时onload就变成了如下:

onload="startTimer(''+alert(/xss/)+'');"

startTimer在执行的时候,其参数是一个表达式,那么就会先计算表达式的值,当计算表达式的值的时候,就会首先执行alert(/xss/)这一句,然后就会弹窗了 

xssgame通关攻略



0x03:第三关 还是先看提示
xssgame通关攻略

xssgame通关攻略

根据提示,在页面上没有可供用户输入的地方,我们应该关注URL 为了方便,我们将题目页面单独打开

xssgame通关攻略

既然是xss,那么我们就看一下它的js代码吧: 

xssgame通关攻略


上面这句代码是用来动态载入图片的,其中chooseTab(name)的参数name就是url中的1,2,3 分别代表三张图片 在这里name被直接拼接到了img标签里,这样我们应该就知道该怎么弹窗了,我们只需要给一个不存在的图片名称,然后再利用onerror不就可以弹窗了吗 payload如下:

4' onerror='alert(/xss/)'

拼接过后的img标签如下:

<img src='/static/img/cat4' onerror='alert(/xss/)' + ".jpg' />


xssgame通关攻略



0x04:第四关 
xssgame通关攻略

xssgame通关攻略


有些时候攻击者不向页面注入dom元素也可以做坏事,如果想要不注入元素就弹窗的话,一般就是通过现有的js函数来执行js,后面又提到了一个重定向,不知道有什么用可以先放着。

打开题目,点击sign up,进入一个页面,要求我们输入邮箱 


xssgame通关攻略


这个页面没有什么可以利用的地方,点击next后跳转到confirm页面


xssgame通关攻略


但是仅仅在confirm页面停顿了一两秒就被重定向到了welcom页面,再结合题目提示中提到了重定向,那么解题很有可能和这个重定向的js有关 那么我们就看一下confirm页面的源码吧,confirm页面有一个重定向,所以我们很难直接捕捉到页面的源码,但是我们可以通过view-source的方法来获得页面源码 我们在浏览器输入:

view-source:http://www.xssgame.com/f/__58a1wgqGgI/confirm

得到页面源码:


xssgame通关攻略


其中的window.location就是重定向跳转的页面,其值就是?next=xxx的值xxx,那么我们可以用javascript:伪协议(不知道这个伪协议的可以自己百度一下)来作为其值 我们给next赋值为:

javascript:alert(/xss/)

那么confirm页面就变成了:

window.location='javascript:alert(/xss/)'


xssgame通关攻略



0x05:第五关
xssgame通关攻略

xssgame通关攻略

刚开始看到一个Angular就想到了Angular(Angular是啥?自己百度去)沙箱逃逸,然后去网上搜对应版本的payload,结果发现这道题并不是考Angular沙箱逃逸的。。。 题目中说到,当在Angular 模板系统运行前修改DOM应该小心。 啥都不说,先看下js代码 


xssgame通关攻略

<script>
      angular.module('myApp', [])
      .controller('myController', ['$scope', function ($scope) {
        $scope.query = "";
        $scope.alert = window.alert;
      }]);

      var UTM_PARAMS = ["utm_content", "utm_medium", "utm_source",
          "utm_campaign", "utm_term"]

      if (location.search)
      {
        var params = location.search.substring(1).split('&');

        for (var p in params) {
          var r = params[p].split('=');

          if (r.length == 2 && UTM_PARAMS.indexOf(r[0]) != -1) {
            var el = document.getElementsByName(r[0]);
            if (el.length) el[0].value = decodeURIComponent(r[1]);
          }
        }
      }
    </script>


当然要读懂这段代码需要了解一点Angular,可以跟着菜鸟教程学习一下 http://www.runoob.com/angularjs/angularjs-tutorial.html


下面我简单说下这段js代码 定义了一个数组 UTM_PARAMS 然后当点击按钮后,执行if里面的语句 params是将url中的get参数取出来分隔存在数组中,比如?a=1&b=2&c=3就变成了[a=1,b=2,c=3] 然后进入for循环,依次取出数组中的元素,取出后按等号分割为数组,比如a=1变为[a,1] 我们可以看到,进入下一个if的条件是r[0]是数组UTM_PARAMS里面的元素,而r[0]对应的正是get参数的参数名 满足if条件后 把r[1]的值url解码后赋值给id为r[0]的元素


所以这道题就很清晰了 r[0]有两个特点: 1.r[0]的值来自于数组UTM_PARAMS 2.r[0]是一个get参数,其值r[1]会赋值给id是r[0]的标签


UTM_PARAMS的值为: ["utm_content", "utm_medium", "utm_source","utm_campaign", "utm_term"] 刚好页面中有id为utm_term和utm_campaign的标签,我们可以通过对这两个标签中的任意一个赋值来弹窗 


xssgame通关攻略


angularjs用{{ expression }}即{{表达式}}来执行js,{{expression}}不用放在script标签中 所以我们可以用{{alert("xss")}}来弹窗 payload:

?utm_campaign={{alert("xss"}}


xssgame通关攻略


0x06:第六关
xssgame通关攻略

xssgame通关攻略

服务端生成html导致Angular表达式注入 其实这道题想了很久,也看了别人写的write up,不过一直每太明白为什么要那样做。不过后面还是想通了


提示说到,服务端会生成html,那么html一定是通过我们提交的数据生成的(POST方式或者GET方式),我们先在文本框输入一个js的弹窗,然后提交: 


xssgame通关攻略

发现script标签被过滤了 那么我们又想像上一题一样,用{{alert("xss")}},那么我们输入试试: 

xssgame通关攻略



双引号被过滤了,没事,我们不用双引号呗,我们用{{alert(1)}} 


xssgame通关攻略

 咦,,,咋个没有弹窗呢,之所以没有弹窗是因为这里使用了ng-non-bindable指令 


xssgame通关攻略


该指令所在标签及其子标签内的内容不会被AngularJS编译

看来想通过这里来达到我们的目的是不太可能了,script标签被实体编码,又不能执行angularjs

既然POST不行,那么我们可以试一试GET 我们在url后面加上

?test=123

非常有意思的一幕出现了,form表单的action属性的值随着我们url的改变而改变 


xssgame通关攻略

而这里没有ng-non-bindable指令,所以我们就可以使用{{alert(1)}}了


xssgame通关攻略


但是我们发现我们的"{{"被过滤了 但是这里我们可以用{对应的实体转义字符{来代替 payload:

?test={{alert(1)}}


xssgame通关攻略



0x07:第七关
xssgame通关攻略

xssgame通关攻略

 看到CSP就知道这道题很可能是考察CSP(内容安全策略)的bypass了 CSP是什么这里就不再赘述了,简单来说就是一种对网站加载资源的白名单,只有符合CSP里面定义的策略的资源才能被加载 不知道CSP的可以去MDN上面查看:https://developer.mozilla.org/zh-CN/docs/Web/Security/CSP

我们先看一下这道题的CSP 


xssgame通关攻略


如下:

default-src http://www.xssgame.com/f/wmOM2q5NJnZS/ http://www.xssgame.com/static/

现在我们再来分析网页,还是先查看首页的源码:


xssgame通关攻略

三个跳转链接,还加载了level7.js,那么我们再继续查看level7.js


xssgame通关攻略


level7.js定义了两个函数,main和callback main函数正则匹配url中的参数menu的值,赋值给m 如果m不为null,那么将m的值base64解码赋值给menu,然后将menu进行url编码后作为参数menu的值传入jsonp页面 callback用于加载页面的title和picture


不懂jsonp的可以看下菜鸟教程里关于jsonp的教程:http://www.runoob.com/json/json-jsonp.html 我们来看下这个jsonp页面:


xssgame通关攻略


其实很好理解: callback里面的title的值就是我们首页的title,pictures就是下面那张图片 比如如果我们选择Cats 


xssgame通关攻略


那么这时侯jsonp页面就变成了: 


xssgame通关攻略

好了,对页面的分析就到这里了,那么这道题该怎么破呢? emmmm。。。其实这道题主要考的是jsonp的注入

jsonp注入又是个什么鬼呢? 关于jsonp注入可以参考安全客这篇文章:https://www.anquanke.com/post/id/85382

我们这里的jsonp存在的一个问题就是回调函数可控 比如我们在jsonp页面给get参数callback赋值将会被写入jsonp页面,如下:

xssgame通关攻略

那么我们就可以通过jsonp?callback=.....来写入任意的东西了,如果这个页面的代码被当作js来执行的话,岂不是就可以实现我们的目的了 在当前页面肯定是不能被作为js运行的,不过如果我们能在其它页面执行<script src=xxx>把这里的xxx该为jsonp?callback=...就能够执行我们的js了 而刚好我们这里有一个参数menu是可控的,而且menu的值经过base64解码后会打印到页面


xssgame通关攻略


那么我们可以控制打印到页面的值为:

<script src='jsonp?callback=alert(1);//'></script>

然后将其base64编码后传给参数menu

<script src='jsonp?callback=alert(1);//'></script>
base64编码后为:
PHNjcmlwdCBzcmM9J2pzb25wP2NhbGxiYWNrPWFsZXJ0KDEpOy8vJz48L3NjcmlwdD4=

xssgame通关攻略


可能有人会有疑问了,为什么我们不直接打印

<script>alert(1);</script>

那么我们将其base64编码后传入后看看会发生什么 


xssgame通关攻略

因为CSP,所以不能使用内联js,因此这里不能这样做,如果这里加了unsafe-inline的话,我们就可以这样做了



0x08:第八关
xssgame通关攻略

xssgame通关攻略

提示看不太明白,大概知道和url有关,那么我们接下来就留意一下url 先看index页面的源码: 

xssgame通关攻略


<!doctype html>
<html lang=en>
  <head>
    <meta charset=utf-8>
    <title>Simple Wire Transfer</title>
  </head>
  <body bgcolor="white" align="center">
    <h1>Foogle Bank</h1>

    <script src="/static/js/level8.js"></script>
    <script src="/static/js/js_frame.js"></script>

    Please set your name (optional):
    <form method="GET" action="set">
    <input type="hidden" name="name" value="name">
    <input size="30" name="value" placeholder="Please specify your name">
    <input type="hidden" name="redirect" id="redirect" value="index">
    <input type="submit" value="Set">
    </form>
    <br>

    Wire transfer:
    <form method="GET" action="transfer">
    <input size="30" name="name" placeholder="Recipient">
    <input size="5" name="amount" placeholder="123">
    <input type="hidden" name="csrf_token" id="csrf_token" value="">
    <input type="submit" value="Send">
    </form>
    <br>
  </body>
</html>

我们可以看到页面有两个form表单,而且都是以get的方式提交参数的 第一个表单是用于设置你的姓名,输入姓名后提交给set页面处理,然后重定向到index页面 第二个是向其它用户转账,输入被转账的用户和金额,然后提交给transfer页面处理,我们注意到这里有一个hidden的csrf_token参数,csrf_token主要是用来防止csrf(跨站请求伪造)的,不知道csrf的可以参考这篇文章:https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/index.html 我们注意到,我们设置的用户名会直接输出到页面 


xssgame通关攻略

但是一看header,又有CSP,并且不允许内联,所以此路不通 页面加载了level8.js,那么我我们再看看level8.js吧

/**
 * Read cookie.
 * @param {string} name - Name of the cookie
 * @returns {string} Cookie value
 */
function readCookie(name) {
    var match = RegExp('(?:^|;)\\s*' + name + '=([^;]*)').exec(document.cookie);
    return match && match[1];
}

var username = readCookie('name');
if (username) {
    document.write('<h1>Welcome ' + username + '!</h1>');
}

document.addEventListener("DOMContentLoaded", function(event) {
    csrf_token.value = readCookie('csrf_token');
});


level8.js定义了readCookie函数,该函数主要作用是读取cookie中信息 接下来又用该函数一次读取了用户名和token,并将token赋值给DOM中name等于csrf_token的标签

这些看起来似乎没什么用,但是如果我们仔细将这些联系起来就有用了 从level8.js我们知道了我们的name和csrf_token都是从cookie中读取的,从这里我们推测,或许页面第一个输入框我们设置的用户名也是保存在cookie中的 我们再来看一下我们设置用户名为admin时候的url: 


xssgame通关攻略

这里的name应该是cookie中保存用户名的变量名,而admin就是name的值 我们可以在console中验证一下: 


xssgame通关攻略



结果和我们所想的一样,那么我们也能通过set?name=csrf_token&value=xxx来改变csrf_token在cookie中的值了

当然感觉这道题比较坑,有一个地方是解题的关键 当我们转账的数目是整数的时候: 

xssgame通关攻略

当我们转账的金额不是整数的时候(比如字母或小数):

xssgame通关攻略

xssgame通关攻略

当我们输入的转账金额不是一个整数的时候,返回页面会报错,并将我们输入的金额的值打印到屏幕 而且这个页面没有CSP的保护

xssgame通关攻略

那么我们试着输入

<script>alert(1)</script>

出现提示验证失败

xssgame通关攻略


然后又提到了不同用户通用的问题,然后再联系一下题目提示:

xssgame通关攻略


这道题考csrf,csrf就是将链接发给其它用户,其它用户点击后也会中招,而每个用户的token是不同的,那么我们可以设定特定的token(我们前面说过,通过set?name=csrf_token&csrf_token=xxx 来设置),那么用户点击我们的链接后它的token也会变成我们设定好的,然后我们再通过amount参数alert 那么我们构造payload如下:

set?name=csrf_token&value=test&redirect=transfer?name=aaa&amount=<script>alert(1)</script>&csrf_token=test

访问:

xssgame通关攻略

黑人问号??? 如果我们观察仔细,就会发现url后面只剩下:

transfer?name=aaa

难怪会失败了,原来后面的都被截断了 这是因为当url带参数跳转时,如果其中有&符号那么&符号后面就会被截断 解决办法:将&符号url编码 &符号的url编码为:%26 所以我们的payload为:

set?name=csrf_token&value=test&redirect=transfer?name=aaa%26amount=<script>alert(1)</script>%26csrf_token=test


xssgame通关攻略



xssgame通关攻略

看不过瘾?合天2017年度干货精华请点击《》

xssgame通关攻略
xssgame通关攻略

别忘了投稿哦!

大家有好的技术原创文章。

欢迎投稿至邮箱:edu@heetian.com

合天会根据文章的时效、新颖、文笔、实用等多方面评判给予100元-500元不等的稿费哟。

有才能的你快来投稿吧!

点击了解投稿详情


版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《xssgame通关攻略》的版权归原作者「合天智汇」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注合天智汇微信公众号

合天智汇微信公众号:hee_tian

合天智汇

手机扫描上方二维码即可关注合天智汇微信公众号

合天智汇最新文章

精品公众号随机推荐