ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

dirsearch目录扫描实战:敏感目录泄露挖掘与字典爆破全解析

dirsearch目录扫描实战:敏感目录泄露挖掘与字典爆破全解析 1. 先把目录扫描这件事想明白1.1 目录扫描在Web安全评估里的定位目录扫描工具我用过不少dirsearch 是最常用的一把。它做的事情一句话就能说清通过字典爆破快速发现 Web 站点上那些不会出现在导航菜单里的目录和文件也就是常说的敏感目录泄露挖掘。几乎所有 Web 安全评估项目我都会把这一步放在比较靠前的位置因为它的投入产出比实在太高了。在完整的安全评估流程里目录扫描属于资源枚举阶段和端口扫描、子域名枚举是并列关系。端口扫描告诉你机器开了哪些门子域名枚举告诉你还有哪些房子目录扫描则是在已经确定的一栋楼里逐个房间去试门把手。搜索引擎收录的只是 Web 应用愿意公开的部分大量功能模块、旧版本页面、管理后台、测试接口并不会出现在任何页面链接里。它们只是安静地躺在服务器上等着被直接输入 URL 访问。dirsearch 这类工具本质上就是在做一件事把那些没有被链接引用的入口找出来。很多新手会低估这个环节觉得目录扫描不就是输入一个 URL、选一个字典、等结果吗实际上参数调优、字典策略、结果验证每一环都能拉开差距。同一位测试人员换个字典命中结果可能翻倍同一条结果会验证的人能拿到源码和数据库配置不会验证的人只觉得“扫到了一个目录”。这篇文章就把整个链路拆开聊一遍从 dirsearch 的安装、字典爆破的思路到敏感目录泄露的挖掘与验证完整过一遍。1.2 敏感目录泄露到底能泄露什么敏感目录和敏感文件的范围比很多人想象中广。我习惯把它们分成几大类方便在扫描结果里快速对号入座。类别典型路径风险等级说明后台入口/admin、/manage、/console、/admin/login高多一条可尝试的登录通道版本控制目录/.git、/.svn、/.hg很高可能还原整个项目源码备份文件/backup、/www.zip、/site.tar.gz、/web.bak很高源码、配置、SQL 脚本可能都在里面配置文件/.env、/config.php.bak、/application.yml.bak很高数据库账号、密钥、内部地址接口文档/swagger-ui.html、/v2/api-docs、/openapi.json中高暴露完整接口结构方便找未授权接口日志与数据/logs、/error.log、/data、/sql中高可能泄露路径、参数、测试数据测试页面/test、/phpinfo.php、/demo中可能存在未清理的调试功能这些内容单独看可能只是信息泄露组合起来就麻烦了。后台入口配合弱口令是经典路线.git 仓库暴露可以直接把源码拉下来代码审计后往往能找到新的漏洞备份文件里如果躺着 .env 和 SQL 脚本就等于把数据库钥匙交出去了。敏感目录泄露挖掘真正重要的不是“扫到了目录”这个动作而是扫到之后你能从里面拿出什么。1.3 授权边界先拿到授权再动手目录扫描不是无成本操作它会向目标发送大量 HTTP 请求可能触发安全设备拦截、导致目标日志暴涨、甚至给源站带来压力。所以我接任何项目第一步永远是确认授权范围和测试时间窗。对自己公司的资产、接过的授权项目、或者本地搭建的靶场随便折腾没问题对没有授权的站点再小的扫描也不要做。这是职业操守也是底线。从防御方角度看了解目录扫描同样重要。很多企业站点被扫出敏感文件后业务方还一脸茫然“这个文件什么时候放上去的”“这个目录我们开发自己都不知道”。如果安全团队能提前通过目录扫描发现这些问题修复成本比被攻击者发现后再处理低得多。这也是我写这篇文章的一个目的——不光是写给做测试的人也是写给负责站点防护的人看。2. dirsearch 上手安装报错、参数语义和第一次完整扫描2.1 安装时的经典报错unable to locate package dirsearch 及解法在 Kali 里 dirsearch 通常是随系统自带的但一旦换成 Debian 或 Ubuntu很多人的第一反应就是执行sudo apt install dirsearch然后碰上一行红字E: Unable to locate package dirsearch我第一次遇到这个报错下意识就是先sudo apt update再重试结果还是一样。后来才搞清楚原因dirsearch 根本不在 Debian 和 Ubuntu 的官方软件源里Kali 的仓库里才有。apt 找不到这个包你再 update 多少遍都没用。正确做法是换一种安装方式。# 方式一从源码运行我推荐这个 git clone https://github.com/maurosoria/dirsearch.git cd dirsearch pip3 install -r requirements.txt python3 dirsearch.py -u http://example.com -e php # 方式二通过 pip 安装 pip3 install dirsearch dirsearch -u http://example.com -e php源码方式的好处是更新方便git pull就能拿到最新版本遇到问题也好排查。pip 方式胜在全局命令直接用适合不想看源码的人。需要注意 Python 版本新版 dirsearch 对 Python 3.7 以下的环境支持不好如果系统自带的 Python 版本太老建议先升级或者用虚拟环境。2.2 高频参数拆解从一条命令到定制化请求第一次跑通之后别急着用默认参数扫先把几个高频参数弄明白否则扫出来的结果会掺杂大量噪音。dirsearch 的帮助信息里有几十个参数但日常项目里常用的就这些参数说明使用场景-u / --url指定目标 URL单目标扫描-l / --list从文件读取多个目标批量资产梳理-e / --extensions指定扩展名根据技术栈追加 php、jsp、js 等-w / --wordlist指定字典文件换用自定义字典时必须用-t / --threads线程数控制扫描速度和服务压力-r / --recursive递归扫描命中目录后继续在该目录下扫-R / --max-recursion-depth最大递归深度防止递归过深导致请求量爆炸-f / --force-extensions强制所有条目追加扩展名配合 -e 使用-x / --exclude-status排除指定状态码去掉 404 等无效结果--random-agent随机 User-Agent避免被按 UA 特征识别-H / --header自定义请求头给目标加 Cookie 或认证头--proxy指定代理配合 BurpSuite 等工具联动这里面有几个容易踩坑的细节。-e指定扩展名时dirsearch 会把字典里的每个条目都追加一次扩展名比如字典里有admin指定-e php,html后它会尝试admin、admin.php、admin.html。扩展名越多请求量越大1 万条字典加三个扩展名就变成了 4 万请求。-f则是强制所有条目都带扩展名适合目标站点文件后缀相对固定的情况。还有一个容易被忽略的点目标 URL 末尾的斜杠。-u http://example.com和-u http://example.com/在拼接路径时的行为可能不一样如果你要扫的是/api/下的内容建议 URL 写成http://example.com/api/这样字典条目会在/api/后面拼接逻辑更清晰。python3 dirsearch.py -u https://target.com/api/ -e php,html -w dict.txt -t 20 -x 4042.3 第一次扫描之后状态码、响应长度与结果过滤扫描结束后终端上会刷出一批状态码和路径这时候最忌讳的就是只看 200。200 的路径要访问确认页面内容是不是敏感信息301/302 要看重定向到了哪里如果 Location 指向登录页很可能就是一个隐藏后台403 的情况比较特殊可能是目录存在但没有权限也可能是默认拦截值得手动访问确认一次。响应长度是识别假阳性最有效的指标之一。很多目标站点做了自定义 404 页面对一切不存在的路径都返回 200如果只看状态码你会得到一大堆没用的“成功页面”。遇到这种情况先手动访问一个绝对不存在的路径看它的 Content-Length把这个长度作为基线。curl -i https://target.com/this-path-does-not-exist-12345拿到基线响应长度后可以用--min-response-size和--max-response-size把特定长度的结果过滤掉。dirsearch 还有--exclude-status、--exclude-sizes等参数多组合几次就能把噪音压到很低。我个人不太建议把 403 直接全局排除因为很多后台入口恰恰就是 403先手动看一眼再下结论更稳妥。3. 字典爆破别让字典拖了后腿3.1 一份好字典的评判标准字典决定了目录扫描的上限引擎决定了效率。dirsearch 的扫描引擎本身很成熟真正拉开差距的是你喂给它的字典。一份好字典首先要有层次基础单词、带扩展名变体、带年份组合、带常见备份后缀每一层覆盖不同的真实场景。其次好字典一定是按场景分类的。后台入口、备份文件、配置文件、日志文件、接口文档这些类别混在一个大字典里不是不行但针对性会差很多。我电脑里的字典是按行业和用途拆开存放的扫电商站点用电商积累的字典扫企业内部系统用另一套命中率差别很明显。最后是大小控制。不是字典越大越好几十万条的海量字典会让扫描时间变得不可接受而且大量不相关条目会稀释真正有用的内容。我常用的目录字典大多在 1 万到 3 万条之间配合按技术栈选定的扩展名效果比一把梭的大字典好得多。3.2 BurpSuite 爆破字典的二次加工网上能找到很多 BurpSuite 爆破字典里面通常把用户名、密码、目录名、文件名、参数名、数据库字段名全塞在一起。直接拿来跑目录扫描不是不行但效率很差因为一半以上的条目都是口令类内容和目录爆破根本不相关。我会先把这类通用字典做一次二次加工再给 dirsearch 用。加工的思路很简单合并、去重、提炼。SecLists 的 Discovery/Web_Content 目录下有一批质量不错的字典比如 raft 系列和 directory-list-2.3 系列先把它们和 BurpSuite 爆破字典里的目录部分合并再把自己历次命中的目录追加进去最后统一去重排序。# 合并去重排序 cat common.txt raft-small-words.txt my-dirs.txt | sort -u merged-dirs.txt # 追加常见备份扩展名变体 awk {print $0 .bak; print $0 .zip; print $0 .tar.gz} merged-dirs.txt merged-dirs.txt sort -u merged-dirs.txt -o merged-dirs.txt注意sort -u是基本礼仪重复条目多了只会拖慢扫描速度。加工完的字典才是真正适合 dirsearch 的形态而不是把 BurpSuite 的原生字典直接扔给它。3.3 自建字典命名规律与素材沉淀自建字典的核心不是凭空造词而是总结真实世界的命名规律。中文互联网环境下的站点目录命名习惯和英文世界有明显的差异比如拼音缩写就非常常见登录是dl管理是gl后台是ht用户是yh。英文命名则集中在admin、manager、dashboard、panel、console这些常见词上。组合模式也很值得关注。admin2023、admin_bak、2024backup、web.bak这类“关键词年份”或“关键词后缀”的变体在真实站点里的命中率相当高。技术栈相关的路径同样不能忽略Spring Boot 的/actuatorSwagger 的/swagger-ui.htmlThinkPHP 的/publicWordPress 的/wp-admin这些路径不依赖业务功能纯粹是框架自带。我的建议是每次授权测试结束后把命中的目录和文件追加到自己的字典库里并按行业做分类。时间越久你手里的字典就越像一份“目标行业的通用路径集合”。字典这种东西没有速成方法就是靠一次次实战堆出来的。3.4 线程、延迟与访问控制的平衡字典确定之后扫描参数直接影响效率和稳定性。线程不是越高越好20 线程对大多数目标来说已经很激进遇到老系统或者慢网络5 到 10 线程才是稳妥选择。线程太高容易触发安全设备拦截也容易把目标打挂——目录扫描本质上是爆破行为大量 404 请求本身就是一种资源消耗。遇到有安全设备或者云防护的站点我的经验是降低线程、加延迟、随机 UA 三件套配合使用。dirsearch 的--delay参数可以控制每个请求之间的间隔--random-agent会随机切换 User-Agent两者能显著降低被识别成扫描器的概率。如果目标需要登录态可以用-H Cookie: xxx带上会话或者用--request-file直接导入从 BurpSuite 导出的请求文件让扫描请求自带完整请求头和身份信息。还要注意扩展名数量对请求量的影响。前面提到过字典 1 万条、扩展名 3 个请求量直接翻四倍。扫一个普通站点是几万请求如果递归加扩展名一起上瞬间就能变成几十万请求。设置之前先估算一下总请求量别让扫描变成一种变相攻击。4. 敏感目录挖掘从命中到验证的一整套打法4.1 敏感目录与文件的分类和风险等级敏感目录挖掘的重点不在“扫出来”而在“扫出来之后怎么办”。拿到 dirsearch 的结果列表后第一步是分类按风险等级排出优先级。后台入口、版本控制目录、备份文件、配置文件属于第一梯队日志和测试页面属于第二梯队接口文档属于第三梯队但具体的风险大小还要结合目标实际情况判断。版本控制目录这个词值得单独说一下。.git目录暴露时攻击者可以用工具把整个仓库拉下来然后通过git log查看历史提交很多开发者在早期提交里放过数据库密码、云服务密钥、内部 API 地址。这些信息删除后依然保留在 git 历史里git diff一翻就原形毕露。排查这种问题不能只看当前文件内容要追溯到历史提交。4.2 命中之后的验证从 .git 到 .env 到备份包以.git泄露为例验证流程相当明确。先确认/.git/HEAD是否可访问返回内容通常是ref: refs/heads/master或ref: refs/heads/main看到这种响应基本就实锤了。之后可以用工具把远端.git目录完整拉下来本地还原工作区再从历史提交里找敏感信息。# 第一步确认 .git 是否存在 curl -s https://target.com/.git/HEAD # 期望输出类似ref: refs/heads/master.env文件是另一种高频命中。很多现代框架会把环境配置放在项目根目录的.env里里面通常有数据库地址、账号、密码、应用密钥等。访问到.env后重点看DB_*、APP_KEY、SECRET_KEY这些字段。我的习惯是验证到“确认存在明文敏感配置”就停止不继续尝试用这些配置连接内部系统把发现写进报告就够了。备份文件处理起来要更细心一些。下载后先用file命令确认文件类型再用列文件内容的命令查看压缩包内结构不要急着解压执行。压缩包里的文件可能包含恶意内容解压前先看清里面有什么是安全习惯。file config.zip zipinfo -l config.zip tar -tf backup.tar.gz重点找config、sql、.env、.git目录、以及源码里写死的密码和密钥。备份文件的信息集中度往往比单一点的泄露更高因为备份一般会把整个项目打包带走。4.3 误报、状态码陷阱与干扰处理目录扫描的误报比例不低常见的有这么几类。第一种是自定义 404 返回 200前面提过用响应长度基线过滤就能解决。第二种是统一重定向系统对任意路径都 302 到登录页只看状态码会觉得什么都是“后台”对比一下 Location 就能发现所有路径都指向同一个页面。第三种是安全设备拦截后的批量错误。触发拦截后后续请求可能统一返回 403 或者 503而且响应长度都很接近扫描结果里会突然刷出一大片 403。这时候不是目标路径真的存在而是你被拦截了。遇到这种情况先停掉扫描看看是不是线程太高或者 UA 特征太明显。第四种是泛解析和 CDN 场景对任意路径都返回同样的页面内容。这种可以通过随机访问几个不存在的路径对比 Content-Length 来判断。dirsearch 本身支持按状态码和响应大小过滤结果合理利用这些参数能省下大量手动确认的时间但过滤条件别设得太激进宁可多看几条结果也别把真正有用的内容过滤掉。5. 实战复盘一次授权测试中的目录挖掘过程5.1 目标信息与扫描策略为了把前面的理论串起来我讲一个脱敏的实战案例。某次授权测试目标是一个企业内网使用的管理系统部署了多年前端是 Vue 单页应用登录页看起来干干净净客户自己都觉得没什么可测的。我拿到授权范围后没有急着登录先把技术栈摸了一遍从响应头和页面特征判断后端是 Java Spring Boot前端是 Vue。基于这个判断扫描策略就很清晰了。扩展名选了js、html、json因为前端资源大量使用 js 和 jsonjava 后端可能存在的.do或.action路径也值得加进去。字典用了raft-small-words和一份我自己的常见目录字典线程压到 15开启--random-agent排除 404把结果保存到文件。python3 dirsearch.py -u https://app.example.com \ -e js,html,json,do \ -w raft-small-words.txt \ -t 15 \ --random-agent \ --exclude-status404 \ -o first-run.txt第一次扫描跑了不到二十分钟结果里筛出了几个值得关注的点。这个案例里面工具本身没有做任何特殊的操作就是中规中矩跑了一遍但字典选得对命中质量就高。5.2 关键命中与完整排查链路这次扫描命中了四条关键路径/api-docs、/actuator、/backup/config.zip、/.git/HEAD。我把它们按风险等级排了个序然后一个一个验证。/api-docs打开是 Swagger UI接口列表可以完整浏览其中有一个“导出用户数据”的接口从文档看居然不需要鉴权。我没有实际调用这个接口但已经在报告里标注了潜在风险。/actuator直接暴露了 Spring Boot Actuator 端点继续访问/actuator/env能看到部分环境配置信息数据库地址和内部服务地址都在里面。到这里我确认了信息泄露存在没有再往下翻更敏感的内容因为验证目标已经达成。/.git/HEAD返回了ref: refs/heads/master实锤了源码泄露。我用工具把仓库拉下来后在历史提交里发现了一份application.yml里面有数据库账号密码是加密的但另一个 service 文件里硬编码了一个第三方 API Key这个 Key 可以直接使用。/backup/config.zip下载后用zipinfo看了一下里面有config.sql和.env文件.env里是测试库的明文密码。到这里整条链路的入口已经全部找到了我没有继续尝试用这些信息做进一步利用而是整理成报告。5.3 风险评估与修复建议这次评估的发现可以组合成一条完整的攻击链源码泄露还原出硬编码密钥硬编码密钥可能用于调用内部接口接口文档又暴露出未授权接口备份文件里的数据库凭据更是直接把敏感数据的入口摆了出来。单独看每一条可能都只是“信息泄露”组合起来就是高风险。风险项等级验证结果修复建议.git 仓库可访问严重可还原源码禁止访问 /.git 路径清理服务器上的 .git 目录备份文件可下载严重包含 .env 和 SQL移除线上备份文件备份应存放在不可直接访问的位置Actuator 端点暴露高可读取环境配置关闭或限制 Actuator 端点访问必要时加认证Swagger 文档公开中高可查看全部接口对文档页面加访问控制不在生产环境开放给客户的核心修复方案也很常规在 Nginx 层直接拦住敏感路径这是最见效的一步同时要求开发把硬编码的密钥全部轮换改动代码后重新发布Swagger 和 Actuator 的访问控制要落到配置层面不能只靠“没人知道路径”来保护。location ~* \.(git|env|bak|sql|tar\.gz|zip)$ { deny all; } location ^~ /.git { deny all; } location ^~ /actuator { deny all; }这一条 Nginx 规则能挡住一大批基于路径的敏感文件访问但要注意它不能替代代码层面的修复只是临时的访问控制手段。6. 把目录扫描沉淀成自动化资产巡检能力6.1 从 BurpSuite 历史记录里沉淀字典BurpSuite 的 HTTP history 是路径金矿。日常测试中凡是真实存在的页面、静态资源、接口都会在 history 里留下记录。把这些真实路径提取出来就是一份最贴合站点实际情况的字典。我每次测试结束后都会把 Burp 的 HTTP history 导出来用脚本提取其中的 URL 路径。import re import sys paths set() for line in sys.stdin: m re.search(rhttps?://[^/](/[^ ?]*), line) if m: paths.add(m.group(1)) for p in sorted(paths): print(p)cat burp_history.txt | python3 extract_paths.py burp_paths.txt把提取出的路径和 dirsearch 的自带字典合并再手动剔除掉带参数的接口路径剩下的就是一套非常有价值的目录字典。这套字典不只是给当前项目用也可以沉淀到自己的字典库里为后续项目服务。字典越积累越贴合真实世界这是任何公开字典都比不了的。6.2 定时巡检脚本与落地姿势企业安全团队可以在自己的资产上配置定时巡检每周跑一遍核心系统的目录扫描再对比增量结果。敏感目录不是只出现一次就结束了开发迭代过程中随时可能把备份文件传上去或者把 .git 目录带到了生产环境。定时巡检的价值在于持续发现问题。#!/bin/bash for url in $(cat targets.txt); do python3 dirsearch.py -u $url -e php,html,js,zip,bak \ -t 10 \ --random-agent \ --exclude-status404 \ --formatplain \ -o report_$(date %F)_$(echo $url | sed s/[^a-zA-Z0-9]/_/g).txt done落地时有几个细节。目标列表只放已授权资产扫描时间选业务低峰脚本输出要保留原始日志。还有一个容易被忽略的点对比历史结果。新出现的敏感目录往往就是近期变更引入的问题直接找出增量比要求运维每天看一堆积压的报告更有效。6.3 别忽略 JS 文件里的真实路径这几年前端工程化普及大量接口路径不会出现在传统目录结构里而是以字符串形式打包在 JS 文件中。dirsearch 扫出了一些 JS 文件后别急着收工先把这些 JS 拉下来搜一遍路径。curl -s https://app.example.com/static/js/app.js \ | grep -oE /[a-zA-Z0-9_/-]{2,} \ | sort -u搜出来的路径往往包含大量业务接口比如/api/user/export、/api/admin/list这类真实存在的地址。把这些路径汇总后再用 dirsearch 或者直接浏览器访问重点测未授权访问。目录扫描加 JS 路径提取基本能把一个单页应用的真实接口面摸清楚。我自己现在的习惯是每做完一次评估都会把命中的目录、JS 里提取的路径、Burp 历史里的路径全部回收到字典库。下一次 dirsearch 跑起来速度可能没变但命中率越来越好看。目录扫描这件事工具只是起点真正值钱的是你手里的字典和验证思路。
RELATED READING

延伸阅读

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