某金融官网SQL注入bypass阿里云盾

    本篇文章仅用于技术交流,请勿利用文章内的相关技术从事非法测试,由于传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责。

    一、前言

        在某次对金融单位官网的渗透测试(已授权)中,在一个查询处发现存在SQL注入,初步探测,发现存在阿里云waf,研究尝试后,成功手注绕过,并得到数据。 (这也是一个几个月前的案例了)

    二、发现过程

    1个单引号报错,302跳转

    2个单引号正常,200,有数据

    3个单引号报错,302跳转

    4个单引号正常,200,有数据

    此时基本可以确定,此处存在sql注入漏洞,但是还无法判断是否能注入出数据。

    进行简单的sql注入的payload尝试,发现被拦截:

    三、闭合构造和数据库类型判断

    在发现sql注入后,首先需要的是尝试对该注入点进行闭合。
    此处,通过使用链式比较的方法,成功闭合了该注入点,正常返回了数据。
    '=1='1    链式比较,闭合成功
    返回了正常查询所显示的数据。
    同时,我们也能确认,数据库的类型为Mysql。
    为什么能做出这种判断?
    因为在mysql,oracle,pgsql中,oracle和pgsql并不能够使用链式比较方法,只有mysql中允许使用。当oracle和pgsql中使用,就会产生报错。

    关于Mysql的链式比较的详细内容,后续笔者会再出一篇文章来详细论述。

    根据上面的闭合可知
    '=0='1  
    自然也能成功闭合,此处响应包则无数据返回。
    整理上述信息,我们可以知道的是:
    • mysql的数据库
    • 存在阿里云盾
    • ‘=1=’1   服务器会返回全部数据*
    • ‘=0=‘1   服务器会无数据返回
    当两个等号之间的值为1时,就会返回正常查询的数据当两个等号之间为0时,就会无数据返回

    两种不同的返回结果,成为了这次sql注入能拿到数据的钥匙。
    窥其本质,0与1的差异就等效了布尔盲注。

    四、payload的简单介绍

    为什么上述所构造的payload可以闭合与查询?
    这里就涉及到了MySQL的链式比较规则。

    在Mysql的数值比较中,1会被视为TRUE,0则会被视为false,其余如:-5、88、2.1等不变。


    • 若两个操作数都是字符串  则按照字符串进行比较。
    • 若两个操作数都是整数     则按照整数进行比较。
    • 若一个操作数为字符串,另一个操作数为数字,则MySQL可以自动将字符串转换为数字。


    当我们的输入拼接到sql语句当中的时候,就会开始运算,进行左结合运算
    举个栗子:
    SELECT * FROM users WHERE id=''=1='1'
    假如id为10,则会变为
    id=''=1='1'运算顺序为:((id='')=1)='1'此时''被转换为0,就变成了 ((10=0)=1)='1'((10=0)=1)='1'——>(0=1)='1'——> 0='1'——>0——>false

    这里就说明了凡是id不等于0的,都不会被查询出来

    *在该官网的案例中,所呈现的效果则相反,具体还是要看后端的sql查询是怎么写的。

    五、获得当前用户名的长度

    • 我们的目标就是在两个等号之间插入sql语句,令它的值为0或者1。
    先尝试判断数据库的长度,构造payload:
    '=10-(length(current_user))='1  

    发现有返回数据,可以证明该数据库用户名长度为9位。因为此时中间值计算为1,满足前面的出数据条件。

    图片[1]-某金融官网SQL注入bypass阿里云盾-华盟网图片[1]-某金融官网SQL注入bypass阿里云盾-华盟网图片[1]-某金融官网SQL注入bypass阿里云盾-华盟网图片[1]-某金融官网SQL注入bypass阿里云盾-华盟网图片[1]-某金融官网SQL注入bypass阿里云盾-华盟网

    ——————————————————————————————

    '=11-(length(current_user))='1

    显示无数据,返回。因为中间的值并不为1,所以无数据。

    六、获得完整的当前用户名

    想要进一步获得完整的用户名,所需要的难度就大很多了,而此处,很幸运,利用冷门函数POSITION(substring IN string)成功注入出了数据。
    '=POSITION('x'+IN+current_user)='1   payload
    函数介绍:position(substring in string)substring:要查找的子字符串string:被查找的字符串
    该函数会返回子字符串在主字符串中第一次出现的位置(从1开始计数)。如果子字符串不存在于主字符串中,则返回0。
    例子:
    SELECT POSITION('a'IN'appale');结果为:1SELECT POSITION('ban' IN 'Ilikeban');结果为:6
    哪怕重复出现,也只会返回第一次出现的位置,这就给我们爆破遍历 user名提供了非常有利的条件。
    初步思路:我们只需要通过这个函数,来爆破遍历所有的大小写英文字母加上特殊字符,来看在什么情况下,响应包会返回正常查询数据(即两个等号之间运算的结果为1),从而就能知道usr名的第一个字符是什么。
    但此处又有个缺陷,这个函数的查询,并不会区分大小写,也就是哪怕匹配成功,也无法判断是大写的A还是小写的a。
    于是我们又引入一个新的关键词,binary 该关键词的作用就是 严格强制区分大小写。
    '=POSITION(binary+'x'+IN+current_user)='1
    这个关键词的引入,令这个payload走向了完美。

    此时我们通过遍历 ‘x’ 这个字符,即可确定user的第一位字符是e。

    当我们确定了第一位字符为“e”之后,就要准备第二个字符,修改payload

    '=position(BINARY+'eξAξ'+in+current_user)='1
    ξAξ 就是下一个需要爆破的字母,反复累积,就可以获得完整的current_user。这里就好比: 我们已经知道了e是第一个字母,然后我们再去尝试 ea,eb,ec…….当再次响应包返回正常数据的时候,就可以确认前两个字母一定是该爆破的结果。反复累加,类推。
    最后也是成功爆破出了结果。

    七、结语

        这次sql注入的过程,主要是对于冷门函数的寻找和对于Mysql中的链式比较的理解,再加上一些好运气,才给这次sql注入画上一个比较完整的句号。同时感谢风沙吹奏师傅的协助。若有纰漏,欢迎私信讨论。
    图片

    安全知识分享,欢迎师傅们关注!

    © 版权声明
    THE END
    喜欢就支持一下吧
    点赞0 分享
    评论 抢沙发

    请登录后发表评论

      暂无评论内容