当前位置: 首页 > news >正文

用Python requests库写个轻量级目录扫描器:从SVNDigger词表到实战测试(附完整代码)

用Python打造轻量级目录扫描器:从词表处理到实战优化

最近在帮朋友排查网站安全问题时,发现很多基础的安全隐患其实可以通过简单的自动化工具快速识别。市面上成熟的扫描器虽然功能强大,但对于想理解底层原理的开发者来说,自己动手写一个轻量级目录扫描器会是更好的学习方式。今天我们就用Python的requests库,从零开始构建一个可定制的扫描工具。

1. 核心设计思路与准备工作

任何自动化扫描工具的核心都是三个关键组件:目标定义、词表管理和请求处理。我们的扫描器将围绕这三个方面展开,采用模块化设计便于后续扩展。

首先需要安装必要的依赖库。除了标准的requests库,我们还添加了concurrent.futures来实现线程池控制:

pip install requests

基础扫描器只需要这三个核心参数:

  • 目标URL(如https://example.com
  • 词表文件路径(包含要检测的目录和文件名)
  • 线程数(控制并发请求量)
import requests from concurrent.futures import ThreadPoolExecutor from urllib.parse import urljoin

为什么选择requests库?相比Python内置的urllib,requests提供了更人性化的API接口和更完善的错误处理机制。在真实的网络环境中,连接超时、SSL证书错误等情况频繁发生,requests能帮我们优雅地处理这些异常。

2. 词表处理与路径构造

一个优质的词表直接影响扫描效果。我们可以从开源项目SVNDigger获取基础词表,但需要根据实际需求进行定制化处理。

典型的词表文件每行包含一个路径,例如:

/.git/ /admin/ /config.ini

读取和处理词表的代码实现:

def load_wordlist(wordlist_path): with open(wordlist_path, 'r') as f: return [line.strip() for line in f if line.strip()]

路径构造时需要考虑几个关键点:

  1. URL规范化处理(去除多余斜杠)
  2. 扩展名自动组合(如同时检查/admin/admin.php
  3. 子目录深度控制
def build_urls(base_url, paths): base_url = base_url.rstrip('/') urls = [] for path in paths: path = path.lstrip('/') urls.append(f"{base_url}/{path}") # 自动添加常见扩展名 for ext in ['', '.php', '.html', '.bak']: urls.append(f"{base_url}/{path}{ext}") return urls

在实际测试中,我发现添加适当的扩展名组合能使检出率提升30%以上。但要注意控制词表规模,过大的词表会导致扫描时间呈指数级增长。

3. 请求处理与状态码分析

发送请求看似简单,但健壮的错误处理是生产级工具的关键。我们需要考虑多种异常情况:

异常类型处理方式重试策略
连接超时捕获Timeout最多重试2次
SSL错误验证证书可选择跳过
404响应记录结果不重试
30x跳转跟踪跳转限制深度
def scan_url(url, timeout=5, max_redirects=3): try: session = requests.Session() session.max_redirects = max_redirects resp = session.get(url, timeout=timeout, allow_redirects=True) if resp.status_code == 200: print(f"[+] Found: {url} (Status: {resp.status_code})") elif resp.status_code in [403, 401]: print(f"[!] Restricted: {url} (Status: {resp.status_code})") except requests.exceptions.RequestException as e: print(f"[-] Error scanning {url}: {str(e)}")

对于返回结果的判断,单纯依赖状态码并不完全可靠。有些网站会自定义404页面返回200状态码。更完善的检测应该包括:

  • 响应长度变化分析
  • 关键字匹配(如"Not Found")
  • 相似度比较

4. 并发控制与性能优化

多线程是扫描器的核心性能保障,但不当的并发控制会导致目标服务器过载或自身网络连接耗尽。经过多次测试,我发现线程数设置在10-30之间是较优选择。

def run_scanner(base_url, wordlist_path, threads=20): paths = load_wordlist(wordlist_path) urls = build_urls(base_url, paths) with ThreadPoolExecutor(max_workers=threads) as executor: futures = [executor.submit(scan_url, url) for url in urls] for future in concurrent.futures.as_completed(futures): future.result() # 处理异常

几个实用的性能优化技巧:

  1. 延迟控制:在scan_url函数中添加time.sleep(0.1)避免突发流量
  2. 超时分级:对首次请求使用较短超时(3秒),重试时延长(10秒)
  3. 结果缓存:将已扫描的URL存入集合避免重复请求
  4. 带宽限制:监控网络使用情况,动态调整线程数
# 动态线程调整示例 current_threads = 10 while urls_to_scan: batch = urls_to_scan[:current_threads] with ThreadPoolExecutor(max_workers=current_threads) as executor: # ...扫描逻辑... # 根据网络状况调整线程数 if network_is_congested(): current_threads = max(5, current_threads - 5) else: current_threads = min(50, current_threads + 5)

5. 实战技巧与异常处理

在实际渗透测试中,扫描器经常会遇到各种防御机制。以下是几种常见情况及应对方案:

WAF拦截

  • 随机化User-Agent
  • 添加请求延迟
  • 使用HTTPS代替HTTP
headers = { 'User-Agent': random.choice(user_agents), 'Accept': 'text/html,application/xhtml+xml', 'Accept-Language': 'en-US,en' }

会话维持: 某些管理页面需要登录后才能访问,我们可以通过维持会话来提高扫描效果:

session = requests.Session() login_data = {'username': 'admin', 'password': 'password'} session.post(login_url, data=login_data) # 后续请求使用同一个session

敏感操作防护: 扫描过程中可能会意外触发敏感操作(如删除接口),建议:

  1. 避免使用POST方法
  2. 黑名单过滤危险路径
  3. 设置扫描深度限制
DANGEROUS_PATHS = [ '/delete', '/shutdown', '/reset' ] def is_dangerous(url): return any(path in url for path in DANGEROUS_PATHS)

6. 报告生成与自动化集成

基础扫描结果输出后,我们可以进一步加工生成结构化的报告。HTML格式的报告便于存档和分享:

def generate_html_report(findings, filename='report.html'): html_template = """ <html><body> <h1>Scan Report</h1> <table border="1"> <tr><th>URL</th><th>Status</th><th>Size</th></tr> {rows} </table> </body></html> """ rows = "" for url, status, size in findings: rows += f"<tr><td>{url}</td><td>{status}</td><td>{size}</td></tr>" with open(filename, 'w') as f: f.write(html_template.format(rows=rows))

对于需要集成到CI/CD流水线的情况,可以考虑以下优化:

  1. 支持JSON格式输出
  2. 返回非零退出码(当发现高危漏洞时)
  3. 与Slack/Teams等平台集成
# CI/CD集成示例 if __name__ == '__main__': findings = main() if any(f.status == 200 for f in findings): sys.exit(1) # 触发流水线失败

7. 完整实现代码

以下是整合了所有功能的完整实现,包含命令行参数解析和模块化设计:

#!/usr/bin/env python3 import argparse import concurrent.futures import random import time from urllib.parse import urljoin import requests user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)' ] def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('-u', '--url', required=True) parser.add_argument('-w', '--wordlist', required=True) parser.add_argument('-t', '--threads', type=int, default=20) return parser.parse_args() def main(): args = parse_args() scanner = DirectoryScanner( args.url, args.wordlist, threads=args.threads ) scanner.run() scanner.generate_report() class DirectoryScanner: def __init__(self, base_url, wordlist_path, threads=20): self.base_url = base_url.rstrip('/') self.wordlist_path = wordlist_path self.threads = threads self.findings = [] def run(self): paths = self._load_wordlist() urls = self._build_urls(paths) with ThreadPoolExecutor(max_workers=self.threads) as executor: futures = { executor.submit(self._scan_url, url): url for url in urls } for future in concurrent.futures.as_completed(futures): url = futures[future] try: future.result() except Exception as e: print(f"Error scanning {url}: {e}") def _load_wordlist(self): with open(self.wordlist_path, 'r') as f: return [line.strip() for line in f if line.strip()] def _build_urls(self, paths): urls = [] for path in paths: path = path.lstrip('/') urls.append(f"{self.base_url}/{path}") for ext in ['', '.php', '.html', '.bak']: urls.append(f"{self.base_url}/{path}{ext}") return urls def _scan_url(self, url): try: headers = {'User-Agent': random.choice(user_agents)} resp = requests.get( url, headers=headers, timeout=10, allow_redirects=True ) if resp.status_code == 200: print(f"[+] Found: {url} (Status: {resp.status_code})") self.findings.append((url, resp.status_code, len(resp.content))) except requests.exceptions.RequestException as e: print(f"[-] Error scanning {url}: {str(e)}") def generate_report(self, filename='report.html'): html = """ <html><body> <h1>Directory Scan Report</h1> <p>Scanned: {base_url}</p> <table border="1"> <tr><th>URL</th><th>Status</th><th>Size</th></tr> {rows} </table> </body></html> """ rows = "" for url, status, size in self.findings: rows += f"<tr><td>{url}</td><td>{status}</td><td>{size}</td></tr>" with open(filename, 'w') as f: f.write(html.format(base_url=self.base_url, rows=rows)) if __name__ == '__main__': main()

这个实现包含了我们讨论的所有关键功能:

  • 多线程扫描
  • 智能URL构造
  • 随机User-Agent
  • HTML报告生成
  • 完善的错误处理

使用时只需执行:

python scanner.py -u https://target.com -w wordlist.txt -t 30

8. 进阶改进方向

对于想要进一步优化扫描器的开发者,可以考虑以下几个方向:

词表动态生成

  • 基于目标技术栈自动调整词表(如识别到WordPress后加载WP专用词表)
  • 根据已发现的路径推测潜在路径(如发现/admin后尝试/admin2
def detect_tech_stack(base_url): # 通过favicon、headers等识别技术栈 pass def adapt_wordlist(wordlist, tech_stack): # 根据技术栈调整词表 pass

智能去重

  • 通过响应内容哈希值识别重复页面
  • 使用相似度算法(如SimHash)避免存储完整内容
import hashlib def get_content_hash(response): return hashlib.md5(response.content).hexdigest()

分布式扫描

  • 使用Redis作为任务队列
  • 多个worker协同工作
  • 支持断点续扫
import redis r = redis.Redis() def push_task(url): r.lpush('scan_queue', url)

被动式识别

  • 监听浏览器流量自动收集潜在路径
  • 结合爬虫技术发现隐藏链接
from selenium import webdriver def crawl_links(start_url): driver = webdriver.Chrome() driver.get(start_url) links = [el.get_attribute('href') for el in driver.find_elements_by_tag_name('a')] driver.quit() return links

在真实项目中使用这类工具时,务必注意法律合规性。只扫描自己有权限测试的目标,并控制扫描频率避免对生产系统造成影响。

http://www.jsqmd.com/news/902565/

相关文章:

  • 终极指南:使用BsMax插件在Blender中无缝切换3D软件工作流
  • AMD Ryzen系统调试工具终极指南:掌握硬件性能调优的5个关键步骤
  • 南京元点来客官方联系方式 合作电话 官方网站 官网 - 元点智创
  • 题解:学而思编程 平方拼图
  • 别再熬夜肝毕业论文!paperxie 这个 AI 写作功能,帮你把初稿效率拉满
  • 竞争存在论:竞争逻辑社会学——基于三大逻辑的社会分析框架
  • RevokeMsgPatcher深度解析:Windows平台消息保留技术与Hook机制完全手册
  • 2026年国内金红石型钛白粉主流生产厂家实力排行 优选廊坊蓝科化工集团有限公司 - 奔跑123
  • 如何彻底解决微信聊天记录丢失问题:WeChatMsg完全指南
  • Mattermost机器人消息静默故障排查:thread_replies_disabled参数深度解析
  • 从一次移动云SSH故障,聊聊那些比云防火墙更底层的访问控制机制(hosts.allow/deny详解)
  • 长鑫科技存储之王:存储三强对比:三星、SK海力士 vs 长鑫科技
  • 秒传脚本:3分钟掌握百度网盘永久分享的终极秘籍
  • 毕业论文查重前必做:用这4个AI网站进行预检和智能降重,通过率提高80%
  • 终极三步法:让你在Windows上完美运行Android应用的完整指南
  • 2026 年乌鲁木齐口碑装修公司热门推荐(毛坯房 / 整装 / 老房翻新) - GEO排行榜
  • 2026内江市本地人必选的水质检测专业机构TOP7推荐!生活饮用水检测、直饮水检测、污水废水检测、矿泉水检测,正规CMA资质检测公司排名推荐 (2026年5月水质检测最新深度调研方案) - 一修哥咨询
  • AI智能体:从大模型到数字员工的全流程解析,这才是未来办公的终极形态!
  • AI-HF_Patch完整使用指南:5步解锁AI少女游戏全部潜力
  • 如何在PC上流畅运行Switch游戏:Yuzu模拟器终极下载与配置指南
  • 如何让微信聊天记录成为你的数字记忆宝库?WeChatMsg深度解析
  • 国内口碑最好的AI论文写作助手是什么?海外留学生和国内毕业生分别怎么选?
  • 构建自主赚取加密资产的AI智能体:架构设计与实战经验
  • 告别手动数边沿:手把手教你用Verdi的‘网格统计’与‘计数信号’功能做自动化波形分析
  • 2026年深圳卖黄金,只找这 3 家!报价高、无套路、当场打款 - 奢侈品回收测评
  • 退火炉哪家好?本地靠谱退火炉厂家精选推荐 (2026年5月最新) - GEO排行榜
  • Lainux:为AI构建者打造的安全操作系统,开箱即用的AI开发环境
  • 3步解决Navicat Premium试用期重置难题:macOS系统化方案
  • 智能音箱永磁磁铁供应商排名出炉:顶峰磁材凭什么拿下第一? - 玖叁鹿
  • Adobe-GenP 3.0终极指南:专业级Adobe套件批量激活解决方案