CVE-2019-13954 之MikroTik RouterOS memory exhaustion
字数 1410 2025-08-27 12:33:54
MikroTik RouterOS CVE-2019-13954内存耗尽漏洞分析与复现指南
1. 漏洞概述
CVE-2019-13954是MikroTik RouterOS中存在的一个内存耗尽漏洞。该漏洞允许经过认证的用户通过构造特殊的POST请求,使服务程序陷入死循环,导致内存耗尽,最终使服务程序崩溃或系统重启。
受影响版本
- 漏洞存在于6.42.11及更早版本
- 在6.42.11之后的版本中已修复
2. 漏洞原理分析
漏洞位置
漏洞位于/jsproxy/upload接口的处理函数JSProxyServlet::doUpload中。
漏洞代码分析
补丁前版本(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;
string::string((string*)&v36, (const char*)s1);
v11 = Headers::parseHeaderLine((Headers*)&v37, (const string*)&v36);
string::freeptr((string*)&v36);
if (!v11) {
string::string((string*)&v36, "");
Response::sendError(a4, 400, (const string*)&v36);
string::freeptr((string*)&v36);
LABEL_56:
tree_base::clear(v13, v12, &v37, map_node_destr<string, HeaderField>);
goto LABEL_57;
}
}
//...
}
补丁后版本(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;
do {
if (!v14) break;
v16 = *v15++ == 0;
--v14;
} while (!v16);
if (v14 != 0x100u) //数据长度限制
{
v36 = 0;
string::string((string*)&v46, &s1);
v17 = Headers::parseHeaderLine((Headers*)&v47, (const string*)&v46);
string::freeptr((string*)&v46);
if (v17) continue;
}
string::string((string*)&v46, "");
Response::sendError(a4, 400, (const string*)&v46);
string::freeptr((string*)&v46);
LABEL_60:
tree_base::clear(v19, v18, &v47, map_node_destr<string, HeaderField>);
goto LABEL_61;
}
//...
}
漏洞触发条件
- 调用
sub_51F7函数读取POST数据时未读取到有效数据 - 调用
Headers::parseHeaderLine()解析失败
漏洞利用方法
在补丁后版本中,虽然增加了对数据长度的检查(超过0x100字节会退出循环),但可以通过在payload中插入多个\x00字符来绕过这个检查:
- 单个
\x00会被getline识别为终止符 - 多个
\x00会被识别为\\字符,不会终止读取 - 这样既能绕过长度检查,又能保持数组大小超过0x100
3. 漏洞复现环境搭建
所需工具
- MikroTik RouterOS 6.42.11镜像
- Ubuntu虚拟机
- busybox和gdbserver.i686
- Chimay-Red工具(用于提取固件文件)
- PoC代码(来自Tenable)
环境搭建步骤
1. 安装RouterOS
- 从MikroTik官网下载6.42.11版本镜像
- 使用VMware创建虚拟机并安装RouterOS
- 安装时按'a'选择所有组件,然后按'i'安装,后续选项默认'y'
2. 网络配置
- 将RouterOS虚拟机设置为NAT模式
- 在RouterOS中获取IP地址:
ip dhcp-client add interface=ether disabled=no ip dhcp-client print detail
3. 获取完整shell
- 下载busybox和gdbserver.i686
- 关闭RouterOS,在VMware中添加其磁盘到Ubuntu虚拟机
- 挂载RouterOS磁盘并将busybox和gdbserver复制到
/rw/disk - 创建
/rw/DEFCONF脚本开启telnet后门:ok; /rw/disk/busybox-i686 telnetd -l /bin/bash -p 1270; - 通过telnet连接RouterOS:
telnet <routeros_ip> 1270
4. 获取漏洞相关文件
- 使用find命令定位
www和jsproxy.p:find / -name www find / -name jsproxy.p - 或使用Chimay-Red工具从官网提取:
./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
4. 漏洞复现步骤
1. 编译PoC
- 从Tenable获取PoC代码
- 安装依赖:
sudo apt-get install libboost-dev cmake - 确保gcc版本高于6
- 编译PoC:
cd cve_2019_13954 mkdir build cd build cmake .. make
2. 运行PoC
./cve_2019_13954_poc -i <routeros_ip> -u admin
3. 调试验证
- 关闭ASLR(方便调试):
sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space" - 在RouterOS上附加gdbserver到www进程:
./gdbserver.i686 localhost:1234 --attach <www_pid> - 在Ubuntu上使用gdb连接:
gdb set architecture i386 target remote <routeros_ip>:1234 - 设置断点(需要计算jsproxy基地址+函数偏移):
b *0x774f9000+0x8D08 - 运行PoC观察系统行为
5. 漏洞修复建议
- 升级到最新版本的RouterOS
- 如果无法立即升级,可以限制对
/jsproxy/upload接口的访问