The email standard comes from a multitude of RFCs written over 50 years ago. Emails can have quoted values, comments, escapes, encodings, and much more. Many applications use email for user identification. This post discusses exploiting email parsers to bypass account isolation mechanisms that rely on the perceived domain of the email.
While giving weird inputs to PostFix and Sendmail, they saw an interesting error message: DSN (delivery status notification) with an invalid host. In particular,
oastify.com!collab\@example.com had caused this error to occur. UUCP is an ancient protocol that existed before the Internet and email, allowing messages to be sent between Unix systems. The exclamation mark is a separator between the domain and the user part of the email. This domain goes to oastify.com because of the UUCP support. We're getting somewhere!
Doing similar things on Postfix gave them the output of collab%psres.net(@example.com via the ancient protocol source routes. Source routes allow you to chain servers together to send mail. This was sent to BOTH example.com and psres.net as a result. The key is that the ( is commenting out the domain part of the email which Postfix uses the local-part of the source route to send the email to an unexpected location. Regardless, all of this made Gareth want to dive deeper into email parsing.
Encoded word is an email scheme that allows different characters to be used than what is provided. In encoded word,
=? can be used to indicate the start of an encoded word. Next, you provide the charset, type of encoding within question marks and then the encoded data. Finally, the encoded word is ended with
?= in the email. For instance,
=?utf-8?q?=41=42=43@psres.net results in
ABC@psres.net.
Upon testing this on several systems, they found that several websites using Ruby were accepting it. The library accepted utf-7 and several other charsets. Armed with all this knowledge, they began tackling real targets, such as GitHub, to see what they could uncover. The main goal was to use their ability to trick the email provider to domain to gain access to something that they shouldn't have access to. One problem with exploitation is the lack of feedback though.
On GitHub, they played around with double quotes, encoding and such for a long time. Eventually, they noticed that encoded @ signs would be processed. Unfortunately, it was still failing because of the rest of the data following. So, they just added an extra encoded null byte to it, which cancelled the rest of the email data out. This allowed them to have an arbitrary trailing domain but have the email get sent to a user-controlled location. This allowed bypassing the IdP verification on GitHub. A similar thing was done on Zendesk.
On GitLab, they were able to use encoded spaces to get an email sent to more than one user! By including =20 to encode the email, it would add a space between the emails. According to email standards, this is alright to do to send for multiple emails. The rest of the provided email was treated as the second email, even though the service itself only saw the second email for validation purposes. They found a similar exploit using > as well.
They found that another library for email parsing supported Punnycode within the email. They used this trick within Joomla to get XSS by converting the domain character being rendered in the page from a domain to an opening style tag. From there, they leaked the CSRF token via XSS and got RCE via installing a malicious extension. Pretty neat!
The end of the article has several other interesting attack vectors, like using double quotes to add optional fields into an email, like the ORCPT field. To protect against this, the article says to block all encoded-word related characters like =[?].+[?]=. Besides this, the domain of an email should not be fully trusted when it comes from an SSO provider. Great post on parser differentials, once again from Portswigger!