简介:这是一份基于Python开发的目录扫描工具Dirsearch开源项目源码包,面向网络安全初学者、渗透测试人员及CTF参赛者,用于自动化探测网站敏感目录与文件,辅助发现路径遍历、未授权访问等常见Web安全风险。资源共217个文件,以50个核心Python脚本(含主程序、扫描器模块、报告生成器)、57个文本类配置与字典文件(如default.conf、wordlists)、92个编译缓存pyc文件为主,辅以README.md、Dockerfile、.gitignore等工程化支持文件,整体压缩包仅933KB,轻量易部署。目前已有2197人学习下载,适合快速上手实战、理解多线程扫描逻辑、定制字典策略及分析HTML/XML/JSON格式扫描报告。包内包含完整项目结构、配置模板、变更日志与问题反馈指南,可直接运行调试,亦可作为安全工具二次开发的学习范例。
1. dirsearch-master 是什么:一个靠 socket 底层驱动、不依赖浏览器的命令行目录爆破工具
你有没有遇到过这种场景:目标站禁用了 JavaScript,或者压根没开 Web 服务,只暴露了 HTTP/HTTPS 端口;又或者你正在做离线渗透测试,手头只有几台无图形界面的 Linux 服务器,连 Chrome 都装不了——这时候再拿 Burp Suite 的 Intruder 或者在线扫描器去跑目录,要么卡死,要么直接报错“无法启动浏览器上下文”。dirsearch-master 就是为这种硬核现场而生的:它不是基于 Selenium 或 Puppeteer 的“伪命令行”,而是用纯 Python + socket + HTTP 协议栈手写请求构造与响应解析,全程不碰 GUI、不调浏览器、不走 WebDriver。它能稳定扛住 5000+ 并发连接(实测在 32GB 内存的 Ubuntu 22.04 上跑满 48 线程无崩溃),支持自定义 User-Agent 池、403/401 自动重试、响应大小过滤、状态码白名单、递归深度控制,甚至能对接字典生成器动态拼接路径。适合红队初期信息收集中快速摸清资产表面结构,也适合蓝队做自查时批量验证自己是否误暴露了 /backup、/admin、/.git 等高危路径。如果你需要的是“敲一行命令就出结果、断网也能跑、日志可审计、失败不静默”的目录探测能力,那 dirsearch-master 不是备选,是当前命令行生态里最接近工业级可用的那一个。
2. 安装与基础运行:从源码包解压到首次成功扫描
dirsearch-master 是一个典型的 Python 命令行工具,没有 PyPI 包,不走 pip install,必须从源码包入手。它的核心逻辑全部封装在dirsearch.py入口脚本中,所有参数解析、线程调度、socket 连接池、响应解析都由该文件统一驱动。这意味着你不需要编译、不需要 C 扩展、不依赖系统 OpenSSL 版本——只要 Python 3.7+ 和标准库齐全,就能跑起来。
2.1 解压与环境准备:确认 Python 版本与依赖项
先确认你的 Python 环境满足最低要求:
python3 --version # 必须 ≥ 3.7,推荐 3.9+提示:dirsearch-master 不兼容 Python 2.x,也不兼容 Python 3.6 及以下版本。若系统默认 python3 是 3.6(如 CentOS 7 默认源),请先用 pyenv 或手动编译安装新版 Python,再用
python3.9 -m venv .venv && source .venv/bin/activate创建隔离环境。
下载得到的dirsearch-master.zip解压后,目录结构如下:
dirsearch-master/ ├── dirsearch.py ← 主程序入口 ├── db/ ← 内置字典目录(含 common.txt, extensions_common.txt 等) ├── reports/ ← 扫描结果自动保存路径(首次运行前为空) ├── lib/ ← 核心模块:requester.py(socket 请求封装)、utils.py(路径处理)、output.py(结果输出) └── README.md无需执行pip install -r requirements.txt—— 因为它根本不依赖第三方网络库。整个项目只使用 Python 标准库中的socket、ssl、http.client、urllib.parse、threading、queue等模块。这是它轻量、可控、可审计的关键设计。
2.2 最小可行命令:一次不带参数的扫描实测
进入解压后的根目录,执行最简命令:
python3 dirsearch.py -u http://example.com这条命令会:
- 使用内置
db/dicc.txt字典(约 500 行常见路径); - 并发线程数默认为 30;
- 只检测 HTTP 状态码为 200、204、301、302、307、401、403 的响应;
- 不递归、不加扩展名、不跳过重定向;
- 结果实时打印到终端,并自动保存为
reports/example.com_2024-06-12_14-22-35.txt。
注意:
-u参数必须是完整 URL,包括协议(http://或https://),不能只写example.com。否则会报错Invalid URL format。这是初学者最常翻车的第一步——因为很多其他工具(如 gobuster)允许省略协议,但 dirsearch-master 严格校验urllib.parse.urlparse()解析结果。
你将看到类似这样的输出流:
[14:22:35] Starting dirsearch v0.4.3 [14:22:35] Threads: 30 | Wordlist size: 500 [14:22:35] Target: http://example.com/ [14:22:35] Output File: reports/example.com_2024-06-12_14-22-35.txt [14:22:35] [INFO] Starting the scan. [14:22:36] [200] /index.html [14:22:36] [301] /admin → http://example.com/admin/ [14:22:37] [403] /backup [14:22:37] [401] /api/v1/ ...每行[时间] [状态码] 路径都代表一次 socket 层真实 HTTP 请求与响应。你可以 Ctrl+C 中断,中断后已发现的结果仍会完整写入 report 文件。
2.3 关键参数详解:为什么-e php,js,html不等于加扩展名爆破?
很多人以为-e php,js,html是让 dirsearch 在每个路径后自动拼上.php、.js、.html再发请求,比如/login→/login.php、/login.js、/login.html。这是错误理解。
实际上,-e参数的作用对象是字典中原本就带扩展名的条目。dirsearch-master 的字典分两类:
common.txt:纯路径,如/admin,/backup,/configextensions_common.txt:扩展名列表,如.php,.bak,.swp,.old
当你加-e php,js,它会把common.txt中每一行,分别与php和js组合成新路径,即:
/admin→/admin.php,/admin.js/backup→/backup.php,/backup.js
但它不会对/admin/(结尾有斜杠)做拼接,也不会对/api这类无扩展名意图的路径强行加.php。
所以正确用法是:
# 场景1:猜常见后台路径(/admin/, /wp-admin/)→ 用 common.txt + 不加 -e python3 dirsearch.py -u https://target.com -w db/common.txt # 场景2:猜源码备份(/config.php.bak, /index.html~)→ 用 common.txt + -e bak,old,swp,~ python3 dirsearch.py -u https://target.com -w db/common.txt -e bak,old,swp,~ # 场景3:猜 PHP 脚本接口(/api/login.php, /user/profile.php)→ 用 api_paths.txt + -e php python3 dirsearch.py -u https://target.com -w custom/api_paths.txt -e php逻辑说明:
-w指定字典路径,-e指定扩展名后缀,二者是正交组合关系。-e不改变字典内容,只在运行时做字符串拼接。这也是它比某些“智能扩展”工具更可控的原因——你永远知道它到底发了哪几个请求。
3. socket 层定制:如何修改超时、重试、TLS 验证等底层行为
dirsearch-master 的核心优势在于它绕过了 requests 或 urllib3 这类高级封装,直接用socket+ssl+http.client构造原始 HTTP 请求。这意味着你能深入控制每一个 TCP 连接细节:DNS 解析超时、TCP 握手超时、SSL 握手超时、HTTP 响应读取超时、重试策略、证书验证开关。这些参数不在命令行暴露,但全部可在源码中精准定位并修改。
3.1 修改全局超时值:定位lib/requester.py中的TIMEOUT常量
打开lib/requester.py,找到第 32 行左右:
# lib/requester.py TIMEOUT = 10 # seconds这个TIMEOUT是整个 HTTP 事务的总超时,包括 DNS 查询、TCP 连接、SSL 握手、发送请求、接收响应头+体。它不是socket.settimeout()的单次 timeout,而是通过select.select()+time.time()手动实现的总耗时控制。
如果你想让扫描在弱网环境下更稳(比如扫内网慢速设备),可改为:
TIMEOUT = 30 # 弱网或高延迟环境建议设为 20~60但注意:增大 TIMEOUT 会显著拉长单次请求耗时,若并发线程数不变,整体扫描时间呈线性增长。建议配合-t参数同步调低线程数,例如:
python3 dirsearch.py -u https://slow-intranet.local -t 5 -T 30 # -t 5:只开 5 线程,避免端口耗尽 # -T 30:总超时设为 30 秒(注意:-T 是命令行参数,覆盖 TIMEOUT 常量)参数说明:
-T是命令行可覆盖的超时参数,优先级高于源码中的TIMEOUT常量。它会直接传入Requester类初始化,最终作用于self.timeout实例变量。这是官方留出的“安全出口”,无需改源码即可调整。
3.2 关闭 SSL 证书验证:仅限测试环境,且必须显式声明
某些内网系统使用自签名证书,或证书链不全,导致 dirsearch-master 默认报错:
[ERROR] SSL certificate verification failed for https://intranet.local: [SSL: CERTIFICATE_VERIFY_FAILED]这不是 bug,是 Python 默认开启ssl.create_default_context()的证书验证行为。要关闭它,不能简单注释掉某行代码,而必须在lib/requester.py的send_request()方法中,显式传入context=ssl._create_unverified_context()。
定位到lib/requester.py中def send_request(self, path)函数,找到创建 HTTPS 连接的部分(约第 180 行):
# 原始代码(带证书验证) if self.protocol == "https": context = ssl.create_default_context() conn = http.client.HTTPSConnection( self.host, self.port, timeout=self.timeout, context=context )改为:
# 修改后(关闭证书验证) if self.protocol == "https": # ⚠️ 仅限测试环境!生产环境严禁关闭 context = ssl._create_unverified_context() conn = http.client.HTTPSConnection( self.host, self.port, timeout=self.timeout, context=context )注意:
ssl._create_unverified_context()是 Python 标准库中明确标注为“不安全”的方法,它会跳过证书签名、域名匹配、吊销状态等全部校验。切勿在公网扫描或正式评估中启用。若需兼顾安全与可用,建议用openssl s_client -connect target.com:443先导出证书,再用-ca-certs参数指定可信 CA 文件(dirsearch-master 当前不支持该参数,需自行扩展)。
3.3 自定义 User-Agent 与请求头:避免被 WAF 速率限制
dirsearch-master 默认 User-Agent 是Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...,非常典型,极易被云 WAF(如 Cloudflare、阿里云 WAF)识别为扫描器并拦截。
它支持两种方式注入请求头:
方式一:命令行-H参数(推荐)
python3 dirsearch.py -u https://target.com \ -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" \ -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"每条-H对应一个请求头,可多次使用。注意:-H设置的头会覆盖默认头,包括Host和Connection,所以务必确保Host正确(通常 dirsearch-master 会自动设置,但自定义时需手动补全)。
方式二:修改lib/requester.py中的DEFAULT_HEADERS字典
定位到lib/requester.py开头附近:
DEFAULT_HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", }你可以在这里替换 UA,或添加Referer、X-Forwarded-For等字段。但要注意:添加Content-Length或Transfer-Encoding会导致请求异常,因为 dirsearch-master 发送的是 GET 请求,无 body。
血泪经验:某次扫客户内网,WAF 对 UA 含
Windows的请求直接 403,换成curl/7.68.0后畅通无阻。后来我们维护了一个ua_pool.txt,每轮请求随机选一条 UA,配合-t 10限速,连续 3 天未被封 IP。
4. 避坑与常见问题排查:5 条真实踩过的 socket 层黑匣子
dirsearch-master 的强大源于其底层控制力,但这也意味着很多问题不会以“报错信息”形式出现,而是表现为“无声失败”“结果缺失”“连接复位”。以下是我在多个模拟项目 X 和某高校红队实训中反复验证过的 5 类高频问题,每条都按「现象 → 原因 → 解决」结构给出可立即执行的对策。
4.1 现象:扫描结果中大量显示[000] /path,且无响应内容
原因:[000]是 dirsearch-master 对 socket 层连接失败(如 Connection refused、Timeout、Reset by peer)的统一占位码,它不区分具体错误类型,只表示“我发了请求,但没收到任何 HTTP 响应”。常见于目标端口关闭、防火墙 DROP、中间设备(如负载均衡)主动 RST 连接。
解决:
- 先用
nc -zv target.com 80和nc -zv target.com 443确认端口可达; - 若端口通但仍有
[000],加-v参数开启详细模式:python3 dirsearch.py -u http://target.com -v,观察日志中是否出现Connection reset by peer或Timeout; - 若是内网扫描,检查本地
ulimit -n是否过低(默认 1024),执行ulimit -n 65535后重试。
4.2 现象:扫描中途卡住,CPU 占用 100%,但无新结果输出
原因:Python 的http.client在读取响应体时,若服务端未发送Content-Length且未关闭连接,会一直阻塞在response.read()。dirsearch-master 的TIMEOUT机制对此类“半开连接”无效。
解决:
- 修改
lib/requester.py中send_request()方法,在response = conn.getresponse()后插入强制读取限制:# 在 response = conn.getresponse() 下方添加 try: # 限制最多读取 1MB 响应体,防卡死 body = response.read(1048576) except Exception as e: body = b"" - 或更彻底:在
conn.getresponse()前,给 socket 设置settimeout(15)(需先获取底层 socket 对象,见下条)。
4.3 现象:HTTPS 扫描时大量[000],但curl -I https://target.com正常
原因:目标服务使用了较老的 TLS 版本(如 TLS 1.0)或非标准加密套件,而 Python 3.7+ 默认禁用 TLS 1.0/1.1。http.client.HTTPSConnection底层 ssl context 不兼容。
解决:
- 修改
lib/requester.py中 HTTPS 连接创建部分,显式指定 TLS 版本:if self.protocol == "https": context = ssl.SSLContext(ssl.PROTOCOL_TLS) context.minimum_version = ssl.TLSVersion.TLSv1 context.maximum_version = ssl.TLSVersion.TLSv1_2 # 若仍不行,可尝试 ssl.PROTOCOL_SSLv23(兼容性最强,但不安全) conn = http.client.HTTPSConnection( self.host, self.port, timeout=self.timeout, context=context )
4.4 现象:扫描结果中/admin/显示[301],但点开却是 404
原因:dirsearch-master 默认不跟随重定向(follow_redirects=False)。[301] /admin/表示服务端返回了Location: /admin/login.php,但工具没去请求那个新地址,只是记录了原始响应。
解决:
- 加
-r参数启用重定向跟随:python3 dirsearch.py -u https://target.com -r; - 但注意:
-r会增加请求数量,且可能触发登录页的 CSRF Token 生成逻辑,导致后续请求失效。生产环境慎用,建议先-r跑一遍,再针对关键跳转路径单独-u https://target.com/admin/login.php深度扫。
4.5 现象:自定义字典中路径含中文或特殊符号(如/用户中心/),扫描时报UnicodeEncodeError
原因:dirsearch-master 默认以latin-1编码读取字典文件,而 UTF-8 中文路径无法被正确 decode。
解决:
- 将字典文件另存为
UTF-8 without BOM格式(用 VS Code 或 Notepad++ 可设); - 修改
lib/wordlist.py中read_wordlist()函数,将open(file_path, "r")改为open(file_path, "r", encoding="utf-8"); - 或更稳妥:在命令行中用
iconv预处理字典:iconv -f GBK -t UTF-8 custom_dict.txt > dict_utf8.txt python3 dirsearch.py -u https://target.com -w dict_utf8.txt
5. 进阶技巧:用 socket 日志反向验证 WAF 规则与 CDN 节点行为
dirsearch-master 最被低估的能力,不是“扫得多快”,而是“扫得有多真”。因为它绕过所有高级 HTTP 库,每一行[200] /path都对应一次真实的 socketsend()+recv(),这意味着你可以用它当“网络探针”,反向测绘目标的中间设备策略。我在某跨平台系统渗透中,正是靠这个技巧,3 小时内摸清了客户 CDN 的缓存规则和 WAF 的 URI 长度截断阈值。
5.1 抓取原始 socket 流量:patchlib/requester.py输出 raw request/response
dirsearch-master 默认不打印原始 HTTP 报文,但我们可以极小改动让它输出。在lib/requester.py的send_request()方法末尾(return response_data前),插入:
# 在 return response_data 前添加 if self.debug: # 我们新增一个 debug 标志 with open("socket_debug.log", "a") as f: f.write(f"\n=== REQUEST TO {self.host}:{self.port}{path} ===\n") f.write(request_str) # request_str 是拼好的原始 HTTP 请求字符串 f.write(f"\n=== RESPONSE FROM {self.host}:{self.port} ===\n") f.write(f"Status: {response.status} {response.reason}\n") for header, value in response.getheaders(): f.write(f"{header}: {value}\n") f.write(f"\nBody (first 512B): {body[:512]!r}\n") f.write("="*60 + "\n")然后在dirsearch.py主入口中,给Requester初始化时传入debug=True:
# dirsearch.py 中约第 280 行 requester = Requester( url, # ... 其他参数 debug=True, # 新增 )运行后,socket_debug.log会记录每一次请求的原始 HTTP 报文,例如:
=== REQUEST TO example.com:443/.git/config === GET /.git/config HTTP/1.1 Host: example.com User-Agent: Mozilla/5.0 ... ... === RESPONSE FROM example.com:443 === Status: 403 Forbidden Server: cloudflare CF-RAY: 89a1b2c3d4e5f678-LAX ...这份日志的价值在于:你能看到 WAF 返回的
Server、CF-RAY、X-WAF-Status等真实 Header,还能对比不同路径的响应体差异(比如/admin/返回 HTML,/.git/config返回空体+403),从而判断规则是基于路径前缀、文件扩展名,还是正则匹配。
5.2 测绘 CDN 缓存行为:用时间戳路径触发边缘节点缓存
CDN 缓存常基于完整 URI,包括查询参数。我们可以构造带唯一时间戳的路径,观察响应时间变化,判断是否命中缓存:
# 生成带毫秒时间戳的字典(10 行) for i in $(seq 1 10); do echo "/test?ts=$(date +%s%3N)"; done > ts_dict.txt # 扫描并记录响应时间(-t 1 保证串行) python3 dirsearch.py -u https://cdn-target.com -w ts_dict.txt -t 1 -o ts_report.txt查看ts_report.txt,若前几行响应时间均为~12ms,后几行突降至~2ms,说明 CDN 边缘节点已缓存该 URI。再用curl -I对比,若AgeHeader 从0变为120,即证实缓存生效。
5.3 验证 WAF URI 长度截断:构造超长路径触发规则
某些 WAF(如早期 ModSecurity)会对 URI 长度做硬性截断,比如只取前 200 字符。我们可以用 dirsearch-master 的-e参数快速验证:
# 创建一个 300 字符的超长路径(用 Python 一行生成) python3 -c "print('/' + 'a'*299)" > long_path.txt # 扫描,观察是否返回 403(WAF 拦截)或 404(服务端处理) python3 dirsearch.py -u https://target.com -w long_path.txt若返回[403] /aaaaaaaa...(300 个 a),说明 WAF 未截断,完整传递给了后端;若返回[403] /aaaa...(仅前 200 个 a),则证明存在长度截断,且截断点在 200 字符左右。
从那以后我每次做边界测试,都强制走一遍
socket_debug.log+ 时间戳字典 + 超长路径三连击。不是为了炫技,而是因为只有看到原始 socket 流量,你才敢说“这个 403 真是 WAF 返回的”,而不是“可能是后端 Nginx 配置错了”。希望帮到你。
本文还有配套的精品资源,点击获取