​Cisco Cook常用方法与技巧

2021-09-07 10:53:08 浏览数 (1)

一、介绍

1.Cisco近几年的安全漏洞:

Cisco近几年披露了诸多的安全漏洞。The Holy Grail Cisco IOS Shellcode And Exploitaion Techniques---Michael Lynn:披露如何绕过Cisco堆检查;GeekPwn大会上的相关内容;以及众多主要的漏洞:IKEv2 Exploit(cve-2016-1287)、EXTRABACON(snmp协议)、IKEv1 Exploit(cve-2016-1287)、Cisco Cluster Management Protocol(CMP)(cve-2017-3881)…..

2.Cisco diversity

Cisco的多样性是其一项标志性特征,主要分为系统多样性和指令架构多样性。 系统多样化:Cisco IOS、Cisco IOS XE、Cisco NX-OS、Cisco IOS XR、ASA OS   指令架构多样化:PowerPC、MIPS、x86_64

3.常见目标特征:

(1)需要对Cisco IOS固件进行逆向分析   (2)通常镜像都是一个大型二进制文件,需要静态分析   (3)在IOS中,所有代码都是在提权模式下进行,因此可以使用特权指令   (4)在IOS中,好几段虚拟内存可能映射的是同一段物理空间(例如20000000与80000000)   (5)溢出执行完shellcode要将控制流返回至正常服务   (6)当IOS服务触发异常时,Cisco IOS会重启设备(dos攻击很简单,RCE需要再构造)   Cisco IOS没有其他的API函数或者指令支持,因此如果想调用里面的一些功能(比如tcp连接),需要去定位相关的功能函数

4.常见防护:

(1)DEP:栈、堆等内存中不可执行,要做ROP攻击 (2)ASLR:栈、堆具有随机化特征,要绕过地址随机化 (3)堆检查:IOS会在固定时间检查堆结构,在堆释放的时候也会进行堆检查(具体的检查方法在之前的公众号文章里有讲),而且IOS的栈的空间也是在堆中的,因此栈溢出和堆溢出利用都可能被检查 (4)代码完整性检查:完整性检查会是否在镜像文件里植入了后门或者shellcode(一般利用签名) (5)计时器:如果shellcode运行时间太久,计时器会触发然后终止攻击进程 (6)Cisco多样化:思科镜像多样性,exp在镜像间的移植需要时间 (7)I-cache、D-cache防护:Powerpc架构的处理器会隔离代码区域和数据区域,因此有时候将控制流劫持到数据区域是无法执行的

5.Cisco IOS漏洞利用整体思路:

二、常用cook方法:

1.Exploit Debugging:

想要实现漏洞利用首先是需要能执行漏洞调试,这里主要介绍两种调试方式。 虚拟平台调试: ①安装Cisco dynamips调试平台(并支持gdb调试版本):

代码语言:javascript复制
git clone https://github.com/Groundworkstech/dynamips-gdb-mod
cd dynamips-gdb-mod/src
updatedb
locate libelf.a

②利用dynamips启动对应的模拟调试:

代码语言:javascript复制
dynamips -Z  连接的端口 -j(禁用JIT编译器) -P  模拟的硬件平台 -t 2621 -s 0:0:tap:tap1 -s 0:1:linux_eth:eth0  镜像文件

③利用gdb连接调试: 注意,这里用的gdb连接调试需要使用对应架构的gdb,有两种解决方案: 一是利用gdb-multiarch;二是利用buildroot或者交叉编译工具链交叉编译一个对应架构的gdb调试工具。

代码语言:javascript复制
gdb$ target remote 192.168.9.1:6666

虚拟调试平台脚本:https://github.com/Groundworkstech/dynamips-gdb-mod

实体设备调试: 虽然虚拟平台调试比较方便,但是有很多版本以及型号的限制,因此最好使用实体设备进行调试。实体设备调试需要利用cisco设备自带的调试栈开启调试。 ①实体设备连接: 首先进行串口调试配置,对于Linux系统,需要指定串口驱动程序。因此需要先查找相应串口驱动模块:

代码语言:javascript复制
lenovo@ubuntu:~$ dmesg l grep ttyS*
[      0.00000] console [tty0]enabled
[838830.952225] usb 2-2.1:FTDI USB serial Device converter now attached to ttyUSB1
[844005.477214] ftdi_sio ttyUsB0: FTDI USB Serial Device converter now disconnected fron ttyUSB1
[1471721.288079] usb 2-2.1:FTDI USB serial Device converter now attached to ttyUSB1

利用串口通信工具连接至指定串口驱动模块,并设置Cisco IOS串口通信的硬件信息,即可建立连接:

代码语言:javascript复制
lenovo@ubuntu:~$ sudo picocom -b 9600 /dev/ttyUSB1
picocom v1.7
port is   : /dev /ttyUSB1
flowcontrol   : none
baudrate is   : 9600
parity is   : none
databits are   : 8

②使用gdb kernel在实体设备上启动gdb调试模式:

对于Cisco IOS新版本,会屏蔽相应调试功能,需要进入ROMMON中开启调试功能。

代码语言:javascript复制
rommon1>confreg 0x2100
C1921(config)#config-register 0x2100
MIPS: break ‘0000000d’
PPC:trap ‘7fe00008’

③利用调试脚本连接对应串口,实现调试功能:

代码语言:javascript复制
python 调试脚本.py /dev/ttyUSB1

调试脚本参考: https://github.com/klsecservices/ios_mips_gdb https://gist.github.com/nstarke/50a1519067f62c223e39a98ba32ed7d5         mips、arm和ppc的调试脚本其实都大同小异,甚至可以自己编写修改调试脚本,注意对应不同的架构时,要修改capstone的对应架构,以及设置断点时的寄存器数值。

2.获取控制流:

通常利用栈溢出漏洞获取控制流(Phrack Magazine Burning the bridge Cisco IOS exploits (2002))

3.DEP绕过:

利用ROP攻击绕过DEP防护,对于ppc指令,可以通过常见返回指令去找gadgets:blr blrl bctr bctrl 常见ROP利用技巧:   (1)利用ROP gadgets直接构造shellcode(cve-2017-3881) (2)利用gadgets直接重写指定数据甚至代码,看能不能起到效果 (3)利用gadgets去禁掉DEP防护,然后在栈上执行shellcode (4)开启在代码段的写权限 ROP攻击限制:ROP攻击可能导致在栈上存放过多的数据(因为shellcode长的话,要在栈上构造很多个gadgets的地址),这样容易触发堆检查机制或者是影响其他的正常数据,因此在栈上不能构造太长的ROP攻击。

4.Gadgets构造的拓展技巧:

(1)Write-4 Primitive (参考34c3交流会议)因为前面所说,不方便构造太多的gadgets,因此可以利用几个简短的gadgets(这几个gadgets的功能就是向内存写一段在栈上存放的4字节的数据),将想执行的shellcode每4字节逐次写到内存中,最后再劫持控制流到内存中即可。这样的话shellcode不论长短,都可以写到内存中,因此不需要在栈上构造过长的gadgets。 在mips和ppc上都有这种类似的write-4的gadgets:

代码语言:javascript复制
lwz     r0,0x14(r1)
mtlr    r0
lwz     r30,8(r1)     #value
lwz     r31,0xC(r1)   #dst address
addi    r1,r1,0x10
blr
stw     r30,0(r31)    #store value
lwz     r0,0x14(r1)
mtlr    r0
lmw     r30,8(r1)
addi    r1,r1,0x10
blr

(2)Blrl Gadgets 由于C语言和PowerPC架构的调用约定,想找到从栈向r3-r17寄存器加载的gadget比较难,但是此类gadget又很常用,因为从r3开始的低号寄存器是PPC架构的传参寄存器,经常需要利用这种gadget向调用函数传参。 解决方法一:可以分几个阶段,先初始化寄存器,再向大号寄存器进行传参(这种gadget很多),然后利用大号寄存器向小号寄存器进行赋值操作。这种办法可以,但是有点麻烦,浪费堆栈空间。 解决方法二:利用blrl gadget,blrl gadget通常具有几个特点:通常都结合低号寄存器使用,而且通常比较多样,因此可以利用blrl gadget,节省堆栈空间。

代码语言:javascript复制
lwz     r5,0xC(r1)    #Load Word and Zero
mr      r6,r20        #Move Register
mtlr    r27           #Move to link register
blrl                  #Branch unconditionally

(3)Indirect Call Gadgets 有时候ROP攻击的shellcode比较复杂,需要调用各类函数,比如memcpy函数,或者是禁止安全机制的函数,或者是调用另一个shellcode,特别是当这些函数位于其他区段时,利用Indirect Call Gadget可以解决。

代码语言:javascript复制
1.mtlr    r28        #Move to link register
  blrl               #Branch unconditionally
  lwz     r0,0x1C(r1)
  mtlr    r0
2.mtctr   r0         #Move to count register
  bctr
3.mtctr   r31        #Move to count register
  mr      r3,r30     #Move Register
  bctrl              #Branch unconditionally
  lwz     r0,0x10 arg_4(r1)
  mtlr    r0

(4)Multitask Gadget 有些一个Gadget可以执行多个功能,例如在栈上存储数据,下面就是一个例子,可以同时执行3个功能:

代码语言:javascript复制
mtctr    r29          #Move to count register
bctrl                 #1st task
mtlr     r28          #Move to link register
blrl                  #2nd task
lwz      r0,0x1C(r1)
mtlr     r0           #Move to link register
lwz      r28,8(r1)    #3rd task
lwz      r29,0xC(r1)
lwz      r30,0x10(r1)
lwz      r31,0x14(r1)
addi     r1,r1,0x18   #Add Immediate
bl

(5)Stack Keeper 功能就是保存一下当前的栈指针,其实就是对r1寄存器进行一下赋值操作:

代码语言:javascript复制
mr     r3,r1     #Move Register
blr              #Branch unconditionally

(6)Debug Gadget Debug gadget是用来调用调试器的。

代码语言:javascript复制
trap         #Trap Word Unconditionally
blr          #Branch unconditionally

上述只是对一些重要gadgets的举例,其中Write-4 Primitive是重要的构造技巧,因为可以实现很多shellcode的写入与执行。

5.调试中的地址随机化问题:

Cisco IOS固件在IDA的解析中基址固定不变,但是某些型号的设备其IOS加载地址随机变化,但是可以通过指令计算IOS加载偏移:

根据show region得出的加载基址,同IDA加载基址进行偏移的计算,即可得出偏移量,然后对比IDA和实体设备gdb调试得到的汇编代码,解决ASLR问题。

6.漏洞利用中的代码随机化问题:

前面讲到,Cisco IOS具有DEP防护机制,这种机制可以通过ROP攻击绕过,但是当代码段也存在地址随机化时,无法直接在栈上布置指定地址的Gadgets,但是这个问题可以通过ROMMON解决。 ROMMON在内存中的加载地址一直不会变化,因此可以利用ROMMON中的代码构造ROP攻击。整体流程可以分为以下三步: (1)首先利用栈溢出,劫持返回地址进入ROMMON部分,构造ROP链。 利用ROP攻击,通过write-4 primitive方法将shellcode写入内存。 将shellcode写入内存段后,再构造栈溢出,控制流劫持到该内存区域,执行shellcode。

7.利用路由器崩溃

Cisco IOS可以将崩溃信息写道内存卡里或者闪存里,也可以通过TFTP服务器传到远端。不同版本路由器可能提供的转储信息记录功能不相同,但是基本信息都是可以记录的,可以通过路由器crash文件追踪漏洞所在位置。崩溃转储功能要进行一下配置。

代码语言:javascript复制
radio#conf t
Enter configuration commands,one per line. End with CNTL/Z.
radio (config) #exception core-file radio-core
radio (config) #exception dump 192.168.2.5
radio (config) #^2

三、cook实例

2017年,Cisco官网披露并修复了SNMP协议中存在的漏洞,漏洞使得攻击者发送构造好的SNMP数据包,实现Dos攻击或RCE攻击。 以C1900系列路由器为例,该漏洞位于SNMP服务处理函数中:

其调用子函数sub_23BEC474进行处理,子函数主要功能为对v19地址进行赋值操纵,v19在子函数中为参数a1,主要功能为对a1地址进行赋值,写入长度由a3控制。

在子函数sub_23BEC474函数中,存在栈溢出漏洞。父函数的v19是长度为16的数组,存放在栈空间上,而子函数的赋值操作的次数可以人为控制,并且该函数的赋值操作没有额外的检查,因此会造成栈溢出。该函数赋值操作过长,会使栈上的v19所在地址的栈空间溢出,影响栈结构,造成溢出,因此可以覆盖父函数返回地址实现ROP攻击。 我们首先利用前面所讲方法解决调试中的ASLR防护,通过show region计算出动态与静态加载基址的偏移量,解决地址随机化问题。通过检查汇编代码是否一致,来判断是否正确计算代码段偏移,可知整体偏移量为0x5160。

验证漏洞,利用scapy构造并发送超长的SNMP数据包:

代码语言:javascript复制
>>> oid = "1.3.6.1.2.1.1.1.0' ".55'*100
>>>sr1(IP(dst='192.168.88.1' )/UDP(sport=161,dport=161)/SNMP(community-"public" ,PDU-SNMPget(varbindlist=[ SNMPvarbind(oid=oid)]) ))
Begin emission :
Finished to send 1 packets.

根据代码偏移量,在父函数的返回地址处设置断点,查看返回地址的覆盖情况,成功实现栈溢出攻击。

继续执行,路由器崩溃重启。

因为C1900系列存在ASLR防护,如果想实现RCE攻击,可以利用ROMMON构造ROP chain,注意一点,ROMMON中的汇编代码具有非连续特点,因此需要编写IDA python脚本进行批量刷写。

四、参考

https://www.powerofcommunity.net/poc2017/george.pdf

文章由ChaMd5安全团队

0 人点赞