记一次xss之旅

事情的起因是我做完了那个xssme的小闯关 里面有些原理我也不是很懂 QAQ

我的js水平很差 js就没怎么好好用心学 最近在学thinkphp js画贪吃蛇代码不是太懂

然后就想起了之前渗透的表白墙网站 正好当靶场练练手

这次站长给我发了一个远古版本表白墙源码 基本功能就是把数据写入一个txt文件 然后php读取文件

然后再把数据展示出来 全程都没有用到数据库 你说厉不厉害 反正像我我这种废物都不会开发的 (最多是看懂别人写的代码

image-20230408013238442.png

大概就长这个样子 哈哈 是不是很古老

既然是留言板 那我们就看看有没有什么xss攻击的地方

先来看看文件的基本功能

image-20230408013831720.png

index.php代码如下(也就是表白墙的主页

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>表白墙</title>
        <script>
        alert("表白网站后期会更新美化,当前版本不够漂亮但能正常使用,后期会做处理,本表白网站数据将会永久保存!有需要删除某数据的可以联系邮箱:xxxxxxx@qq.com");
            window.onload=function() {    
                var llq=document.documentElement.clientHeight;
                var nr=document.getElementById("nr");
                var bbq=document.getElementsByClassName("bbq");
                var wxhn=document.getElementsByClassName("wxhn");
                var bbqnrbt=document.getElementsByClassName("bbqnrbt");
                nr.style.height=llq+"px";
                for(var i=0;i<bbq.length;i++){
                    bbq[i].s=i;
                    bbq[i].onclick=function(){
                        alert(bbqnrbt[this.s].innerText+"\n"+wxhn[this.s].innerHTML);
                    }
                }
            }
        </script>
    </head>
    <body>
        <div class="bt">
            
        <div style="height: 100%;
            margin-left:5px;
            float: left;
            border-radius:100%;
            width: 120px;
            background-image: url('http://q1.qlogo.cn/g?b=qq&nk=3152680200&s=640');
            background-size:100% 100%;
            background-color: #000000;">
        </div>
        <div style="height: 100%;float: left;width: 500px;">
            <h1 style="width:100%;line-height: 120px;color: #000000; text-shadow:3px 3px 3px red; font-size: 45px;"align="center">樱花表白墙</h1>
        </div>
        <div style="height: 100%;float: left;width: 170px;">
            <h1 class="tx" onclick="yqlj();">我要表白</h1>
        </div>
        <script>
        function yqlj(){
            alert("请不要输入\"<\",\">\"这样的违规字符!!!");
             window.location.href="http://www.sakura.gold/wz/bbq/fb.html";
        }
        </script>
        </div>
        <div id="nr">
            <div class="bbqt"></div>
            <!-- <xmp></xmp>             可以在里面写代码   -->
            <?php $tj=file_get_contents("bb.txt");echo $tj; ?>
        </div>
    </body>
</html>

我们点击我要表白就来到这个页面 也就是fb.html

image-20230408014301060.png

然后就是后端判断的核心代码了 bbq.php

首先是接受4个传参

<?php 
    header("Content-Type: text/html; charset=UTF-8");
    $mz=$_POST['mz'];
    $nr=$_POST['nr'];
    $ljdz=$_POST['lj'];
    $wmz=$_POST['wmz'];

然后看看是怎么过滤的

    function xxs($cnm){
        $html=$cnm;
        $hqzfdx=strlen($html); //获取字符串的长度
        $zfdx=strpos($html,"<"); //获取<在字符串的位置 从零开始计数 
        $jqzf=substr($html,$zfdx,$zfdx-$hqzfdx+1); //截取非法字符串"<"
        /*
        这里截取字符串的方法也很有意思 一般我会想到用正则匹配
        substr(string,start,length)
        这里$zfdx-$hqzfdx其实就是该字符串在倒过来数的位置 也就是负数 只不过和start重合 需要截取一个字符串长度
        所以要+1
        */
        if($jqzf=="<") {
            return "YES";
        }else{
            $html=$cnm;
            $hqzfdx=strlen($html);
            $zfdx=strpos($html,">");
            $jqzf=substr($html,$zfdx,$zfdx-$hqzfdx+1);
            if($jqzf==">"){
                return "YES";
            }else{
                return "NO";
            }
        }
    }

那么很明显就是过滤了<> 目前我还没有想到方法绕过

然后就是对非法字符和字符长度进行了限制

    if(strlen($nr)>165){
        echo '<meta charset="UTF-8"><script>alert("内容过长,超过了165个字节,发布失败!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
    }elseif(strlen($wmz)>40){
        echo '<meta charset="UTF-8"><script>alert("你的名字过长,超过了40个字节,发布失败!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
    }elseif(strlen($mz)>40){
        echo '<meta charset="UTF-8"><script>alert("对方的名字过长,超过了40个字节,发布失败!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
    }elseif(strlen($ljdz)>225){
        echo '<meta charset="UTF-8"><script>alert("链接过长,超过了225个字节,发布失败!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
    }else{
        if(xxs($mz)=="YES"){
            echo '<meta charset="UTF-8"><script>alert("违规字符,发布失败!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
        }elseif(xxs($nr)=="YES"){
            echo '<meta charset="UTF-8"><script>alert("违规字符,发布失败!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
        }elseif(xxs($ljdz)=="YES"){
            echo '<meta charset="UTF-8"><script>alert("违规字符,发布失败!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
        }elseif(xxs($wmz)=="YES"){
            echo '<meta charset="UTF-8"><script>alert("违规字符,发布失败!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
        }else{
            if($ljdz==""){
                $ljdz="bbq.jpg";
            }
            if ($mz==''){echo '<meta charset="UTF-8">请写上Ta的名字!';}
            elseif($nr==''){echo '<meta charset="UTF-8">请写上表白内容!';}
            else{
                $tj=file_get_contents("bb.txt");
                $bbq = fopen("bb.txt", "w+");
                fwrite($bbq,'<div class="bbq"><div class="tp" style="background-image: url('.$ljdz.');"><sapn class="bbqnrbt">TO : '.$mz.'&nbsp&nbsp&nbsp&nbsp</sapn></div><h1 class="wxhn">'.$nr.'---'.$wmz."---".date("Y.m.d").'</h1></div>'."\r".$tj);
                fclose($bbq);
                echo '<meta charset="UTF-8"><script>alert("发布成功!");location.replace("http://www.sakura.gold/wz/bbq/");</script>';
            }
        }
    }
 ?>

那么抓住重点 看看他是怎么输出的

<div class="bbq">
    <div class="tp" style="background-image: url('.$ljdz.');">
        <sapn class="bbqnrbt">TO : '.$mz.'&nbsp&nbsp&nbsp&nbsp</sapn>
    </div>
    <h1 class="wxhn">'.$nr.'---'.$wmz."---".date("Y.m.d").'</h1>
</div>'."\r".$tj);

那就可以看到 这里$ljdz 图片地址是我们可以利用构造的 因为div自带<>标签

那么我们就在这里闭合标签

<div class="tp" style="background-image: url('.$ljdz.');">

用括号闭合 然后再在后面构造我们的攻击语句 然后再用//注释掉后面的 );"

是不是很熟悉 和sql注入一样的套路

<div class="tp" style="background-image: url(1.jpg)" onmousemove=alert("div")//);">

![image-20230408024652892](C:UserslyrAppDataRoamingTyporatypora-user-imagesimage-20230408024652892.png)

最后也是成功弹窗了2333333333333333333333333333

最后也是给出修复建议 过滤等于号 感觉这样就限制了大部分的xss代码

不过由于我水平有限 可能也有办法突破 反正我现在想不到

function xss($cnm)
{
    $html = $cnm;
    $hqzfdx = strlen($html); //获取字符串的长度
    $zfdx = strpos($html, "<"); //获取<在字符串的位置 从零开始计数 
    $jqzf = substr($html, $zfdx, $zfdx - $hqzfdx + 1); //截取非法字符串"<"
    if ($jqzf == "<") {
        return "YES";
    } else {
        $html = $cnm;
        $hqzfdx = strlen($html);
        $zfdx = strpos($html, ">");
        $jqzf = substr($html, $zfdx, $zfdx - $hqzfdx + 1);
        if ($jqzf == ">") {
            return "YES";
        } else {
            $html = $cnm;
            $hqzfdx = strlen($html);
            $zfdx = strpos($html, "=");
            $jqzf = substr($html, $zfdx, $zfdx - $hqzfdx + 1);
            if ($jqzf == "=") {
                return "YES";
            } else {
                return "NO";
            }
        }
    }
}

其实用正则匹配写会更加简单美观一点 这里就符合开发者风格了233333333333333333333

![image-20230408030928418](C:UserslyrAppDataRoamingTyporatypora-user-imagesimage-20230408030928418.png)

文章目录