XSS漏洞详解

每天一个小知识之GET、POST区别
1、GET是从指定的资源请求数据,POST是向指定的资源提交要被处理的数据。
2、GET参数是带在URL后面,POST请求放在请求体Request Body中。
3、GET方法提交的数据大小长度有限制,POST方法没有对长度进行限制。
HTTP协议规范没有对URL长度进行限制。GET方法提交数据大小的限制是特定的浏览器及服务器对它的限制。IE对URL长度的限制是2083字节(2K+35)
4、GET请求能够被cache,POST不进行缓存。
GET请求能够被保存在浏览器的浏览历史里面。

跨站脚本攻击XSS

XSS备忘录里记录了多种XSS的绕过方式,为了给专业安全测试人员提供一份跨站脚本漏洞检测指南
XSS备忘录

一、XSS介绍及危害

1、介绍

XSS又叫CSS(Cross-SiteScripting),跨站脚本攻击。攻击者往Web页面里注入可执行解释的payload(脚本代码)。当用户访问该网页时,嵌入其中恶意代码会自动加载并执行,从而达到攻击者目的。

2、危害

 1. 网络钓鱼,包括盗取各类用户账号; 
 2. 窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作;
 3. 劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等; 
 4. 强制弹出广告页面、刷流量等;
 5. 网页挂马,进行恶意操作,例如任意篡改页面信息、删除文章等; 
 6. 进行大量的客户端攻击,如DDoS攻击;
 7. 获取客户端信息,例如用户的浏览历史、真实IP、开放端口等; 
 8. 控制受害者机器向其他网站发起攻击;
 9. 结合其他漏洞,如CSRF漏洞,实施进一步作恶; 
 10. 提升用户权限,包括进一步渗透网站;
 11. 传播跨站脚本蠕虫等。

二、漏洞利用类型及利用场景

1、反射型XSS

反射型XSS攻击一般是攻击者通过特定手法,诱使用户去访问一个包含恶意代码的URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。
此类XSS攻击通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端Cookies或进行钓鱼欺骗。

2、存储型XSS

攻击者事先将恶意代码上传或者储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此存储型XSS攻击的危害会更大。此类攻击一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。

3、DOM型XSS

客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。例如客户端如从URL中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的JavaScript脚本,而这些脚本没有经过适当的过滤或者消毒,那么应用程序就可能受到DOM型XSS攻击。需要特别注意以下的用户输入源document.URL、location.hash、location.search、document.referrer等。

三、DVWA对XSS漏洞详解

1、反射型XSS

(1)Low级别

在该级别下,输入框中输入taozi,返回的值仍为taozi
在这里插入图片描述
我们尝试输入一个html标签,<script>alert('taozi')</script>
在这里插入图片描述
漏洞成功利用,这里可以使用html标签获取想要的信息了
查看一下服务器端的代码
在这里插入图片描述
可以看到,这里对获取到的name没做任何处理,直接引用的name参数值

(2)Medium级别

在该级别下进行low级别同样的测试时,发现只能显示标签里的内容,猜测对script标签进行了过滤
在这里插入图片描述
尝试修改一下script标签的大小写,<ScrIpt>alert('taozi')</script>
在这里插入图片描述
发现能够成功利用该漏洞
查看一下服务器端的代码
在这里插入图片描述
可以看到这里对script标签进行了一个过滤,使用str_replace函数将script标签替换成了空格,我们尝试使用在script标签中嵌套script标签,看能否进行绕过
使用<sc<script>ript>alert('taozi')</script>发现也能成功绕过

该级别的漏洞利用有两种方式
1)大小写混合绕过
<ScrIpt>alert('taozi')</script>
2)双写绕过
<sc<script>ript>alert('taozi')</script>
(3)High级别

在该级别下进行script标签进行测试时,发现只能显示>,说明对script标签进行了更为严格的过滤
在这里插入图片描述
尝试换img标签,输入一个不存在的img地址,onerror指定一个alter标签,<img src=1 onerror=alert('taozi')>
在这里插入图片描述
发现能够成功利用
onerror事件会在文档或图像加载过程中发生错误时被触发
应为src=x本身就是一个错误代码,所以触发事件执行
在这里插入图片描述
查看一下服务端的代码
在这里插入图片描述
可以看到这个级别下,对输入的script标签进行了更为严格的过滤,其中preg_replace() 函数用于正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中i表示不区分大小写)不再有效。
这里除了img标签进行绕过外,还能使用body、iframe等标签进行绕过,这里就不再进行展示了

(4)Impossible级别

在该级别下输入script标签进入绕过,发现直接将标签的内容进行了打印,img标签也是如此
在这里插入图片描述查看一下服务端代码
在这里插入图片描述
发现使用htmlspecialchars函数把预定义的字符&、”、 ’、<、>转换为 HTML 实体,防止浏览器将其作为HTML元素。
在这里插入图片描述

2、存储型XSS

打开界面是一个留言板,一般留言板是XSS漏洞存在的常见页面,尝试在留言板输入攻击代码。
在这里插入图片描述

(1)Low级别

在留言板上name输入“taozi”,message输入一个<script>alert('taozi')</script>
在这里插入图片描述
发现能够弹出弹窗,且每次进入这个页面都会弹出该弹窗,说明已经在留言板上留下了这个js代码
在这里插入图片描述
尝试在name框输入标签,发现name框对输入的数据有长度限制,我们修改一下前端的代码
在这里插入图片描述
将最大数据长度改为了10000,在进行测试
发现也能进行绕过
查看一下服务端的代码


<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = stripslashes( $message );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Sanitize name input
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?>

这里对几个函数进行一下介绍

trim(string,charlist)
函数用于删除字符串左右两边的空格或预定义字符,并返回修改后的字符串,预定义字符包括、\t、\n、\x0B以及\r,可选参数charlist支持添加额外需要删除的字符。
stripslashes(string)
函数删除字符串中的反斜杠。
mysql_real_escape_string(string,connection)
函数会对字符串中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义。

从代码可以看出,这里对输入并没有做XSS方面的过滤与检查,且存储在数据库中,因此这里存在明显的存储型XSS漏洞。

(2)Medium级别

在该级别下进行测试,发现name还是有长度限制,先试试能不能再message框进行绕过
在message框下输入<script>alert('taozi')</script>
在这里插入图片描述
根据返回的值,发现不能进行绕过,直接将script标签进行了过滤,输出的值为标签里的内容
那再尝试一下大小写混合和双写能否进行绕过
发现也是不行的
那只能在name框进行测试了,跟low级别一样,name框的输入有长度限制,修改一下前端页面的最大长度
在这里插入图片描述
使用<script>alert('taozi')</script>无法绕过
发现使用双写和大小写混合能够成功绕过<scr<script>ipt>alert('taozi')</script>
<sCriPt>alert('taozi')</script>
查看一下服务端代码

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = strip_tags( addslashes( $message ) );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = str_replace( '<script>', '', $name );
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?>

代码中函数的介绍

strip_tags
函数用于剥去字符串中的HTML、XML以及PHP的标签
addslashes()
函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串

从代码里可以看到对name的处理方式是将script标签替换为空,也就是使用大小写混合和双写能够顺利绕过,对message框的处理是使用了htmlspecialchars函数进行编码,因此无法再通过message参数注入XSS代码。

(3)High级别

依旧是修改name框的最大限制长度,对注入的双写和大小写混合script标签都被忽略了,只能在尝试img标签
<img src=1 onerror=alert('taozi')>
发现能够正常绕过,猜测是对script标签进行了较为严格的过滤
查看一下服务端的代码

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = strip_tags( addslashes( $message ) );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?>

从代码能看出,对name框中的参数做了正则匹配,过滤掉script标签,但并未对别的标签做过滤
对message框中的参数进行的还是XSS过滤

(4)Impossible级别
<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = stripslashes( $message );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = stripslashes( $name );
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $name = htmlspecialchars( $name );

    // Update database
    $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
    $data->bindParam( ':message', $message, PDO::PARAM_STR );
    $data->bindParam( ':name', $name, PDO::PARAM_STR );
    $data->execute();
}

// Generate Anti-CSRF token
generateSessionToken();

?>

在该级别下,对name框中的参数也进行了严格的过滤,将name框和message框中的参数都进行了htmlspecialchars实体化

3、DOM型XSS

打开是一个带下拉框的页面,当我们选择某个选项时,这个选项便会写入到DOM节点中,是一个XSS DOM漏洞典型的地方。
在这里插入图片描述

(1)Low级别

尝试直接在url中加入攻击代码
http://127.0.0.1/DVWA/vulnerabilities/xss_d/?default=English<script>alert('taozi')</script>成功弹出弹窗
查看一下前端代码
在这里插入图片描述
可以看到,从选择列表选择的值赋值给default附加到url后,这段js代码将url中default的值赋给option标签的value属性节点和文本节点。
查看一下服务端代码
在这里插入图片描述
发现没有进行任何防护,可直接进行利用

(2)Medium级别

利用low级别的方法,无效
查看一下服务端代码


<?php

// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
    $default = $_GET['default'];
    
    # Do not allow script tags
    if (stripos ($default, "<script") !== false) {
        header ("location: ?default=English");
        exit;
    }
}

?>

通过代码可以看到对script标签进行了过滤

stripos
函数返回字符串在另一个字符串中第一次出现的位置

根据网页源代码,构造一个payload
</options></select><img src=1 onerror=alert('taozi')>
对前面的options标签和select标签进行一个闭合,然后使用img标签进行绕过,服务端代码只对script标签进行了过滤,所以我们可以使用img标签进行绕过
还有一个种绕过方式,就是
?#default=<script>alert('taozi')</script>
这种方式就是URL的部分发往服务器时#号后面的并不会发送到服务器,但是javascript代码还会正常读取,所以利用这个特性来绕过服务器端的检查。

(3)High级别

查看一下服务端代码

<?php

// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {

    # White list the allowable languages
    switch ($_GET['default']) {
        case "French":
        case "English":
        case "German":
        case "Spanish":
            # ok
            break;
        default:
            header ("location: ?default=English");
            exit;
    }
}

?>

可以看到,这里使用了白名单,只有在白名单列表中的才允许通过
我们还是使用#进行绕过
?#default=<script>alert('taozi')</script>
成功绕过

(4)Impossible级别

查看一下服务端代码

<?php

# Don't need to do anything, protction handled on the client side

?>

这里没有做什么处理,看了一下help文档,说是浏览器会精确的对url进行编码,防止xss攻击。

四、XSS绕过

1、<>被过滤的情况下

假如在特殊标签下的时候,可以构造一些事件触发
autofocus onfocus=aler('taozi')

2、alert被过滤的情况下

编码、prompt和confirm也可以弹窗
base64编码
<a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgndGFvemknKTwvc2NyaXB0Pg==>
url编码
<a href=data:text/html;%3Cscript%3Ealert('taozi')%3C/script%3E>

3、on事件被过滤的情况下

<form><button formaction=javascript&colon;alert('taozi')>M
可以执行js的属性
formaction action href xlink:href antofocus src content data

4、其他

标签和属性之间并不是只能出现空格
<img/src=x onerror=alert('taozi')>
有时候并不需要一个合法的标签:
<M/onclick="alert('taozi')">M

五、防御

1、阻止恶意代码注入

2、阻止恶意操作执行

不管是反射型还是存储型xss,都能通过服务端过滤进行防御:
(1)黑名单:过滤特殊符号及字符
如<、>、%、#、/、”、’、;、(、)、script、 svg、 object、 on事件等
(2)白名单:只允许特定类型或符号
根据输入的数据特征限制使用的类型,如年龄限制为数字类型;输入类型为字符型限制为仅可使用大小写的26个字母、数字-及_等
(3)编码及转义
输出在标签或属性中进行HTML编码;
输出在script标签或事件中进行JavaScript编码;
输出在url中进行ur1编码。
(4)cookie 中设置httponly
setcookie将httponly选项设置为true,防范cookie劫持
(5)确保执行脚本来源可信
开发者明确告诉客户端,哪些外部资源可以加载和执行(CSP策略)
(6)不使用有缺陷的第三方库
PHP:htmlentities() 、htmlspecialchars()
Python:cgi.escape()
ASP:Server.HTMLEncode()
ASP.NET:Server.HtmlEncode() 、Microsoft Anti-Cross Site Scripting Library
Java:xssprotect(Open Source Library)
Node.js:node-validator
htmlspec ialchars默认配置是不过滤单引号的。只有设置了:quotestyle选项为ENT QUOTES才会过滤单引号。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值