美好的一天,也许很多人听说过Mikrotik路由器中的最新漏洞,该漏洞使您可以提取所有用户的密码。 在本文中,我想详细展示和分析此漏洞的本质。
所有材料仅供参考,因此利用此漏洞的代码将不在此处。 如果您对了解特定漏洞的原因和内部结构不感兴趣,可以继续阅读。
让我们开始吧
首先要开始的是Winbox客户端和设备之间的流量分析
Winbox是用于Windows OS的应用程序,它完全重复了Web界面,并设计为使用板载路由器OS来管理和配置设备。 支持2种操作模式,TCP和UDP
在开始之前,您应该在Winbox中禁用流量加密。 这样做如下:您需要启用复选框
工具 ->
高级模式 。 之后,界面将更改如下:
取消选中
安全模式 。 启动Wireshark并尝试登录设备:
如下所示,在授权之后,
列表文件被请求,然后其内容被完全传输给我们,看来一切都很好,但是让我们看一下本次会议的开始:
从一开始,Winbox就发送与请求
列表文件完全相同的软件包:
考虑其结构:
- 37010035-包装尺寸
- M2是指示数据包开始的常量
- 0500ff01-值为True的变量0xff0005
- 0600ff09 01-值1中的变量0xff0006(发送的数据包数)
- 0700ff09 07-变量0xff0007的值为7(以读取模式打开文件)
- 01000021 046967374-变量0x01000001 4字节的字符串列表(通常,此变量负责文件名)
- 0200ff88 02 ... 00-大小为2个元素的0xff0002数组
- 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个字节用于分配变量
此外,每个软件包都包含:
- 特殊标记指示包装的开始
- 包装尺寸
- 大型包装控制市场
发现常数
- 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
如果一切正常,则将
webfig或
pckg目录的路径连接到文件名的开头
第二步
如果一切顺利,则打开文件并将其句柄保存到全局对象。
如果无法打开文件,那么在响应中我们将收到错误消息:
无法打开源文件 。
因此,为了接收文件的内容,必须满足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开发人员如何修复它:
现在,在第一次检测到“
.. ”时退出验证周期。 是的,对我来说,还不是很清楚为什么他们要增加一个点的检查。 不幸的是,由于
开发用户的激活机制发生了变化,因此无法动态地看到这一点。
总结一下
- 路由器OS即使在用户授权之前也可以毫无问题地处理传入数据包
- 由于过滤条件不正确,我们可以访问任何文件
在前面的段落中,我们可以轻松地:创建,删除,读取和写入文件,以及创建任意目录
因此,可以未经授权访问任何文件也就不足为奇了,首先要做的就是使用用户密码读取文件。 幸运的是,该网络拥有大量有关其位置以及如何从中提取数据的信息。
另外,此漏洞可以很好地替代以前已知的激活开发人员模式的可能性,因为您不需要重新启动设备,请立即
备份 \
恢复配置文件。