Contents
Introduction
Most ransomware families these days focus on encrypting data on a filesystem-level, either locally on infected client systems or remotely on accessible file servers. However, what if ransomware would start encrypting data on an application-level too? Would your backup solutions cover this? Would your planned recovery strategies work in practice? How would your incident response team react to such unfamiliar and potentially new situations? And, are such malware variants even possible, i.e. can be implemented in practice?
To answer these questions and prepare for the case of emergency, we simulated such an application-level ransomware attack for one of our customers. In this blog article we give a little insight, in how we developed the corresponding proof-of-concept (PoC) malware sample. Also, we try to attract some notice on the Component Object Model (COM) – a component of the native Windows API enabling interaction between software objects – which is known for having been misused by malware in the past.
Attack Scenario
We elaborate the above subject matter on a concrete example, namely on Outlook / Exchange e-mailing infrastructures. We show how malware can leverage Outlook’s Component Object Model (COM) to interface with a victim’s mailbox in order to encrypt contained items, such as e-mails, attachments, contacts or even calendar entries.
From the perspective of a ransomware author, encrypting mailbox items on the application-level could be preferable in comparison to encrypting a mailbox copy locally on a victim’s filesystem (if at all available). This is due to the fact that Outlook will synchronize the modified/encrypted items with all the Exchange servers. The item contents will be encrypted server-side, meaning that your server-side backup capabilities will decide on your success to restore encrypted mailboxes.
If your server-side infrastructure is managed by a third-party (Cloud) provider, such as e.g. Microsoft in the case of Exchange Online, the restoring success would also depend on their capabilities, the corresponding configurations you applied, as well as your collaboration with the provider in case of emergency.
Outlook MAPI COM
Next, we demonstrate how such an application-level Exchange ransomware could technically work. After having infected a client system, the ransomware might use the client-side MAPI Component Object Model (COM) of Outlook, to edit items in the victim’s mailbox. To do so, the ransomware does not need to have any elevated privileges. It simply needs to ensure that Outlook is running (either by waiting for the victim to access its mailbox, or secretly starting it in the background).
As shown below, we implement the ransomware PoC in the Python programming language. Although, the usage of other languages is certainly possible, Python was chosen since it has an easy to use MAPI COM interface to Outlook and its syntax is suitable to easily understand the required concepts.
To interact with Outlook, we implement an OutlookCOM class. It has two main functions, which are explained next.
OutlookCOM Init Function
The __init__ function is called whenever our OutlookCOM class gets instantiated. The function uses the imported win32com.client Python module to access a COM object of the victim’s mailbox. This object can then be used to access and traverse the mailbox structure.
import sys, win32com.client, pywintypes class OutlookCOM: def __init__(self): # COM object of Outlook mailbox self.mailbox = win32com.client.Dispatch('Outlook.Application').GetNamespace('MAPI') def traverse(self, folder, level=0, folder_function=None, item_function=None, recursive=True, logging=False): # CUT... if __name__ == '__main__': # CUT...
OutlookCOM Traverse Function
Within the scope of this article, you can think of an Exchange mailbox as having a tree-like structure. The mailbox consists of a list of folders, each of which might have a number of subfolders. In addition to subfolders, a folder can contain other items, such as e.g. mail items.
To process these tree-like structures, the OutlookCOM class implements a generic traverse function. As a parameter, the function expects a folder, from which the traversal should start. The function is called generic, since it accepts two input functions as parameters, the first to be applied on folders, the second to be applied on contained items. In the case of encrypting mails, no folder function would be required, and the function applied to (mail) items, would encrypt their content.
import sys, win32com.client, pywintypes class OutlookCOM: def __init__(self): # CUT... def traverse(self, folder, level=0, folder_function=None, item_function=None, recursive=True, logging=False): """ Traverse a mailbox folder and apply supplied methods to identified (sub-)folders and/or their contained items. Args: folder: The folder to traverse. level: The level of the folder. folder_function: The function to apply on each folder. The function needs to have the following format: function_name(folder, level=0). The function should return the number of times the function was successfully applied. item_function: The function to apply on each item. The function needs to have the following format: function_name(item, level=0). The function should return the number of times the function was successfully applied. recursive: Boolean flag that specifies whether or not to traverse subfolders recursively. logging: Boolean flag that specifies whether or not output should be logged to stdout. """ try: # Process folder if folder_function is not None: folder_function(folder, level=level) # Process items if item_function is not None and hasattr(folder, 'Items'): items = folder.Items for i in range(items.Count): item_function(items[i], level=level) if logging: print('\t', max(level-1, 0) * ' ', '|___ ', folder.Name if hasattr(folder, 'Name') else 'Unknown Folder', ' [{0}]'.format(items.Count), sep='') # Process subfolders if recursive and hasattr(folder, 'Folders'): subfolders = folder.Folders for i in range(subfolders.Count): self.traverse(subfolders[i], level+1, folder_function, item_function, recursive, logging) except pywintypes.com_error as err: print("[!]\tCOM Error: {}".format(err)) except Exception as err: print("[!]\tUnexpected Error: {}".format(err)) if __name__ == '__main__': # CUT
OutlookCOM Example
The following code snippet shows an example of how to instantiate the OutlookCOM class. Two sample (folder and item) functions are used to print some basic information about the accessed mailbox.
import sys, win32com.client, pywintypes class OutlookCOM: def __init__(self): # CUT... def traverse(self, folder, level=0, folder_function=None, item_function=None, recursive=True, logging=False): # CUT... if __name__ == '__main__': # Sample folder_function def print_folder_name(folder, level=0): if(hasattr(folder, 'Name')): print(level * ' ', folder.Name) # Sample item_function def print_message_info(item, level=0): # Only print MailItem objects (olMail) if not hasattr(item, 'Class') or not item.Class == 43: return # Ensure the MailItem has required attributes if not (hasattr(item, 'To') and hasattr(item, 'Sender') and hasattr(item.Sender, 'Address') and hasattr(item, 'Subject')): return print(level * ' ', ' {') print(level * ' ', ' To : ', item.To) print(level * ' ', ' From : ', item.Sender.Address) print(level * ' ', ' Subject: ', item.Subject) print(level * ' ', ' }') # Generate Outlook COM object outlook_com = OutlookCOM() # Print mailbox folders and mails mailbox = outlook_com.mailbox outlook_com.traverse(mailbox, folder_function=print_folder_name, item_function=print_message_info)
When run, the script will produce an output similar to the one below:
C:\> python outlook_com.py damian.pfammatter@[CUT].com Deleted Items Inbox { To : Damian Pfammatter From : [CUT] Subject: Sample HTML Formatted Mail } { To : Damian Pfammatter From : [CUT] Subject: Sample RTF Formatted Mail } { To : Damian Pfammatter From : [CUT] Subject: Sample Plain Formatted Mail } Outbox Sent Items Tasks [CUT]
OutlookCOM Ransomware
For the simulation at our customer, we implemented the encrypt / decrypt functionality of email contents as well as attachments. The screenshots below show a test mailbox before and after the ransomware execution.
Conclusion
Likely, it is only a question of time till ransomware will start encrypting data on an application-level too. Solutions like Outlook/Exchange might be predestined for such attacks, first, since they are omnipresent in the business environments, and second, since they provide client-side (COM) interfaces for easy interaction by malware.
Your backup and recovery strategies, processes and incident response teams should prepare for such attacks. In case your infrastructure is managed by an external third-party, your recovery success will also depend on the external providers’ capabilities, as well as your processes and collaboration with them.
References
- https://docs.microsoft.com/en-us/windows/win32/com/the-component-object-model
- http://docs.activestate.com/activepython/2.4/pywin32/com.html
Credits
Hat tip to Salvador Richter for its igniting thoughts on this topic. Its people like him who think ahead of time and share ideas that helps us prepare for the future. Thank you!
Leave a Reply