跳到主要内容
那 1085 次密码尝试,没有一次是在猜你的密码

那 1085 次密码尝试,没有一次是在猜你的密码

图南
图南

· 阅读约 9 分钟

先看一个数字:48 秒。

一台扔在新加坡的机器,从拿到公网 IP 到收到第一个不请自来的 TCP 连接,中间只隔了 48 秒。法兰克福 107 秒,纽约 324 秒。三个区域,三个云厂商的机架,都是开机没多久就开始挨敲。

48 秒这个数,比这台机器上 cloud-init 跑完还短。说人话就是:加固脚本还没被调度起来,赛跑已经结束了。问题不在脚本写得慢,在"部署完再加固"这个顺序本身,时序上就不成立。

但 48 秒抓人归抓人,它是个障眼法。这篇要说的不是"公网很危险"——这话谁都会说。要说的是这批流量到底是什么东西。它既不是攻击,也不针对你,它是一份清单被逐项核对的过程。把这件事搞清楚了,你自然知道该防哪一层。

先说最容易搞混的地方

45 分钟,三个区域加起来 3,480 次连接尝试,来自 860 个不同的源地址。

看到"3,480 次连接",第一反应通常是"有三千多次攻击"。这里最容易被搞混的就是这个。tcpdump 抓到的是入向 TCP SYN 包,SYN 不是连接,SYN 是敲门。门后面有没有人应答、三次握手走没走完、会话有没有真的建立起来,全是另一回事。这 860 个源地址里有 672 个,78%,在整个观测窗口里只发了一个包。

78% 不能读成"78% 的扫描者放弃了"。更准确的读法是:这部分流量从一开始就不打算跟你建立会话,它是无状态扫描器的单发探测。有响应就记一笔,没响应就再也不回来。它们不想跟你说话,它们在核对清单。

剩下那 22%,才是愿意花时间跟你握手的部分,也是这次实验唯一有看头的地方。

每小时七八百次,这是地板

先给个量级锚点。把最吵的那个源剔掉之后,三台机器的入向速率落在每小时 677 到 829 次之间。

法兰克福原本记了 2,325 次,其中一台韩国电信的主机单独就发了 1,663 个包,几乎全冲着 telnet 去。把这一台拿掉,法兰克福就掉回跟另外两个区域差不多的水平。这个细节挺重要:所谓"某个机房被扫得更凶",绝大多数时候只是被单个高频源扭曲出来的错觉。数据里看着像趋势的东西,往往是一个 IP 在刷分。

(做这类测量有个基本功,先剔 top talker 再看分布。不剔,你看到的永远是那个最勤快的家伙。)

所以真正的基线大概就是每小时七八百次。这个数字跟你是谁没关系,跟你开没开服务没关系,跟你的域名有没有被人知道更是没关系。机器没进 DNS,没签任何证书,没在任何地方被公开提到过,理论上只有云厂商知道它存在。然后它每小时被敲七八百次。

机制上解释这件事只有一句话:扫描器扫的不是你,是整个 IPv4 地址空间。你只是恰好在这一轮枚举的路径上。这不叫锁定,这叫路过。

顺带说敲的是哪些门,也有意思。最多的是 23 端口,telnet。然后是 8088,每台机器上都有稳定流量,这个端口对应 Hadoop YARN 和各种管理面板。5555 也被瞄着,那是 Android Debug Bridge,暴露出来等于把手机或电视盒子递出去。至于 80 和 443 上的 HTTP 请求,绝大多数连 Host 头都没带,就是一个裸的 / 探测,这是扫描器的抓法,不是浏览器的抓法。

现在说那 1,085 次

这才是最值钱的一段。

在全部尝试里,有 1,085 次是真的往 telnet 假登录提示符里填了密码的。而这 1,085 次,总共只用了 107 组不同的用户名密码组合。平均一组被重放了十次出头。

107 组,这就是全部字典。一个数字就把性质说清楚了:这不是在猜密码,这是在过一张清单。

清单上分几类。一类是 annie2015、annie2014、annie2016 这样带年份序列的。一类是 OxhlwSG8、S2fGqNFs、tlJwpbo6 这种八位随机串,看着随机,其实是某个 botnet 家族内置换着用的凭据表。剩下的就有来头了:motorola、epicrouter、7ujMko0admin、Zte521、123456。

7ujMko0admin 是大华摄像头的后门账号,epicrouter 是 Conexant 方案 DSL 猫的出厂默认,Zte521 是中兴路由器的出厂默认。

而这里真正该注意的是没出现什么。password1、qwerty、letmein 这些人类密码猜测榜上的常客,一个都没有。

一个缺失比一堆出现更能说明问题。对面根本没在猜"人会设什么密码",他们在试"这东西出厂的时候密码是什么"。这两件事在成本结构上完全不是一回事,值得单独拆。

为什么押出厂默认,而不是猜人

说白了就是一笔账。

人类密码的空间是无限的。同一个词,有人大写首字母,有人加年份,有人加感叹号,有人干脆用生日。你要猜中,得先猜中这个人属于哪一类用法习惯,再猜中具体取值,每往下走一步成功率都掉一截,而且猜中了也只是这一个入口。

出厂默认是另一回事。它是有限的、公开的、有确定枚举上限的。某款摄像头的默认账号就那一个,不是一个分布。更关键的是收益的时间结构:这台设备一旦被拿下,它大概率永远不会收到固件更新。厂商早就不管了,用户也不会去动它。你今天花一次尝试换来的访问权,明天还在,明年还在。

一边是收益递减的无限空间,一边是一次投入长期持有的确定性资产。往哪边押注不用想。

所以这三台机器收到的不是"攻击",是一次设备普查。对面不把你当人,也不把你当服务器,对面把你当成一台可能带着出厂密码上了网的东西,清单上哪一项在你这应验了,就顺手收走。

我一开始想把这段写成"这些 bot 有多懒",写到一半发现不对,得反过来说:这不是懒,这是算得很清楚的一步棋。押注出厂默认是这类流量的最优解,不是次优解。

一个把我绊了一下的细节

假 telnet 服务第一版收不到任何密码。日志里只有连接,没有任何登录尝试。

原因是这些 bot 在发密码之前会等服务器先做 telnet 的选项协商,IAC DO/WILL 那一套。你得先把那几行字节吐出去,对方才会把用户名密码推过来。改完监听器让它模仿一个真实 telnet daemon 的协商行为,1,085 次尝试才冒出来。

这个坑本身不稀奇,稀奇的是它透露的信息:对面跑的是一个完整的 telnet 客户端状态机,不是拿个 socket 裸发字符串。写这些 bot 的人对协议的理解,比这个蜜罐的第一版还到位一点。

"挨家挨户敲门"这个类比到这儿就该收了。前面对付的是路过式扫描,敲门的是无状态探测器,那层用类比讲没问题。但在 telnet 这一层,对面不是随便敲敲就走,它在正经跑协议,在等你的应答。类比撑不住的地方就在这儿。

加固这件事,抽象层会咬你

记一个跟主实验没什么关系、但我还是想记一笔的坑。在 Ubuntu 24.04 上把 SSH 从 22 挪走,改 sshd_config 里那行 Port,没用。因为 SSH 是被 systemd socket 激活的,配置文件里那行直接被忽略,真正决定监听端口的是 systemd 的 socket unit。

然后去改那个 socket,一台机器当场掉线,只能重建。这个错重复了一次才收手,最后真 SSH 就一直留在 22。

这事跟扫描没关系,但它和扫描背后是同一类问题:你以为你在配置 A,实际生效的是 B。加固动作和它的实际效果之间隔着一层抽象,这层平时不显形,只在出事的时候咬你一口。挪端口那点收益,已经不值得再折腾了。

这套设置测不到什么

边界得说清楚,不然这堆数字很容易被读成别的东西。

这个实验测到的是"无目标流量的地板",不是威胁模型。真正冲着你去的人在这套设置里是完全隐形的:一个已经知道你 IP、知道你在跑什么服务的人,不会用 telnet 默认密码字典来敲你,他有别的路子,而那些路子恰恰不会出现在这 860 个源地址里。

所以每小时七八百这个数字的正确用法是当背景噪声的基线,不是拿来估风险。它的价值在于告诉你:任何一个新 IP 从上线第一分钟起就在这个噪声里,跟你做没做错事无关。至于噪声里有没有夹着针对你的东西,这套设置回答不了。

有人问过换成 IPv6 会不会好一点。没测过,但预期是有差别的:单个 /64 让穷举扫描变得不现实,无差别那一层大概会消失。但它换掉的只是发现方式,不是暴露本身。IPv6 主机的发现路径会转向 DNS、反向解析、证书透明日志、出站流量泄漏,还有各种公开的命中名单。而且这里有个反过来的性质:你主动向外宣告一次存在,那一段就都暴露了,因为你没法只暴露一个地址而不泄漏结构。

意思就是,IPv6 拿走的是"路过",拿不走"被发现"。一台自己报出名字的机器,本来也没打算隐身。

收尾

绕了这么一圈,能落下来的其实很朴素:默认拒绝得在镜像里,不能在脚本里。不是因为它更优雅,是因为脚本在时序上根本赶不上——48 秒比 cloud-init 跑完还短,这场赛跑在调度发生之前就已经结束了。

那 1,085 次密码尝试呢,记住它们的性质就够了。对面不是在猜你的密码,是在核对你有没有用出厂密码。这条清单能不能在你身上应验,跟你的安全习惯好不好几乎没关系,只跟那台机器出厂时的密码改没改有关系。这也顺带解释了为什么真正被盯上的是那些装完就再没人管的东西——摄像头、机顶盒、路由器,它们大概率一辈子等不到一次固件更新。

懂了这层,你自己就能判断哪台机器该紧张,哪台只是恰好站在了别人扫描的路径上。