掌控校园内所有投影仪和摄像头
摘要
科罗拉多矿业大学的一名学生构建了一个快速的暴力DNS枚举工具,用于发现校园网络中的所有设备,首先用Python实现,然后改用Rust,通过枚举本地DNS的子域名。
暂无内容
查看缓存全文
缓存时间: 2026/05/16 06:37
# 掌控校园里每一台投影仪和摄像头
来源:https://www.edna.land/blogs/posts/scanning/
当我开始科罗拉多矿业大学的第一年时,我发现了一个相当有趣的事实:本地的 DNS 服务器会给每个连接到网络的设备分配一个子域名。这意味着一个名为 "meow" 的设备在校园 Wi-Fi 上会显示为 "meow.mines.edu",尽管网络仍然会阻止所有流量。这让我暗自思索,我能利用这个做些什么,尤其是能否用这种信息追溯到网络上的设备。
主要问题是访问底层的 DNS 记录,这些记录将特定子域名映射到特定 IP(实际上比这复杂一点,但你懂的)。有几种方法可以解决这个问题:
### 区域传输(Zone Transfer)
虽然这是最简单的选择,但我怀疑 IT 部门会直接把区域传输给我(而且他们确实不应该随便给任何人进行区域传输)。我的设备列表也不会随着新设备加入或离开网络而更新。再说了,这样搞还有什么乐趣呢?
### 证书
许多子域名会注册证书,以确保你的数据来源正确(TLS、HTTPS 证书)。这些证书会添加到只增的账本或日志中,比如 let's encrypt 的证书透明度日志(CT logs)。虽然这些对网站来说有用且必要,但我不明白为什么我的大学会为连接到其 Wi-Fi 的每个设备注册 TLS 证书,更何况这些设备甚至无法从互联网访问。
### 暴力破解
我看到的最后一种方法,也是本篇博客的重点,就是暴力破解。有几种实现方式,包括搜索所有可能的域名,或者使用常用主机名字典来减少查询次数。我个人不喜欢在这个项目中使用字典方法。虽然在实际中更实用,但我特别感兴趣的是编写一个足够快的程序来穷举所有组合。这会呈指数级变难,因为可能的域名数量是 37^n,其中 n 是子域名的字符长度。
在决定通过暴力破解进行排列(可能是最差的选择)后,我开始着手工作。第一个程序是我用 Python 写的,目的是让我理清思路。我使用了 itertools 的 permutation 函数来找到字母和数字的所有组合,以生成子域名(剧透警告:这成了瓶颈)。我知道它需要是异步的,否则会阻塞等待每个 DNS 响应。作为程序来说还行,有一个像样的最小 TUI,但尽管是异步的,速度还是太慢了。不过仍然足以在合理时间内枚举出 3 个字符。
Python 版本(https://www.edna.land/blogs/posts/scanning/1.png)
大约在这个时候,我开始转向 Rust。我知道 Rust 中有很多很酷的项目,但之前从未觉得有必要用它构建什么。Python 一直能满足我对速度的需求,直到现在。我也开始玩 [Helix](https://helix-editor.com/),一个模态编辑器,并意识到我有多喜欢它。虽然我很少使用超出 Python 语法高亮范围的编辑器,但在 Rust 中,语言服务器成了必需品。
Helix 编辑器(https://www.edna.land/blogs/posts/scanning/2.png)
挺漂亮的!
我的第一次尝试使用了 rust itertools 库中的多笛卡尔积函数,但很快就意识到,递增一个整数然后将其转换为 base36 会快得多。排列线程的速度变得相当重要,因为它是唯一进行大量 CPU 运算且不易并行的部分。在 Python 版本中,我使用相同的排列生成前缀,然后将每个前缀分配给一个线程,但在 Rust 中我真的不想处理这个。相反,我使用 bash 脚本为我的程序创建了多个进程,并告知每个进程总进程数和它的特定偏移量。每个进程会递增代表 IP 的整数,递增量是进程总数(而不是 1),从它的偏移值开始,因此覆盖了所有进程之间的每个值。
在 Rust 中,我可以直接访问处理 DNS 服务器连接的 UDP 端口,这意味着读写可以在不同的异步函数中发生。我将读取器分配在一个循环中继续运行,直到它从 socket 中读取的次数与我发送请求的次数相同,并且只打印那些没有响应 NXDOMAIN(域名不存在)的结果。在这里处理这个问题相当重要,因为早期我使用 grep 过滤域名,结果它消耗的 CPU 几乎和进程本身一样多。写入器则相当简单,它将整数转换为 base36 值,将 DNS 查询写入 socket,然后退出。
有一次,我遇到了一个相当严重的内存泄漏,导致进程占用了数百 GB 的 RAM。这是因为我将每个写入器函数的调用追加到一个列表中,以便在进程结束时可以等待所有写入器退出。为了解决这个问题,我首先尝试丢弃这些句柄,改为等待读取器完成,但这并没有阻止泄漏。我得出结论,实际上是 tokio(一个 Rust 异步库)内部的异步栈在泄漏,因为我生成查询的速度超过了它们被执行的速度。为了解决这个问题,我一旦达到一定数量就阻塞查询,等到所有查询完成后才继续。完美的解决方案是保持异步栈大小恒定。但在实际中,这只会带来很小的性能提升,同时需要我重写大量程序,所以我维持了现状。
经过优化,我最终将程序的速度提升到了每 2 个线程 200 Mbps(线程数相当重要,因为我正在使用的服务器限制为 500 个线程,而且只有 96 个核心可用)。这相当于 480 个线程时的约 50.33 Gbps,但我测试的最后一个全容量版本只达到了 4.04 Gbps,而且无论如何我只能用到大约 96 个线程(或约 10.06 Gbps)的容量。
在某一点上,我达到了一个阈值,DNS 服务器无法再跟上并崩溃了。后来我发现,这导致了全校范围内托管计算机大约 15 分钟的中断,因为没有计算机能够进行 DNS 查找来挂载其网络驱动器。IT 部门礼貌地让我停止对 DNS 服务器的垃圾攻击,所以我照做了。
IT 怎么知道是我的?我为此唠叨了两周!
唠叨(https://www.edna.land/blogs/posts/scanning/3.png)
枚举子域名,或者根据你问的人不同,也可以说成是搞垮 DNS 服务器
现在,我获得了相当一部分子域名,但仅限于在穷举 37^n 个查询变得不切实际之前。幸运的是,就在这时我得知了另一个秘密的第四种选择:
### PTR 记录
这是另一种形式的 DNS 记录,它将 IP 映射回域名。例如,我可以将 `10.0.0.0` 映射回 `meow.mines.edu`。这意味着我只需要扫描分配给网络内的 IP 数量。对于这部分,我写了一个更简单的 Rust 脚本,为所有我知道属于学校或者是网络中的域名发送 DNS 查询。效果还不错,我看到了网络上的各种奇怪设备。不幸的是,大多数设备都挺无聊的,比如 `computer-precision-tower-5810` :(。
既然我现在知道了每台计算机……我能拿它们做什么呢?大多数情况下,网络不允许你打开到非 IT 服务器之外的任何连接。在某些特定情况下(我不会深入探讨),网络是允许的。这让我想了解更多,于是我开始了端口扫描器的构建。
一开始,我用 tokio 的 TcpStream 实现了一个简单的网络连接检查,仅检查是否可以连接,然后断开连接。它枚举了 /16 子网中的每个 IP,并扫描一组端口,同时阻塞以确保每台机器在任何时候只扫描约 4000 个端口。这样虽然可行,但需要大量 CPU 才能有所进展,而且我知道可以做得更快。
大约在这个时候,我开始研究 AF_XDP,这是 Linux 内核的一部分,允许创建能够(在不同程度上)绕过内核网络栈的网络套接字,并围绕它编写了一个名为 convoy 的新程序。内核创建了 4 个队列和一段称为 Umem 的内存区域,用于与 NIC 驱动程序交互。对于 convoy,最复杂的交互发生在 Umem、TX 队列和 Completion 队列之间。分配 Umem 后,数据包被写入其中,然后对应于 Umem 中这些数据包的偏移量(也称为帧描述符)通过 TX 队列发送到驱动程序。当这些数据包被处理后,驱动程序将偏移量发送回 convoy,以便它可以写入更多数据包。
AF_XDP 示意图(https://www.edna.land/blogs/posts/scanning/4.png)
这就是疯狂的样子
在这个版本中,我同样采用了横向扫描:先扫描所有机器上的一个端口,然后再扫描下一个端口。这在一定程度上分散了机器(以及网络,程度稍低)的并发负载。效果不错,我可以在一个免费虚拟机的单个核心上每秒扫描约 30 万个端口,同时带宽使用比之前的方法少得多。在测试过程中,我看到了一个起初我以为是扫描器 bug 的现象:局域网上的设备在它们绝对不应该响应的时候却响应了。我花了相当长的时间才真正检查出这是什么,然后我对我看到的结果感到非常担忧。
摄像头控制(https://www.edna.land/blogs/posts/scanning/5.png)
求求你们别用默认密码
然后我看到了 *真正* 可怕的东西
摄像头流(https://www.edna.land/blogs/posts/scanning/6.png)
呃,这是什么鬼
我确实尝试连接到一个摄像头流(通过 RTSP 和设置 RTMP 服务器),但没能得到任何输出。我认为这是因为我的学校在他们的部分网络中使用 Palo Alto,所以我被一个针对此子网上 rtsp 和 rtmp 的深度包检测规则阻止了。也有可能是我学校的一台防火墙在搞鬼,但我对 IT 处理这种情况的能力没有太大信心。
我发现我可以控制 36 个摄像头,并写了一个 bash 脚本与它们的 API 交互(从网页界面逆向工程而来),并命令每个摄像头同步移动,就像一群傻乎乎的小猫在嬉戏。
摄像头跳舞(https://www.edna.land/blogs/posts/scanning/7.gif)
点头点头
然后我发现了更傻的东西!几乎每个教室的控制界面,让我可以切换输入,让屏幕升起或降下。
投影仪界面(https://www.edna.land/blogs/posts/scanning/8.png)
投影仪应该开始喵喵叫
发现这个之后不久,我就向 IT 部门报告了,因为这太疯狂了。而且我也不想被讲座摄像头跟踪。他们告诉我这会在夏天修复(???),但似乎大部分已经修复了。我被告知这个网络段是因为需要无线投屏到某些投影仪才开放的(我只遇到两台实际具备此功能的投影仪)。我没有得到任何补偿 :<
### AI 使用
我用 AI 解决了一个 Rust 作用域问题,谷歌没有给我明确的答案。
[有问题?联系我!](mailto:[email protected])
相似文章
@kl_secservices: 攻击者不需要花哨的技巧来入侵学校:窃取的账户、Potato提权,然后用PsExec进行横向移动。过时的系统……
攻击者使用窃取账户和过时系统等简单方法入侵学校,勒索软件组织DragonForce和LockBit 3以私立学校为目标索取赎金。一份报告分析了巴西的事件并提供了保护建议。
大规模AI工具发现:只需DNS
本文提出ToolDNS,一个将语义工具发现改造到DNS基础设施上的框架,实现了可扩展的O(log N)解析,并在包含超过33,000个跨多种协议的真实世界工具的基准测试中,将搜索空间减少了95.26%。
@noisyb0y1:中国学生在 GitHub 上发现一个改变一切的文件,但他先花了 1600 美元在 eBay 买了 7 台 Mac Mini……
一名中国学生将七台二手 Mac Mini 组成分布式集群,并在 GitHub 分享了一个名为 CLAUDE.md 的文件。
无需触碰,通过音箱入侵你的电脑
一位安全研究人员对 Creative Sound Blaster Katana V2X 的固件进行了逆向工程,发现了漏洞,攻击者可在15米范围内将音箱变成隐蔽的窃听工具和无需物理接触的 Rubber Ducky。
黑客可利用9种最流行AI工具组建大规模僵尸网络
研究人员设计了一种名为HalluSquatting的基于拉取的提示注入攻击,利用AI编程助手易出现资源标识符幻觉的特点,从而能够组建大规模僵尸网络并发起大规模攻击。