1. 先弄明白dirsearch扫描为什么会被WAF拦1.1 一次目录扫描的典型困境做Web目录扫描的人几乎都用过dirsearch也几乎都被WAF教育过。我印象很深的一次授权测试目标是一个带前置WAF的业务系统我拿到授权后顺手跑了默认配置的dirsearch结果前20秒还正常第30秒开始返回码从200密集地变成403再过一会儿连目标IP的响应都超时了——不是目标挂了是我的出口IP被WAF直接拉进了黑名单。这不是个别现象。很多同行一上来就把线程拉满字典选最大的觉得扫得越快发现越多。但在WAF眼里这种行为的特征实在太好认了一个IP在极短时间内发出大量不同路径的GET请求User-Agent是扫描器默认值没有业务链路里的Referer甚至没有浏览器常见的Accept头。这个画像一出来基本就是“目录扫描”四个字写脸上。所以这篇文章要解决的不是“怎么让dirsearch更快”而是“怎么让你的扫描流量看起来不像扫描”。以下5个技巧全部来自实际授权测试里的验证不是纯理论。1.2 WAF拦截目录扫描的底层逻辑WAF拦截目录扫描一般是按以下四个维度叠加判断的第一黑名单特征。这是最直观的。很多WAF规则库里直接写了常见扫描器的User-Agent特征、路径关键字比如/admin、/backup、/.git以及高频参数。dirsearch默认的UA在规则库里几乎是明牌不拦你拦谁。第二频率与并发。WAF会统计单位时间内的请求数通常以秒或分钟为窗口。如果你在10秒里对同一个域名发了几十个请求且路径互不相关这种模式很容易触发速率限制。更严格一点的WAF还会统计“404占比”——正常访客访问一个站不可能一半以上的路径都是404而目录扫描天然就是高404比例。第三会话行为缺失。浏览器访问页面会带上Cookie、Referer、User-Agent、Accept、Accept-Language甚至会有完整的浏览路径。而默认的dirsearch请求往往是裸奔的没有会话、没有来源、没有页面上下文每条请求都像一个凭空出现的陌生人。第四响应内容校验。有些WAF会先返回一个JS挑战页或者验证码观察你是不是真的浏览器。如果你的请求不执行JS、不携带Cookie下一步就会被判为可疑流量。理解了这四层逻辑你才能明白后面每个技巧的针对性伪装UA是对付特征识别控制速率是对付频率统计优化字典是为了减少无效请求、降低404比例配置多出口IP是为了避免单IP被拉黑后全军覆没。1.3 授权测试的合规边界在往下聊之前必须把丑话说在前面下面所有技巧只适用于你有明确授权的目标。授权测试通常需要书面确认明确测试范围、时间窗口、允许的测试方式以及数据保密要求。没有授权哪怕是“我就看一下”从法律上也属于未授权访问。WAF绕过这个话题本质上是一个中性的技术能力。对于防御方它可以用来评估WAF规则是否真的严密、哪些绕过路径真实存在从而针对性地加固。对于攻击者它就是一把刀。刀本身没问题关键看拿刀的人是不是在做正事。这篇博文里的所有内容请一律在授权场景下使用。2. 请求伪装把扫描请求“打扮”成普通访客2.1 User-Agent与常规Headers定制dirsearch默认的User-Agent长什么样经常做测试的人一眼就能认出来更别说WAF规则库了。所以第一步就是把UA换成主流浏览器的真实UA。这里有个细节不是随便找一个Chrome UA就完事最好UA版本和你的其他Headers能对得上。比如你用Chrome UAAccept头却写成*/*这在行为分析里就有点不协调。比较实用的搭配是dirsearch -u https://example.com \ --user-agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 \ --header Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,*/*;q0.8 \ --header Accept-Language: zh-CN,zh;q0.9,en;q0.8 \ --header Referer: https://example.com/为什么Referer很重要因为正常用户从某页面点击链接进入另一个页面一定会带Referer。如果你的每个请求都无来源WAF的行为画像里就会多一个疑点。Referer最好指向目标站点自己的页面比如首页或者一个真实存在的业务入口。你可以先手动访问目标看它的URL结构然后用那个URL做Referer。--random-agent参数也可以自动随机UA但我更建议自己指定UA。原因有两个一是随机UA池里有些UA已经过时反而看起来奇怪二是自选UA搭配固定Headers一致性更好。如果你还是想用随机UA至少要配合我自己指定的Accept等Headers一起用。2.2 请求速率线程、延迟与随机化很多人的第一反应是把--threads调到50、80觉得并发高速度才快。但在WAF场景下高并发是最无需智慧的送人头方式。我见过一个比较有意思的项目测试同一台机器、同一个目标线程从默认的10提到30之后扫描量确实上去了但被拦率从不到5%直接飙到90%以上最后能用的结果几乎为零。推荐的起点是--threads 4或--threads 8配合--delay 0.2 ~ 0.5。--delay是每次请求之间的间隔秒数它能压低短时间窗口内的请求频率。如果目标站是重业务系统或者WAF对速率特别敏感建议把线程降到2、delay拉高到0.8宁可多花二十分钟也比被封IP之后重来一个小时强。--timeout也值得设置默认值在部分网络环境下可能偏短导致大量请求超时重试看起来就像是在高频重连。我习惯设成10秒dirsearch -u https://example.com \ --threads 8 \ --delay 0.3 \ --timeout 10另外dirsearch的delay是固定间隔。实际真实用户不太可能精确、均匀地每0.3秒发一个请求所以有条件的话可以用外部脚本控制请求节奏或者配合多出口节点让同一个目标看到的请求来自不同IP、不同时间这样更像多用户在访问。2.3 常用命令组合参考把上面几个维度组合起来一个比较顺手的开局长这样dirsearch -u https://example.com \ -w /path/to/custom_dictionary.txt \ -e php,html,js \ --threads 6 \ --delay 0.3 \ --timeout 10 \ --user-agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 \ --header Accept: text/html,application/xhtmlxml \ --header Accept-Language: zh-CN,zh;q0.9 \ --header Referer: https://example.com/ \ --exclude-status 404,500注意不要盲目把403排除掉。WAF返回的403和业务系统真实的403含义完全不同。前者说明你的请求被拦了需要调整策略后者往往说明路径确实存在只是禁止当前身份访问——这种反而是有价值的发现。所以我一般只排除404和500403先留着后面人工验证。3. 字典优化让每一次请求都更有价值3.1 默认字典的局限性dirsearch自带的字典覆盖面很全从admin、backup到各种常见文件名列了一大堆。但全也有全的问题第一这些路径太“标准”早就在WAF的规则库里形成模式第二大量通用路径对特定目标来说根本没意义比如一个电商系统不会存在/webmail一个内网OA也不会出现/wp-content这些无意义请求只会拉高404比例给WAF提供判断依据。所以与其扛着2万条字典硬扫不如做一个2000条的高质量定制字典。你会发现请求总量下来了命中率上去了404比例也从80%以上降到60%左右WAF那边反而先给自己松绑了。3.2 基于指纹的定向字典定制字典的核心是先做目标指纹识别。你不一定要用复杂工具手动看几个点就行响应头里的Server、X-Powered-By字段能告诉你后端是Apache还是Nginx是否是特定开发框架。Set-Cookie字段的格式往往能暴露框架类型不同框架的Cookie命名差异很大。首页HTML里的版权信息、资源路径、JS文件命名经常会暴露具体的建站系统或二次开发框架。通过JS文件列表可能发现后台入口、API前缀、公共方法名这些都是比通用字典更精准的路径线索。举个例子有一次模拟项目X里遇到“某开源商城系统”通用字典扫了一轮只发现几个静态资源路径。后来我去翻它前端的bundle.js在代码里找到了一条类似/merchant/api/的前缀再加入字典定向扫描直接把管理端接口暴露了。这比暴力遍历/admin有质量得多。3.3 路径变体大小写、编码与后缀WAF规则里常见的路径黑名单通常是全小写匹配或者对特定模式做精确匹配。适当的大小写变体有时能绕过一些比较基础的规则/Admin和/admin在某些大小写敏感的服务端和后端路由里是两个路径而WAF规则可能只写了小写。类似/BACKUP、/Backup这种变体也值得放进字典。URL编码如/%61dmin在某些老旧的中间件上会被解码但现代WAF大多会先解码再匹配所以这个只能算补充手段不能当主力。后缀方面的思路是让你扫的路径与目标技术栈匹配。发现目标有PHP痕迹就重点扫.php、.phtml、.php5看到是Java业务就扫.do、.action、.jsp。dirsearch的-e参数可以指定扩展名也可以用-f强制每个路径都尝试这些后缀。不过-f会让请求量翻倍建议先小范围试用。3.4 实例一个电商站的字典优化过程还是刚才那个模拟项目X第一次使用默认字典2万条跑完耗时40分钟命中像样的路径不到10条还被拦截了几次。后来我把字典裁剪到800条加上了从JS里提取的API前缀、从Cookie里推测的框架路径、以及改版后的后台别名5分钟扫完命中4个隐藏接口和2个管理后台路径。方向对了少就是多。4. 扫描节奏与递归策略别把自己“扫”出去4.1 线程数与时长的平衡看响应码分布是调参数最快的方法。启动扫描后前30秒多观察如果大量403说明请求特征被识别了先停改UA或延迟如果是429说明WAF在做频率限制把线程降一档、delay加一档如果是正常200、301、302混合说明当前速率基本被接受可以继续。尽量不要一个命令从头扫到尾。分阶段扫描会更可控先扫根目录拿到初步结果后再针对有价值的子路径做第二轮。长时间高频扫描对WAF来说就是在宣告“我来了”很多严格一点的WAF会在第几分钟后启动IP黑名单哪怕你前面的请求都伪装得很好。分段扫描的命令思路# 第一轮根目录低线程收集基础情况 dirsearch -u https://example.com -w small_first_round.txt --threads 4 # 第二轮对发现的疑似后台/接口目录继续 dirsearch -u https://example.com/api -w api_related.txt --threads 34.2 深度递归的正确用法dirsearch支持递归扫描也就是扫描到目录之后继续往下一层目录扫。这在人工测试时很好用但默认的递归如果没有节制请求量会指数级膨胀。一个目录下可能套着多个子目录每个子目录又是一批请求很快你就会发现扫了半天请求全部被拦截结果还没存下来。我的做法是限制递归深度只对指定状态码的目录递归。比如只对返回200或301的真实目录继续深入而不是看到404目录也进去挖。参数方向是--recursive配合--deep 2再配合--exclude-status过滤掉无意义的目录。不要无脑扫到5层、8层正常情况下2到3层足够覆盖大多数测试需求。4.3 结果验证状态码、内容比对与误报过滤目录扫描不等于拿到结果就完事。大量“命中”其实是WAF的软404它不直接回404而是回200但内容是一个统一的“页面不存在”模板。如果你只看状态码会把整个站点扫出一堆假后台。判断软404比较简单抽出几个不同路径的响应体看Content-Length是否完全一致页面标题是不是都是同一个“未找到”之类的字眼。dirsearch在输出结果时注意看长度列如果不同路径的返回长度相同大概率是统一错误页。403状态码要单独重视。它不表示路径一定存在但可能表示“路径存在但禁止访问”。用浏览器直接访问一下如果看到的是登录跳转或权限校验那这就是有价值的敏感目录。301/302也要跟踪Location。有些扫描工具不会访问重定向后的页面导致你以为找到了一个重要路径实际上默默跳转到了首页。手动验证几个关键命中比批量“扫描即结论”可靠得多。我习惯在扫描后用curl批量复核一批URL把状态码、响应大小、标题一起拉出来while read url; do curl -s -o /dev/null -w %{http_code} %{size_download} $url\n \ -A Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 $url done urls_need_check.txt这样能快速排除大量假阳性后续人工验证就轻松很多。5. 网络出口配置多IP轮换与链路优化5.1 为什么单IP容易触发风控即使你把UA、Headers、速率、字典都调到位了还有一个绕不开的维度IP。WAF在统计频率的时候最常见的时间窗口是按IP聚合的。一个IP在10分钟内发出500个请求哪怕每个请求都像浏览器从总量上看也超出了正常单用户的行为范围。更麻烦的是WAF可以在一段时间内对单个IP直接拉黑。一旦IP被拉黑你的扫描流量再像人也没用所有请求都会在接入层被丢弃。所以如果你的测试环境允许配好网络出口、实现多IP轮换是避免“全军覆没”的关键一环。5.2 出口配置的通用思路这里就是标题里提到的“网络出口配置”部分。为了说清楚先给一个总的方向让dirsearch的请求不是直接从本机IP发出而是经过一个或多个前置出口节点转发然后在多个出口IP之间切换。第一步确认你的测试环境有没有可用的出口链路。通常情况下这类能力来自你所在团队的安全测试基础设施比如合规的远程测试节点、按项目分配的跳板主机或者由安全团队统一管理的出口池。我在这里不做任何工具推荐因为你所在环境的接入通道可能完全不同。第二步在dirsearch中查看当前版本支持的连接参数。不同版本对网络出口相关参数的命名略有差异请执行dirsearch --help找到与“连接”“上游”“出口”相关的选项组。一般这类参数支持指定协议http/https/socks、上游节点地址和端口。按照你的出口服务提供方给出的接入说明填写即可。第三步配置完成后先做连通性验证。用一个简单的curl请求确认当前出去的IP确实是期望的出口IPcurl --http1.1 ifconfig.co curl -S -m 5 https://api.ipify.org如果你配置了多个出口节点还应该分别检查每个节点出去的IP是否不同而不是全部走了同一个。5.3 一个通用的配置模板思路下面这份配置只是把原理写清楚具体字段名以你本机dirsearch版本的帮助输出为准# dirsearch 出口配置思路 [network] ; 出口节点协议http / https / socks outbound_protocol http ; 出口节点地址与端口 outbound_addr 你的出口节点:端口 ; 是否开启多出口轮换 rotate true ; 轮换间隔秒 rotate_interval 120关键点是轮换间隔不要太短。有些新人会把轮换设成每10秒甚至每个请求都切IP看起来很难被限制但实际上这种高频率的出口切换本身就是异常特征更严格的WAF会把它判定为分布式扫描或脚本化请求。我实测下来200到300个请求切换一次或者间隔一两分钟切一次被识别的概率要低得多。另外多出口IP尽量不要选同一IP段。如果两个出口IP在同一个C段WAF按IP段限速时照样会一起被限制。不同段、不同运营商的效果更好但这取决于你手头有多少可用资源。5.4 配置检查清单与踩坑根据我自己的使用经验出口配置最容易踩的坑有这几个第一节点延迟过高。如果你在境内测试境内目标但出口节点绕了大半个网络每次请求的RTT明显变高扫描速度会大幅下降而且超时量增多。这种情况优先选择离目标区域近的节点。第二共享出口IP的连带问题。有些出口池里的IP是很多测试任务共用的如果其他人正在高频扫描同一个目标你也会被连带拉黑。所以刚开始扫描时如果发现一上来的403比例就异常高先怀疑出口IP的“名声”是不是已经坏了。第三你以为切换了IP结果没有生效。有时候配置写对了但dirsearch没有真正走出口流量还是直连。所以一定先做连通性验证再看扫描日志里的出口IP变化不要埋头扫半天才发现问题。5.5 合规提醒网络出口配置是一个非常敏感的话题多说两句。我在这里默认的前提是你用的是自己团队分配的正规测试通道而不是某种未经授权的手段。如果你没有合法的测试通道可用请绝对不要自己去寻找来路不明的出口链路。测试工作应该有边界技术能力不该用错地方。6. 一次完整实战WAF环境下的扫描记录6.1 场景设定有次项目测试里目标是一个模拟业务系统前端有一层商用WAF后端是某Java框架。授权明确测试窗口3小时。我一开始想直接跑一遍默认dirsearch快速摸底。6.2 分步配置与执行第一个轮次默认配置线程10自带UA默认字典。结果是扫描开始后约40秒大量请求变40380秒后出口IP被封连接直接超时。有效命中为零。第二轮次只改伪装和速率线程8delay 0.3自定UA和Headers排除404。这次明显撑得久了一些但扫到1600多个请求时还是出现了一波403说明频率维度还是没过关。第三轮次加入定制字典和出口轮换线程5delay 0.5字典裁剪到1500条出口节点两个轮换间隔90秒。这一轮跑完全程没有再出现大范围403发现了一批真实存在的路径包括一个管理后台接口、两个未授权访问的导出接口。6.3 结果对比配置方案请求总数明显被拦数量有效命中总耗时默认配置1万大量403直至封IP0中断伪装UA速率控制4700约500435分钟定制字典出口轮换2500约801120分钟这个对比很直观不是请求越多越好而是有效请求越多越好。调优之后请求总量反而更低命中率却高得多。6.4 常见问题速查现象可能原因处理思路大量403UA/Headers被识别或出口IP已被封换真实UA、加Referer检查出口IP能否正常访问目标429 Too Many Requests请求频率超过阈值降线程、加delay拉长轮换间隔全部200但内容一样WAF软404比较Content-Length和页面标题排除统一错误页目标响应极慢/无响应触发了IP级封锁或反扫描机制暂停扫描稍后从另一出口IP小流量试探扫到一半开始超时出口节点质量下降或目标限流检查节点连通性降低并发减少线程数这些问题的排查顺序我一般是从“出口IP是否干净”开始再到“请求特征是否正常”最后查“频率是否过高”。因为如果IP已经黑了你改再多UA都白搭。最后再分享一个实际的体会真正高效的目录扫描不是靠蛮力堆线程而是让每一次请求都有意义。伪装UA、控制速率、定制字典、合理递归、输出配置这五件事是环环相扣的单独拧任何一个都不够。你可以先从最简单的UA伪装和线程调整入手跑一个中等规模的目标试试感受一下WAF的反馈变化再逐步加入字典定制和出口轮换。另外中途的扫描结果随手存文件别等封了IP才想起上一轮的数据没保留。以上技巧记住一条底线授权范围内使用。工具是中性的但使用工具的人心里要有数。