zoukankan      html  css  js  c++  java
  • XSS实战训练————XSSGame挑战赛

    前言

    这是一个国外的XSS游戏平台,一共6关,在玩的时候需要挂VPN!如果在游戏的过程当中需要查看源代码或者提示可以在输入框下面点击相应的功能进入相应的选项哦!

    平台地址:https://xss-game.appspot.com

    过关录

    Leve 1

    特点:未进行严格的过滤,可以直接构造xss payload实现xss攻击

    查看源代码

    page_header = """
    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
      </head>
     
      <body id="level1">
        <img src="/static/logos/level1.png">
          <div>
    """
     
    page_footer = """
        </div>
      </body>
    </html>
    """
     
    main_page_markup = """
    <form action="" method="GET">
      <input id="query" name="query" value="Enter query here..."
        onfocus="this.value=''">
      <input id="button" type="submit" value="Search">
    </form>
    """
     
    class MainPage(webapp.RequestHandler):
     
      def render_string(self, s):
        self.response.out.write(s)
     
      def get(self):
        # Disable the reflected XSS filter for demonstration purposes
        self.response.headers.add_header("X-XSS-Protection", "0")
     
        if not self.request.get('query'):
          # Show main search page
          self.render_string(page_header + main_page_markup + page_footer)
        else:
          query = self.request.get('query', '[empty]')
           
          # Our search engine broke, we found no results :-(
          message = "Sorry, no results were found for <b>" + query + "</b>."
          message += " <a href='?'>Try again</a>."
     
          # Display the results page
          self.render_string(page_header + message + page_footer)
         
        return
     
    application = webapp.WSGIApplication([ ('.*', MainPage), ], debug=False)

    可以从上面看到对于传入的参数query并没有进行任何过滤处理,所以我们可以直接构造xss攻击payload进行攻击:

    payload:<svg/οnlοad=alert(/1/);>

    Level 2

    特点:查找输出点,闭合HTML标签,构造xss payload

    源代码

    index.html

    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
     
        <!-- This is our database of messages -->
        <script src="/static/post-store.js"></script>
       
        <script>
          var defaultMessage = "Welcome!<br><br>This is your <i>personal</i>"
            + " stream. You can post anything you want here, especially "
            + "<span style='color: #f00ba7'>madness</span>.";
     
          var DB = new PostDB(defaultMessage);
     
          function displayPosts() {
            var containerEl = document.getElementById("post-container");
            containerEl.innerHTML = "";
     
            var posts = DB.getPosts();
            for (var i=0; i<posts.length; i++) {
              var html = '<table class="message"> <tr> <td valign=top> '
                + '<img src="/static/level2_icon.png"> </td> <td valign=top '
                + ' class="message-container"> <div class="shim"></div>';
     
              html += '<b>You</b>';
              html += '<span class="date">' + new Date(posts[i].date) + '</span>';
              html += "<blockquote>" + posts[i].message + "</blockquote";
              html += "</td></tr></table>"
              containerEl.innerHTML += html; 
            }
          }
     
          window.onload = function() { 
            document.getElementById('clear-form').onsubmit = function() {
              DB.clear(function() { displayPosts() });
              return false;
            }
     
            document.getElementById('post-form').onsubmit = function() {
              var message = document.getElementById('post-content').value;
              DB.save(message, function() { displayPosts() } );
              document.getElementById('post-content').value = "";
              return false;
            }
     
            displayPosts();
          }
     
        </script>
     
      </head>
     
      <body id="level2">
        <div id="header">
          <img src="/static/logos/level2.png" /> 
          <div>Chatter from across the Web.</div>
          <form action="?" id="clear-form">
            <input class="clear" type="submit" value="Clear all posts">
          </form>
        </div>
     
        <div id="post-container"></div>
     
        <table class="message">
          <tr>
            <td valign="top">
              <img src="/static/level2_icon.png">
            </td>
            <td class="message-container">
              <div class="shim"></div>
              <form action="?" id="post-form">
                <textarea id="post-content" name="content" rows="2"
                  cols="50"></textarea>
                <input class="share" type="submit" value="Share status!">
                <input type="hidden" name="action" value="sign">
              </form>
            </td>
          </tr>
        </table>
     
      </body>
    </html>
    

    level.py

    class MainPage(webapp.RequestHandler):
     
      def render_template(self, filename, context={}):
        path = os.path.join(os.path.dirname(__file__), filename)
        self.response.out.write(template.render(path, context))
     
      def get(self):
        self.render_template('index.html')
     
    application = webapp.WSGIApplication([ ('.*', MainPage) ], debug=False)

    store.js

    /*
     * Objects to implement a client-side post database.
     */
     
    function Post(message) { 
      this.message = message;
      this.date = (new Date()).getTime();
    }
     
    function PostDB(defaultMessage) {
      // Initial message to display to users
      this._defaultMessage = defaultMessage || "";
     
      this.setup = function() {
        var defaultPost = new Post(defaultMessage);
        window.localStorage["postDB"] = JSON.stringify({
          "posts" : [defaultPost]
        });
      }
     
      this.save = function(message, callback) {
        var newPost = new Post(message);
        var allPosts = this.getPosts();
        allPosts.push(newPost);
        window.localStorage["postDB"] = JSON.stringify({
          "posts" : allPosts
        });
     
        callback();
        return false;
      }
     
      this.clear = function(callback) {
        this.setup();
     
        callback();
        return false;
      }
     
      this.getPosts = function() {
        return JSON.parse(window.localStorage["postDB"]).posts;
      }
     
      if(!window.localStorage["postDB"]) { 
        this.setup();
      }
    }

    可以找到输出点为:

    那么我们在这里只需要闭合前后的HTML标签即可

    payload:</blockquote><img src=# οnerrοr=alert(/1/);><blockquote>

    Level 3

    特点:查找输出点、闭合单引号、使用on事件构造payload

    源代码

    index.html

    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
     
        <!-- Load jQuery -->
        <script
          src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
        </script>
     
        <script>
          function chooseTab(num) {
            // Dynamically load the appropriate image.
            var html = "Image " + parseInt(num) + "<br>";
            html += "<img src='/static/level3/cloud" + num + ".jpg' />";
            $('#tabContent').html(html);
     
            window.location.hash = num;
     
            // Select the current tab
            var tabs = document.querySelectorAll('.tab');
            for (var i = 0; i < tabs.length; i++) {
              if (tabs[i].id == "tab" + parseInt(num)) {
                tabs[i].className = "tab active";
                } else {
                tabs[i].className = "tab";
              }
            }
     
            // Tell parent we've changed the tab
            top.postMessage(self.location.toString(), "*");
          }
     
          window.onload = function() { 
            chooseTab(unescape(self.location.hash.substr(1)) || "1");
          }
     
          // Extra code so that we can communicate with the parent page
          window.addEventListener("message", function(event){
            if (event.source == parent) {
              chooseTab(unescape(self.location.hash.substr(1)));
            }
          }, false);
        </script>
     
      </head>
      <body id="level3">
        <div id="header">
          <img id="logo" src="/static/logos/level3.png">
          <span>Take a tour of our cloud data center.</a>
        </div>
     
        <div class="tab" id="tab1" onclick="chooseTab('1')">Image 1</div>
        <div class="tab" id="tab2" onclick="chooseTab('2')">Image 2</div>
        <div class="tab" id="tab3" onclick="chooseTab('3')">Image 3</div>
     
        <div id="tabContent"> </div>
      </body>
    </html>

    level.py

    class MainPage(webapp.RequestHandler):
     
     
      def render_template(self, filename, context={}):
        path = os.path.join(os.path.dirname(__file__), filename)
        self.response.out.write(template.render(path, context))
     
      def get(self):
        self.render_template('index.html')
     
    application = webapp.WSGIApplication([ ('.*', MainPage), ], debug=False)

    可以发现,这一关的输出点是在这里:

    那么我们这里需要先闭合前面的单引号,之后再添加事件,这里推荐on事件,我们可以构造如下payload
    payload: ' οnerrοr=alert(1)>

    Level 4

    特点:模板渲染、JS动态调用参数

    index.html

    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
      </head>
     
      <body id="level4">
        <img src="/static/logos/level4.png" />
        <br>
        <form action="" method="GET">
          <input id="timer" name="timer" value="3">
          <input id="button" type="submit" value="Create timer"> </form>
        </form>
      </body>
    </html>

    level.py

    class MainPage(webapp.RequestHandler):
     
      def render_template(self, filename, context={}):
        path = os.path.join(os.path.dirname(__file__), filename)
        self.response.out.write(template.render(path, context))
     
      def get(self):
        # Disable the reflected XSS filter for demonstration purposes
        self.response.headers.add_header("X-XSS-Protection", "0")
     
        if not self.request.get('timer'):
          # Show main timer page
          self.render_template('index.html')
        else:
          # Show the results page
          timer= self.request.get('timer', 0)
          self.render_template('timer.html', { 'timer' : timer })
         
        return
     
    application = webapp.WSGIApplication([ ('.*', MainPage), ], debug=False)
    

    timer.html

    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
     
        <script>
          function startTimer(seconds) {
            seconds = parseInt(seconds) || 3;
            setTimeout(function() { 
              window.confirm("Time is up!");
              window.history.back();
            }, seconds * 1000);
          }
        </script>
      </head>
      <body id="level4">
        <img src="/static/logos/level4.png" />
        <br>
        <img src="/static/loading.gif" onload="startTimer('{{ timer }}');" />
        <br>
        <div id="message">Your timer will execute in {{ timer }} seconds.</div>
      </body>
    </html>

    这一关的考点是在模板渲染,js动态引用参数问题。在这里我们需要先闭合startTimer()函数,然后弹框即可。

    参考payload:');alert(1);//

    Level 5

    特点:通过使用javascript伪协议XSS攻击

    源代码

    confirm.html

    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
      </head>
     
      <body id="level5">
        <img src="/static/logos/level5.png" /><br><br>
        Thanks for signing up, you will be redirected soon...
        <script>
          setTimeout(function() { window.location = '{{ next }}'; }, 5000);
        </script>
      </body>
    </html>

    level.py

    class MainPage(webapp.RequestHandler):
      def render_template(self, filename, context={}):
        path = os.path.join(os.path.dirname(__file__), filename)
        self.response.out.write(template.render(path, context))
     
      def get(self):
        # Disable the reflected XSS filter for demonstration purposes
        self.response.headers.add_header("X-XSS-Protection", "0")
     
        # Route the request to the appropriate template
        if "signup" in self.request.path:
          self.render_template('signup.html', 
            {'next': self.request.get('next')})
        elif "confirm" in self.request.path:
          self.render_template('confirm.html', 
            {'next': self.request.get('next', 'welcome')})
        else:
          self.render_template('welcome.html', {})
         
        return
     
    application = webapp.WSGIApplication([ ('.*', MainPage), ], debug=False)

    signup.html

    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
      </head>
     
      <body id="level5">
        <img src="/static/logos/level5.png" /><br><br>
        <!-- We're ignoring the email, but the poor user will never know! -->
        Enter email: <input id="reader-email" name="email" value="">
     
        <br><br>
        <a href="{{ next }}">Next >></a>
      </body>
    </html>

    welcome.html

    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
      </head>
     
      <body id="level5">
        Welcome! Today we are announcing the much anticipated<br><br>
        <img src="/static/logos/level5.png" /><br><br>
     
        <a href="/level5/frame/signup?next=confirm">Sign up</a> 
        for an exclusive Beta.
      </body>
    </html>

    这道题是对于输入转为链接过滤不严,导致可以用javascript伪协议来xss

    参考payload:

    https://xss-game.appspot.com/level5/frame/signup?next=javascript:alert(1);

    Level 6

    特点:

    源代码

    gadget.js

    	
    /* This is a completely awesome invisible gadget */

    index.html

    <!doctype html>
    <html>
      <head>
        <!-- Internal game scripts/styles, mostly boring stuff -->
        <script src="/static/game-frame.js"></script>
        <link rel="stylesheet" href="/static/game-frame-styles.css" />
     
        <script>
        function setInnerText(element, value) {
          if (element.innerText) {
            element.innerText = value;
          } else {
            element.textContent = value;
          }
        }
     
        function includeGadget(url) {
          var scriptEl = document.createElement('script');
     
          // This will totally prevent us from loading evil URLs!
          if (url.match(/^https?:///)) {
            setInnerText(document.getElementById("log"),
              "Sorry, cannot load a URL containing "http".");
            return;
          }
     
          // Load this awesome gadget
          scriptEl.src = url;
     
          // Show log messages
          scriptEl.onload = function() { 
            setInnerText(document.getElementById("log"),  
              "Loaded gadget from " + url);
          }
          scriptEl.onerror = function() { 
            setInnerText(document.getElementById("log"),  
              "Couldn't load gadget from " + url);
          }
     
          document.head.appendChild(scriptEl);
        }
     
        // Take the value after # and use it as the gadget filename.
        function getGadgetName() { 
          return window.location.hash.substr(1) || "/static/gadget.js";
        }
     
        includeGadget(getGadgetName());
     
        // Extra code so that we can communicate with the parent page
        window.addEventListener("message", function(event){
          if (event.source == parent) {
            includeGadget(getGadgetName());
          }
        }, false);
     
        </script>
      </head>
     
      <body id="level6">
        <img src="/static/logos/level6.png">
        <img id="cube" src="/static/level6_cube.png">
        <div id="log">Loading gadget...</div>
      </body>
    </html>

    level.py

    class MainPage(webapp.RequestHandler):
      def render_template(self, filename, context={}):
        path = os.path.join(os.path.dirname(__file__), filename)
        self.response.out.write(template.render(path, context))
     
      def get(self):
        self.render_template('index.html')
     
    application = webapp.WSGIApplication([ ('.*', MainPage), ], debug=False)

    通过fragment获取外部js路径,然后加载路径。但是不能包含http://或者https://字符,那么我们这里可以使用伪协议来进行绕过,构造xss payload:

    https://xss-game.appspot.com/level6/frame#data:text/javascript,alert(1);

    最后成功通关

    总会有不期而遇的温暖. 和生生不息的希望。
  • 相关阅读:
    sqli-labs第五,六题
    Java 发送邮件
    Java 数据结构
    Java 序列化
    Java 文件注释
    Java 泛型
    Java 网络编程
    网站收藏
    JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
    Java 8 中的 Streams API 详解
  • 原文地址:https://www.cnblogs.com/devi1/p/13486648.html
Copyright © 2011-2022 走看看