Content Injection in Native Applications
A little under a year ago, I began using an application called MailPilot. MailPilot is an email client built around the concept of inbox zero and is available for both iOS and OSX.
Being someone in the security field, I frequently send and receive emails that contain exploit vectors.
A few months into using MailPilot, I had sent an email that had a Cross-Site Scripting vector in it which caused my inbox to render strangely. Of course I had to tinker with it, and ended up getting code execution through simple content injection within the context of the applications NSWebView which is used to render the email view.
The 3 vectors I used were:
1 | <input type="text" onfocus="prompt(window.parent.parent.parent.getContactsSource());" autofocus="true"> |
1 | <svg onload='v=prompt;v(Object.keys(window.parent.parent.parent))' /> |
1 | <a href="javascript:v=prompt;v(1)">XSS</a> |
In the spirit of responsible disclosure, I reported the vulnerability to the company, and it appeared to be fixed. I sent myself the same vector, and it did not execute. Here is the timeline of disclosure:
7/3/14 - Initial Contact
7/3/14 - MailPilot Inital Response, Silent Patch
7/17/14 - Second Contact, Addition Vulnerabilities Reported
7/17/14 - MailPilot Responds
8/27/14 - Update sent to Apple for review
A few weeks later, however, the problem reappeared.
Round Two
MailPilot had resolved the issue by escaping outbound emails, so emailing yourself the exploit code would no longer cause execution. When sent as raw text from another client, I was able to get JS execution once more.
This time around, I decided to dig deeper, and see what potential the context had for further exploitation. I ended up discovering a large set of DOM functions used internally by the application to communicate between the Objective-C application and the NSWebView, among other things.
Here are the dangerous functions that I discovered I had access to. (Dangerous in terms of functions you would not want an attacker to control.)
1 | [ |
After enumerating all 67 of these functions I was able to:
- Exfiltrate contact lists
- Send the email to other users (to create an email worm, effectively)
- Open local files
- Post data to external servers
- Add contacts to the OS address books
- Delete email drafts
- Change email signatures
- Post notifications to the notification center
- Read speech with speech synthesis
##Dangerous URI Directives
I had also discovered another unique problem, one that didn’t depend on JS execution necessarily – the application also utilized special URI directives to bridge data between JS and Obj-C.
The URI Directives I discovered were:
mp-app://
mp-app-forward://
mp-app-show-original://
mp-app-open-draft://
mp-app-signature://
mp-app-file://
mp-app-file-remove://
mp-delete-draft://
mp-app-begin-saving-draft://
Using an <a>
tag, which is perfectly normal within an email client, with one of these directives allowed me to:
- Forward the email
- Access other emails
- Write a new email
- Read/edit the users signature
- Read, write, and delete files and drafts
Example:
1 | <a href="mp-app-forward://[emailID/address]">Unsubscribe</a> |
And for fun, I wrote a simple fuzzer to test out these protocols. The end result was not all that interesting apart from what I already knew, but I did discover I could effectively shut down a user’s machine by repeatedly opening windows. The windows would even spawn on top of any Utilities that might attempt to close the program resulting in a Denial of Service (and me having to reboot my computer multiple times).
Code Execution
The most dangerous exploitation vector I discovered, however, was in a preview window that would display how many threads were selected in a batch thread operation. This preview window pulled the first argument passed into stringWithFormat
from a text file under attacker control, also known as a Format String Vulnerability.
A Format String Vulnerability allows an attacker to read and write arbitrary data from/to arbitrary locations in memory. You can see an example of the reading arbitrary memory in the screenshot below:
The end result of the above, and why you should care, is that a Cross-Site Scripting (Content Injection) became native code execution with little user interaction. It’s not just about the browser anymore.
It’s good to remember that when you render a native WebView, you potentially do the work of escaping the browser sandbox for an attacker. Many iOS and native applications are moving into using HTML and JavaScript to render UI frames, because they are easy to write, standardized, and work well across different platforms. When you do this however, don’t forget to sanitize user input, and encode output according to context.
In this case, MailPilot has resolved their upcoming 2.0 release by choosing a different method to render the page, avoiding the use of javascript to tackle dynamic rendering. For something as security critical as an email client, this was an excellent decision. For other applications, it may be too extreme of a measure, and properly handling user inputs will suffice.