本环境是蛇矛实验室基于"火天网演攻防演训靶场"进行搭建,通过火天网演中的环境构建模块,可以灵活的对目标网络进行设计和配置,并且可以快速进行场景搭建和复现验证工作。火天网演中,内置大量固件设备,包含大型网络设备及物联网设备,可以灵活选取进行测试验证。
背景
MikroTik RouterOS是一种路由操作系统,是基于Linux核心开发,兼容x86 PC的路由软件,并通过该软件将标准的PC电脑变成专业路由器,在软件的开发和应用上不断的更新和发展,软件经历了多次更新和改进,使其功能在不断增强和完善。特别在无线、认证、策略路由、带宽控制和防火墙过滤等功能上有着非常突出的功能,其极高的性价比,受到许多网络人士的青睐。12月初,MikroTik爆出俩个越界访问高危漏洞,在这一小节中,我们了解一下MikroTik RouterOS的消息机制,并以CVE-2022-45315为例进行简单分析。
环境搭建
在开始前,从靶场场景中调用MikroTik RouterOS的环境。具体的本地环境搭建方式,这里不再赘述。本小节中RouterOS的调用的测试版本为6.47
通过靶场拓扑编辑器配置好ip后,我们可以通过ip地址来访问web管理界面,我们还可以在登录界面下载winbox进行连接管理,winbox管理操作与webfig相同。
前置基础
如何ROOT
默认情况下,MikroTik RouterOS安装好之后仅支持RouterOS命令,没有提供任何shell命令来查看系统内部信息和文件信息。对于安全研究人员来说,这种情况下进行漏洞分析无疑是个巨大的挑战,所以我们需要对路由器进行root,进而方便对系统进行操作和调试等等。
在6.44版本之前,我们可以使用Jacob Baines提供的工具Cleaner Wrasse(https://github.com/tenable/routeros/tree/master/cleaner_wrasse)进行root,该工具利用俩个cve漏洞,给路由器植入了一个"后门"。通过这个工具可以很方便的root。但是在6.44版本之后,官方已经修复了俩个漏洞,所以该方法不再适用。但是好在众多RouterOS研究人员开发了新的root方法。众多方法的开发原理都是基于开启"devel"隐藏后门。例如Margin Research团队提供了新root方法(https://margin.re/2022/06/pulling-mikrotik-into-the-limelight/)和工具(https://github.com/MarginResearch/FOISted),以及其他研究者开发的方法(https://ufo.stealien.com/2022-06-01/how-to-root-your-routeros-v7-virtual-machine)。
选择任意一种方法进行root便可以获得到shell。此时我们可以查看系统信息和文件系统等等,那么现在我们就可以正常进行安全研究以及测试了。
消息传递和处理
在通过web管理界面和winbox管理界面进行管理路由器时,我们抓包发现MikroTik RouterOS通信过程被加密。好在我们可以通过一些方法或者工具进行解密(https://github.com/tenable/routeros)。wireshark通信包裹Content-Type头中的msg意为该请求nova message。
解密后的nova message有俩种形式,分别为伪json形式和二进制流形式。俩种形式的message传递信息的意思是等同的。下面例子中(来自于https://www.youtube.com/watch?v=fkigIlDe6vs),我们可以看到nova message的伪json形式,message中包含了几个键值对,key的高亮色前置符号表示了value的类型。例如小写的b代表是布尔类型,小写的s表示是字符串,小写的u表示是32位的整数。小写的m意思是nova message消息本身的类型,同样类型的大写表示这是一个数组消息,例如大写B表示布尔类型数组,大写M表示nova message数组,并且在nova message中消息可以相互嵌套。
这里面key在消息传递过程中具有特殊含义,其中比较重要几个含义为,如ff0001表示sys_to,其意思是该消息要发送到哪里。ff0002表示sys_from,其意思为该消息是由哪里发送过来的。而ff0007表示要执行的command。
那么不同的前置符号加上key对应的value同样具有特殊含义,例如上面例子中Uff0001的value为[13 , 7],其含义为要发送的地址为一个32位整数数组(routeros中通常一个数组包含2个元素),13和7的意义分别为程序id和handler id。简明理解一下这个过程,可以类比在一个经典的tcp/ip交互过程中,我们通常需要源地址和目的地址,并且他们都包含了ip和port。那么这里的ip即为程序id,port即为对应的handler id。Uff0002:[70,1]的含义为一条消息从[70,1]发送出来。类似这俩个例子,其他key对应的value也是一样,uff0007:0xfe000d中ff0007表示sys_cmd,其对应command的32位整数,根据上图对照表中,这里为get函数。
那么什么是程序id和handler id呢?在RouterOS中有一个叫/nova/etc/loader/system.x3的二进制文件,里面记录了所有的程序的信息,该文件同样是加密过后的。我们可以通过工具进行分析,下图中展示了所有nova程序对应的程序id。
handler id我们需要在对应的程序中找到,例如本小节中的漏洞程序snmp中,handler id我们可以通过routeros中的工具进行查找,也可以逆向分析nv::Looper::addHandler函数进行发现,其中handler id有4,5,1,2四个。
此时我们把上面的信息串联起来就组成了程序间消息传递机制(IPC,inter-process communication)。以下图为例,我们简单了解一下程序间消息传递的过程。
请求过程如图中蓝色部分,假设foo程序要向bar(id为34)程序中的sub(sub为handler,id为50)发送消息,foo构建好包含SYS_TO:[34,50]和SYS_FROM:[]的nova message,并调用相关函数将其发送给loader程序,然后loader程序根据SYS_TO数组中value的第一个item将其传递给bar程序中,在这个过程中,loader会给foo程序注册一个随机id(这里为12)。并且在传递消息的过程中,它会删除SYS_TO消息数组中的第一个item,并在SYS_FROM数组中添加foo的程序id。bar程序根据当前SYS_TO消息数组中value的第一个item(此时为50),将其转发给sub handler。同样的,这个过程中它会删除当前SYS_TO消息数组中的第一个item。sub接收到消息后,发现SYS_TO为空,便会直接处理消息。
响应过程如图中黄色部分,sub处理完消息后进行响应,此时sub会直接翻转SYS_TO和SYS_FROM的消息数组value构建nova message,此时SYS_TO:[12]和SYS_FROM:[]。sub将消息发送给bar程序,随后bar程序会插入sub的id到SYS_FROM数组中,并将消息发送给loader程序,loader根据SYS_FROM识别出源地址为bar程序,并且根据SYS_TO识别出目标程序为foo。随后,loader程序插入bar的程序id到SYS_FROM消息数组中,并删除了SYS_TO消息数组value中的第一个item。处理完毕后将消息发送给foo程序。foo程序发现SYS_TO为空,直接进行处理,至此整个消息传递过程结束。知道了整个过程后,如果我们想要手动模拟向程序发送消息,通过使用(https://github.com/tenable/routeros)工具,我们就可以同样构建出相同的nova message。
篇幅有限,无法精确描述每一个步骤,所以细节方面大家可以自行查找资料或者进行逆向分析。现在我们了解了整个消息传递的过程后,接下来我们就可以开始漏洞分析了。
漏洞分析
该漏洞为越界访问漏洞,漏洞点在Item::regenerateKeys函数中,漏洞成因是v2变量由参数传入为用户可控,当攻击者输入一个精确计算的数值时,28乘v2变量后加上0x8074B84就变得攻击者可控。若v2变量为负值,则直接导致后续指令访问v3为不可访问地址,导致程序崩溃。
用户可控参数的赋值情况如下,Item::setConfig函数通过调用nv::message::get<nv::u32_id>函数,获取用户传进来的32位整数(函数中的第2个参数即为传入id)。随后以该值作为参数传入漏洞函数中。
那么用户的消息是如何传进来触发的呢?当snmp接收到用户传来的消息后,snmp的Looper从SYS_TO的第一个item中识别出了handler的id。并将其发送给对应handler进行处理。在漏洞触发过程中,snmpLooper识别出了handler id为1,随后将SYS_TO消息数组value的第一个item去除,并转给对应handler处理。下图中hander id为1的instance为CommuityKeep。
下图中的off_8073828即为handler 1的vtable。在处理用户命令消息时,nv::Handler::handle函数比较传入命令的value值并调用nv::Handler::handleCmd函数对用户传入command进行处理。经过动态调试后发现,程序调用了sub_805F386函数进行相关处理。
随后在sub_805F386函数中,函数调用了sub_805F2FC函数,该函数将off_8073220 vtable(Item::setConfig函数在其中)被传递给了a1并作为参数传给了vector_base::vector_base函数。随后调用了libubox.so库中的AMap::cmdAddObj函数对用户传入addObj命令进行处理, 该函数调用了Item::setConfig触发了用户消息value的赋值。随后便进入Item::regenerateKeys函数触发了漏洞。
动态调试过程如下,routeros中启动gdbserver并attach snmp进程。gdb远程调试运行后,发送poc消息。程序断在了sub_805F386函数,其实此时stack的分布也能看出sub_805F386由AMap::cmdAddObj函数调用,并且backtrace中的函数调用和我们的分析相同。
随后进入sub_805F2FC函数,运行后触发断点0x806ddfc。
赋值过程如下,此时eax即为我们传进来id为20的value数据。0x806dec2指令便会将取出数据存入(this + 6)地址中。
进入Item::regenerateKeys函数后,EDI(28*v2)后将与0x8074B84相加。
相加后的v3变量如下,在snmp程序中,程序地址为0x8048000-0x809a000,此时EDI的值已经越界。程序下一条指令便是取出[edi+4]的内容,所以程序往下运行便会崩溃。
程序已经崩溃。在整个漏洞触发过程中,(this + 6)地址中值为负值,若为精确数值,我们便可精确控制Item::regenerateKeys中的v3变量,进行后续exp利用。
漏洞复现
routerOS正常运行状态下的snmp程序
运行poc,发送msg成功后
snmp程序崩溃并重启。
此漏洞明确可以在routeros中通过rop攻击调用dlopen函数打开上传so库的方法进行获得shell,危害较大。
总结
这一小节,我们简单了解了MikroTik routerOS的消息传递机制,以及学习了越界访问漏洞的原理。文章来源:https://www.toymoban.com/news/detail-512647.html
蛇矛实验室成立于2020年,致力于安全研究、攻防解决方案、靶场对标场景仿真复现及技战法设计与输出等相关方向。团队核心成员均由从事安全行业10余年经验的安全专家组成,团队目前成员涉及红蓝对抗、渗透测试、逆向破解、病毒分析、工控安全以及免杀等相关领域。文章来源地址https://www.toymoban.com/news/detail-512647.html
到了这里,关于网络靶场实战-RouterOS漏洞分析(CVE-2022-45315)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!