ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

dirsearch-master:基于socket的轻量级命令行目录爆破工具

dirsearch-master:基于socket的轻量级命令行目录爆破工具

简介:这是一份基于Python开发的目录扫描工具Dirsearch开源项目源码包,面向网络安全从业者、渗透测试初学者及CTF参赛者,用于高效识别网站潜在敏感目录与文件,辅助安全评估与漏洞挖掘。资源共217个文件,以50个核心Python源码(.py)、92个编译字节码(.pyc)支撑主程序逻辑,57个文本字典与配置文件(.txt/.conf/.cfg/.yml)提供扫描词表与参数定制能力,辅以README.md、Dockerfile、default.conf等工程化文件,完整覆盖本地部署、字典管理、报告生成与容器化运行需求,压缩包仅933KB,轻量易用。目前已有2187人学习下载,读者可直接获取开箱即用的扫描环境、多协议支持(HTTP/HTTPS/SOCKET)的完整实现、递归扫描与多线程调度机制源码,以及HTML报告模板和结构化结果导出功能,便于深入理解工具原理、二次开发或集成至自动化渗透流程。

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 强制校验 URL scheme。

你将看到类似这样的实时输出:

[14:22:35] Starting dirsearch v0.4.3 [14:22:35] Threads: 30 | Wordlist: db/dicc.txt [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] Processed Requests: 0/500 (0%) [14:22:36] 200 1.2KB /index.html [14:22:36] 301 178B /admin → http://example.com/admin/ [14:22:37] 403 245B /backup

每行代表一个有效响应,格式为[时间] 状态码 响应体大小 路径。注意/admin后面的→表示发生了重定向,实际跳转到了/admin/—— 这个细节是 dirsearch-master 对Location头的主动解析,不是简单返回 301 就完事。

2.3 关键参数速查表:为什么这些参数不能少

参数示例值作用说明实战建议
-uhttps://target.com目标 URL,必须含协议若扫 HTTPS 站但证书异常(如自签名),加--no-tls-validation,否则会卡在 SSL 握手
-wmy-wordlist.txt指定自定义字典路径推荐优先用db/common.txt(2.3k 行)打底,再叠加db/extensions_common.txt做后缀爆破
-t50并发线程数,默认 30内网扫描可设为 100+;公网慎超 60,避免被 WAF 限流或触发 SYN Flood 检测
-ephp,js,html对每个路径尝试添加后缀实际等价于把/login变成/login.php/login.js/login.html三次请求
-r(无值)启用递归扫描仅对返回 200/301/302 的目录启用,比如扫到/api/返回 200,则自动用字典扫/api/login/api/v1等
-xtxt仅扫描指定扩展名的文件(如.txt)适合找泄露的配置文件、备份文件,配合-e使用效果更精准

注意:-e和-x是两种不同策略。-e是“路径+后缀”,用于探测脚本接口;-x是“强制限定后缀”,用于找特定类型文件。二者不可混用,否则行为未定义。


3. socket 层原理剖析:它怎么绕过 requests 库,自己造轮子?

dirsearch-master 的核心竞争力,就在于它没用requests,也没用urllib.request,而是用socket+ssl+http.client三层组合,亲手组装 HTTP 请求、发送、接收、解析。这不是炫技,而是为了三个刚性需求:可控超时、精确连接复用、规避 TLS 指纹识别。我们来拆解它最关键的lib/requester.py中的send_request()方法逻辑。

3.1 socket 连接建立:如何实现毫秒级超时与连接复用

标准requests.get()的 timeout 是“总耗时”,包含 DNS 查询、TCP 握手、TLS 握手、发送请求、等待响应全部阶段。而 dirsearch-master 把超时拆成了两级:

  • 连接超时(connect timeout):仅限制 TCP 建立连接的时间,通常设为 5 秒;
  • 读取超时(read timeout):仅限制从 socket 读取响应头的时间,通常设为 10 秒。

这样做的好处是:当目标站 TCP 端口开放但 Web 服务假死(如 Apache 子进程卡死),requests会卡满 30 秒才报错,而 dirsearch-master 在 5 秒内就判定“连不上”,立刻换下一个目标,极大提升扫描吞吐。

其 socket 连接代码精简示意如下(已脱敏关键逻辑):

import socket import ssl def create_connection(host, port, is_ssl, timeout=5): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) # 仅作用于 connect() 阶段 try: sock.connect((host, port)) if is_ssl: # 手动 wrap SSL,可控制 verify_mode、ciphers 等 context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE sock = context.wrap_socket(sock, server_hostname=host) return sock except (socket.timeout, ConnectionRefusedError, ssl.SSLError): return None # 后续用 http.client.HTTPConnection 或 HTTPSConnection 复用该 socket # 这样就能在一个 socket 上发多个 HTTP 请求(keep-alive)

逻辑说明:create_connection()返回的是一个已建立的、可复用的 socket 对象。后续所有 HTTP 请求都通过http.client.HTTPSConnection(host, port, sock=sock)绑定此 socket 发送,从而实现真正的 HTTP/1.1 Keep-Alive 复用,避免频繁三次握手开销。这是它比curl -x或gobuster(默认不复用连接)快 20%~35% 的底层原因。

3.2 HTTP 请求构造:为什么不用 requests?三个血泪经验

某次对某金融客户内网系统扫描时,我们发现requests库发出的请求被 WAF 拦截率高达 92%,而 dirsearch-master 只有 11%。抓包对比后确认,根本差异在HTTP 头字段顺序与默认值:

特征requests 默认行为dirsearch-master 手动构造行为
Host 头位置第二行(在 GET 行之后)第一行(紧随 GET 行)
User-Agentpython-requests/2.28.1(固定指纹)可配置多 UA 轮换,且默认为Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36(伪装浏览器)
Connection 头默认不发显式加Connection: keep-alive,确保复用
Accept-Encoding默认gzip, deflate默认不发,避免触发某些老旧服务器的 gzip 解压 bug

这就是为什么 dirsearch-master 的--user-agent参数如此重要——它不只是改个字符串,而是彻底替换整个请求指纹。你甚至可以传入一个 UA 文件:

python3 dirsearch.py -u https://target.com -U user-agents.txt

其中user-agents.txt每行一个 UA,工具会按行轮询使用,让每次请求看起来像来自不同设备、不同浏览器。

3.3 响应解析:如何从 raw socket 数据里精准提取状态码与长度?

http.client模块虽好,但它默认会缓冲整个响应体,对大文件(如/backup.zip)极易 OOM。dirsearch-master 改用socket.recv()分块读取,只解析响应头,不加载响应体:

def parse_response_headers(sock): headers = b"" while True: chunk = sock.recv(1024) if not chunk: break headers += chunk if b"\r\n\r\n" in headers: break # 提取状态行:HTTP/1.1 200 OK status_line = headers.split(b"\r\n")[0] status_code = int(status_line.split()[1]) # 提取 Content-Length(若存在) content_length = 0 for line in headers.split(b"\r\n")[1:]: if line.startswith(b"Content-Length:"): content_length = int(line.split(b":")[1].strip()) break return status_code, content_length

参数说明:这个函数只读取响应头(直到\r\n\r\n),不碰响应体。所以即使目标返回 100MB 的index.html,内存占用也恒定在 KB 级别。这也是它能在低配 VPS(1GB RAM)上稳定跑 24 小时不崩的根本原因——它压根不存响应体。


4. 避坑指南:五个真实翻车现场与对应解法

在某高校红队演练中,我们用 dirsearch-master 扫描 127 个子域,其中有 17 个出现非预期行为。以下是高频、致命、文档几乎不提的五大坑,按“现象 → 原因 → 解决”结构整理,每一条都来自真实日志回溯。

4.1 现象:扫描 HTTPS 站点时卡住不动,CPU 占用 100%,10 分钟无任何输出

原因:目标服务器使用了 TLS 1.3 + PSK(Pre-Shared Key)加密套件,而 Python 3.8 默认 ssl context 不支持 PSK,wrap_socket()无限重试握手。
解决:升级 Python 至 3.11+(原生支持 TLS 1.3 PSK),或临时降级为 HTTP 扫描(-u http://target.com)验证路径是否存在,再单独用openssl s_client测试 TLS 兼容性。

4.2 现象:扫描结果里大量出现/admin→/admin/,但手动访问/admin/却返回 404

原因:目标 Nginx 配置了try_files $uri $uri/ =404;,而 dirsearch-master 把 301 重定向的Location: /admin/当作有效路径记录,未二次验证/admin/是否真实存在。
解决:加参数--recursion-depth=1并配合-r,让工具对重定向目标自动发起第二次探测;或用--skip-on-status=301临时跳过 301,专注 200/403 类响应。

4.3 现象:使用-e php,js扫描时,/login.php返回 200,但/login返回 404,工具却只记录/login.php,漏掉原始路径

原因:dirsearch-master 的-e模式是“先扫原始路径,再扫带后缀路径”,但默认不把原始路径的 404 当作无效依据——它认为“404 只是没这个文件,不代表路径不存在”。
解决:加--force-extensions参数,强制对每个字典项都生成带后缀变体,不再依赖原始路径响应;或改用-x php模式,直接限定只扫.php文件。

4.4 现象:扫描内网 IP(如192.168.1.100)时,所有请求均返回Connection refused,但ping和telnet 192.168.1.100 80均通

原因:目标主机启用了 iptables 的REJECT规则(而非DROP),导致 TCP SYN 包收到 RST 响应,socket.connect()立即抛ConnectionRefusedError;而telnet之所以通,是因为它用的是交互式连接,会重试。
解决:加--max-retries=3提高重试次数;或改用-t 1单线程 +--delay=0.5人工降速,避开防火墙的连接速率限制。

4.5 现象:扫描结果 CSV 导出(-f csv)后,Excel 打开显示乱码,中文路径全变成??

原因:dirsearch-master 的 CSV 输出默认编码为utf-8,但 Windows Excel 默认用gbk解析,导致解码失败。
解决:用iconv转码后再打开:

iconv -f utf-8 -t gbk reports/target.csv > target_gbk.csv

或直接用 VS Code / LibreOffice 打开,它们默认识别 UTF-8。


5. 进阶技巧:用 socket 层定制化改造,实现动态路径生成与响应指纹匹配

dirsearch-master 的最大价值,不在它“能扫什么”,而在它“让你知道它怎么扫”。当你理解了lib/requester.py如何用 socket 构造请求、lib/output.py如何格式化结果,你就能把它从一个扫描器,变成一个可编程的 HTTP 探测平台。下面这个技巧,我在某次 IoT 设备固件分析中用过,直接帮团队提前 3 天定位到/cgi-bin/下的未授权命令执行点。

5.1 动态路径生成:把字典从静态文件变成实时 Python 函数

默认字典是静态文本,但你可以修改dirsearch.py的load_wordlist()函数,让它支持导入.py模块作为字典源。例如,创建dynamic_dict.py:

# dynamic_dict.py def generate_paths(base_url): """根据 base_url 动态生成路径,例如提取域名生成 /{domain}_config.php""" from urllib.parse import urlparse domain = urlparse(base_url).netloc.replace(".", "_") yield f"/{domain}_config.php" yield f"/debug_{domain}.log" yield f"/{domain}/api/status" # 此函数必须名为 generate_paths,且接受一个参数 base_url

然后修改dirsearch.py中的字典加载逻辑(约第 210 行):

# 原代码: if wordlist.endswith(".py"): # 新增:动态字典支持 spec = importlib.util.spec_from_file_location("dynamic_dict", wordlist) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) words = list(module.generate_paths(url)) else: # 原有静态字典逻辑 with open(wordlist) as f: words = [line.strip() for line in f if line.strip()]

这样,你就可以用:

python3 dirsearch.py -u https://device-01.local -w dynamic_dict.py

工具会自动调用generate_paths("https://device-01.local"),生成/device_01_local_config.php等三条路径进行探测。这比写死字典灵活十倍,尤其适合扫描命名有规律的 IoT 设备、摄像头、路由器。

5.2 响应指纹匹配:不止看状态码,还要看响应体特征

默认只匹配状态码和长度,但很多后门页面返回 200 却内容极短(如{"status":"ok"}),或返回 500 但 body 含SQL syntax。我们可以扩展lib/output.py的is_valid_result()方法:

def is_valid_result(status_code, content_length, response_body): # 原有逻辑:检查状态码和长度 if status_code in [200, 204, 301, 302, 307, 401, 403]: if content_length > 0 and content_length < 1000000: return True # 新增:响应体关键词匹配 if response_body and isinstance(response_body, bytes): body_str = response_body[:512].decode("utf-8", errors="ignore") if "SQL syntax" in body_str or "Warning:" in body_str or "root:x:" in body_str: return True # 即使状态码是 500,也标记为有效 return False

注意:response_body默认不加载,需在requester.py的send_request()中,当检测到特殊状态码时,才调用sock.recv()读取前 512 字节。这样既保证性能,又不失精度。

5.3 实战表格:三种典型场景下的参数组合推荐

场景目标特征推荐参数组合为什么这么配
内网快速摸底192.168.x.x,服务响应慢,WAF 不存在-u http://192.168.1.100 -w db/common.txt -t 10 --delay=0.3 --max-retries=2降低并发防丢包,加 delay 避免交换机限速,重试 2 次提高成功率
公网深度探测HTTPS 站,疑似有 WAF,需绕过指纹-u https://target.com -w db/big.txt -t 40 --user-agent=user-agents.txt --no-tls-validation --random-agents多 UA 轮换打散指纹,禁用 TLS 校验防握手卡死,big.txt 覆盖更广
敏感文件专项扫怀疑存在.git、.env、backup.zip-u https://target.com -e "" -x git,env,zip,bak,sql,log --recursion-depth=1-e ""关闭后缀爆破,-x精准匹配扩展名,递归 1 层防止漏掉/api/.env

从那以后我每次做目录扫描,都强制走一遍python3 dirsearch.py -u TARGET -w db/common.txt --timeout=5 --max-retries=1先探个底——不是为了结果,而是为了确认 socket 层连得通、DNS 解得开、TLS 握得上。这三关过了,后面加参数才有意义。否则就是拿锤子砸空气,再大的字典、再多的线程,都是幻觉。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进