header("Content-Type: text/plain; charset=utf-8");
mysql_connect("localhost","root","root");
mysql_select_db("test");
$row = mysql_fetch_array(mysql_query("SELECT * FROM users where uid < 100 ORDER BY uid limit {$_GET['p']}, 10"));
if($row){
var_dump($row);
}else{
echo mysql_error();
}
在mysql中新建test库,新建users表,并插入数据
order by limit注入方法适用于<=MySQL 5.5中,在limit语句后面的注入
SELECT * FROM table WHERE id > 0 ORDER BY id LIMIT injection_point
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name' export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]
procedure
和into
,先了解这两个函数是做什么的procedure:存储过程;
SELECT....PROCEDURE
指定了一个procedure,用于处理结果集中的数据
存储过程是一组为了完成特定功能的 SQL 语句集合。使用存储过程的目的是将常用或复杂的工作预先用 SQL 语句写好并用一个指定名称存储起来,这个过程经编译和优化后存储在数据库服务器中,因此称为存储过程。
into:SELECT...INTO
用来将查询结果存储在变量或者写入文件中。
SELECT…INTO var_list,将查询结果存储在变量中;
SELECT…INTO OUTFILE 将查询结果写入一个文件,还可以指定列和行终止符以生成特定的输出格式。
SELECT…INTO DUMPFILE 将单行数据写入文件,没有任何格式。
SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max_elements,[max_memory]])
ANALYSE ()
通过分析select查询结果对现有的表的每一列给出优化的建议,好像和我们注入没什么关系,在本地MySQL下进行尝试SELECT * FROM users where uid > 0 ORDER BY uid LIMIT 1,1 PROCEDURE ANALYSE(1,1);
SELECT * FROM users where uid > 0 ORDER BY uid LIMIT 1,1 PROCEDURE ANALYSE((select IF(MID(version(),1,1) LIKE 5, sleep(5),1)),1);
SELECT * FROM users where uid > 0 ORDER BY uid LIMIT 1,1 PROCEDURE ANALYSE(EXTRACTVALUE(1,CONCAT(0x3e,VERSION())),1);
magic_quotes_gpc函数在php中的作用是判断解析用户提示的数据,如包括有:post、get、cookie过来的数据增加转义字符“\”,对POST、GET以及进行数据库操作的sql进行转义处理,以确保这些数据不会引起程序,特别是数据库语句因为特殊字符引起的污染而出现致命的错误。防止sql注入
当magic_quotes_gpc = On时,输入数据中含单引号(’)、双引号(”)、反斜线(\)与 NULL(NULL 字符)等字符,都会被转义
注意:这个特性在PHP5.3.0中已经废弃并且在5.4.0中已经移除了,如果使用5.4之前的版本可以修改php.ini配置文件
//连接数据库部分,注意使用了gbk编码,把数据库信息填写进去
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES 'gbk'");
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE id='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error()); //sql出错会报错,方便观察
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>新闻</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "{$row['title']}
{$row['content']}
\n"
;
mysql_free_result($result);
?>
</body>
</html>
SELECT * FROM news WHERE tid='{$id}'
,就是根据文章的id把文章从news表中取出来。在这个sql语句前面,我们使用了一个addslashes函数,将$id
的值转义。这是通常cms中对sql注入进行的操作,只要我们的输入参数在单引号中,就逃逸不出单引号的限制,无法注入。由于我设置的id类型为int型,1'
在比较时转为数字变成了1,所以下图中依然查询到了结果'
变成\'
,让引号变得不再是“单引号”,只是一撇而已。一般绕过方式就是,想办法处理\'
前面的\
:1.想办法给
\
前面再加一个\
(或单数个即可),变成\\'
,这样\
被转义了,'
逃出了限制
2.想办法把\
弄没有。
%df'
看会怎样:\
也就是%5c变成了一个汉字“綅”,而'
逃逸了出来。因为两个字节代表一个汉字,所以我们可以试试添加%df%dfset names gb2312
修改测试是否可以进行宽字节注入0xA1~0xF7
,低位范围是0xA1~0xFE
,而\
是0x5c,是不在低位范围中的。所以,0x5c
根本不是gb2312中的编码,所以自然也是不会被吃掉的。所以,把这个思路扩展到世界上所有多字节编码,我们可以这样认为:只要低位的范围中含有0x5c
的编码,就可以进行宽字符注入。mysql_real_escape_string
会转义sql语句中特殊字符,并考虑当前字符集addslashes
替换成mysql_real_escape_string
来抵御宽字符注入,接下来,将代码中的 addslashes替换,进行测试mysql_set_charset
函数,设置当前连接的字符集为gbk。mysql_set_charset
函数设置连接字符集,在调用mysql_escape_string
过滤用户输入来修复宽字符注入addslashes
过滤,我们也不可能一个一个取修改。我们第二个解决方案是:将character_set_client
设置为binary(二进制),只需要在所有sql语句中执行一下语句:SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary
charac_set_client
,使用charac_set_client
进行解码,然后通过character_set_connection
编码,然后进入具体表和字段后,在转换为字段对应的编码,当查询结果产生后,会从表和字段的编码,转换成character_set_results编码,返回给客户端。