Mikrotik Winbox漏洞概述。 或大文件

美好的一天,也许很多人听说过Mikrotik路由器中的最新漏洞,该漏洞使您可以提取所有用户的密码。 在本文中,我想详细展示和分析此漏洞的本质。
所有材料仅供参考,因此利用此漏洞的代码将不在此处。 如果您对了解特定漏洞的原因和内部结构不感兴趣,可以继续阅读。

让我们开始吧


首先要开始的是Winbox客户端和设备之间的流量分析
Winbox是用于Windows OS的应用程序,它完全重复了Web界面,并设计为使用板载路由器OS来管理和配置设备。 支持2种操作模式,TCP和UDP
在开始之前,您应该在Winbox中禁用流量加密。 这样做如下:您需要启用复选框工具 -> 高级模式 。 之后,界面将更改如下:


取消选中安全模式 。 启动Wireshark并尝试登录设备:


如下所示,在授权之后, 列表文件被请求,然后其内容被完全传输给我们,看来一切都很好,但是让我们看一下本次会议的开始:


从一开始,Winbox就发送与请求列表文件完全相同的软件包:


考虑其结构:

  1. 37010035-包装尺寸
  2. M2是指示数据包开始的常量
  3. 0500ff01-值为True的变量0xff0005
  4. 0600ff09 01-值1中的变量0xff0006(发送的数据包数)
  5. 0700ff09 07-变量0xff0007的值为7(以读取模式打开文件)
  6. 01000021 046967374-变量0x01000001 4字节的字符串列表(通常,此变量负责文件名)
  7. 0200ff88 02 ... 00-大小为2个元素的0xff0002数组
  8. 0100ff88 02 ... 00-大小为2个元素的0xff0001数组

协议反向的结果,以及客户端和服务器端的相应二进制文件,可以还原和了解Winbox与设备进行通信的协议结构。

NvMessage协议说明

字段类型(名称:数字指定)


  • u32:0x08000000
  • u32_array:0x88000000
  • 字符串:0x20000000
  • 字符串数组:0xA0000000
  • addr6:0x18000000
  • addr6_array:0x98000000
  • u64:0x10000000
  • u64_array:0x90000000
  • true:0x00000000
  • 假:0x01000000
  • bool_array:0x80000000
  • 讯息:0x28000000
  • message_array:0xA8000000
  • 原始:0x30000000
  • raw_array:0xB0000000
  • u8:0x09000000
  • be32_array:0x88000000

错误类型(名称:数字标记)


  • SYS_TO:0xFF0001
  • STD_UNDOID:0xFE0006
  • STD_DESCR:0xFE0009
  • STD_FINISHED:0xFE000B
  • STD_DYNAMIC:0xFE0007
  • STD_INACTIVE:0xFE0008
  • STD_GETALLID:0xFE0003
  • STD_GETALLNO:0xFE0004
  • STD_NEXTID:0xFE0005
  • STD_ID:0xFE0001
  • STD_OBJS:0xFE0002
  • SYS_ERRNO:0xFF0008
  • SYS_POLICY:0xFF000B
  • SYS_CTRL_ARG:0xFF000F
  • SYS_RADDR6:0xFF0013
  • SYS_CTRL:0xFF000D
  • SYS_ERRSTR:0xFF0009
  • SYS_USER:0xFF000A
  • SYS_STATUS:0xFF0004
  • SYS_FROM:0xFF0002
  • SYS_TYPE:0xFF0003
  • SYS_REQID:0xFF0006

错误值(名称:数字指定)


  • ERROR_FAILED:0xFE0006
  • ERROR_TOOBIG:0xFE000A
  • ERROR_EXISTS:0xFE0007
  • ERROR_NOTALLOWED:0xFE0009
  • ERROR_BUSY:0xFE000C
  • ERROR_UNKNOWN:0xFE0001
  • ERROR_BRKPATH:0xFE0002
  • ERROR_UNKNOWNID:0xFE0004
  • ERROR_UNKNOWNNEXTID:0xFE000B
  • 错误超时:0xFE000D
  • ERROR_TOOMUCH:0xFE000E
  • ERROR_NOTIMP:0xFE0003
  • ERROR_MISSING:0xFE0005
  • STATUS_OK:0x01
  • STATUS_ERROR:0x02

包中的字段结构


在任何字段的开头都是它的类型-4个字节(3个字节-变量的用途,后面再讲1个字节-直接是此变量的类型),然后长度是1-2个字节和值本身。

数组


可以用以下结构描述该数组:

struct Array { uint32 type; uint8 count; uint32 item1; uint32 item2; ... uint8 zero; } 

类型(4字节)/元素数(1字节)/元素(4字节)/字节末尾\ x00

线数


字符串不是以null结尾的,但具有明确定义的长度:

 struct String { uint32 type; uint8 length; char text[length]; } 

数字


包中最简单的类型,可以表示为值类型:

 struct u* { uint32 type; uint8/32/64 value; } 

根据类型,该值具有相应的位尺寸。

布尔型


字段的大小为4个字节,高字节负责值(True \ False),低3个字节用于分配变量

此外,每个软件包都包含:

  1. 特殊标记指示包装的开始
  2. 包装尺寸
  3. 大型包装控制市场


发现常数


  • 0xfe0001-包含会话标识符(1个字节)
  • 0xff0006-发送的数据包编号(1字节)
  • 0xff0007-文件访问模式(1个字节)

档案存取模式

  • 7-开放供阅读
  • 1-打开录音
  • 6-创建目录
  • 4-阅读
  • 5-删除


现在,了解了协议的工作原理,我们可以随机生成所需的程序包,并观察设备如何响应它们。

在设备方面,可执行文件/ nova / bin / mproxy负责处理数据包。 由于未保存函数名称,因此我调用了一个函数,该函数处理程序包并决定如何处理file_handler()文件。 看一下函数本身:


PS:我们会感兴趣的代码用箭头标记。

第一步


收到打开文件以供读取的包时,它将从以下块开始处理:


首先,使用函数nv :: message :: get <nv :: string_id>()从包中提取文件名。

接下来, tokenize()函数使用“ / ”字符作为分隔符,将结果字符串拆分为单独的部分。

结果字符串数组传递到path_filter()函数,该函数检查接收到的字符串数组中是否存在“ .. ”,如果出现错误,则返回错误ERROR_NOTALLOWED(0xFE0009)


如果没有文件权限,还将在响应中收到PS ERROR_NOTALLOWED

如果一切正常,则将webfigpckg目录的路径连接到文件名的开头

第二步



如果一切顺利,则打开文件并将其句柄保存到全局对象。

如果无法打开文件,那么在响应中我们将收到错误消息: 无法打开源文件


因此,为了接收文件的内容,必须满足3个条件:

  1. 文件路径不包含“ .. ”;
  2. 有访问文件的权利;
  3. 该文件存在,可以成功打开。

现在,让我们尝试发送一些软件包以测试此功能的功能:

 $ ./untitled.py -t 192.168.88.1 -f /etc/passwd Error: SYS_ERRNO => ERROR_FAILED Error: SYS_ERRSTR => cannot open source file $ ./untitled.py -t 192.168.88.1 -f /../../../etc/passwd Error: SYS_ERRNO => ERROR_NOTALLOWED $ ./untitled.py -t 192.168.88.1 -f //./././././../etc/passwd Error: SYS_ERRNO => ERROR_FAILED Error: SYS_ERRSTR => cannot open source file 

这样啊 但这已经很奇怪了……我们记得,如果path_filter()中的检查没有通过,则会出现ERROR_NOTALLOWED ,否则我们仍会收到一条有关缺少访问权限的消息,但是在后一种情况下,事实证明该文件是在顶级目录中搜索的?

让我们尝试这种方式:

 $ ./untitled.py -t 192.168.88.1 -f //./.././.././../etc/passwd xvM2        1Enobody:*:99:99:nobody:/tmp:/bin/sh root::0:0:root:/home/root:/bin/sh 

而且有效。 但是为什么呢? 让我们看一下path_filter()函数代码:


该代码清楚地表明,实际上正在搜索结果字符串数组中是否出现“ .. ”。 但是,最有趣的部分是我用红色突出显示了该片段。
该代码的本质是: 如果上一项也是“ .. ”,则检查被视为失败。 否则,请认为一切都很好。

即 为了使一切正常工作,您只需要交替使用“ /./ ”和“ /../ ”即可成功浏览任何目录并下降到FS的任何级别。


让我们看看Mikrotik开发人员如何修复它:


伪C代码比较


现在,在第一次检测到“ .. ”时退出验证周期。 是的,对我来说,还不是很清楚为什么他们要增加一个点的检查。 不幸的是,由于开发用户的激活机制发生了变化,因此无法动态地看到这一点。

总结一下


  1. 路由器OS即使在用户授权之前也可以毫无问题地处理传入数据包
  2. 由于过滤条件不正确,我们可以访问任何文件

在前面的段落中,我们可以轻松地:创建,删除,读取和写入文件,以及创建任意目录

因此,可以未经授权访问任何文件也就不足为奇了,首先要做的就是使用用户密码读取文件。 幸运的是,该网络拥有大量有关其位置以及如何从中提取数据的信息。

另外,此漏洞可以很好地替代以前已知的激活开发人员模式的可能性,因为您不需要重新启动设备,请立即备份 \ 恢复配置文件。

Source: https://habr.com/ru/post/zh-CN416067/


All Articles