| / __ _ |/ | | | | | | | | | || | | ( | | ___ | | | || | | || | _ | / _ / _` | | | | || || | ) | || __/ (| | || _/|/ __|_,|
FOISted 是针对 MikroTik RouterOS 中两个认证后漏洞的利用工具。它可以远程越狱运行 6.34(2016 年)到 6.49.6(最新的 v6 版本)的 RouterOS。
本仓库包含一个针对 x86 设备的利用脚本。该漏洞在其他设备版本上同样存在;编写 ropchain 的任务就留给读者作为练习吧 :)
想了解更多信息,请查看我们关于 RouterOS 内部原理的博客文章:https://margin.re/blog/pulling-mikrotik-into-the-limelight.aspx
Automagic:
$ python3 exploit.py -H <router_ip> -u <username> -p <password>
然后稍后:
$ nc <router_ip> 1337
利用脚本会自动确定 RouterOS 版本并部署正确的 ropchain。注意:目前仅支持 x86 架构的 RouterOS。
如果由于某些原因无法识别你的版本,可以使用以下参数显式指定:
-v <version> # e.g. 6.49.6
如果你在比 6.49.6(公开发布时的最新版本)更新的 RouterOS 版本上运行此工具,你的 RouterOS 版本可能不在 gadget 数据库(./db)中。此时你可以改为传入 /nova/bin/www 的路径,利用脚本将自动尝试为 ropchain 找到合适的 gadget:
-f /path/to/nova/bin/www
FOISted 利用 RouterOS v6 中的两个漏洞来实现远程代码执行。在本节中,我们将回顾一些关于 RouterOS IPC 的背景知识,并讨论这两个漏洞。
注意:本节主要是我们的完整博客文章的简略版本。一定要去看看那篇文章了解更多细节!
在 MikroTik 的 RouterOS 内部,程序之间通过自定义 IPC 协议进行通信。
实际的数据包是 Nova 消息(内部称为 nv::message)。它们以伪 JSON 格式(6.38 之前)和序列化二进制格式存在:

每个进程在 RouterOS 系统内部都有一个固定的地址;例如,/nova/bin/user 位于地址 13,/nova/bin/www 位于地址 70。此外,每个程序都可以注册 handler,在子命名空间中实现某些特定功能。例如,/nova/bin/user 在地址 4 处有一个 handler,充当“登录”端点并为其他服务执行身份验证:

IPC 通信是 RouterOS 运行的关键组成部分。它用于:
在我们的逆向工程工作中,我们编写了一个内部消息跟踪工具,它使我们能够可视化路由器运行期间交换的所有消息。
在下面的演示中,你可以看到我们在 Web 界面中翻页时交换的所有消息:https://youtu.be/Em1hVWnbzQ4
RouterOS 的 Web 界面由 /nova/bin/www 这个二进制程序实现。不过,特定的页面可能由独立的“Servlet”库处理,这些库在单独的共享库中实现功能。
例如,jsproxy.p servlet 处理对 /jsproxy 的请求,winbox.p servlet 处理对 /winbox 的请求,等等……
这些 servlet 是在_第一次_需要时加载到 /nova/bin/www 中的库。例如,我们第一次加载 /jsproxy 时,jsproxy.p 库就会被加载到内存空间中。
在这个库加载过程中,我们在消息跟踪工具中注意到一些有趣的流量:

具体来说,我们发现了一条从 www 二进制程序发送到 www 的 handler #2 的消息。这本身就可疑,因为 RouterOS IPC 是用于_进程间通信_的,而不是用于同一进程内部的通信……
此外,我们注意到其中两个参数似乎是虚拟指针(32 位 x86),这引起了我们的兴趣,因为这种情况非常不寻常。
检查 /nova/bin/www 的 handler #2 中的实际函数时,我们发现一个名为 FoisHandler::cmdUnknown 的函数,它会在收到这类消息时运行。
令人惊讶的是,这个函数从消息中取出参数 0x11,并_将其作为函数调用_,使用另外两个参数作为函数的参数!
所以很明显,如果我们能发送一条经过构造的消息命中这个 handler,就可以调用我们想要的任何函数。从那里开始,转向一个 ropchain 并做更复杂的事情就相当容易了。
作为 RouterOS 的用户,有几种方式可以发送内部 IPC 消息。事实上,所有外部客户端都允许你在认证后发送任意消息:
8291 访问)——由 winbox.exe 客户端使用这些接口在初始认证握手的方式上有所不同,但一旦完成认证,用户就可以将任意 Nova 消息代理到内部系统中。关于 Winbox 和 MAC Telnet 加密协议逆向工程的更多内容,请参阅我们的博客文章和仓库!
在这个利用实现中,我们将 WebFig 端点作为主要的通信机制。有关我们逆向工程出的客户端实现,请参阅 webfig.py。
然而,当我们尝试调用易受攻击的 FoisHandler 端点时,有一个问题:
RouterOS 中的每个 handler 都可以定义一个“策略”位掩码,用于指定允许哪些用户调用它。事实证明,FoisHandler 的策略为 0x80000000,这表示仅允许内部访问(即来自其他系统进程的消息)。
作为管理员用户,我们通过 GUI 能设置的最大权限位掩码仅为 0x7fffe,这是不够的。
这就引出了我们的第二个漏洞:从管理员到“超级管理员”的权限提升。
虽然 GUI 只允许我们设置 0x7fffe 的权限位掩码,但在内部,它实际上只是发送一条 IPC 消息,其中一个字段包含该位掩码值:

所以我们只需伪造一条自己的消息,将权限位掩码值设置为 0xffffffff 即可!
一旦我们这样做,就可以不受限制地访问系统中的任何端点!
我们的利用首先通过 FTP 向系统上传两个文件:
stage2:包含一个监听 1337 端口的反向 shell 生成器busybox:为我们提供合适的 shell 环境然后,我们的利用会执行权限提升,使我们能够命中 FoisHandler 端点。
最后,我们发送一条精心构造的消息,转向嵌入在消息中的 ropchain。该 ropchain 计算 uClibc 中 chmod 和 execve 的地址,并执行:
chmod 0777 stage2execve stage2一旦 stage2 开始运行,你就可以连接到 1337 端口并获得一个 shell!
不能,这两个漏洞都需要管理员凭据才能利用。
这些漏洞至少存在于 6.27(我们能下载到的最早软件)到最新的 v6 版本:6.49.6。RouterOS v7 对 Web 界面进行了重构,易受攻击的 handler 被彻底移除。我们的 POC 是针对 x86 编写的。
该利用脚本(已测试!)适用于从 6.34 到 6.49.6 的每个 RouterOS 版本。