XSS(Stored)-low level
源代码
<?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() 函数移除字符串两侧的空格,以确保数据在插入到数据库时没有多余的空白字符。
使用 stripslashes() 函数去除反斜杠,同时使用 mysqli_real_escape_string() 函数转义特殊字符。
使用 mysqli_real_escape_string() 函数将特殊字符转义为它们的 Unicode 编码,以确保它们不会被视为 SQL 语句的一部分。
从源代码来看,它没有明确的防御 XSS 攻击的措施。
姿势
基于Message板块
Payload:<script>alert("qiu")</script>
基于Name板块
Name只允许输入八个字符,而XSS语句是比八个字符长的。
绕开长度限制: \color{#00FF00}{绕开长度限制:}绕开长度限制: 将页面Name元素的maxlength改为100
Payload:<script>alert("qiu")</script>
XSS(Stored)-medium level
源代码
<?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(); } ?>
对留言内容 $message 进行了三种过滤:
使用 strip_tags() 函数移除所有 HTML 和 PHP 标签
使用 addslashes() 函数将字符串中的特殊字符转义(例如单引号、双引号和反斜杠)
使用 htmlspecialchars() 函数将message中特殊字符(例如 < > ' " &)转换为相应的 HTML 实体,以防止 XSS 攻击。
对姓名 $name 进行了两种过滤:
使用 str_replace() 函数将字符串中的<script>替换为空字符串
使用 mysqli_real_escape_string() 函数转义字符串中的特殊字符(例如单引号和双引号)以防止 SQL 注入攻击。
姿势
双写绕过
以message为注入点,Payload:<scrip<script>t>alert(1)</scr<script>ipt>
无回显,原因:htmlspecialchars() 函数将message中的特殊字符(例如 < > ' " &)转换为相应的 HTML 实体
以Name为注入点:
大小写绕过
由于str_replace() 函数对大小写敏感,可通过大小写绕过限制。
以Name为注入点,Payload:<Script>alert(1)</sCript>
Xss标签绕过
由于针对Name的str_replace() 函数只对<script>起过滤作用,因此可使用不同的Xss标签进行绕过。
以Name为注入点,Payload:<img src=1 onerror=alert(1)>
XSS(Stored)-high level
源代码
<?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(); } ?>
对留言内容 $message 进行了三种过滤:
使用 strip_tags() 函数移除所有 HTML 和 PHP 标签
使用 addslashes() 函数将字符串中的特殊字符转义(例如单引号、双引号和反斜杠)
使用 htmlspecialchars() 函数将特殊字符如 < > ' " &转换为相应的 HTML 实体,以防止 XSS 攻击
对姓名 $name 进行了两种过滤:
使用 preg_replace() 函数将字符串中的 <script> 替换为空字符串
使用mysqli_real_escape_string() 函数转义字符串中的特殊字符(例如单引号和双引号)以防止 SQL 注入攻击。
姿势:Xss标签绕过
切换 X S S 标签 \color{#FF00FF}{切换XSS标签}切换XSS标签
以Name为注入点,Payload:<img src=1 onerror=alert(1)>
以Name为注入点,Payload:<audio src=1 onerror=alert(1)>
XSS(Stored)-Impossible level
源代码
<?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(); ?>
代码审计
if( isset( $_POST[ 'btnSign' ] ) ) {
1
该行通过 isset() 函数判断 PHP 脚本是否是由提交按钮 btnSign 触发的。如果是,则执行后续代码。
接着,代码调用了 checkToken() 函数,用于验证 Anti-CSRF token 是否匹配:
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
这个函数需要三个参数:用户提交的 CSRF token、服务器存储的 CSRF token 和当前页面的 URL。函数会检查两个 token 是否相同,以及请求是否来自于正确的来源,从而避免跨站点攻击。
接下来的代码获取了用户输入的姓名和留言信息:
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
trim() 函数移除字符串两侧的空格。这样可以确保数据在插入到数据库时没有多余的空白字符。
然后,使用 stripslashes() 函数去除反斜杠,同时使用 mysqli_real_escape_string() 函数转义特殊字符:
$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 ); $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 );
mysqli_real_escape_string() 将特殊字符转义为 Unicode 编码。
最后,使用 htmlspecialchars() 函数对用户输入的数据进行 HTML 编码,以防止 XSS 攻击。该函数将 HTML 特殊字符转义为实体,从而避免恶意代码在浏览器中执行。
接下来的代码,使用 PDO 对用户数据进行插入:
$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();
$db 是一个预先创建的 PDO 数据库连接。这个代码段使用了 PDO 的预准备语句(prepared statement)功能,这是一种避免 SQL 注入攻击的最佳方法之一。使用 bindParam() 函数将实际插入的值与数据库字段绑定起来,确保即使用户输入包含非法字符也不会对 SQL 查询产生影响。
最后,调用 generateSessionToken() 函数来生成 Anti-CSRF token:
generateSessionToken();
1
这个函数采用某些规则生成随机的 session_token,并将其存储在 PHP 会话中。
总结
以上为[网络安全]DVWA之XSS(Reflected)攻击姿势及解题详析合集,读者可躬身实践。
[网络安全]DVWA之XSS合集:
[网络安全]DVWA之XSS(DOM)攻击姿势及解题详析合集
[网络安全]DVWA之XSS(Reflected)攻击姿势及解题详析合集
我是秋说,我们下次见。