前言
存储型XSS可以将用户有害输入信息存储在后台数据库中,不需要攻击者构造URL链接诱使受害人单击而触发攻击,目标网站的其它用户只要访问插入恶意代码的网站相关页面即可触发代码执行。相比较反射型XSS更隐蔽性,受害者范围更广。
存储型XSS危害程度高于反射型XSS,利用它,可以
- 窃取管理员帐号或Cookie,入侵者可以冒充管理员的身份登录后台。使得入侵者具有恶意操纵后台数据的能力,包括读取、更改、添加、删除一些信息。
- 窃取用户的个人信息或者登录帐号,对网站的用户安全产生巨大的威胁。例如冒充用户身份进行各种操作。
- 网站挂马。先将恶意攻击代码嵌入到Web应用程序之中。当用户浏览该挂马页面时,用户的计算机会被植入木马。
- 发送广告或者垃圾信息。攻击者可以利用XSS漏洞植入广告,或者发送垃圾信息,严重影响到用户的正常使用。
LOW
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php if( isset( $_POST[ 'btnSign' ] ) ) { $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); $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)) ? "" : "")); $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)) ? "" : "")); $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>' ); } ?>
|
分析:
-
trim(string,charlist)
: 移除string字符两侧的预定义字符,预定义字符包括\t 、 \n 、\x0B 、\r以及空格,可选参数charlist支持添加额外需要删除的字符;
-
stripslashes(string)
: 去除掉string字符的反斜杠\;
-
mysqli_real_escape_string(string,connection)
:函数会对字符串string中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义;
-
$GLOBALS
:引用全局作用域中可用的全部变量,GLOBALS[index]的数组中存储了所有全局变量,变量的名字就是数组的键;
对输入的message和name并没有进行XSS过滤,而且数据存储在数据库中,存在比较明显的存储型XSS漏洞;
攻击测试
判断注入点
在输入框输入如下内容,弹出弹框,说明存在XSS注入;
![image-20201119110626925](/Users/leeyuxun/Library/Application Support/typora-user-images/image-20201119110626925.png)
重新刷新页面,依旧弹出弹框,表明XSS代码已经存储在数据库中,为存储型XSS漏洞;
漏洞利用
这里尝试窃取Cookie
首先在XSS Platfrom生成获取受害者Cooike的代码,通过步骤一,将其添加到页面中;
随后在XSS Platfrom即可查看到受害者的访问cookie;
MEDIUM
分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php if( isset( $_POST[ 'btnSign' ] ) ) { $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); $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 ); $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)) ? "" : "")); $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>' ); } ?>
|
分析:
-
addslashes(string)
:函数返回在预定义字符之前添加反斜杠的字符串,预定义字符 ‘ 、” 、\ 、NULL
-
strip_tags(string)
:函数剥去string字符串中的 HTML、XML 以及 PHP 的标签
-
htmlspecialchars(string)
: 把预定义的字符 “<” (小于)、 “>” (大于)、& 、‘’、“” 转换为 HTML 实体,防止浏览器将其作为HTML元素
绕过方法:
可以拿出message限制过多,但name限制较少,但前端限制了输入字符串长度,不过可以通过抓包修改进行注入操作,如下
URL编码绕过,将XSS注入代码<SCRIPT>alert('hack')</SCRIPT>
进行URL编码得%3c%53%43%52%49%50%54%3e%61%6c%65%72%74%28%27%68%61%63%6b%27%29%3c%2f%53%43%52%49%50%54%3e
结果如下
HIGH
分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php if( isset( $_POST[ 'btnSign' ] ) ) { $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); $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 ); $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)) ? "" : "")); $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>' ); } ?>
|
分析:
在MEDIUM的基础上对name标签进行了script的正则表达式过滤,此处可以使用IMG标签绕过
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' ] ) ) { checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); $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 ); $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(); } generateSessionToken(); ?>
|
分析:
对name参数也进行了更严格的过滤,导致name参数也无法进行XSS攻击。
使用了Anti-CSRF token防止CSRF攻击,杜绝了XSS漏洞和CSRF漏洞。