MikroTik RouterOS-CVE-2019-13954漏洞复现
产品描述:
Mikroik RouterOS是一种路由器操作系统,其通过PC电脑成为专业路由器,并通过该软件成为专业的软件,历来不断更新和改进,在不断更新和完善。路由器操作系统具备多种路由系统的功能、ISP网路接入社区、ISP网路接入点等功能,备受业界瞩目。等网络设备的接入架构,基于标准的x86。
漏洞利用分析:
漏洞描述
CVE-2019-13954
是MikroTik 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是回车,
评论