文章目录
0x00 前言
最近开始了有关数据库的课程,又想到 ctf 中也有这方面的题目(虽然好像难度高的题的难点都不在sql上),感觉 web 也是需要了解一下,于是看起了 《CTF特训营》的 web 部分,顺便写一下相关的 sql 注入的笔记,不得不说大佬队伍的书还是挺好的,有一定基础的时候去看感觉能学到许多,即便不是很理解还是可以拓展一下见识。由于只是初步的认识,我的个人理解可能和实际有所偏差,期望大师傅们可以多加指正。
0x01 简单的分类
SQL 注入可以分为可回显、不可回显和二次注入三种类型。
可回显:可以联合查询的注入、报错注入、注入DNS请求来达到可回显的目的。
不可回显:布尔盲注、时间盲注。
二次注入:二次注入。
0x02 可回显的注入
一、联合查询注入
(这个应该是最简单的注入了吧)如果数据库的查询结果会直接回显到页面中,那么就可以尝试一下联合查询注入。
我们可以输入:
-1'union+select+1+--+
则 php 中
$getid ="SELECT ld FROM users WHERE user_id = '$id'";
会变成
SELECT ld FROM users WHERE user_id = '-1'union select 1 --'
playload 中的单引号会和前面的单引号形成一个闭合,而两个减号作为注释符将最后面的引号注释了,就形成了一个 SQL 注入,而利用到了 union 语句,所以称之为联合查询注入。同时传入参数的 “+” 在查询语句中消失的原因时服务器自动将加号转义为空格了。
注释符号:–、--+、#
二、报错注入
这个要求注入点有SQL报错信息,下面介绍三种MySQL数据库的报错注入方法:updatexml、floor 和 exp。
1、updatexml
这种报错注入的方式实质上就是函数报错,然后得到函数报错的回显。
关于 updatexml ()
函数:
UpdateXML(xml_target,xpath_expr,new_xml)
#xml_target: 需要操作的 xml 片段
#xpath_expr: 需要更新的 xml 路径(Xpath格式)
#new_xml: 更新后的内容
具体作用:此函数用来更新选定 XML 片段的内容,将 XML 标记的给定片段的单个部分( xml_target )替换为新的XML片段 new_xml ,然后返回更改后的 XML 。xml_target 替换的部分 与 xpath_expr 用户提供的 XPath 表达式匹配。如果 xpath_expr 未找到表达式匹配 ,或者找到多个匹配项,则该函数返回原始 xml_targetXML 片段。所有三个参数都应该是字符串。当Xpath路径语法错误时,就会报错,报错内容含有错误的路径内容,我们也就可以利用这点得到数据库的信息。例子如下
其中
concat ()
函数作用为将多个字符串连接为一个字符串,而 “0x7e” 经过 sql 转义后为字符 “~” ,此处使用concat ()
函数的原因可能是想让被连接的函数能够成功调用。
2、floor
floor 报错的原理是 rand 和 order by 或 group by 的冲突。
关于 floor ()
函数:
floor ()
函数作用为向下舍入为指定小数位数。例子:
floor(1.156,0)= 1 #此意即为向下舍去(也就是只舍不入)小数,知道小数位数为 0 。
同样也有一个向上舍入的函数:
ceiling ()
;还有一个遵守四舍五入的函数:round ()
关于 rand ()
函数:
这是一个伪随机函数,可以返回一个0~1之间的数,但当指定了参数后,其返回的值是可以预测的,所以称之为伪随机函数。
关于 group by
语句:
这是一个 SQL 语句,可以对数据进行分组,例如:
select column_name_1 from table_name group by column_name_1;
#意为将表 table_name 中的 column_name_1 的数据,按照 column_name_1 的数据分类合计后显示。
关于 floor 报错注入:
select count(*) from test group by floor(rand(0)*2);
在上面的语句中,group by
语句分组合计时会建立一张虚拟表,而 count (*)
函数为其中的计数值;由于 rand () 函数在固定参数时所得到值时可预测的,floor(rand(0)*2) 可得到一个固定的序列 01101 ;group by 进行分组时,floor(rand(0)\*2)
执行一次(查看分组是否存在),如果虚拟表中不存在该分组,那么在插入新分组的时候 floor(rand(0)\*2)
就又计算了一次。
为什么
group by
在插入新的分组时rand ()
就一定会重新计算一遍值。原因是官方文档上说了会多计算一次。
#payload 利用方式:
and select count(*), concat((select database()), ‘-’, floor(rand(0)%2))x from information_schema.tables group by x;
#将select database()换成你想要的东西
#floor(rand(0)%2))x 将前者取了个别名 x
#上述注入可以爆出当前使用的数据库
3、exp
exp 报错的本质就是溢出错误
关于 exp ()
函数:
exp 函数就是以e为底的指数函数,但这个函数的参数大于 709 时会产生溢出而报错。
关于 exp 报错注入:
1' and exp(~(select* from (select user())x))%23
#select user() 执行后得到用户信息
#select * from...... 成功执行后会返回 0
#exp(~(......)) 利用 ~ 取反后,由于数字过大会产生报错
当函数成功执行时,一般会返回 0 ,再加上符号 “~” ,将 0 取反得到最大的无符号 int 数 (18446744073709551615)。
三、DNS 注入
通过我们构造的数据,访问搭建好的 DNS 服务器,查看 DNS 访问的日志即可获取我们想要得到的数据
使用场景:
在某些无法直接利用漏洞获得回显的情况下,但是目标可以发起请求,这个时候就可以通过 DNSlog 把想获得的数据外带出来。
感觉这个注入挺难的,总结起来都不知道怎么总结,还是看其他师傅的原理讲解吧:
0x03 不可回显的注入
一、布尔盲注
由于开发者屏蔽了报错信息,我们只能知道成功就跳转到正确页面,失败就跳转到错误页面。
关于注入的方法:
当注入为整型注入时,可以再输入点后面添加 and 1=1
和 and 1=2
来判定是否有布尔盲注。
如果存在布尔盲注,则
and 1=1
不会对结果产生影响,同时若是遇到将1=1
过滤的情况,可以使用不常见的数字等式。
如果注入为字符串型注入,需要注意单引号的闭合等问题。
书中含有一些注入常用函数可以了解一下,这里就不列出来了(P46)。
二、时间盲注
时间盲注出现的本质原因是由于服务器端拼接了 SQL 语句,但是正确和错误存在同样的回显。错误信息被过滤,不过,可以通过页面响应时间进行按位判断数据。
关于注入的原理:
其注入类似于布尔盲注,区别在于布尔盲注是根据返回页面的不同判断,而时间盲注是根据页面相应时间来判断结果的。与其相关的常见函数有 sleep ()
函数和 benchmark ()
函数,具体一些的利用方式书上在讲函数时也有讲(P49)。
0x03 二次注入
二次注入的起因是数据在第一次入库的时候进行了一些过滤及转义,当这条数据从数据库中取出来在SQL语句中进行拼接,而在这次拼接中没有进行过滤时,我们就能执行构造好的SQL语句了。
感觉这个不是我能简单的总结的了,还是看书上怎么写的吧(P50)。
0x04 其它的注入
一、宽字节注入
这种注入可以理解为:通过拼凑转义符("\"),来组成一个新的字。
关于注入产生的原因:
在 SQL 中有这样一个函数 addslashes ()
函数:会对单引号 ( ’ ),双引号 ( " ),斜杠 ( \ ) ,和 null 字符进行转义,就是在字符前添加一个转义符。
关于宽字节注入:
为了对付上面那个函数的问题,当数据库编码为 GBK 时,我们可以在这四个字符前添加 %df ,就可以使得 %df 和转义符拼接成一个新的字(在 GBK 中两个字节代表一个汉字),而后面那个单引号就逃逸了。例如:%df\’ = %df%5c%27 = 縗’
二、Cookie 注入 & base64 注入
感觉这位师傅写的很详细清楚了:cookie注入&& base64注入 原理详解_m0_46304840的博客-CSDN博客
三、XFF 注入攻击
还是这位师傅写的博客,挺好的:XFF头注入原理分析_m0_46304840的博客-CSDN博客