简介:WebCrack 是一款开源免费的 Web 后台弱口令与万能密码批量检测工具,面向网络安全从业者、渗透测试学习者及站点管理员,用于授权范围内的安全审计与弱口令风险排查。工具以自动化字典尝试方式发现后台登录隐患,支持自定义用户名与密码组合,并通过任务流程组织解析、爆破与字典生成等模块,便于读者理解弱口令检测的基本思路与工程结构。压缩包共 18 个文件,约 114KB,以 Python 脚本为主体,辅以密码字典与 URL 配置文本、说明文档及运行截图,体量轻便,适合本地阅读源码和搭建测试环境。相关页面显示已有 407 人学习,具备一定参考热度。读者可从中获得一套可读性较强的检测脚本、模块划分示例、字典与配置样例以及后续二次开发的基础,用于加深对 Web 登录安全测试流程的认识;使用时需遵守法律法规,仅在合法授权场景中运行。
1. 后台入口自查,弱口令这一关绕不过去
上个月帮一个朋友看他公司的资产表,表里躺着四十多个后台入口:运维面板、数据导出页、老版 CMS、几个早就没人维护的管理端。真正让人心里一紧的不是这些页面有多老,而是其中七八个的管理员账号还叫 admin,密码是年份加感叹号。WebCrack 就是冲这个场景来的——一款开源免费的 web 后台弱口令/万能密码批量检测工具,Java 写的,带图形界面,把目标管理、登录表单识别、字典枚举、SQL 注入式绕过检测、验证码处理、结果留存串成一条流水线。它适合谁:做等保自查的安全运维、接授权渗透项目的测试人员、以及手里有一堆后台入口需要定期体检的团队。前提只有一个,写在最前面——只对自有资产或拿到书面授权的目标跑,这条线越过去,工具再好也白搭。
2. 检测模型拆解:WebCrack 怎么认表单、怎么判成功
在动手之前先把内部逻辑捋一遍,否则后面看到"命中"两个字你都不知道该不该信。WebCrack 的整套流程可以压缩成一句话:对每个目标,反复构造一次登录请求,然后用一套判定规则判断这次请求算不算成功。听起来简单,真正决定工具好不好用的是三个环节——表单怎么识别、请求怎么发、结果怎么判。这三块任何一块出问题,都会表现为"扫了一晚上全绿"或者"命中几十条没一条能用"。
2.1 三个核心对象:目标、登录表单、判定规则
WebCrack 的数据模型是三层:目标(一条 URL)、表单(这个 URL 上登录请求的字段结构)、判定规则(什么样的响应算登录成功)。目标层最好理解,一条记录就是一个后台入口地址。表单层是很多人第一次用会卡住的地方——工具需要知道用户名填到哪个参数、密码填到哪个参数、还有没有隐藏字段(比如 csrf token、时间戳、跳转地址)。判定规则层最容易出问题,常见的有三种判法:响应里出现某个成功关键字、HTTP 状态码变成 302 且 Location 指向后台首页、或者响应体长度与失败样本出现明显差异,也就是常说的布尔型盲判。
我一般会先手动打开一个目标,用浏览器开发者工具把登录请求完整抓一遍,看清楚三件事:请求方法是 GET 还是 POST、参数名分别叫什么、有没有随机的隐藏字段。这三件事决定了后面能不能自动跑起来。如果是纯 POST 表单,参数名固定,那 WebCrack 的自动识别基本能一次过;如果登录页每次刷新都带一个新的 token,那就得看工具能不能配置"先 GET 登录页取 token 再 POST"这套两步流程,或者干脆放弃自动、改用半手工的目标清单。
提示:先在单个目标上把表单结构调对,再往批量清单上套。反过来做,你会花一晚上排查一堆其实配置没错、只是目标本身不可达的条目。
判定规则这一块,血泪经验是别偷懒用"响应里包含 success"这种关键字。中文后台的成功提示可能是"登录成功""欢迎您""操作已完成",也可能什么都不提示直接跳转。比较稳的做法是先用一个确定错误的密码打一次,把失败响应的长度、状态码、跳转地址记下来当基线,再用一个确定正确的账号打一次,对比两者差异。差异点在哪,判定规则就写在哪。这一步花十分钟,能省掉后面几个小时的误报复核。
2.2 万能密码与注入式绕过的检测逻辑
WebCrack 名字里的"万能密码"指的是另一类检测:登录框是否存在 SQL 注入式的认证绕过。原理不复杂——如果后端把用户名直接拼进 SQL 语句,那么构造一个特殊的用户名字符串,就可能让查询条件恒真,从而在不掌握真实口令的情况下进入系统。工具内置了一批公开的绕过测试串,在跑字典之前先打一轮,如果这一轮就命中了,说明这个入口的问题比弱口令严重得多,属于该立刻上报、立刻修的级别。
这里必须说清楚边界:检测的目的是发现"存在这个风险",不是把利用过程展开。实际自查时,只要工具报出注入式绕过命中,你需要的动作是记录目标、记录时间、截图、提单,然后推动开发改成参数化查询。不需要、也不应该在报告里写完整的利用链。我见过有同行的自查报告把 payload 抄得清清楚楚,结果报告在内部流转时被当成了攻击手册,这是纯粹的给自己找麻烦。
另一个容易忽略的点是:注入式绕过的命中率对表单结构极其敏感。如果登录表单还带 csrf token 且没有正确携带,那么即使后端真的存在拼接,工具打出去也会被拦在 token 校验这一步,表现为全部失败。所以跑这一轮之前,务必确认表单层的隐藏字段已经配好。参数没配对就下结论说"没有注入风险",是自查里最常见的假阴性来源。
2.3 验证码、频率限制与请求特征的处理
真实世界的后台入口,一大半带验证码。WebCrack 对验证码的处理能力决定了它能不能在这些目标上跑出结果。常见做法是两条路:一是图形验证码识别,工具接入识别模块,对每次请求返回的验证码图片做 OCR,识别结果回填到请求参数里;二是直接跳过——如果验证码识别率长期低于可用阈值,强行跑只会把账号锁死或者把 IP 打进黑名单,不如把这类目标单独拉一个清单,改成人工核对。
频率限制是另一道坎。很多后台连续失败五次就锁账号,或者触发 WAF 返回一堆 403。这时候工具的多线程和高并发不是优势,是灾难。我的习惯是把目标按"敏感度"分组:内部系统、测试环境可以放开跑;对外暴露的生产后台,线程数压到个位数,请求间隔拉到秒级,宁可跑一晚上也不要惊动防护设备。同一批目标里如果有多个入口指向同一套账号体系,还要注意别把同一个账号在多个入口上同时打,那样锁得更快。
请求特征这块也值得提一句。工具的默认 User-Agent、默认请求头顺序、默认的并发节奏,在成熟的防护面前辨识度很高。这不是让你去做对抗,而是说:如果你的自查跑到一半开始大面积返回 403 或 302 到验证页,先怀疑是不是被防护拦了,而不是怀疑字典不够大。遇到这种情况正解是降速、加间隔、换时间段重跑,而不是加线程硬顶。
3. 跑通一轮完整扫描:从环境准备到结果落盘
原理清楚了,进入实操。这一章的目标很明确:让你在半小时内跑出第一份可用的结果文件,并且知道每一行结果是怎么来的。整个流程拆成启动、配置、执行、解读四步,每一步都给出可抄的东西。
3.1 运行环境与启动方式
WebCrack 是 Java 项目,运行需要 JDK。常见的坑是版本不匹配——项目比较老,用太新的 JDK 可能起不来,用太老的又缺图形库。稳妥的做法是准备一个 JDK 8 环境,桌面环境要有,因为主界面是 Swing 写的图形界面,纯命令行服务器上直接跑会报 headless 异常。
# 确认当前 JDK 版本,优先 8 java -version # 图形界面模式启动(需要有桌面环境) java -jar webcrack.jar # 无桌面环境的服务器上,如需运行请先确认是否有 X11 转发或虚拟显示 # 否则会抛 java.awt.HeadlessException第一段命令是版本确认,java -version输出里如果看到1.8.0_xxx就没问题。第二段是常规启动,-jar后面跟实际的文件名。第三段是提醒:如果你在云主机上跑,没有图形界面,直接执行会失败。这种情况要么本地跑、要么给服务器配一个虚拟显示环境,但说实话,这类工具在本地桌面上跑体验最好,因为配置过程需要频繁看浏览器对照表单。
启动之后界面一般分三块:目标列表区、配置区、日志与结果区。先把这三块认清楚,后面配置就不会点错地方。
3.2 目标清单与登录表单配置
目标清单建议用文件导入,别在界面里一条条敲。我一般写个小脚本把资产表转成工具认识的格式,同时做一次去重和存活预检——这一步能砍掉三成无效目标,省下来的时间很可观。
# 从资产表生成目标清单:去重、补协议、粗筛存活 import csv from urllib.parse import urlparse seen = set() out = [] with open("assets.csv", newline="", encoding="utf-8") as f: for row in csv.DictReader(f): url = (row.get("url") or "").strip() if not url: continue # 补全协议,避免工具把裸域名当成相对路径 if not url.startswith(("http://", "https://")): url = "http://" + url host_path = urlparse(url).netloc + urlparse(url).path.rstrip("/") # 同一路径不同协议视为重复,只保留一条 if host_path in seen: continue seen.add(host_path) out.append({"target": url, "note": row.get("system", "")}) with open("targets.txt", "w", encoding="utf-8") as f: for item in out: f.write(item["target"] + "\n") print(f"去重后剩余 {len(out)} 个目标")这段脚本做三件事。第一,startswith那段补协议,因为工具对没有协议的地址解析行为不稳定,补成http://最省事,如果是 https 站点让工具自动跟随跳转即可。第二,netloc + path做去重键,注意这里故意忽略了协议和查询串——同一台机器的同一个路径,不管走 http 还是 https,都是同一个后台入口,重复跑没有意义,还会让结果文件里出现大量重复行。第三,输出成一行一个纯 URL 的文本,这是导入最不容易出错的格式。assets.csv需要至少包含url列,system列可选,用来做备注。
导入之后是表单配置。前面说过,先把一个目标在浏览器里抓包看清楚。工具里通常需要填:登录页地址、提交地址(有时候两者不同,登录页是/login而提交是/api/auth)、用户名参数名、密码参数名、额外的固定参数。如果没有验证码,配到这一步就可以试跑一次单目标。如果有验证码,还要打开识别开关,并把验证码图片的地址规则填进去。
3.3 执行、中断与结果文件解读
配置好之后先跑单目标验证。用一个你确定知道的正确账号打一次,看工具是不是判定成功;再用一个错误密码打一次,看是不是判定失败。一正一反都对了,才说明判定规则可信,这时候再放开批量。
# 批量执行时的常用运行参数示例(以实际界面/配置项为准) # 并发线程数:对外生产后台建议 1-5,内部系统可到 10-20 # 请求超时:默认偏短,跨机房目标建议调到 8000ms 以上 # 失败重试:1-2 次即可,重试太多会把锁账号风险放大 java -Xmx1024m -jar webcrack.jar-Xmx1024m是堆内存上限,目标清单上千条的时候默认堆容易吃紧,调到 1G 比较稳。线程数和超时这两项如果工具界面上能配,就按注释里的建议来;如果只能改配置文件,找到对应的键改成同样的数值即可。重试次数这个参数新手最爱调大,实际上没什么好处——第一次超时往往是目标本身挂了或者被拦了,重试两次还是同样的结果,只会让日志更难读。
跑的过程中要盯着日志区。出现连续大量超时,立刻停下来检查网络和目标存活;出现连续大量 403,说明被防护拦了,降速重跑;出现零星的命中,先别激动,把命中的目标挑出来人工复核。中断是正常操作,工具一般支持暂停和继续,不需要从头再来。
结果文件通常是一份带分隔符的文本或者 CSV,包含目标地址、命中的用户名、命中的密码、命中时间、判定依据。解读时注意两件事:一是确认"判定依据"这一列,不同依据的可信度不一样,跳转类判定通常比关键字判定可靠;二是把命中条目按目标归并,同一个目标命中多个账号的,优先处理权限最高的那个。
4. 字典与并发:把命中率和封禁风险同时压下来
工具本身的逻辑是固定的,真正拉开差距的是两个可调项:喂什么字典、用多大并发。这两项调好了,一次扫描能出有效结果还不惊动任何人;调不好,要么全是误报,要么把账号锁死一片、把 IP 送进黑名单。
4.1 字典分层:通用弱口令加业务特征词
字典不要一锅端。我的做法是分三层,从小到大依次跑,前一层出了结果就可以考虑停。
第一层是"极短通用表",几十条那种,admin/admin、admin/123456、test/test 之类。这一层的作用不是覆盖,是快速筛出那些完全没做口令策略的入口。跑完这一层大概几分钟,能把最烂的一批捞出来。
第二层是"业务特征词组合"。很多弱口令不是纯数字,而是跟业务强相关——公司简称加年份、系统名加@123、项目代号加!。这一层需要你对着资产表手工构造,量不大但命中率高。构造的时候注意大小写和常见后缀变体,Abc@2024、abc2024、Abc2024!都值得各来一条。
第三层才是通用大字典。这一层放在最后,因为它最慢、最容易触发锁定,而且命中率往往不如前两层。
# 用业务特征词快速生成第二层字典:系统名 + 年份 + 常见后缀 #!/bin/bash # 输入:systems.txt 每行一个系统简称,如 oa、crm、hr # 输出:biz_dict.txt 形如 oa2024、Oa@2024 的组合 YEARS="2023 2024 2025" SUFFIX=("" "@123" "@1234" "!" "123" "@2024") > biz_dict.txt while read -r name; do [ -z "$name" ] && continue for y in $YEARS; do for s in "${SUFFIX[@]}"; do echo "${name}${y}${s}" >> biz_dict.txt echo "${name^}${y}${s}" >> biz_dict.txt # 首字母大写变体 done echo "${name}@${y}" >> biz_dict.txt done done < systems.txt sort -u biz_dict.txt -o biz_dict.txt wc -l biz_dict.txt这段脚本的核心是笛卡尔积:系统简称 × 年份 × 后缀。${name^}是 bash 的首字母大写展开,用来覆盖Oa2024这类写法。sort -u去重很有必要,因为不同组合可能撞车,不去重会让工具重复发同样的请求,白白增加锁定风险。跑完看一眼行数,一般控制在几百到一两千条之间比较合理,太多就说明后缀加得过宽,该收一收。
注意:字典里不要塞入任何来源于真实泄露库的内容。自查场景下,用公开的通用弱口令表和自己的业务词组合就够了,来源不明的字典既不合规也容易把结果搞脏。
4.2 并发、延时与失败重试的取舍
并发这个参数,我给的经验值是:对外可达的生产后台,线程数 1 到 3,请求间隔 1 到 2 秒;内部测试环境,线程数可以到 10,间隔 0。判断标准不是"能开多大",而是"这个目标挂了会不会有人半夜找你"。
延时参数比线程数更值得重视。有些工具只提供线程数,没有独立延时,那就用线程数间接控制——线程少,自然慢。如果两者都有,优先调延时,因为延时是均匀分布的,对防护设备更友好;线程数是瞬时的,容易在某一秒打出一个尖峰。
失败重试建议设成 1。理由前面提过:超时和 403 都是确定性失败,重试改变不了结果。唯一值得重试的是网络抖动导致的连接重置,但这种情况下重试一次也就够了。把重试设成 5 次的,日志里会充斥着同一目标的重复记录,复核的时候非常痛苦。
还有一个容易被忽略的参数是超时时间。默认值往往偏短,跨机房或者目标本身响应慢的时候,正常请求也会被判成超时,表现为"这个目标怎么打都是失败"。我一般先把超时调到 8 到 10 秒,跑一轮看日志里的超时比例,如果还是很高,那就不是超时参数的问题,是目标真的不可达。
4.3 结果复核:从疑似命中到确认可用
工具报出来的命中,在写进报告之前必须人工确认。确认流程很简单:拿命中的账号密码,用一个干净浏览器、在非生产时段、手动登录一次。能进后台,截图,记为确认;进不去,记为疑似,回头查判定规则。
疑似命中的成因主要有三类。第一类是判定规则太宽,比如用"响应里包含 index"当成功标志,结果登录失败页的 HTML 里正好有个index.css,全部判成功。第二类是目标把失败也重定向到首页,导致跳转类判定失效。第三类是验证码识别串了——识别出的验证码其实是上一次请求的,偶尔碰巧对上了,就被当成登录成功。这三类都指向同一个动作:回去看判定依据那一列,把可疑的判定方式逐条比对响应内容。
复核还有个纪律问题:确认过程中不要用命中的账号去做任何写操作,只看首页、只看权限菜单,不点任何按钮。这条不是技术问题,是职业习惯问题——你是在做自查,不是在做渗透。
5. 常见问题排查:五类翻车现场
这一章全部来自实际跑崩过的场景。每一条按"现象、原因、解决"写,遇到对得上的直接照着改。
5.1 全部失败,但浏览器里明明能登进去
现象:跑了几百条,日志全是失败,随手拿一个账号在浏览器里登录,一次就进去了。
原因:九成是表单结构没配对。最常见的是隐藏字段没带——登录页每次都下发一个新的 token,工具没先 GET 取 token 就直接 POST,服务端一律拒绝。其次是提交地址填错,登录页是/login但真正的提交接口是/api/login,工具往错误地址打,返回的当然是 404 或 400,被判定为失败。
解决:用开发者工具把登录请求完整抓一遍,逐字段比对工具里的配置。重点看三处:请求方法是不是 POST、有没有csrf/token/timestamp这类动态字段、Content-Type是表单还是 JSON。动态字段的处理方式是开启"先取页面再提交"的两步模式,或者对该目标单独手工构造。
5.2 命中一大堆,复核全进不去
现象:结果文件里有几十条命中,逐条手工验证,一条都登不上。
原因:判定规则误判。前面提过的三类成因——关键字太宽、失败也重定向、验证码串号。还有一种少见但很坑的情况:目标在连续失败若干次后返回一个"账号已锁定"的提示页,这个页面的长度和成功页接近,布尔型盲判会把它判成成功。
解决:先把判定依据那一列拉出来统计,看误报集中在哪种判定方式上,把那种方式关掉或者改成更严格的条件。然后重新构造基线:用确定的错误密码打一次,记录响应长度和状态码;用确定的正确密码打一次,再记录。两者的差异点才是可靠的判定信号。
5.3 跑到一半目标全部超时
现象:前一百个目标正常,从某个时间点开始所有目标都超时,日志刷屏。
原因:两种可能。一是本机网络出问题,或者出口 IP 被目标侧的防护设备拉黑了——后者在并发开大、失败请求密集的时候特别常见。二是工具本身的连接池耗尽,Java 的 HttpClient 在大量超时后如果没有正确释放连接,会拖垮后续所有请求。
解决:先换一个网络环境重跑同样的目标,如果恢复正常,说明是本机出口的问题,等一段时间或者换出口再跑。如果换环境还是超时,把工具重启,线程数砍半、延时加倍重跑。日常预防手段是把并发压在低位,并且在目标清单里混入几个已知可达的探针目标,一旦探针开始超时,立刻停手,不要硬跑。
5.4 验证码识别率低到没法用
现象:带验证码的目标几乎全部失败,日志里能看到识别结果和实际图片明显对不上。
原因:验证码识别模块对特定字体、干扰线、扭曲方式敏感。目标站点如果用了比较新的验证码方案,识别率会掉到个位数。另一种情况是验证码和会话绑定了,工具每次请求新建会话,取到的验证码图片和提交时的会话对不上,识别再准也没用。
解决:先确认会话保持是否正常——同一会话里连续取两次验证码图片,如果内容完全不同且都无效,说明会话没保持住,需要在工具里开启 Cookie 保持。会话没问题但识别率仍低,就把这类目标单独列出,改人工核对,不要浪费时间调识别参数。数量不多的话,人工反而更快。
5.5 结果文件里同一目标重复出现
现象:一个目标在结果文件里出现十几行,账号密码还不一样。
原因:目标清单里有重复条目,或者多个入口指向同一套账号体系,工具把它们当成不同目标各跑了一遍。命令行参数里如果同时给了 http 和 https 两个版本,也会触发这种情况。
解决:回到第 3 章的清单生成脚本,确认去重键用的是netloc + path而不是完整 URL。结果文件在导入报告系统之前,按目标地址做一次归并,同一个目标的多个命中合并成一行,账号列表用分号拼接。归并这一步我一般用一段简单的 awk 或者 python 做,别手工改,手工改必漏。
6. 进阶:把一次扫描固化成季度自查流水线
单次扫描的价值有限,真正省事的是把它变成固定动作。我目前的习惯是按季度跑一轮,流程固定成四步:资产表更新、目标清单生成、分层字典扫描、结果归并出报告。资产表更新这一步不能省——很多后台入口是业务方临时开的,没人登记,等到出事才发现清单里根本没有。我的做法是每季度让各业务线回填一次,同时用被动资产发现补一遍,两边对账。
报告部分用一个固定表格承接,字段不多但每次都要齐:
| 字段 | 说明 | 填写要求 |
|---|---|---|
| 目标地址 | 后台入口完整 URL | 不带查询串 |
| 系统归属 | 业务线或系统名 | 与资产表一致 |
| 检测类型 | 弱口令 / 注入式绕过 | 二选一 |
| 命中账号 | 确认可用的账号 | 只填确认过的 |
| 判定依据 | 跳转 / 关键字 / 长度差异 | 便于复核 |
| 风险等级 | 高 / 中 / 低 | 按权限范围定 |
| 整改状态 | 待修 / 修复中 / 已复测 | 每轮更新 |
风险等级的判定我一般看两件事:这个账号进去能看到多少数据、这个入口对外是不是可达。两个都占的,直接定高,当天提单。只占一个的定中,进季度整改计划。剩下的定低,记录下来观察。这套分级不是为了严谨,是为了让整改有优先级——一口气提五十个高危,没人会理你。
自动化这块,我没有把整个工具做成无人值守,原因很实际:判定规则需要人看,误报需要人核,这两件事自动化不了。能做自动化的是前后两头——前面用脚本生成清单和分层字典,后面用脚本归并结果、对比上一季度的差异。中间那一小时的人工配置和复核,反而是最该保留的。有一次我图省事,把一个新接手的资产段直接丢进批量队列,判定规则还是上一批目标用的,结果跑出来两百多条命中,复核了一下午发现全是误报,原因是那批站点的失败页里恰好有个success:false的 JSON 字段被关键字匹配上了。从那以后我每次换目标段,都强制先拿三个目标手工跑通、确认判定规则对得上,再放开批量。这个习惯救过我不止一次。
如果你手上也有一批需要定期体检的后台入口,按上面的流程走一遍,大概一个下午能把第一轮跑完,后面每季度就是重复劳动。工具在项目仓库里能直接拿到,字典和脚本自己按业务改一改就行。希望帮到你。
本文还有配套的精品资源,点击获取