
做安全测试的人应该都有体会目录扫描看起来是 Web 渗透里最基础的操作但真要把一个目标的目录结构摸清楚往往比后面的漏洞利用更费时间。我自己从 DirBuster 用到 dirsearch再到后来接触 dirmap最大的感受是——工具之间的差距不在能不能扫而在会不会扫。dirmap 是一款基于 Python 的开源 Web 目录/文件扫描工具它的特别之处在于不只会拿着字典去撞路径还会在扫描前先识别目标的操作系统、Web 容器、脚本语言甚至 CMS 类型然后自动选择对应的字典和扫描策略。这篇文章我就以一个实际使用者的角度从安装到高级参数组合、从单目标测绘到批量任务管理把 dirmap 的完整玩法逐层拆开讲清楚给正在做授权渗透测试、红队评估或者准备面试的同行一份可以直接参考的实战笔记。1. 别急着扫先搞清楚 dirmap 的设计思路1.1 目录扫描的本质在无地图的情况下做路径测绘目录扫描的核心逻辑并不复杂通过字典碰撞的方式向目标 Web 服务器发起大量 HTTP 请求根据响应状态码和内容长度判断某个路径是否存在。但简单只是表象真正实操过的人都知道这里面藏着不少门道。首先你要扫的是静态目录还是动态接口两者的字典设计逻辑完全不同。静态目录偏重admin、backup、upload、images这类管理性、资源性的路径而动态接口则需要关注api、action、service、getUserInfo这类语义化命名。其次服务器处理 404 的方式千差万别有的返回标准 404有的把所有未知路径都返回 200还有一些会重定向到一个统一的自定义错误页。如果不能处理这些差异扫描结果的误报率会高到没法看。我早期做目录扫描的时候踩过最大的坑就是拿到一份几千行的字典就开始扫结果扫出来上千个200 状态码的路径人工验证下来 90% 都是软 404——服务器对任何路径都返回同一个首页内容只是状态码是 200。后来我学乖了扫之前先手动请求一个绝对不存在的路径记录它的响应特征再拿这个基线去过滤扫描结果。这个习惯我一直保留到现在。目录扫描的真正价值在于为后续测试提供地图。一次完整的 Web 渗透测试路径测绘的结果决定了你后续能发现多少攻击面。这也解释了为什么 dirmap 这类工具宁可做得重一些也要把目标识别、字典匹配、结果治理这些环节包含进去。1.2 dirmap 的核心优势把扫描变成一条自动化的决策链dirmap 是安全研究员 H4lo 开源的项目定位是比 DirBuster、dirsearch 更高级的目录扫描工具。它最吸引我的地方不是多线程或者递归这些每个扫描器都有的功能而是它对目标感知的处理。具体来说dirmap 启动扫描后会先做一轮轻量级探测根据响应头里的Server、X-Powered-By、Set-Cookie等字段判断 Web 容器和脚本语言根据页面 DOM 特征判断是否使用了 WordPress、Drupal、ThinkPHP 等常见 CMS。拿到这些指纹之后它会自动加载对应的专属字典。比如识别出目标是一个 WordPress 站点就会把wp-admin、wp-content、wp-includes、xmlrpc.php这些路径的优先级提高识别出 ThinkPHP 框架就会追加runtime、application这类框架特征路径。这个设计解决了一个很实际的问题当你手里有一批类型迥异的目标时手工逐个配置字典基本不现实而用同一个通用字典去扫所有目标命中率又低得可怜。dirmap 把目标识别—字典匹配—扫描执行串成了一条自动化的链路相当于帮你省掉了信息收集环节最繁琐的一步。另外dirmap 支持的几个高级能力也是我选择它的原因递归扫描扫出的目录自动作为新起点继续向下探测可控制深度页面爬取解析从返回的 HTML 中提取链接自动加入扫描队列robots.txt 和 sitemap.xml 解析把网站自曝的路径直接变成扫描素材配置驱动通过-lcf加载统一配置文件把常用参数固化下来团队协作时特别好用这些功能单个拿出来都不算稀奇但整合到一条流水线里效果就很可观了。后面我逐个展开讲。2. 安装部署与第一次扫描2.1 环境准备三行命令搞定dirmap 依赖 Python 3 环境官方推荐 3.7 以上版本。安装过程很简单git clone https://github.com/H4lo/dirmap.git cd dirmap pip3 install -r requirements.txt如果你在 macOS 或者 Linux 上用这里基本不会遇到什么问题。Windows 上稍微注意一点建议用 Python 官方版本不要用 Microsoft Store 那个版本否则装依赖的时候可能会遇到 PATH 解析的问题。依赖装完以后先不要急着扫描跑一下帮助命令确认环境正常python3 dirmap.py --help能看到完整的参数列表和用法说明说明环境就没问题了。如果报错缺少某个模块就用pip3 install 模块名单独补一下这种情况多发生在网络环境不稳定的情况下依赖没有一次装全。2.2 第一条命令-lcf 的妙用dirmap 的入门命令其实就一条python3 dirmap.py -i https://example.com -lcf-i指定目标-lcf是 load config file 的缩写意思是加载配置文件。这个参数是 dirmap 区别于其他工具的一个很贴心的设计。项目里预置了一份配置文件里面写好了请求头、User-Agent、Cookie、线程数、请求延时、超时时间、状态码过滤条件、字典路径等一堆参数的推荐值。你只要加上-lcf工具就会按作者的推荐配置跑一次完整扫描。我强烈建议新手第一次用 dirmap 时老老实实带着-lcf跑。原因在于dirmap 的参数之间有不少隐含联动关系。举个例子递归扫描开启之后如果没有同时设置合理的递归字典深度或者没有配合状态码过滤条件扫描请求量会成倍增长最后得到一个又慢又吵的结果。配置文件把这些联动关系都预调好了你先跑一次拿到一个标准结果再在这个基础上根据自己的需求调整参数思路会清晰很多。第一次扫描跑完dirmap 会在输出目录中生成结果文件。我这边习惯在跑之前先建好一个单独的工作目录方便结果归档。扫描过程中终端会实时打印每个命中路径的状态码和响应大小看着很有成就感。3. 核心参数逐条拆解与配置思路3.1 目标管理单目标、批量目标与配置文件的关系单目标扫描用-i指定这个没什么好说的python3 dirmap.py -i http://192.168.1.10 -lcf批量扫描的时候用-c加上一个目标列表文件每行写一个目标python3 dirmap.py -c targets.txt -t 50这里我要专门提醒一个容易踩的坑批量扫描时-t线程数的行为在单目标和批量模式下表现不一样。单目标模式里50 个线程全部打向同一个目标批量模式下这 50 个线程是多个目标共享的还是每个目标各开 50 个线程不同版本的处理逻辑有差异。我见过有人拿 200 个目标的列表去跑线程数设了 100结果瞬间把目标服务器打挂半天缓不过来。这不是工具的问题是使用者对请求规模的预估太乐观了。我的建议是批量任务一次控制在 50 个目标以内线程数先设 10-20 跑一轮观察一下目标和网络的响应情况再逐步往上加。稳永远是第一位的一个稳定的低配扫描效果好过一个把目标打死的高配扫描。3.2 字典体系dirmap 是怎么组织字典的字典是目录扫描的灵魂这一点我在前面已经强调过。dirmap 的字典体系不是简单的一个dict.txt而是分成了几个层次通用基础字典所有目标都会扫的路径比如admin、backup、test、upload、images、css、js、index.php等扩展名字典根据目标语言环境加载PHP 站点会扫.phpJava 站会扫.jsp、.do静态资源则关注.zip、.bak、.sql、.tar.gz这类备份文件指纹专属字典识别出 WordPress 后追加 WP 专属路径识别出 ThinkPHP 后追加框架特征路径这个分层设计的价值在于把有限的请求预算花在正确的地方。同样是一万条请求扫一个 NginxPHP 站点时用 PHP 扩展名和 ThinkPHP 特征路径组成的字典命中率远高于混入大量 JSP 路径的通用字典。自定义字典用-d参数指定python3 dirmap.py -i https://example.com -d ./my_dict/common.txt我自己的习惯是建立一套按场景分类的字典目录比如api.txt专门放接口路径、backup.txt专门放备份文件名、admin.txt专门放后台入口命名。这样在遇到不同类型的测试任务时可以根据目标特征快速组合字典比每次现场拼一个乱七八糟的大字典高效得多。3.3 线程、延时与超时怎么控制扫描节奏目录扫描本质上就是高频发请求所以节奏控制直接关系到扫描的成败。线程参数用-t指定我根据不同的测试场景总结了一套参数组合内网授权测试线程 50-100延时 0 秒。内网带宽大、网络链路短目标机器一般也不会有太强的防护可以放开手脚跑公网生产目标线程 10-20延时 0.1-0.3 秒。这类目标通常在 CDN 或 WAF 后面请求太快容易出现大量 403 和 429反而拖慢整体进度目标已经出现性能问题线程降到 5 以内延时拉到 0.5 秒以上甚至可以临时停一下等目标恢复再继续判断线程开得合不合适有一个很直观的信号扫描过程中如果响应里出现大量的 429请求过多或者 503服务不可用说明你已经给目标造成了压力。这时候不要硬扛着继续跑建议停下来把线程数降一半延时加上再继续。很多新手容易忽略这个信号觉得反正字典还没扫完结果把目标扫挂了后面什么测试都做不了。超时设置也很关键。默认超时在弱网环境下会显得偏长但设太短又容易把慢速页面误判为超时漏掉真实存在的路径。我在实际项目里一般把超时设为 10-15 秒既给正常响应留了足够的时间也不会在不可达的 IP 上浪费时间。3.4 递归扫描深度控制的艺术递归扫描是 dirmap 最有价值的特性之一。普通扫描扫完一层就结束了比如你扫出/admin但不会自动去看/admin/下面还有什么。而开启递归之后dirmap 会把扫出的目录当作新的扫描起点继续向下探测。python3 dirmap.py -i https://example.com -lcf -R-R开启递归配合-D参数控制向下探测的层数。我推荐默认深度控制在 2-3 层再深就会出现两个问题一是请求量指数级膨胀二是有大量重复和低价值路径。举个例子如果字典里同时有admin和admin/login这种二级路径而递归深度又设了 3 层实际请求量会比预想的多好几倍扫一段时间后你会发现大量路径是重复的。我在实际项目中递归扫描一般只针对已经发现的高价值目录开启比如后台入口、上传目录、API 根路径。全站无差别递归的情况很少因为大部分场景下前两层扫描已经能覆盖 80% 以上的有效路径了。与其耗费几个小时做深度递归不如把时间花在分析已发现路径的页面逻辑上。4. 高级功能爬虫、解析与自动识别4.1 页面爬取把 JS 里藏的接口翻出来dirmap 的爬虫模块可以在扫描过程中解析返回的 HTML 页面从里面提取链接和脚本引用的路径自动加入扫描队列。这个功能在对付单页应用或者接口路径不按常规命名的目标时特别有用。python3 dirmap.py -i https://example.com --crawl我自己常见的用法是先用普通字典扫一遍拿到应用入口比如登录页或首页然后对这个入口单独开一次爬取。很多后台系统的导航栏和前端 JS 里存着大量字典里永远不可能出现的接口路径比如/api/v1/getUserList这种。这些路径在未授权状态下访问可能直接返回敏感数据是授权测试中非常值得关注的攻击面。爬虫模式的代价是扫描时间明显拉长因为每个页面都要额外做 HTML 解析和链接提取。所以我不建议在一开始就全站开爬虫最好是先字典后爬虫分阶段进行。4.2 robots.txt 与 sitemap.xml网站自曝的路径清单这两个文件本来是给搜索引擎爬虫看的但在安全测试里简直是送分题。robots.txt里Disallow的路径往往是网站不希望被收录的敏感目录比如/admin/、/backup/、/internal/而sitemap.xml会把站点的主要页面路径全部列出来相当于一份官方的路径清单。dirmap 把这两个文件的解析做成了开关参数python3 dirmap.py -i https://example.com --robots --sitemap我的使用习惯是扫描开始前先解析这两个文件把得到的路径人工快速过一遍。很多时候一个/backup/目录里直接放着整站压缩包比你扫半天字典高效得多。而且这两个文件给出的路径是真实存在的不存在误报问题可以作为后续扫描的种子目录。4.3 自动指纹识别dirmap 最聪明的地方dirmap 的自动指纹识别机制说起来其实就是三步发送少量探测请求根据响应头Server、X-Powered-By、Set-Cookie判断操作系统、容器和脚本语言根据页面内容的特征字符串、HTML 结构和引用的静态资源路径判断 CMS 类型综合以上信息从内置字典库中选择最合适的组合再开始正式扫描这套机制的实际价值在于批量化测试时不需要人工逐个判断目标类型。比如你批量给了 30 个目标里面有 ApachePHP 的有 NginxJava 的有套了 CDN 的还有纯静态站的dirmap 会针对每个目标分别做决策用对应的字典去扫。这比一个字典打天下的方式命中率高出一大截。不过指纹识别不是万能的。遇到纯前端 SPA 应用页面内容全靠 JS 动态渲染的时候静态 HTML 里的特征很少识别结果可能不太准确。这时候就需要手动指定字典甚至结合爬虫模式来补充路径。我的经验是指纹识别出的结果只能作为参考扫描结束后一定要人工复核关键路径不能把工具的判断当成最终结论。5. 实战场景演练从单目标到批量任务5.1 场景一对授权目标做一次完整的目录测绘假设你拿到了一个授权测试目标https://target.com完整测绘流程我一般分四步第一步先解析基础信息python3 dirmap.py -i https://target.com --robots --sitemap拿到 robots 和 sitemap 里的路径人工快速浏览一遍标记出高价值目录。第二步用通用字典跑一遍基础路径python3 dirmap.py -i https://target.com -d ./my_dict/common.txt -t 20这一步的目的是快速建立目标的结构认知——后台在哪、上传目录在哪、API 根路径在哪。第三步对发现的高价值目录开递归python3 dirmap.py -i https://target.com -R -D 2 -t 20递归时要注意只对确实存在的目录追加扫描不要全站递归否则容易陷入路径爆炸。第四步对关键入口页面开爬虫python3 dirmap.py -i https://target.com/login --crawl把这四步做完一个中等复杂度的 Web 应用半小时内基本能形成一张相对完整的目录结构图。我在项目里就是这么做的比上来就跑一个十万行的全量字典要高效得多也能避免大量无效请求干扰目标。5.2 场景二带认证信息的扫描很多应用的所有路径都在登录鉴权后面匿名扫描时所有请求都被 302 重定向到登录页扫出来的结果全是登录页 跳转地址没有实际价值。解决办法是带上认证身份再扫。dirmap 通过自定义请求头的方式传递认证信息python3 dirmap.py -i https://target.com -H Cookie: sessionyour_session_value -H X-Forwarded-For: 127.0.0.1这里有个非常容易踩的坑Cookie 里的 session 如果有效期短扫描过程中就会过期后续请求全被踢回登录页但工具不会主动提示你 session 失效了只会默默记录一堆 302。我的建议是扫描之前先用 curl 带同样的 Cookie 请求两三次确认 session 的有效时长再估算扫描任务的耗时。如果预计要扫半小时以上最好去后台设置里把 session 的过期时间调长或者干脆在授权前提下临时关闭鉴权扫完再恢复。还有一个细节有些应用的 Cookie 是绑定 IP 或者 UA 的换了环境就失效。dirmap 支持自定义 UA这时候要把 UA 也带上保持和浏览器一致。5.3 场景三结果输出与自动化处理dirmap 支持 TXT 和 JSON 两种输出格式。我推荐批量扫描时统一用 JSON方便后续用脚本做数据分析。输出结果里每条命中记录的信息大概包括请求的 URL、HTTP 状态码、响应内容长度、重定向的 Location、请求耗时等。拿到结果之后我的筛选流程是这样的先把状态码为 200 且响应长度大于 0 的路径单独拉出来人工逐个访问确认403 的路径千万不要跳过。很多管理后台在未授权状态下返回的就是 403路径确实是存在的302 重定向的路径要记录重定向的 Location 字段如果重定向到了登录页说明该路径存在但需要认证如果重定向到一个奇怪的外部地址可能涉及开放重定向问题对响应长度完全相同的一批路径保持警惕这大概率是软 404批量场景下我会写一个简单的脚本去读取 JSON 结果自动过滤掉响应长度和错误页一致的记录再生成一份去噪后的路径清单发给团队成员做后续分析。6. 常见问题排查与调优技巧6.1 扫不出结果先排查再换工具遇到跑了几千条请求一个有效路径都没发现的情况先别急着怀疑工具不行大概率是下面几个原因之一目标服务器对所有不存在的路径都返回 200也就是软 404。验证方法很简单手动请求一个绝对不存在的路径比如https://target.com/this_path_does_not_exist_12345看看返回什么。如果返回 200说明所有的 200 结果都不一定可信需要结合响应长度来判断目标有 WAF 拦截表现为所有请求都返回 403、406 或者一个统一的拦截页面。这时候扫描参数再合理也没用先确认自己在授权范围内然后考虑降低请求频率超时设置过短大量响应被当成了超时丢弃。把超时时间适当延长再试一次字典和目标严重不匹配。比如目标是一个纯静态展示站路径就那么几个你的字典全是动态接口命名命中率自然低排查的第一步永远是手工验证。先用 curl 请求一两个字典里的路径看看返回什么很多时候问题立刻就能定位。6.2 误报与漏报怎么降低噪音误报问题的核心在于软 404 和统一错误页。最实用的降噪手段是基线对比法扫描前手动请求一个不存在的随机路径记录响应状态码和响应长度扫描结束后把结果里状态码和响应长度都与基线一致的记录过滤掉剩下那些响应长度明显不同的路径才是真正需要关注的这个方法通用性极强用任何扫描器都适用。我在 dirmap 的 JSON 输出上写了一个小脚本自动化完成这步过滤每次能砍掉 60%-80% 的噪音数据。漏报问题则主要出在字典上。工具再先进字典里没有的路径它就是扫不到。最常见的漏报来源包括指纹识别不准确导致针对性字典没有加载、目标路径带有年份或者特殊命名比如bak_2021、test_0520、应用自定义的语义化命名比如/getUserInfo而不是/user/info。解决漏报没有捷径只能靠不断扩充和维护自己的字典库。我的做法在后面总结里会说。6.3 扫描效率优化与资源控制最后一节说几个提升效率的实操技巧。第一多目标并行时优先考虑多个进程每个进程一个目标而不是在一个进程里开超多线程。这样单个目标的失败或者网络卡顿不会拖累其他目标排查问题也更方便。第二大型自定义字典在扫描前做一次去重和排序。去重能避免重复请求排序则可以让字典中优先级高的路径比如admin、backup先被扫到万一中途要中断任务你已经拿到了最重要的那部分结果。第三对同一目标重复扫描时想办法复用连接。HTTP 握手在整体耗时里占比不低如果目标支持 keep-alive扫描速度会有明显提升。第四资源占用方面dirmap 是 Python 实现单实例的 CPU 和内存占用都不高。但如果你同时开几十个进程批量跑内存涨得还是很快的。建议在服务器上做资源限制或者用容器把任务隔离起来别把宿主机搞挂——我有一次批量扫描把跳板机的内存打满了SSH 都连不上去后来所有批量任务都老老实实加了资源限制。7. 写在最后我的实战心得dirmap 用了两年多前前后后跑了上百个授权目标我最深的体会是任何目录扫描工具都只是信息收集环节的一个组件真正的价值取决于你怎么把它嵌进整个测试流程。dirmap 最大的贡献是帮我把识别目标—选择合适的字典—执行扫描—产出结构化结果这条链路自动化了我只需要专注于分析扫描结果、验证高价值路径把省下来的时间花在更有深度的测试上。最后再分享一个小技巧扫描结果不要扫完就扔。我从第一次用 dirmap 开始就把每次项目的 JSON 结果按日期和目标分类归档。跑了一年以后这些历史结果本身就是一份宝贵的字典素材。把这些历史命中路径去重、清洗、按类型整理进自己的字典库下一轮扫描的命中率会越来越高。这个扫描—归档—反哺字典的正循环才是让工具价值最大化的关键。