如果小结中有理解错误的地方,麻烦大家提出。漏洞本质: php 使用 php_escape_shell_cmd这个函数来转义命令行字符串时是作为单字节处理的而当操作系统设置了GBK、EUC-KR、SJIS等宽字节字符集时候,将 ...
<?php header('Content-type: text/html; charset=gbk'); //连接MySQL $conn = mysql_connect("localhost", "root", ""); //选择数据库 mysql_select_db("test", $conn); //设置字符集编码 mysql_query("SET CHARACTER SET 'gbk'", $conn); //创建DEMO表如果不存在 mysql_query("CREATE TABLE IF NOT EXISTS `demo` ( `uid` int(10) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL, `password` varchar(32) NOT NULL, PRIMARY KEY (`uid`) ) ENGINE=MyISAM DEFAULT CHARSET=gbk AUTO_INCREMENT=1;", $conn); //插入个测试数据 mysql_query("REPLACE INTO `demo` VALUES('','admin','admin888') ",$conn); //获取用户输入 $username = isset($_REQUEST['username']) ? $_REQUEST['username'] : ''; //执行查询并且DEBUG $sql = "SELECT * FROM demo WHERE username = '{$username}' LIMIT 1"; echo "sql: ".$sql." "; $res = mysql_query($sql, $conn); $row = mysql_fetch_array($res); echo "result: <br/>"; var_dump($row); ?>
当GPC=OFF时:
// 对用户传入的变量进行转义操作 if (!get_magic_quotes_gpc()) { $username = addslashes($username); }
看上去貌似没问题了,但是由于多字节编码问题,同样还是可以注入的
$sql = "SELECT COUNT(*) ". " FROM " . $ecs->table('admin_user') . " WHERE user_name = '" . trim($_REQUEST['username']). "' AND password = '" . md5(trim($_REQUEST['password'])) . "'";
我们来看下$_REQUEST['username'] 的获取过程
$_REQUEST['username'] = json_str_iconv($_REQUEST['username']); json_str_iconv()这个函数在includes/lib_base.php中定义,其功能是将非UTF-8编码的字符串进行转换,然后return ecs_iconv('utf-8', EC_CHARSET, $str); ecs_inonv这个函数也在 includes/lib_base.php中定义,看下函数吧: function ecs_iconv($source_lang, $target_lang, $source_string = '') { static $chs = NULL; /* 如果字符串为空或者字符串不需要转换,直接返回 */ if ($source_lang == $target_lang || $source_string == '' || preg_match("/[\x80-\xFF]+/", $source_string) == 0) { return $source_string; } if ($chs === NULL) { require_once(ROOT_PATH . 'includes/cls_iconv.php'); $chs = new Chinese(ROOT_PATH); } return $chs->Convert($source_lang, $target_lang, $source_string); }
先是引入了includes/cls_iconv.php这个文件,然后实例化了Chinese这个类,在调用类的Convert的方法见line 127 |