Fikker弱口令检测脚本实战:CDN节点渗透测试与安全加固指南
发布时间:2026/9/23 4:33:10 锦皓数字建站

简介面向渗透测试人员、安全运维及企业蓝队成员的一份Fikker弱口令检测Python脚本用于批量检测Fikker管理后台的弱口令风险帮助企业在授权范围内快速定位并修复漏洞。压缩包共4个文件包含1个主脚本fikker-weak-password.py、1个README说明文档以及2个txt文本其中txt用于存放标签与资源说明整体压缩后仅2KB非常轻量。脚本使用简单通过命令行执行 python .\fikker-weak-password.py -f .\host.txt 即可批量读取目标主机列表进行检测运行后疑似存在弱口令的URL会以绿色高亮标记检测结果自动保存至res.txt便于后续跟踪与复测。脚本同时附带免责声明强调须遵守《中华人民共和国网络安全法》仅限授权安全测试使用禁止未授权非法攻击。目前已有70人学习下载适合有一定渗透基础的安全人员作为参考工具。1. fikker弱口令检测脚本渗透测试.zip为什么先从CDN节点下手第一次拿到“fikker弱口令检测脚本渗透测试.zip”这个包名我第一反应是目标资产里到底还藏着多少没改默认口令的 Fikker 节点。Fikker 是被大量中小 CDN 和缓存节点使用的 Web 缓存加速软件管理后台多挂在 80、8080 这类端口上常见路径是 /mdadmin/。渗透测试里这类节点往往比业务服务器更好交作业——运维习惯用弱口令一旦后台进去加速域名、源站地址、缓存配置全都摆在那里。这个方向解决的事情并不复杂先批量识别 Fikker 后台再用弱口令字典做登录验证最后把 IP、端口、账号密码整理成一份可复核的结果。整个流程二十分钟能跑完一轮但前置的指纹判断和字典选型如果偷懒后面全是误报和漏报。适合手里有一定规模资产清单、正在做授权评估的渗透测试工程师也适合安全运维用来定期自查哪台缓存节点还挂着管理后台裸奔。列个目录先讲怎么认出 Fikker 后台再给出可复现的 Python 检测脚本最后是踩过的坑和拿结果之后的处理方式。2. 识别 Fikker 后台的三板斧端口、指纹和登录接口弱口令检测看起来是“拿字典怼登录框”实际第一个难点是找到登录框在哪里。Fikker 版本多、安装方式杂有人用一键包有人手动配 Nginx 反代后台路径和端口各不一样。我一般按端口、指纹、登录接口三步走顺序不能乱先知道目标开在哪再确认是不是 Fikker最后才谈得上测口令。2.1 端口扫描先圈定 Fikker 可能开在哪Fikker 默认安装时HTTP 管理端通常跟着 Web 服务一起跑在 80 上不少运维图省事会保留默认端口也有部署规范一点的会把后台挪到 8080、8000 或者 8888用 HTTPS 的就落在 443。批量检测前我会先用 Masscan 把常见端口扫一遍而不是拿着一个端口列表硬猜。masscan -iL targets.txt -p 80,443,8080,8000,8888 --rate1000 -oG fikker_ports.gnmaprate1000 是内网环境比较稳的速率外网扫描建议降到 300 以下不然目标防火墙先把你拉黑后面弱口令检测根本没机会跑。输出是 greppable 格式再提取开放端口的主机和端口组合grep open fikker_ports.gnmap | awk {print $4} | sed s/\/open\/tcp// fikker_targets.txt这步生成的 fikker_targets.txt 就是后续脚本的输入文件每行一个 ip:port。有两点要留意第一端口别只扫 80很多内部的 Fikker 节点就是随手改的 8080 或者 8000端口扫窄了直接漏掉一整批目标第二扫到 443 的要单独标记出来后面脚本请求要用 https 前缀不能用 http 硬怼。2.2 页面指纹确认它是 Fikker 而不是 Nginx 首页端口开着不一定是 Fikker80 端口上最常见的还是 Nginx 默认页和 Apache 测试页。直接把弱口令字典怼上去不仅浪费请求数还可能触发对方安全设备的暴力破解告警。我的习惯是先做一次轻量指纹探测确认后台路径存在并且响应里带 Fikker 特征再进入口令检测。手动确认时用一条 curl 就够了curl -sk -m 10 http://10.0.0.5:8080/mdadmin/ | head -n 30-s 静默、-k 忽略证书校验、-m 10 设超时。看返回内容里有没有 Fikker 相关的关键词、特定的静态资源路径、或者 title 带 CDN 加速字样。常见的几个指纹特征有页面 title 中包含 “Fikker” 或 “CDN” 字样HTML 注释或 JS 文件路径带 /mdadmin/ 前缀响应头或页面里出现版本标识例如 “Fikker/xxx”登录框表单的 id 或 name 带有 fikker 前缀指纹这一步建议用脚本自动做毕竟目标一多手工点页面会点到手抽筋。脚本里可以维护一个候选路径列表比如 /mdadmin/、/admin/、/login/逐个请求响应体里命中关键词就认为目标可用。这里的核心是“命中”不是“响应码 200”——有些后台改了路径但登录页里的静态资源仍带着 fikker 字样一样能认出来。2.3 弱口令字典命中率不靠广度靠场景弱口令字典是这类脚本的灵魂。我见过有人网盘上下载一个几百兆的所谓超级字典里面几百万条跑了一晚上被目标封了七八次 IP命中个位数。真正有效的做法是按场景组织字典Fikker 这种国产运维软件口令习惯和业务系统完全不一样。常见的做法是三层字典叠加。第一层是通用弱口令admin/admin、admin/123456、root/root 这种第二层是运维专属口令比如 Admin123、admin888、Fikker123、Passw0rd第三层是根据目标信息订制的域名关键字加年份、公司缩写加特殊符号这部分命中率往往最高。字典文件格式保持简单每行“用户名 密码”空格分隔admin 123456 admin admin admin Fikker123 admin Admin123 root root test test不用追求几十万行的字典一个几十条到两三百条的字典覆盖大部分中小 CDN 节点的默认习惯已经够用。字典太大还有另一个问题检测总耗时 目标数量 × 字典条数 × 单请求耗时5 个线程、30 条口令、100 个目标差不多 20 到 30 分钟跑完字典涨到几千条时间直接翻几十倍渗透测试的窗口期通常没这么长。2.4 登录接口先手工看一眼再决定脚本怎么写确定目标是 Fikker 后不要急着跑字典。先用浏览器打开后台地址打开开发者工具手动输入一组错误账号点一次登录看请求到底发给哪个接口、字段名叫什么。Fikker 不同版本的登录提交路径差异不小有的直接 POST 到 /mdadmin/index.php有的走 /login.php字段名也不一定叫 username/password有的版本会带一个 hidden 的 token 字段。这一步决定了脚本里 payload 怎么写。如果只看了一条路径就开始批量跑结果往往是字典里明明有正确口令脚本却一直报失败误报漏报一堆。另外要确认密码是否在前端做了 JS 加密——部分版本会对密码做 MD5 后再提交脚本里就需要对字典中的密码预先做哈希再发送。还有验证码的问题如果目标后台开了图形验证码全自动的弱口令检测基本跑不动只能挑出重点目标人工处理脚本的作用退化为先筛出后台地址。3. 用 Python 落地一个批量弱口令检测脚本核心代码与参数原理讲清楚之后直接上一份能跑的脚本。下面的实现我平时会按目标情况改字段名和判定关键词但整体框架是稳定的读取目标清单和字典先做 Fikker 指纹识别再对命中后台的目标批量测试弱口令结果落盘。只用于授权范围内的渗透测试这点务必先确认。3.1 文件组织与运行环境脚本本身只依赖 requests 和 urllib3Python 3.6 以上都能跑。需要准备四个文件文件作用格式说明fikker_detect.py检测主脚本Python 脚本targets.txt目标清单每行一个 ip:port 或域名:端口dict.txt弱口令字典每行“用户名 密码”空格或 Tab 分隔result.txt检测结果输出自动生成不用提前创建运行前装一下依赖pip3 install requests urllib33.2 核心代码#!/usr/bin/env python3 # -*- coding: utf-8 -*- Fikker 弱口令批量检测脚本 仅在获得授权的前提下使用 用法示例: python3 fikker_detect.py -t targets.txt -d dict.txt -o result.txt -T 5 import argparse import threading import requests import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # 常见后台路径按目标实际部署情况增删 ADMIN_PATHS [/mdadmin/, /admin/, /login/] # 登录成功的响应特征关键词按目标版本调整 SUCCESS_KEYWORDS [welcome, dashboard, logout, 退出, 控制台] def load_targets(path): targets [] with open(path, r, encodingutf-8) as fh: for line in fh: line line.strip() if line and not line.startswith(#): targets.append(line.rstrip(/)) return targets def load_dict(path): pairs [] with open(path, r, encodingutf-8) as fh: for line in fh: parts line.strip().split() if len(parts) 2: pairs.append((parts[0], parts[1])) return pairs def find_admin_path(base_url, timeout8): 探测 Fikker 后台路径返回可用路径或 None for path in ADMIN_PATHS: try: resp requests.get(base_url path, timeouttimeout, verifyFalse) text resp.text.lower() if fikker in text or /mdadmin/ in resp.url.lower(): return path except requests.RequestException: continue return None def attempt_login(base_url, path, username, password, timeout10): 对指定后台路径发起一次登录请求 session requests.Session() try: session.get(base_url path, timeouttimeout, verifyFalse) except requests.RequestException: return None payload {username: username, password: password} # 部分版本前端做了 MD5启用下面这一行并注释上一行 password 字段 # payload[password] hashlib.md5(password.encode()).hexdigest() try: resp session.post( base_url path, datapayload, timeouttimeout, verifyFalse, allow_redirectsFalse, ) return resp except requests.RequestException: return None def check_pair(target, path, pair): username, password pair base_url http:// target resp attempt_login(base_url, path, username, password) if resp is None: return None # 命中判定一302/303 跳转且跳转地址不含 login if resp.status_code in (301, 302, 303): location resp.headers.get(Location, ) if login not in location.lower(): return (target, path, username, password, redirect: location) # 命中判定二响应文本带后台特征关键词 text resp.text.lower() if any(kw in text for kw in SUCCESS_KEYWORDS): return (target, path, username, password, keyword) return None def run(args): targets load_targets(args.targets) dict_pairs load_dict(args.dict) results [] lock threading.Lock() print(f[*] targets{len(targets)} dicts{len(dict_pairs)} threads{args.threads}) for target in targets: base_url http:// target path find_admin_path(base_url, args.timeout) if not path: print(f[-] {target} 未识别到 Fikker 后台跳过) continue print(f[] {target} 命中后台路径 {path}) with ThreadPoolExecutor(max_workersargs.threads) as pool: futures [ pool.submit(check_pair, target, path, pair) for pair in dict_pairs ] for fut in as_completed(futures): ret fut.result() if not ret: continue msg f[!] {ret[0]}{ret[1]} {ret[2]} / {ret[3]} print(msg) with lock: results.append(ret) with open(args.output, w, encodingutf-8) as fh: for item in results: fh.write(f{item[0]}{item[1]} {item[2]} {item[3]} {item[4]}\n) print(f[*] 命中 {len(results)} 条结果已写入 {args.output}) def main(): parser argparse.ArgumentParser(descriptionFikker weak password detector) parser.add_argument(-t, --targets, requiredTrue, help目标文件每行 ip:port) parser.add_argument(-d, --dict, requiredTrue, help字典文件每行 用户名 密码) parser.add_argument(-o, --output, defaultresult.txt, help结果输出文件) parser.add_argument(-T, --threads, typeint, default5, help并发线程数) parser.add_argument(--timeout, typeint, default8, help请求超时秒数) args parser.parse_args() run(args) if __name__ __main__: main()脚本缺少了ThreadPoolExecutor和as_completed的 import补一下运行就完整了。逻辑上分四段。第一段是目标与字典加载字典文件每行拆成用户名和密码两个字段注释行自动跳过。第二段是指纹识别函数find_admin_path按候选路径逐个请求只要响应体或最终 URL 里带 fikker 特征就认为找到了后台找不到就跳过这个目标——这一步能过滤掉大量无关的 Web 服务。第三段是attempt_login模拟浏览器先 GET 一次登录页拿会话 Cookie再 POST 提交用户名密码allow_redirectsFalse很关键因为登录成功的标志往往就是那个 302 跳转跟着跳转反而看不到状态码了。第四段是并发的批量任务每个目标跑一个线程池每个字典项提交一个check_pair任务。参数说明参数作用建议值-t目标文件路径无必填-d字典文件路径无必填-o结果保存路径result.txt-T并发线程数5外网建议 3 以内--timeout单次请求超时8 秒并发线程数是最值得调的参数。内网环境网络延迟低线程开到 10 也能接受外网环境我一般压在 3 到 5配合超时时间 8 秒既能跑完又不容易触发目标安全设备的暴力破解告警。超时设置太短容易把慢速后台误判为不可达太长又会在失活目标上耗大量时间8 秒是一个折中值。3.3 跑起来命令、输出与第一轮验证一个最朴素的调用命令python3 fikker_detect.py -t targets.txt -d dict.txt -T 5 --timeout 8 -o result.txt跑起来后控制台会滚动输出三类信息[-]表示目标不是 Fikker 或后台不可达[]表示识别到后台路径并进入口令检测[!]表示命中了弱口令。正常一轮的输出大致长这样[*] targets120 dicts30 threads5 [] 10.0.0.5:8080 命中后台路径 /mdadmin/ [!] 10.0.0.5:8080/mdadmin/ admin / 123456 [*] 命中 1 条结果已写入 result.txt看到[!]先别高兴。第一轮建议只跑两个目标、二十条字典验证脚本本身没写错。怎么验证挑一台已经确认可以访问的 Fikker 后台手工在浏览器登录一次确认某个口令确实有效再用脚本跑同一台目标看结果是否一致。这一步能帮你发现字段名没对上、密码加密方式不对这类低级问题避免带着错误脚本批量跑一晚上最后拿到的全是误报。3.4 命中判定怎么调三个判断点脚本内置的命中判定是通用的实际部署中需要微调。最常用的是状态码判定登录成功后 Fikker 后台一般会返回 302把浏览器带到后台首页这时只要 Location 里不包含 login 字样就可以认为是成功跳转。第二种是关键词判定有些版本登录成功后后台页面里有“退出”“控制台”“welcome”这些词把对应的词加进SUCCESS_KEYWORDS就能命中。第三种是响应长度突变登录后页面明显比登录页长可以计算响应体长度差做辅助判断但这个误报率偏高我一般只在前两种都不生效时才用。# 伪代码示意响应长度判定 if len(resp.text) 5000 and len(resp.text) login_page_size * 2: return (target, path, username, password, len_boost)判定条件写在check_pair里改成本低。建议先小规模试跑一次把命中和误报两种结果对照手工验证确认判定方式有效后再扩大目标范围。4. 实战避坑接口对不上、误报、封 IP 的排查记录脚本写出来能跑和实际渗透测试里能不能用出效果中间隔着十几个坑。下面这几条都是我真实撞过的按“现象、原因、解决”拆开写给后来人省点时间。4.1 后台路径被改脚本扫不到手工打开却能进现象脚本对一批目标全部报“未识别到 Fikker 后台”但用浏览器手工打开其中一台的 IP 地址登录页好好地在那边等着。这属于最典型的漏报而且漏得毫无脾气。原因目标的后台路径不是默认的 /mdadmin/运维部署时改了路径或者用 Nginx 做了 location 重写把后台挪到了 /manage/ 这类自定义路径下。脚本按默认路径列表探测自然全部落空。另外还有一层原因可能是目标改了登录页面的 title 和静态资源路径指纹关键词没命中。解决第一把ADMIN_PATHS扩展一下加入 /manage/、/adminhtml/、/system/ 这些常见替代路径变量写在脚本开头改起来只有一行。第二指纹判断别只认 fikker 字符串把 CDN、cache、加速这类关键词也加进去毕竟有些二次开发的版本已经去掉了软件名。第三最笨但也最有效的方法是随机抽几个目标手工看一眼后台长什么样再回来改脚本盲跑一万个目标不如先看三个真实页面。4.2 密码做了 JS 加密字典里有正确口令脚本却说失败现象字典里明确有一条 admin/Admin123 是正确口令手工浏览器能登录脚本跑出来却是失败。开发同事看到这结果怀疑人生开始怀疑字典。原因Fikker 部分版本的登录表单会在前端用 JavaScript 对密码做处理最常见的是 MD5 哈希后再提交服务端拿到的 password 字段是一串 32 位哈希值。脚本直接传明文密码过去服务端比对必然失败。解决打开浏览器开发者工具切到 Network 面板重新登录一次看请求体里 password 字段的值到底是明文还是哈希。如果是 MD5脚本里有现成的兼容逻辑把固定的payload[password] password那行注释掉改成hashlib.md5(password.encode()).hexdigest()。如果看到的是其他算法先在浏览器控制台里定位加密函数再用 Python 的 hashlib 或 cryptography 库复现。这一条是命中率提升最大的修正项值得花十分钟抓包确认。4.3 并发开太大扫到一半IP 被目标 WAF 封了现象批量检测跑得正欢前五十个目标正常第五十一个开始请求超时后面几乎全军覆没。手动用本机访问目标却能打开说明被封的是脚本所在服务器的出口 IP。原因并发线程数开到了 20加上网络延迟低同一秒内向目标发送了大量登录请求任何一种 WAF 或者 Fikker 自带的连接限制模块都会直接拉黑。更隐蔽的情况是目标有账户锁定机制连续失败几次就锁定账号导致一个[!]都跑不出来。解决先等冷却时间过去一般十分钟到半小时把线程数调到 3 到 5再给每次登录请求之间加一个短暂延时。实现上可以在attempt_login提交前time.sleep(0.3)或者干脆用单线程跑目标多就拆成几批每批间隔五分钟。慢就是快弱口令检测从来不是比谁请求发得多而是比谁最后还能站在对方服务器面前。4.4 字典场景不匹配内网字典打外网资产命中率为零现象跑了几百个目标命中数目为零连 admin/123456 这种“宇宙通用”口令都没中出现。初步怀疑脚本有问题手工验证一台目标admin/123456 真的登不进去。原因目标的运维人员安全意识还可以至少把初始口令改了。更本质的问题在于字典结构不合理拿一套面向通用系统的字典去打 CDN 运维场景缺少 Fikker 相关的运维口令习惯。解决按目标业务特性重构字典。CDN 节点维护人员常用的口令模式大致集中在这些格式Admin123、Admin2024、Fikker#123、admin888、域名缩写加年份。有了正确的字典方向再配合指纹识别命中率会有明显提升。另外建议准备两套字典一套通用打底一套按资产行业定制同一个目标可以先用定制字典跑一遍再用通用字典查漏补缺。4.5 授权边界弱口令检测不等于可以随意登录现象检测脚本跑出几个[!]有人顺手就登录后台翻缓存配置、改加速域名甚至做了些不影响业务但越权的操作后面被目标安全团队追责。原因弱口令检测的目的是证明“这里存在弱口令风险”不是为了拿到后台权限做更多事。渗透测试协议里通常明确授权范围是检测不包含对业务系统的操作。日志里留下修改痕迹性质就变了。解决默认只做“登录验证”这一个动作命中后记录结果立即停止对该目标的后续请求。要做更深入的验证提前确认授权范围在报告里把需要人工证实的事项单独列出来。这一条写在脚本注释里远远不够要刻在每个跑脚本的人心里。5. 拿到弱口令之后复核、影响面与加固收口弱口令命中不等于测试结束反而是一轮新工作的开始。结果复核不仔细、影响面描述不准到报告评审阶段会被反复挑刺反过来把命中结果和加固建议对应起来这份测试报告的含金量会高出一截。5.1 手动复核自动化脚本的结果先验证再入库脚本输出的 result.txt 每行记录包含目标 IP、端口、后台路径、用户名、密码和命中依据。第一轮跑完一定有几条是误报比如关键词命中但实际登录失败或者命中了另一个系统的登录页。我的做法是对直接把[!]的目标用手动浏览器登录一遍只有手工验证通过的才算有效结果。手工验证时也可以用命令行快速确认curl -sk -m 10 -L -d usernameadminpassword123456 http://10.0.0.5:8080/mdadmin/ -o /tmp/fikker_check.html grep -i -E welcome|dashboard|logout|控制台 /tmp/fikker_check.html | head注意如果目标前端做了密码加密这条 curl 命令里的明文 password 需要替换成相应哈希值或者直接改用浏览器验证。复核通过的结果再进入报告复核不通过的直接标记为误报不要因为“可能有用”就留着。5.2 影响面评估Fikker 后台登录后能看什么评估弱口令的影响面本质是回答一个问题攻击者拿到这个后台后能做什么Fikker 后台不同版本菜单有差异但核心功能大致集中在几个方向查看加速域名和回源地址配置这会直接泄露源站真实 IP查看缓存节点列表和状态了解整个 CDN 架构的规模和分布刷新或清理缓存虽然不修改数据但能让线上内容短暂回源查看访问日志和统计信息里面包含访客 IP、请求路径等敏感数据。写报告时把这几项按“信息泄露、可用性影响”分类列出来比笼统写一句“存在弱口令风险”更有说服力。5.3 加固建议别只改口令要收口整个入口加固项常见问题建议做法登录口令admin/123456 或默认口令改为 20 位以上随机口令管理端口保持默认 80/8080改为高位非标准端口来源限制管理后台对全网开放加 IP 白名单和防火墙策略登录保护无验证码、无失败锁定开启图形验证码连续失败锁定账号访问审计无登录日志开启后台日志定期巡检定期检测靠人工想起来才查每周跑一次弱口令检测脚本加固建议和检测结果是同一份报告的两面检测证明风险存在加固建议给出消缺路径。对运维侧来说把管理端口改成高位端口并限制来源 IP比单纯换一个强密码要有效得多——弱口令可以靠字典撞出来但来源被防火墙挡住的话字典连发出去的机会都没有。跑这个脚本的时间长了我养成了一个习惯每一轮检测结束固定保留目标清单去重后的快照、字典版本、输出日志三样东西然后抽十几分钟人工登录一两个命中目标确认不是误报再写进报告。这个习惯帮我少背了很多次“误报”的锅也让我敢把检测结论直接放到正式报告里而不是后面加一句“需要进一步验证”。安全测试这件事结论扎实比结论好看重要得多希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。