存储型XSS
攻击者事先将恶意代码上传或储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这就意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此储存型XSS的危害会更大。因为存储型XSS的代码存在于网页的代码中,可以说是永久型的。存储型 XSS 一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。
DVWA中存储型XSS分四个等级, 分别是low、middle、high、impossible
首先有些标签限制了输入长度,可以修改标签里面maxlength属性修改输入限制
如:
Low:
先观察源码
这个级别对输入进行了部分特殊字符校验,没有对script标签校验。使用mysqli_real_escape_string转义部分特殊字符,影响\x00、\n、\r、\、'、"、\x1a。
可以看到最终是存储到mysql数据库中
1 <?php 2 3 if( isset( $_POST[ 'btnSign' ] ) ) { 4 // Get input 5 $message = trim( $_POST[ 'mtxMessage' ] ); 6 $name = trim( $_POST[ 'txtName' ] ); 7 8 // Sanitize message input 9 $message = stripslashes( $message ); 10 // mysqli_real_escape_string转义部分特殊字符,影响\x00、\n、\r、\、'、"、\x1a 11 $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)) ? "" : "")); 12 13 // Sanitize name input 14 // mysqli_real_escape_string转义部分特殊字符,影响\x00、\n、\r、\、'、"、\x1a 15 $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)) ? "" : "")); 16 17 // Update database 18 $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; 19 $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>' ); 20 21 //mysql_close(); 22 } 23 24 ?>
实践: 也就是说可以放心使用script注入代码
如注入代码: <script>alert(document.domain)</script> 获取域名
Middle:
老规矩先看源码:
其中message修改了3点:
1、strip_tags()函数剥去字符串中的HTML、XML以及PHP的标签,但允许使用标签。
2、addslashes() 函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串。
3、htmlspecialchars()函数是使用来把一些预定义的字符转换为HTML实体,&转换为&, "转换为", <转换为<>, 转换为>
而 name 只是简单的对<script>标签做了限制,存在注入点
1 <?php 2 3 if( isset( $_POST[ 'btnSign' ] ) ) { 4 // Get input 5 $message = trim( $_POST[ 'mtxMessage' ] ); 6 $name = trim( $_POST[ 'txtName' ] ); 7 8 // Sanitize message input 9 // 函数剥去字符串中的HTML、XML以及PHP的标签,但允许使用标签。addslashes() 函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串。 10 $message = strip_tags( addslashes( $message ) ); 11 $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)) ? "" : "")); 12 // &转换为&, "转换为", <转换为<>, 转换为> 13 $message = htmlspecialchars( $message ); 14 15 // Sanitize name input 16 // 简单过滤了<script>标签,存在注入点 17 $name = str_replace( '<script>', '', $name ); 18 $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)) ? "" : "")); 19 20 // Update database 21 $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; 22 $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>' ); 23 24 //mysql_close(); 25 } 26 27 ?>
实践:
1、将name标签中maxlength属性改大(原10个字符长度, 修改为100)
2、构造js代码<scr<script>ipt>alert(document.cookie)</script> 或者<ScriPt>alert(document.cookie)</script>, 多重标签或大小写绕过
High:
老规矩先看源码:
message 的代码与middle级别一致,没做修改
name 也对<script>标签严格过滤,但是其他标签没做过滤。毕竟其他标签也是可以写js的
1 <?php 2 3 if( isset( $_POST[ 'btnSign' ] ) ) { 4 // Get input 5 $message = trim( $_POST[ 'mtxMessage' ] ); 6 $name = trim( $_POST[ 'txtName' ] ); 7 8 // Sanitize message input 9 // 函数剥去字符串中的HTML、XML以及PHP的标签,但允许使用标签。 10 $message = strip_tags( addslashes( $message ) ); 11 $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)) ? "" : "")); 12 // &转换为&, "转换为", <转换为<>, 转换为> 13 $message = htmlspecialchars( $message ); 14 15 // Sanitize name input 16 // 对script做了严格校验 17 $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name ); 18 $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)) ? "" : "")); 19 20 // Update database 21 $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; 22 $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>' ); 23 24 //mysql_close(); 25 } 26 27 ?>
1、将name标签中maxlength属性改大(原10个字符长度, 修改为100)
2、构造标签代码<img > <iframe>等, 例如:<img src=1 one rror="alert(document.cookie)" style="display:none" /> 和<iframe src=1 onl oad="alert(document.cookie)" style="display:none" />。 style中display:none 为不显示,可以降低被发现的机率。
Impossible:
查看源码:
message和name的校验代码与middle级别修改一致。暂无法注入。
如果有哪位老兄想到了方法,还请不吝在评论留言。