☰
路由器资产测绘实战:从RouterScan到内网弱口令扫描与资产台账
2026/10/10 3:21:35 网站建设 项目流程

简介:RouterScan中文版是一款面向个人用户与中小企业网络管理员的路由器安全检测工具,用于扫描并识别局域网内的路由器设备,评估其安全配置,排查默认密码、固件未更新、开放端口及不安全服务等常见隐患。资源包共116个文件,约4.2MB,以69个html页面、17张png截图、8个txt说明文档为主,辅以5个js脚本、5个dll动态库及4个exe可执行程序,另含css样式、md文档与ini配置等,结构完整,便于直接运行与查阅。目前已有435人学习下载。通过该工具,读者可快速获取设备安全状况清单,并依据提示完成固件升级、端口关闭与强密码设置等修复操作,同时结合Nmap、Wireshark等工具开展更全面的网络安全评估,适合希望提升路由器防护能力、降低入侵风险的网络使用者参考。

1. 路由器资产测绘:从 RouterScan_中文.rar 说起

很多人第一次拿到 RouterScan_中文.rar 这个包,以为是个绿色版小工具,解压双击就能扫全网路由器。真上手才发现,它背后是一整套针对路由器管理界面的资产测绘思路:识别设备指纹、判断登录入口、批量验证弱口令、导出结构化结果。这套东西在企业内网自查、物联设备盘点、攻防演练前的资产梳理里都用得上,尤其适合手里管着几百上千台网络设备、又不想一台台手工登录的运维和安全从业者。我见过太多人把它当“一键日站神器”,结果扫出来一堆误报,或者把内网扫崩,问题都出在没搞懂它的工作模型。这一章先把 RouterScan 这类工具到底在做什么、能解决什么、不适合什么讲清楚,后面再拆解怎么复现、怎么调参、怎么避坑。

2. RouterScan 的工作模型:指纹、入口与并发

RouterScan 不是靠漏洞利用拿权限,它的核心是“识别 + 验证”。识别阶段抓取目标 HTTP/HTTPS 响应,比对内置指纹库判断设备品牌和型号;验证阶段针对已知登录接口尝试默认口令或弱口令字典。理解这个模型,才能明白为什么它的结果里会有大量“疑似”条目,也才能合理设置并发和超时。

2.1 指纹识别靠什么:响应头、标题与特征路径

路由器管理界面千差万别,但总有一些稳定特征。常见做法是组合多个维度打分:HTTP 响应头里的 Server 字段、页面 title、特定静态资源路径(比如 /cgi-bin/luci 对应某类固件)、登录表单的 action 地址。单一特征容易误判,多特征加权才能把准确率拉上来。

下面是一段用 Python 做基础指纹匹配的示例,思路和 RouterScan 内部逻辑一致,只是简化版:

import re import requests # 指纹规则:每个品牌对应多个特征,命中越多置信度越高 FINGERPRINTS = { "brand_a": { "headers": {"Server": r"lighttpd/1\.4\.3[0-9]"}, "title": r"Router Admin", "paths": ["/cgi-bin/luci"], }, "brand_b": { "headers": {"Server": r"Boa/0\.94"}, "title": r"Management Console", "paths": ["/login.cgi"], }, } def match_fingerprint(url, timeout=5): score = {} try: resp = requests.get(url, timeout=timeout, verify=False) except Exception: return None for brand, rules in FINGERPRINTS.items(): hit = 0 # 检查响应头 for hk, hv in rules.get("headers", {}).items(): if hk in resp.headers and re.search(hv, resp.headers[hk], re.I): hit += 1 # 检查标题 m = re.search(r"<title>(.*?)</title>", resp.text, re.I | re.S) if m and re.search(rules.get("title", ""), m.group(1), re.I): hit += 1 # 检查特征路径 for p in rules.get("paths", []): try: if requests.get(url.rstrip("/") + p, timeout=timeout, verify=False).status_code == 200: hit += 1 break except Exception: pass if hit > 0: score[brand] = hit return score or None

逻辑说明:对每个候选品牌累加命中数,最后返回得分字典。参数上,timeout 建议设 3 到 5 秒,内网可以更短;verify=False 是因为大量路由器用自签证书,不关掉会直接抛异常。特征路径检查会多发一次请求,如果目标量大,可以把这一步做成可选,先用响应头和标题粗筛。

2.2 登录入口探测:表单解析与提交路径

识别出品牌后,下一步是找到登录接口并构造提交。不同固件的登录方式差异很大:有的用 GET 带 query,有的用 POST 表单,有的先拿 token 再提交。RouterScan 类工具通常会内置每个品牌的登录模板,模板里写明提交地址、参数字段名、成功判断关键字。

手工复现时,可以用下面的方式提取表单字段:

from bs4 import BeautifulSoup def parse_login_form(html, base_url): soup = BeautifulSoup(html, "html.parser") form = soup.find("form") if not form: return None action = form.get("action") or "" method = (form.get("method") or "get").lower() fields = {} for inp in form.find_all(["input", "select"]): name = inp.get("name") if not name: continue fields[name] = inp.get("value", "") return { "action": base_url.rstrip("/") + "/" + action.lstrip("/"), "method": method, "fields": fields, }

拿到字段后,把用户名和密码字段替换成字典里的候选值,逐个提交并检查响应里是否出现“登录成功”“logout”等关键字。这里的关键参数是成功判断规则,写得太宽会把失败页也当成功,写得太窄会漏掉真正能登录的设备。我一般会先手工登录一台同型号设备,把成功和失败两种响应各存一份,对比出稳定差异再写规则。

2.3 并发与超时:把扫描速度控制在设备扛得住的范围

RouterScan 默认并发往往偏高,在内网扫小设备时容易把管理页面打挂。常见做法是把并发降到 10 到 20,超时设 3 秒,重试 1 次。如果目标网段里有大量低端设备,并发还要再降。可以用简单的令牌桶控制速率:

import time import threading class RateLimiter: def __init__(self, rate_per_sec): self.interval = 1.0 / rate_per_sec self.lock = threading.Lock() self.next_time = time.time() def wait(self): with self.lock: now = time.time() if now < self.next_time: time.sleep(self.next_time - now) self.next_time = max(now, self.next_time) + self.interval

参数说明:rate_per_sec 表示每秒允许发起的请求数,内网扫描建议从 5 开始试,观察目标设备响应是否变慢再往上调。这个限速器配合线程池使用,能避免瞬间打满目标连接数。

3. 从零复现一次内网路由器资产扫描

这一章按实际流程走一遍:准备环境、生成目标列表、跑识别、跑弱口令验证、导出结果。每一步都给可执行的代码或命令,参数按内网场景给建议值。

3.1 环境准备与依赖安装

建议用 Python 3.8 以上,独立虚拟环境,避免和系统包冲突。依赖主要是 requests、beautifulsoup4、lxml,如果要处理 HTTPS 自签证书还需要 urllib3 的警告抑制。

python3 -m venv venv source venv/bin/activate pip install requests beautifulsoup4 lxml

如果目标网段有大量 HTTPS 设备,建议在代码里统一关闭证书校验并抑制警告,否则日志会被警告刷满,真正有用的信息反而被淹没。

3.2 目标列表生成:从网段到可扫描地址

内网扫描不要直接扫整个 B 段,先确认自己有权扫的范围。常见做法是从资产表或 DHCP 租约里导出地址,再补上常见管理端口。下面这段生成 192.168.1.0/24 的地址列表并附带端口:

import ipaddress def gen_targets(cidr, ports=(80, 443, 8080, 8443)): net = ipaddress.ip_network(cidr, strict=False) targets = [] for ip in net.hosts(): for p in ports: targets.append(f"http{'s' if p in (443, 8443) else ''}://{ip}:{p}") return targets

参数说明:ports 按你实际环境里路由器管理端口来定,很多设备只开 80 和 443,加上 8080/8443 能覆盖一部分改过端口的。如果地址量超过几千,建议先做存活探测再进识别,否则大量超时会拖慢整体进度。

3.3 识别与验证串联:一个可跑的最小流程

把前面的指纹匹配和表单解析串起来,加上弱口令字典,就是一个最小可用的扫描流程。下面这段代码把识别、登录尝试、结果记录连在一起:

import csv import requests from concurrent.futures import ThreadPoolExecutor, as_completed requests.packages.urllib3.disable_warnings() # 弱口令字典,实际使用时按目标品牌补充 CREDS = [("admin", "admin"), ("admin", "123456"), ("root", "root"), ("admin", "")] def try_login(url, form, user, pwd): data = dict(form["fields"]) # 常见用户名字段名 for uk in ("username", "user", "name", "account"): if uk in data: data[uk] = user break for pk in ("password", "passwd", "pwd", "pass"): if pk in data: data[pk] = pwd break try: if form["method"] == "post": resp = requests.post(form["action"], data=data, timeout=5, verify=False) else: resp = requests.get(form["action"], params=data, timeout=5, verify=False) # 成功判断:出现登出链接或管理关键字 if any(k in resp.text.lower() for k in ("logout", "log out", "退出")): return True except Exception: pass return False def scan_one(url): result = {"url": url, "brand": "", "login": ""} score = match_fingerprint(url) if score: result["brand"] = max(score, key=score.get) try: resp = requests.get(url, timeout=5, verify=False) form = parse_login_form(resp.text, url) except Exception: form = None if form: for u, p in CREDS: if try_login(url, form, u, p): result["login"] = f"{u}/{p}" break return result def run(cidr): targets = gen_targets(cidr) rows = [] with ThreadPoolExecutor(max_workers=15) as pool: futures = {pool.submit(scan_one, t): t for t in targets} for f in as_completed(futures): rows.append(f.result()) with open("scan_result.csv", "w", newline="", encoding="utf-8") as fp: writer = csv.DictWriter(fp, fieldnames=["url", "brand", "login"]) writer.writeheader() writer.writerows(rows) if __name__ == "__main__": run("192.168.1.0/24")

逻辑说明:scan_one 先做指纹识别,再抓页面解析表单,然后遍历字典尝试登录,命中就记录。参数上,max_workers 控制并发,内网建议 10 到 20;timeout 统一 5 秒;成功判断关键字按目标语言调整,中文设备常见“退出”,英文常见“logout”。跑完后 scan_result.csv 里 login 字段非空的就是存在弱口令的设备,需要优先处理。

3.4 结果导出与复核:别让误报混进报告

自动扫描的结果一定要人工复核。常见误报来源有两个:一是成功判断关键字出现在登录页本身(比如页面底部有“退出”说明文字),二是设备返回 200 但实际是错误提示页。复核方法是随机抽几台,用浏览器手工登录验证,确认规则没有写宽。导出格式建议至少包含 URL、品牌、命中口令、响应码、页面标题,方便后续按品牌分组处理。

4. 避坑与常见问题:那些让扫描翻车的细节

这一章记录几个我实际踩过的坑,每条按现象、原因、解决写清楚。

4.1 扫到一半目标集体无响应

现象:扫描开始几分钟后,大量目标超时,之前能连上的也连不上了。原因:并发过高,低端路由器管理页面被请求打满,CPU 占满后拒绝新连接。解决:把并发降到 10 以下,加限速器,超时设 3 秒,重试次数设 1。如果目标里有老旧设备,并发还要再降。

4.2 指纹识别把同一品牌判成多个型号

现象:结果里同一台设备出现多个品牌记录。原因:指纹规则里多个品牌共享了相同特征,比如都用 lighttpd 但版本不同,规则没做优先级。解决:给每个特征加权重,版本号更具体的规则权重更高;同一设备只保留得分最高的品牌。

4.3 弱口令验证把失败页当成功

现象:结果里大量设备标记为弱口令,手工验证却登不进去。原因:成功判断关键字太宽,登录失败页里也包含“退出”或“logout”。解决:对比成功和失败两种响应的差异,用更具体的特征,比如成功后才出现的管理菜单链接或特定 cookie。

4.4 HTTPS 设备全部识别失败

现象:HTTP 设备正常,HTTPS 设备全部无结果。原因:自签证书导致 requests 抛异常,代码里没处理。解决:统一 verify=False 并抑制警告;如果目标用非标准端口,确认端口列表里包含。

4.5 扫描结果里混入非路由器设备

现象:打印机、摄像头也被识别成路由器。原因:这些设备的管理页面特征和路由器有重叠,指纹规则区分度不够。解决:增加路由器特有的特征路径,比如特定 cgi 路径;对识别结果做二次确认,检查页面里是否有 WAN/LAN 设置项。

5. 进阶技巧:把一次性扫描变成可持续的资产台账

单次扫描只能反映某一时刻的状态,真正有价值的是把扫描能力变成定期执行的资产台账。我一般会做三件事:把指纹库和口令字典外置成配置文件,方便按目标环境替换;把结果写进数据库而不是 CSV,方便按时间对比;加一个变化检测,只输出和上次相比新增或状态变化的设备。

指纹库外置可以用 JSON:

{ "brand_a": { "headers": {"Server": "lighttpd/1\\.4\\.3[0-9]"}, "title": "Router Admin", "paths": ["/cgi-bin/luci"], "weight": 3 } }

加载时按 weight 排序,高权重的先匹配。口令字典按品牌分文件,扫描时根据识别结果加载对应字典,减少无效尝试。结果入库用 sqlite 就够,表结构至少包含 url、brand、login、scan_time、last_seen。每次扫描后对比 last_seen,超过一定时间没出现的设备标记为下线,新出现的标记为新增。

变化检测的核心逻辑是:同一 url 在两次扫描间 brand 或 login 状态发生变化时告警。比如某台设备上次没有弱口令,这次命中了,说明口令被改弱或设备被替换,需要立即核查。这个机制比单次扫描有用得多,也是我把 RouterScan 这类工具从“扫一次就扔”变成日常运维手段的关键。

最后说个血泪经验:扫描前一定确认授权范围,内网扫描也要走变更流程,否则把核心设备扫出问题,后悔药没地方买。我现在的习惯是先在测试网段跑通全流程,确认并发和超时参数稳定,再放到生产网段,并且全程盯着目标设备的 CPU 和连接数。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询