抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

本文学习XSS基础以及DVWA模拟环境的几道例题。

XSS介绍与原理

XSS攻击是在网页中嵌入客户端恶意脚本代码,一般是使用JavaScript语言编写。

JavaScript可以用来获取用户的Cookie改变网页内容URL跳转,因此攻击者需要做的是向Web页面注入JavaScript,就可以盗取用户Cookie、黑掉页面、导航到恶意网站。

通常在url中加入来实现一些特殊效果,也可以在JavaScirpt中利用url形式来加载外部脚本。

漏洞实现原理

image-20200406140611891

XSS漏洞分类:反射型、存储型、DOM型

XSS漏洞修复

  1. HTML实体编码
  2. 使用白名单过滤用户输入的恶意字符
  3. 根据业务场景对症下药

存储型XSS实战

原理

攻击者在页面上插入XSS代码,服务端将数据存入数据库,当用户访问到存在XSS漏洞的页面时,服务端从数据库中取出数据展示到页面上,导致XSS代码执行,达到攻击效果。

image-20200406150941187

允许用户存储数据的Web应用程序都可能会出现存储型XSS漏洞,当攻击者提交一段XSS代码后,被服务器端接收并存储,当攻击者再次访问某个界面时,这段XSS代码被程序读出来响应给浏览器,造成XSS攻击。

比起其他两种类型的XSS攻击,存储型XSS不需要用户手动去触发。

注意:判断输出数据是否在属性内

当输出数据在属性内,

以上JavaScript代码虽然插入到HTML中,但因为XSS代码在Value属性中,最终当做值来处理,浏览器在解析HML时,会将数据以文本的形式输出在网页。

因此我们需要根据响应的标签构造HTML代码来闭合,插入XSS代码为"/ ><script>alert(1)</script>,最终在HTMl文档中为<input type="text" name="content" value=""/ ><script>alert(1)</script>"/>,这样就可以闭合input标签,使得输出的内容不再Value属性内,从而造成XSS跨站漏洞。

存储型XSS测试步骤

  1. 添加正常留言’helloworld‘,审查元素得知该HTML代码为<li><strong>username</strong><span class="message">helloword</span>

  2. 如果不清楚具体输出位置,有三种模糊测试方法

    • 普通注入 <script>alert(document.cookie)</script>
    • 闭合标签注入 " /><script>alert(document.cookie)</script>
    • 闭合标签注入</textarea>'"><script>alert(document.cookie)</script
  3. 当存储型XSS代码注入后,每次加载留言界面XSS代码都会被执行

总结:留言就是恶意XSS代码伪装的。

反射型XSS

原理

攻击者在URL中插入XSS代码,服务端将URL中的XSS代码输出到页面上,攻击者将带有XSS代码的URL发送给用户,用户打开后受到XSS攻击。

image-20200407165505422

代码解析

程序接受username值后再输出,如果username=<script>恶意代码</script>,则会让恶意代码在服务器端执行。

1
2
3
4
<?php
$username=$_GET['username'];
echo $username;
?>

攻击者利用站内信方式将带有恶意代码的URL发送给正常用户以获取用户的Cookie即登录信息,则攻击者可以利用Cookie(以正常用户的身份)登录该网站。

方法:寻找需要传入参数(形如?id=1)的URL,在闭合标签再加入<script>代码。

DOM型XSS

DOM简介

DOM全称Document Object Model(文档对象模型),使用DOM可以允许程序和脚本动态地访问和更新文件的内容、结果和样式。

HTML DOM树
image-20200308140930363

原理

攻击者在URL中插入XSS代码,前端页面直接从URL中获取XSS代码并输出到页面,导致XSS代码执行,攻击者将带有XSS代码的URL发送给用户,用户打开后受到XSS攻击。(与反射型XSS漏洞相比,DOM型XSS漏洞不需要经过后端处理,只在前端进行)

经典DOM型XSS示例

1
2
3
4
5
// 获取URL中的content值并输出
var temp = document.URL;
var index = document.URL.indexOf("content=") + 4;
var par = temp.substring(index);
document.write(decodeURI(par));

常见方法

输入http://127.0.0.1/dom.html?content=<script>alert(/xss/)</script>就会产生XSS漏洞。

常用XSS漏洞修复函数

在下面实战中我们还会讲解一遍函数的具体作用

  1. Strip_tags() 所有HTML、XML、PHP元素均被删除
  2. htmlspecialchars 将部分字符转换为HTML实体,防止浏览器将其识别为HTML元素。
    • " –> &quot;
    • &–>&amp;
    • '–>'
    • <–>&lt
    • >–>&gt
  3. addslashes() 在字符串中出现预定字符之前添加反斜杠的字符串。
  4. stripslahes(string) 删除字符串中的反斜杠

XSS辅助测试工具

Beef

image-20200407224617512

搭建:

  1. docker pull janes/beef
  2. docker run –rm -p 3000:3000 janes/beef
  3. 访问http://127.0.0.1:3000/ui/panel 默认账号密码beef/beef

使用:当用户执行XSS代码之后,获取信息进行详细分析。

XSS’OR

image-20200407225802626

Encode/Decode 代码编码解码

Codz 测试CSS工具,生成一些POST数据

Probe 给你一个JS文件你可以插入到指定的网页中,以来获取信息。

XSS平台

网上JS漏洞集合平台

IE Tester

模拟IE低版本

DVWA XSS实战

安装DVWA模拟环境

下载并安装docker

docker pull citizenstig/dvwa

docker run -dt -p 8997:80 citizenstig/dvwa

访问http://127.0.0.1:8997 默认账号密码admin/password

XSS(Reflected) Low

代码分析

1
2
3
4
5
6
7
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>

从源代码可以看到代码直接引用name参数,并没有任何的过滤与检查,存在明显的XSS漏洞。

漏洞利用

输入<script>alert(/nzy/)</script>,弹框

image-20200408100811511

url:http://127.0.0.1:8997/vulnerabilities/xss_r/?name=%3Cscript%3Ealert%28%2Fnzy%2F%29%3C%2Fscript%3E#

XSS(Reflected) Medium

代码分析

1
2
3
4
5
6
7
8
9
<?php 
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
$name = str_replace( '<script>', '', $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>

从源代码可以看出对输入进行了过滤,基于黑名单思想,利用str_replace()函数将输入中含有<script>替换成 。但是这种防护机制仍可以轻松绕过。

漏洞利用

  1. 利用双写绕过,输入<scr<script>ipt>alert(/nzy/)</script>,在经过str_replace()函数处理后为<script>alert(/nzy/)</script>
  2. 大小写混淆绕过,黑名单思想只禁止<script>,因此可以利用大小写混淆绕过,输入<Script>alert(/nzy/)</scirpt>

XSS(Reflected) High

代码分析

1
2
3
4
5
6
7
8
9
<?php 
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>

从源代码可以看出同样是使用了黑名单思想,但是preg_replace()函数用于正则表达式的搜索和替换,这样使得Medium级别的双写绕过、大小写混淆绕过方法都是小。

Preg_replace()函数中i表示忽略大小写

漏洞利用

虽然无法再使用带有<script>字样的标签来注入XSS代码,但是可以利用img、body等标签事件或者iframe等标签src来注入恶意的JS代码。

输入<img src=1 onerror=alert(/nzy/)>

XSS(Reflected) Impossible

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php 
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$name = htmlspecialchars( $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
// Generate Anti-CSRF token
generateSessionToken();
?>

在High级别中,我们可以利用img、body等标签事件进行注入恶意JS代码,所以在impossible级别中,利用上文讲到过的htmlspecialchars()函数将部分字符(& " ' < > )转换为HTML实体,防止浏览器将其识别为HTML元素。

XSS(Stored) Low

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php 
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = stripslashes( $message );
$message = mysql_real_escape_string( $message );
// Sanitize name input
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
//mysql_close();
}
?>

针对代码中提到的几个函数解释一下

  1. trim(string,charlist) 功能:移除字符串两侧的空白字符或者其他预定义字符(\t \n \x0B \r ),可选参数charlist支持增添额外需要删除的字符
  2. Mysql_real_escape_string(string,connection)这个函数在 SQL注入防御绕过曾经提到过。功能:对字符串中的特殊符号(\x00 \n \r \ ' " \x1a)进行转义。
  3. stripslahes(string) 功能:删除字符串中的反斜杠

从源代码可以看出对输入没有做XSS方面的过滤与检查就直接存储至数据库了,因此存在明显的存储型XSS漏洞。

漏洞利用

直接输入<script>alert(/nzy/)</script>,需要注意的是name变量在前端中对字数有限制,我们将其修改至30。

image-20200408220418246

XSS(Stored) Medium

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php 
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input
$name = str_replace( '<script>', '', $name );
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
//mysql_close();
}
?>

针对代码中提到的几个函数解释一下

  1. Strip_tags() 功能:删除字符串中的HTML、XML以及PHP标签,但保留<b>标签。
  2. addslashes() 功能:在字符串中出现预定字符(' " / NULL)之前添加反斜杠的字符串。

从源代码可以看出对输入中的message参数使用了htmlspecialchars()函数进行标签转换,因此无法再通过message参数进行XSS注入,但是对name参数只进行形如XSS(Reflected) Medium中的过滤<script>字符串而已,因此存在存储型XSS漏洞。

漏洞利用

基本参见XSS(Reflected) Medium中的双写绕过、大小写混淆绕过两种办法,并且对name参数进行修改maxlength=30。

  1. 双写绕过,输入<scr<script>ipt>alert(/nzy/)</script>
  2. 大小写混淆绕过,输入<Script>alert(/nzy/)</scirpt>

XSS(Stored) High

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php 
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
//mysql_close();
}
?>

从源代码可以看出这道题类似于XSS(Reflected) High,具体参见上文。

漏洞分析

基本参见XSS(Reflected) High中的利用img、body等标签事件或者iframe等标签src来注入恶意的JS代码的办法,并且对name参数进行修改maxlength=30。

输入<img src=1 onerror=alert(/nzy/)>

XSS(Stored) Impossible

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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 = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input
$name = stripslashes( $name );
$name = mysql_real_escape_string( $name );
$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();
?>

还是终极函数htmlspecialchars()函数的出场,解决XSS问题。有一点需要注意的是,如果htmlspecialchars()函数使用不当,攻击者就可以通过编码的方式绕过函数进行XSS注入,尤其是DOM型的XSS。

htmlspecialchars()完整用法:https://www.runoob.com/php/func-string-htmlspecialchars.html

评论