判断是否存在注入
http://192.168.81.210/sqli/Less-3/?id=1’
输入单引号发现页面出现了报错,从出现报错这一点来说就可以确定存在注入了。因为正常的情况下,我们输入的内容数据库应该将查询结果返回给用户,有或者没有,而这里将sql语法错误给爆出来了。出现的sql语法报错它的查询语句类似于
select user from users where id ='1'' limit 0,1
我们插入的单引号跟前面的单引号闭合了,后面多了一个单引号,所以会出现报错。根据报错信息猜测后端的查询语句
select user from users where id =('$id') limit 0,1
将其拿到数据库里执行也可以发现报错信息是一样的(这里的查询仅为测试我们猜测的查询语句是否会报错)
判断注入类型
根据上一个步骤猜测出来的查询语句,然后构造语句判断注入的类型,输入1) and 1=1
和1) and 1=2
,发现页面都有返回内容,因此可以判断注入类型不是数字型,属于字符型注入,为什么可以由此判断出?
- and 逻辑与
当条件表达式两边都为真才是真,有一边为假则是假
从下方图中可以发现,当and有一边为假的时候,是没有返回内容的
回到题目,我们输入两条语句发现都有返回内容,那么它的查询语句应该属于
select user from users where id = ('1 and 1=1')limit 0,1
select user from users where id = ('1 and 1=2') limit 0,1
被当成了一个整体查询。从下方图中的4条语句对比可以发现,当语句是字符型查询(第三条、第四条)的时候,会忽略后面的字符串。所以由此可以判断注入类型是字符型注入。
判断查询列数
ORDER BY 语句用于根据指定的列对结果集进行排序。
当order by的数字大于当前的列数时候就会报错,sql注入利用这个特性来判断列数
输入1') order by 4--+
和1') order by 3--+
发现等于3的时候正常,等于4的时候报错,由此可以知道一共有三列。可以使用二分法进行判断,即第一次可以是order by 1,第二次可以是order by 10。如果都是正常的则在10的基础上x2;如果不正常则在10的基础上/2也就是order by 5,如果5正常6不正常,则列数为6列。
- --+ 注释符
把select a from b where id=('1') order by 4--+') limit 0,1
中的' limit 0,1
给注释掉
确定显示位
什么是显示位?在一个网站的正常页面,服务端执行SQL语句查询数据库中的数据,客户端将数据展示在页面中,这个展示数据的位置就叫显示位。
这里可以使用union
操作符
- UNION 操作符用于合并两个或多个 SELECT 语句的结果集
- UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名,并且UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
这里虽然查询的123都可以查询到,但是回到程序里查询1') union select 1,2,3--+
可以发现并没有查询到123,这里的123实际上就是前面的order by 3这是因为程序在展示数据的时候通常只会取结果集的第一行数据,所以,只要让第一行查询的结果是空集,即union左边的select子句查询结果为空,那么union右边的查询结果自然就成为了第一行,打印在网页上了
从上图可以发现,查询的123只有23显示,所以想要查询数据就需要将想要查询的内容填充到2,3里
获取数据
获取数据库名
查询当前数据库select database();
问题来了,在sql注入中如何查询当前的数据库名呢?只需把database()填充到2或3里
-1') union select 1,2,database()--+
就可以查询到数据库名了,获取到数据库后就可以查询它的表名
获取表名
mysql5.0以上, Mysql自带了Information_schema这个数据库, 5.0以下是没有的,information_schema 数据库跟 performance_schema 一样,都是 MySQL 自带的信息数据库。其中 performance_schema 用于性能分析,而 information_schema 用于存储数据库元数据(关于数据的数据),例如数据库名、表名、列的数据类型、访问权限等。
实际运用
select table_name from information_schema.tables where TABLE_SCHEMA='dvwa';
select column_name from information_schema.columns where table_name='users';
所以可以根据这个特性来获取表名,
-1') union select 1,2,table_name from information_schema.tables where table_schema='security'--+
可以发现查询到了emails
数据表,但是一个数据库里肯定不止个数据表,可以发现security这个数据库里除了emails表之外,还有referers
,uagents
,users
表如何将这几行数据一起获取呢?这里需要用到
group_concat()
函数
- 将多行合并成一行
获取当前数据库全部数据表-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
,这里的security
数据库名、表名等的字符串表示,需要用单引号、双引号包裹住,或者可以使用对应的的十六进制的形式。
获取列名
获取某个数据表的所有列名-1') union select 1,2,(group_concat(column_name)) from information_schema.columns where table_name='emails'--+
获取最终数据
-1') union select 1,2,group_concat(id,email_id) from emails--+