赞
踩
书接上文(有没有一种熟悉的味道),来看存储型XSS,这个最常见,也最好理解。
数据库里的一条数据显示了出来。
我们输入一些东西,下方又会多出来一条数据:
如果重新加载页面,仍旧有这两条数据。这就是存储型,输入数据会被存入数据库,网页每次被打开,都会从数据库里调出显示。
这个像什么?对,就是我们文章下面的评论系统,文章所有的评论会被存进数据库,每一个浏览此文章的人,都能看到所有的评论。
试想,如果有人使坏,写了一段脚本存进数据库了呢?
先点击ClearGuestbook,清空一下。
在message中注入:<script>alert("This is low level")</script>
sign之后:
内容成功显示。
我们先点击一下其他页面,再点回来:
成功被触发了。试想如果我们的评论全是这东西,每个点进来的人,都要先被来一番“信息轰炸”,才能看到想要的界面,搞不好这之前自己的个人信息已经被泄露了出去。
来查看下后台源码:
- <?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()函数,删除掉一些字符,如果第二个参数不指定。则删去:\n, \t, \0, \X0B, \r, space。
stripslashes(),去除字符串中预定义字符之前的反斜杠。对应的,还有一个addslashes,对于一个string = stripslashes( addslashes( string ) )。
其实上面的代码只是对接收到的两个参数删除了一些不必要的信息,加上去除转义的效果。并没有对数据内容进行检测,然后直接进行了insert into:
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
这就是问题所在,来看看medium等级的。
view source:
- <?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,xml,php标签。
htmlspecialchars()函数。前面谈到过,对html中一些预定义字符进行实体化,包括&,',",<,>。
(PS:这就是对XSS的预防,一定要对用户输入进行检测。上面两个函数使用到的话,基本就没戏了。)
message没戏了,看下name参数的处理。
Nice,只是对输入数据过滤了“<script>”字符串。(替换为空)
通过前面我们的绕过姿势,应该没什么问题了吧。基本的两种方法:1.调整大小写;2.复写。
我这里选择第一种演示:
数据输入过程中,你会发现一个问题。Name只能输入10个字符,再多输不进去了。急了个满头大汗,以为键盘坏了,砸了个粉碎。过了会发现冤枉键盘了,因为message还可以继续输入。
(上面的是扯皮)好多地方提到过一句话:“一切在前端的限制,都不是限制。”
因为这个东西是可以修改的。一般有两种通常使用的做法:1.抓包(俚语,专业一点,或许应该称为“截获报文”),修改参数;2.直接在前端修改限制。
我挑个操作简单的,选第二种。
在Name输入框旁边,右键检查。找到限制属性maxlength,直接右键Edit attribute,改成100
修改完毕后按回车:
继续注入:
Name不再受限制了。
sign进数据库。
现在有了两条数据,点击目录中的其他页面,再点击回来(或者直接右键,重新加载页面。但是会又一次的注入)。
低等级提示。
确定后,中等级提示。
致此,知道为何会被称为存储型了吧。
再来看看高等级的呗,也很简单,前面我们见过:
- <?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的处理没变,所以还是没戏。
看name,换成了preg_replace()来正则匹配包含<script的内容(如果了解正则表达式,很好看懂),且不区分大小写。换句话说,对字符串的复写和调整大小,全部没用了。
我们前面遇到过呀。不让用“script”,我们还有img和body。
清空一下。
img注入:<img src=1 οnerrοr=alert("high") />(当然不要忘记,解除name输入长度的限制)
sign进数据库:
显然,成功了。
重新加载页面:
脚本被激活。
impossible等级呢?不说应该也猜到了,对name进行和message同样的处理。
- <?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();
-
- ?>
在update database阶段还进行了预处理,感兴趣的小盆友可以去查询了解下。
连先前high等级注入的XSS,也被实体化后显示了出来:
完。(虽然很突兀,但是真的完了。)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。