
先说个有意思的现象很多人做安全测试时第一反应是拿扫描器去跑漏洞结果漏洞报告出来一大堆真正能打得动的却没几个。原因很简单——你连目标站点的结构都没摸清楚漏洞从哪儿来目录扫描才是信息收集阶段性价比最高的动作一条/backup.zip或者/admin/login.php往往比你在参数里费劲测半天 SQL 注入高效得多。这篇文章就围绕目录扫描这件事把工具、字典、常见泄漏点、绕过思路和防御建议整个串一遍。主要说的就是dirsearch这个工具以及字典爆破和敏感目录挖掘的完整方法。不管你是刚开始接触安全测试的新手还是已经写过不少脚本的老手这篇文章都能给你一些能直接上手的思路。1. 为什么目录扫描是安全测试里“性价比之王”很多刚入行的人以为目录扫描就是“拿个字典去撞路径”听起来好像也不复杂。但真正做过几轮完整测试的人都会认同一个观点目录扫描决定了你后续测试的深度和方向没有目录结构的认知后面的所有动作都像无头苍蝇。1.1 资产梳理是一切测试的前提拿我自己的习惯来说接手一个目标之后第一步不是拿什么重型扫描器去咔咔咔扫端口而是先做内容发现。因为端口告诉你的是“这个服务器开着哪些服务”但目录结构告诉你的却是“这个网站背后到底藏着什么东西”。这两个信息维度差距非常大。举个例子端口扫描发现目标开了443和8080看起来也没什么特别。但目录扫描跑完你发现/api/v1/swagger-ui.html直接暴露了那么多接口文档/.git/泄露了整个源码仓库这个目标的测试重心立刻就变了——根本不需要再去猜参数直接照着接口文档去审逻辑漏洞就好了。再有一种情况目标网站表面上是个展示型的官网所有页面都是静态的。但目录扫描扫出了一个/vendor/目录里面是某个已知 CMS 的旧版本。这个时候你就可以去翻那个版本的公开漏洞往往不需要自己费劲去找新的 0day。所以目录扫描的核心价值在于帮你把攻击面画出来不在看不见的地方浪费时间去盲猜。1.2 敏感目录泄露是真实存在的“低垂果实”“敏感目录泄露”这个词听起来有点抽象我换个说法你站点上那些“不应该被公开访问”的文件或目录被别人通过目录扫描的方式找到了。常见的有这样几类备份文件/backup.zip、/www.zip、/backup.sql、/1.sql.bak版本控制目录/.git/、/.svn/、/.hg/配置文件/.env、/config.php.bak、/web.config管理后台/admin/、/manager/、/console/日志文件/logs/、/runtime/log/接口文档/swagger-ui.html、/api-docs、/v2/api-docs测试页面/test.php、/info.php、/phpinfo.php这些文件一个共同的特点就是它们的价值密度极高。一个.env文件可能直接泄露数据库账号密码一个.git目录可能让你把整个源码扒下来。相比之下你去测一个反射型 XSS可能折腾半天也就证明了个“存在”危害级别完全不是一个量级。1.3 从信息收集到漏洞利用的桥梁再深入一点说目录扫描不仅仅是“收集信息的动作”它直接决定后续漏洞利用路径的选择。比如扫出/admin/login.php接下来就是爆破后台弱口令或者找登录接口的逻辑漏洞。扫出/api/v1/接下来就是测 API 的越权访问、参数注入和未授权访问。扫出/upload/接下来就是看能不能绕过限制上传恶意文件。扫出/phpmyadmin/接下来就是试试弱口令或者找已知的漏洞。所以把目录扫描放在整个测试流程的前置阶段不是“习惯问题”而是逻辑上的必然。你越早把目标的结构摸清楚后面作出的测试决策就越精准。2. dirsearch工具全解析从安装到核心用法说起目录扫描工具市面上的选择其实不少。有御剑这种 GUI 工具也有 gobuster、ffuf 这类命令行工具还有就是本文的主角——dirsearch。我自己的主力工具就是 dirsearch参数简单、字典携带方便、支持递归扫描对我的测试习惯来说非常称手。2.1 安装方法别踩“unable to locate package”这个坑dirsearch 官方推荐的安装方式是从 GitHub 克隆仓库然后直接用 Python 运行。但很多新手会下意识地去试apt install dirsearch然后就撞上一个经典报错unable to locate package dirsearch。这是为什么因为dirsearch 并不在 Debian/Ubuntu 的官方软件源里。所以如果你用apt直接装系统自然找不到软件包。这个报错本身就是正常的不是你的系统有问题也不是源没配好。正确的做法很简单git clone https://github.com/maurosoria/dirsearch.git cd dirsearch pip3 install -r requirements.txt或者干脆一点不装依赖也行用起来再说python3 dirsearch.py -u http://target.com需要注意的一点是dirsearch 对 Python 版本有要求最好是 Python 3.7 以上。老系统自带的 Python 3.6 有可能会出现某些语法兼容问题如果遇到报错建议先确认 Python 版本python3 --version低于 3.7 的话要么升级系统 Python要么用 pyenv 装一个高版本跑起来就顺畅了。2.2 基础参数详解dirsearch 的参数非常直观常用的就那么几个花两分钟就能全部掌握。最基本的用法python3 dirsearch.py -u http://192.168.1.100这样会用默认配置跑一遍够用但是不够灵活。你真正需要掌握的是下面的参数组合参数作用实例-u/--url指定目标 URL-u http://target.com-l/--list从文件读取一批 URL 批量扫描-l urls.txt-w/--wordlist指定字典文件-w /path/to/dict.txt-e/--extensions指定要探测的扩展名-e php,html,js-t/--threads设置线程数-t 20-r/--recursive递归扫描发现目录后继续往深处扫-r--deep-recursive更深层的递归扫描--deep-recursive--exclude-status排除指定状态码减少噪音--exclude-status 403-x排除多个状态码-x 403,404--random-agent使用随机的 User-Agent 请求头--random-agent--format输出格式支持 json、csv 等--format json -o result.json-o/--output保存结果到文件-o result.txt--full-url显示完整 URL--full-url--minimal只显示有实际意义的响应--minimal实战中最常用的组合是python3 dirsearch.py -u http://target.com -e php,html,js,txt -t 30 --random-agent -o result.json --format json这个命令的含义是扫描目标站点探测.php、.html、.js、.txt这几种后缀用 30 个线程加速随机换 User-Agent 避免被拦最后把结果输出成 JSON 文件方便后续分析。2.3 两个最容易被忽略但非常实用的参数很多人用 dirsearch 就是-u一把梭跑完看结果。但有两个参数我觉得非常值得专门拿出来讲。第一个是--minimal。这个参数会让 dirsearch 只输出那些有实际价值的响应。默认情况下一个扫描跑完你会看到大量 302 重定向、403 禁止访问、200 但内容是 404 页面的情况。--minimal会做一层过滤帮助你更快聚焦在真正重要的发现上。第二个是--deep-recursive。普通的-r只会对扫描到的目录做一层递归但--deep-recursive会对发现的目录持续深入扫描下去直到把整个目录树都摸清楚。代价是扫描时间会成倍增加但对某些深目录结构的站点来说这个参数真的能挖到意想不到的东西。举个例子我之前测试过一个后台管理系统外层目录扫描只发现了/admin/但用--deep-recursive跑完之后在/admin/upload/temp/2024/03/下面发现了一个残留的测试上传脚本。这种深层路径靠手动翻目录或者普通扫描根本发现不了。2.4 状态码含义是救命的判断依据几乎所有目录扫描工具都会打印 HTTP 状态码但很多人看的时候只是扫一眼 200 和 404其他状态码直接忽略掉。这是个很大的浪费。以我自己的经验四个状态码最值得关注200 OK路径存在且有内容直接访问看看。301/302 重定向路径存在但会跳转。跳转的位置可能暴露更多信息比如/admin/重定向到/admin/login.php这本身就是一条线索。403 Forbidden路径存在但禁止访问。禁止的原因可能是目录索引被关了也可能是权限配置严格。但“存在”这个事实本身就非常重要。401 Unauthorized需要认证。这类路径往往后面跟的就是登录界面值得加入后续爆破的候补名单。特别要提一下404 状态码也可能有诈。有的网站因为前端框架的关系所有不存在的路径都返回 200但页面内容是 SPA 的空壳还有的网站配置了错误处理所有不存在路径统一返回 302 跳首页。遇到这种情况光靠状态码判断会栽大跟头。我的经验是当一个站点的 404 行为异常时把扫描结果里那些看似“不存在”的路径随机抽几条用 curl 手动看一眼真实响应内容。我有一次就是在所有路径都返回 200 的 SPA 站点上靠curl -L跟进重定向之后发现目标其实是个内部 API 网关后面的测试思路完全是围绕这个发现展开的。3. 字典爆破决定扫描上限的是字典质量工具只是把请求发出去的工具真正决定目录扫描“能不能扫出东西”的关键其实是字典。再强悍的扫描器配上弱智的字典效果也是一场空。反过来一个贴合目标情况的精调字典往往能带来远超预期的发现。3.1 字典到底怎么选如果你刚开始接触目录扫描我建议直接从常用字典起步跑一遍再说。dirsearch 自带的db/dicc.txt和db/dir.txt在通用场景下表现都还不错至少能覆盖掉最常见的命名习惯。但如果你想更进一步就得学会根据目标类型去调整自己的字典。比如目标是 PHP 写的站点字典里就应该放大量.php、config.php、install.php、upload.php这类文件名。目标是 Java 写的站点重点就放在WEB-INF、META-INF、/actuator、/swagger-ui.html、/druid这些路径上。目标是 Windows 服务器web.config、.bak、1.asp这类路径就要进字典。目标是 ThinkPHP/Laravel 这类框架/runtime/、/storage/、/.env、/public/这类框架专属目录就变得非常重要。所以“拿一套字典走天下”的思路基本行不通。好的做法是准备一套基础通用字典再配合几套针对不同技术栈的专项字典根据目标的情况灵活切换。3.2 御剑字典和常见开源字典的特点很多国内安全测试者最早接触目录扫描都是通过“御剑”这个工具它自带的字典包也比较经典到现在仍然很有参考价值。御剑的字典特点是覆盖面广、常用路径收录很全很多中文站点的命名习惯也在里面。另外 GitHub 上还有一个经典项目叫dirsearch的字典就在工具自带的 db 目录里以及SecLists项目里的Discovery/Web-Content/目录。SecLists 中针对不同场景的字典分成很多个文件有专门测常见备份文件的、有专门测管理后台路径的、还有专门收集 API 端点的。我一般这样组合先用 dirsearch 自带字典快速跑一遍求个保底。再用御剑那个几百兆的字典包跑第二轮看看能不能挖出更冷门的路径。最后根据目标的技术栈特征手工整理一份专属小字典精扫一遍重点目录。三轮扫完之后目标的基本结构就非常清晰了。3.3 字典的自定义技巧与“小字典哲学”很多人喜欢用大字典去跑觉得“字典越大扫得越全”。这个思路在小型目标上还行但在真实测试场景中很容易翻车。原因有两点第一字典越大发起的请求就越多被 WAF 封 IP 的概率就越高。很多站点对访问频率有严格限制跑着跑着你就发现自己被拉黑了后面的测试也没法继续了。第二字典里垃圾条目太多扫出来的结果噪音也大。一个只有 200 行的精调小字典可能比一个 10 万行的大字典更有价值——因为前者每一个条目都是针对当前目标精心挑选过的命中率会高很多。我自己维护了一份“高频敏感路径小字典”大概 500 行左右核心就是那些备份文件、部署残留、日志文件和配置文件路径。跑任何目标之前我都会先用这份小字典快速过一遍重点不是求全而是快速锁定高价值目标。3.4 Burp Suite 字典与目录扫描的结合我注意到热词里有“burpsuite爆破字典”说明不少人其实是想用 Burp Suite 来跑目录爆破。这个思路是可行的dirsearch 负责“快速发现”Burp 负责“精细验证”二者结合起来效果非常不错。具体操作是这样先用 dirsearch 扫一遍目标锁定几个值得深入的后台路径和接口。用 Burp Suite 的 Intruder 模块针对锁定的路径做更细粒度的参数爆破比如后台登录用户名、密码、验证码接口等。把 dirsearch 扫出来的路径作为 Burp 的字典来源直接送进 Intruder做一些深度测试。Burp 的 Intruder 模块可以识别§标记的变量位置举个简单的例子你要爆破/admin/login.php的账号密码可以把请求包里的usernameadminpassword123456改成username§admin§password§123456§然后加载字典点击 Start Attack 就可以了。在 Burp 里设置爆破字典时Payload 类型一般选 Simple list然后加载你准备的用户名或密码字典就行。这个时候之前收集的目录扫描结果会变成非常有用的参考——因为你在扫目录的时候就已经知道目标可能是什么 CMS、什么框架所以爆破时准备的账号密码字典也应该跟目标的技术栈相匹配。4. 敏感目录泄露挖掘从路径发现到数据获取目录扫描扫出来的路径到了一定程度就不再是“看到一个路径”的事情了。它变成了一条信息链你可以从一个泄露路径出发顺藤摸瓜挖出一串东西。这一章我详细展开几种常见的敏感信息泄露场景以及对应的利用思路。4.1 .git 目录泄露与源码还原.git目录泄露是所有敏感目录泄露里“含金量”最高的一种。原因很简单只要.git目录可以被访问整个源码仓库的提交历史就相当于直接暴露了你可以从里面还原出全部源码甚至包括已被删除的敏感文件。检测方法很简单直接访问http://target.com/.git/如果返回 200 或 403 而不是 404基本可以断定这个目录存在。接下来就可以用工具来下载整个仓库。常用的工具是GitHack或git-dumper。以git-dumper为例pip install git-dumper git-dumper http://target.com/.git/ /local/output/dir工具会把.git目录里的内容全部下载到本地然后在本地执行git log、git checkout就能看到历史版本和全部源码。实战中我遇到过一个案例扫描发现目标存在.git泄露用工具还原源码之后在git log里看到一个早期的提交记录里面包含了一个数据库连接配置文件账号密码都明文写着。后来我就用这套数据库账号直接连上了目标的数据库整个测试的复杂程度瞬间从“猜谜游戏”变成了“直接看答案”。这就是.git泄露的可怕之处——它不仅暴露当前代码还暴露整个项目的所有历史。4.2 备份文件与配置文件的“高价值命中”备份文件是另一个经常被忽略但价值极高的泄露点。很多开发人员会习惯性地把网站打包备份放到服务器上文件名通常带有明显的标记。比较常见的模式有/backup.zip、/backup.tar.gz、/backup.sql/www.zip、/website.zip、/site.rar/1.zip、/1.sql、/test.zip/.bak、/index.php.bak、/config.php.bak/web.rar、/html.zip还有一种非常典型的情况就是在根目录看到.env文件。.env是很多框架用来存放环境变量的文件里面大概率包含了数据库连接信息、密钥、第三方服务的 API Key 等敏感信息。判断.env是否存在很简单curl http://target.com/.env如果返回的内容里有DB_HOST、DB_USERNAME这些字段你就是撞到大运了。4.3 API 接口文档与未授权访问Swagger 这类接口文档泄露在现在的 Java 站里太常见了。只要接口文档暴露出来整个 API 的路由结构就全在明面上了。常见的接口文档路径/swagger-ui.html/swagger-ui/index.html/v2/api-docs/v3/api-docs/api/swagger-ui.html/doc.html如果你拿到这些接口文档接下来要做的事情就非常明确了逐个看接口定义优先找那些没有鉴权要求的接口然后测未授权访问。举个例子一个接口文档里定义了GET /api/user/{id}这个接口没有标注需要认证。你直接curl http://target.com/api/user/1如果返回了用户信息这就是一个典型的未授权访问漏洞伤害等级可能比一个 RCE 还高——因为它直接泄露了海量用户数据。4.4 实战案例复盘一次完整的敏感目录挖掘链路为了让你更直观地理解整个流程我复盘一个真实的测试案例。目标是一个普通的电商站点我用 dirsearch 带了默认字典先扫了一遍很快发现了几个路径/admin/401 Unauthorized/api/200返回了一个 JSON 数据结构/.git/403说明目录存在看到.git泄露的第一时间我就知道这个站点大概率是“裸奔”的。用 git-dumper 把整个仓库拉下来之后在源码里翻了一下配置文件找到数据库连接信息。连上数据库之后发现里面有所有用户的手机号、收货地址和订单记录。后续甚至不需要再做任何其他测试了。一个.git泄露把整个系统脱了个精光。这个案例给我的教训很深刻目录扫描的价值不在于“扫到了多少路径”而在于“扫到了哪些可以串联起来的信息链”。单个路径可能只是一个线索但多个线索组合在一起往往就能形成一条从外围到核心的完整利用链路。5. 绕过思路与高效扫描的进阶技巧真实测试中目录扫描没你想的那么顺。遇到 WAF、遇到 CDN、遇到假的 404都会让扫描结果变得不可靠。下面这几招都是我实战中验证过能够明显提升扫描有效性的技巧。5.1 高频扫描下的 IP 封禁与绕过目录扫描本质上是一秒钟发几十上百个请求这个频率放在正常用户身上完全不正常。很多站点的防护策略会直接拉黑这种高频访问的 IP。如果你在扫描过程中发现结果里突然大量出现 403 或者 429之后就全是 403、429 甚至直接超时那很可能是被临时封了。应对办法有这么几个降低线程数-t 10甚至-t 5把请求频率控制在防护规则感知不到的区间。加随机延迟部分工具支持随机延时--delay参数让请求时间看起来更像真实用户行为。随机 UA--random-agent避免因为同一个 UA 高频访问而被识别。代理池有条件的可以挂代理池轮换出口 IP但要注意代理的稳定性和延迟不然扫描速度会大打折扣。我的经验是优先用“慢而稳”的策略。一个目标跑 30 分钟没被封比跑 5 分钟被封然后什么都干不了要强得多。5.2 扩展名的选择策略别只会扫 php很多人就只会用-e php去扫但实际上目录扫描的扩展名策略应该跟目标技术栈高度相关。Java 站点.jsp、.do、.action、.jsonASP.NET 站点.aspx、.asmx、.ashxPHP 站点.php、.phtml、.php5通用静态资源.html、.js、.txt、.bak、.conf、.xml、.json还有一个关键点是很多文件名根本不需要扩展名也能访问比如/backup、/config、/readme。所以扫描的时候主体字典不带扩展名的路径和扩展名字典带扩展名的路径要同时跑缺一不可。5.3 多阶段扫描策略先快速再精细我习惯把整个目录扫描过程拆成三个阶段而不是只跑一次就收工。第一阶段叫“快速侦察”。用 dirsearch 默认字典线程数稍微高一点目标是把站点的基本目录结构快速拉出来。这个阶段的目标是求快容忍一定程度的漏报。第二阶段叫“精细深挖”。根据第一阶段的发现锁定重点目录用自定义字典做递归扫描。这个阶段的目标是求深把隐藏的深层路径给挖出来。第三阶段叫“专项验证”。针对扫描得到的所有敏感路径用 curl 或者 Burp 逐个手工确认。因为扫描器有时会误报比如把一个 404 页面的响应当成 200 处理手工验证能过滤掉这些假阳性。这个三阶段思路的核心理念是先用低成本的方式找到高潜力的目标再集中资源对这些目标进行深度测试而不是在整个站点上平摊资源。5.4 递归扫描与重定向跟踪的正确姿势递归扫描是深入挖掘目录结构的关键手段但也要注意控制节奏。默认的-r参数只对扫描到的目录进行一个层级的递归--deep-recursive则会一直递归下去。如果目标目录层级很深这个参数可能产生海量请求对目标造成不必要的压力也容易被封。我建议的做法是先用普通递归跑一遍筛出有价值的目录层级再针对这些层级手动指定一个一个扫。这样比无脑全深递归可控得多。重定向跟踪也是个值得注意的细节。有些路径返回 302但重定向到的位置才是真正的敏感资源。dirsearch 默认不会跟随重定向但我一般会先用curl -L手动确认几个关键路径的重定向目标再决定下一步动作。5.5 敏感路径的优先排查顺序为了让扫描更有条理我把目标路径按“优先级”排了序。这个顺序来自多年实战中“命中即高收益”的经验。第一优先备份文件与环境配置文件。/.git/、/.env、/backup.zip、/www.zip、/config.php.bak。这一类只要命中大概率等于你拿到了目标的钥匙。第二优先管理后台与上传接口。/admin/、/manager/、/upload/、/file/。这类路径是后续弱口令爆破和文件上传测试的入口。第三优先API 与接口文档。/api/、/swagger-ui.html、/v2/api-docs。这类路径直接决定你能不能从接口层面找到未授权访问。第四优先部署信息与日志。/robots.txt、/sitemap.xml、/logs/、/runtime/。这种路径看起来不起眼但往往能给你一些额外的线索。按照这个优先级去安排扫描顺序好处是就算你只跑了一轮就因为某种原因不得不中止至少已经把最可能出成果的方向覆盖完毕了。6. 从攻击视角转到防御视角如何自查敏感目录泄露我这个人有个习惯做完一轮测试之后会顺手给目标写一份自查建议。因为真正的安全测试目的不应该是“证明你有多能打”而是“帮对方知道自己哪里最疼”。所以这一章把防御方的自查清单也整理出来目录扫描的“攻”与“防”其实是同一套知识体系。6.1 开发阶段就应该避开的高危习惯很多敏感目录泄露根子不在配置而在开发习惯。最常见的几个把备份文件放在 Web 目录下。我见过太多站点/backup.zip就堂而皇之地放在网站根目录里。备份文件应该放在 Web 根目录之外的路径或者下载后立刻移除绝不能躺在线上环境里。用.git管理生产环境代码。有些团队会把生产服务器直接作为 Git 仓库来用每次更新代码都git pull导致.git目录直接暴露。生产环境应该用发布流程CI/CD来更新代码而不是在服务器上直接操作 Git。使用默认安装路径或未删除的安装文件。/install/、/wp-admin/install.php这类目录和文件只要存在就有风险安装完成后应该立即删除。敏感信息硬编码在配置文件中。.env、config.php这类文件里的数据库密码、API Key应该使用环境变量或密钥管理系统而不是直接明文写在配置文件里。6.2 Nginx/Apache 规则自查清单服务器层面的配置可以很大程度上缓解目录扫描的风险。虽然无法完全阻止扫描但至少可以让扫描的“信息收益”大幅降低。Nginx 的经典做法是加一条默认拒绝规则location ~ /\.(git|svn|hg) { deny all; }Apache 则在.htaccess里加RedirectMatch 404 /\.git更彻底的做法是针对敏感文件做精确封禁比如location ~* (\.env|\.git.*|\.svn.*|\.bak|\.sql|\.tar\.gz)$ { deny all; }还有一点值得强调403 和 404 的语义差异。对于不存在的路径返回 404 是正常行为。但对于已存在但禁止访问的路径如果返回 403等于直接告诉扫描者“这里有个东西但是不让你看”。所以很多团队的策略是把这些敏感路径同样配置成 404降低被进一步探测的概率。6.3 定期扫描自查防御方也应该养成定期对自己站点做目录扫描的习惯。不需要用什么复杂的工具就用 dirsearch 跑一遍自己的域名看看能不能扫出那些“不该出现”的路径。我自己做安全运维的朋友每个季度就会对自己的线上环境做一轮目录扫描自查。有一次他在一次例行扫描中发现了/logs/目录下面残留了几年前的日志文件里面有大批包含敏感参数的请求日志。如果不是定期自查这个隐患可能一直躺在服务器上。所以目录扫描不只是攻击者的专利防守方同样需要用它来自查。7. 补充几句实战体会说到底目录扫描不是一个“装个工具跑一下”就结束的简单动作。它的背后是一整套信息收集与测试决策的方法论。工具只是加速了这个过程真正的判断力在你自己的脑子里。我对新手的建议一直很简单不要沉迷于新工具先把一个工具用透把字典里的路径分类记清楚把你自己的目标站点翻烂你就已经超过大多数人。dirsearch 是一个很稳定的起点它能帮你完成 80% 的目录发现需求剩下的 20% 靠的是你对目标站点的理解和经验积累。另外做这类测试一定要有边界意识。目录扫描本身是安全测试的常见手段但测试范围一定要限定在自己拥有授权或对方明确许可的目标上。法律红线不能碰技术能力应该用在正经的安全建设方向上。这篇文章就把目录扫描的核心链路讲完了。从工具使用到字典策略到敏感目录挖掘再到绕过思路和防御自查算是一个比较完整的闭环。希望这些踩过的坑、总结出的经验能让你在后面的实际测试里少走点弯路。