XSS:跨站攻击脚本
恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页时
,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户
的目的。
OWASP TOP10 一直排前十
XSS 可以用来进行钓鱼攻击,前端js挖矿、获取用户cookie,甚至对
用户主机进行控制
XSS形成原因:
程序对输入和输出的控制不够严格,导致攻击者的脚本输入后,
在输出到前端时被浏览器当作有效的代码解析执行从而产生危害。
XSS攻击的危害:
1.盗取账号
2.控制企业数据,读取、篡改、添加、删除敏感数据
3.盗窃企业重要的具有商业价值的资料
4.非法转账
5.强制发送电子邮件
6.网站挂马
7.控制受害者机器,向其它网站发起攻击
反射型XSS,也叫非持久性CSS,当用户访问一个带有XSS代码的
URL请求时,服务器端接收数据后处理,然后把带有XSS代码
的数据发送到浏览器,浏览器解析这段XSS代码的数据后,
最后造成XSS漏洞。这个过程就像一次反射,故称反射型XSS
反射型XSS不会存储在服务器端 我们利用需要结合社工等条件。
存储型XSS
存储型XSS和反射型XSS形成原因一样,不同的是存储型XSS
后台会将构造的payload保存起来,构成更加持久的危害,因此
存储型XSS也称“永久型XSS”
存储型XSS 不需要我们结合社工等条件触发,破坏性要大于反射型XSS
可以从网上搜集payload
HTML DOM 树
DOM XSS 是一种特殊类型的反射型 XSS, 它是基于DOM文档
对象模型的一种漏洞。
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
echo 'Hello '
. $_GET[ 'name' ] . '
';
}
?>
array_key_exists(key,array) 函数检查某个数组中是否存在指定的键名,如果键名存在则返回 true,如果键名不存在则返回 false
key 必需。规定键名。
array 必需。规定数组。
这关我们由源代码知道,作者并没有对我们的输入进行过滤,所以我们可以任意插入js代码,比如我们插入
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( ''
. ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
//mysql_close();
}
?>
$GLOBALS — 引用全局作用域中可用的全部变量
trigger_error(errormsg,errortype) 函数创建用户级别的错误消息。
errormsg 必需。规定错误消息。最大长度 1024 字节。
errortype 可选。规定错误类型。可能的值:
E_USER_ERROR
E_USER_WARNING
E_USER_NOTICE(默认)
mysql_query(query,connection) 函数执行一条 MySQL 查询
query 必需。规定要发送的 SQL 查询。注释:查询字符串不应以分号结束。
connection 可选。规定 SQL 连接标识符。如果未规定,则使用上一个打开的连接。
作者对我们的输入进行了两边去空,然后去除了message变量的反斜杠,并且对我们的输入SQL语句中的特殊字符,但并不影响我们进行xss攻击。
我们可以直接从message一栏输入我们想要攻击的代码(因为name一栏的最长限制为10,所以如果我们想要在name处攻击,那么就需要更改前端或者抓包更改)
服务器端代码
# No protections, anything goes
?>
由源代码知道,作者没有做任何防护,所以我们直接在地址栏提交我们的xss攻击
http://127.0.0.1/dvwa/vulnerabilities/xss_d/?default=%3Cscript%3Ealert(1)%3C/script%3E
header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Get input $name = str_replace( '
XSS(Stored)
Source Code
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( '
cript>alert(2)cript>XSS(DOM)
Source Code
// 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, "
Impossible
XSS(Reflected)
Source Code
// 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 "
Hello ${name}"; } // Generate Anti-CSRF token generateSessionToken(); ?>htmlspecialchars() 函数把预定义的字符转换为 HTML 实体。
预定义的字符是: & (和号)成为 & " (双引号)成为 " ' (单引号)成为 ' < (小于)成为 < > (大于)成为 >
Solution
此难度下,作者不仅验证了我们的token还将我们的所有的输入都当做字符串,且预定义字符转换为HTML实体,因为我们注入的js代码都是标签,都必须有<>,所以我们就彻底不能进行绕过了
XSS(Stored)
Source Code
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(); ?>
Solution
由源代码可知,作者不仅验证了我们的身份,而且还对我们的所有输入进行了 htmlspecialchars过滤,所以我们无法进行xss攻击
XSS(DOM)
Source Code
# Don't need to do anything, protction handled on the client side ?>
这里服务器端代码没有了,那么一定是在前端代码上做了手脚。
Solution
我们可以看到前端的源码与前三个难度的源码唯一区别是在,对于lang变量的url解码,但是impossible难度并没有对我们的输入进行解码,所以上传上去的只是URL编码,所以就不存在了XSS攻击。
本文所有函数解析参考自w3cschool