Emails and Malicious Macros – What Can Go Wrong?

Intro

A few months ago, we published a blog post that examined the telemetry available through Office 365, including email visibility. If you read the blog and thought to yourself, I wish that I could get more comprehensive email visibility, beyond just the basic meta-data, then the Splunk Microsoft O365 Email Add-On is something you want to explore, and is the subject of this blog post.

Why Is This Type of Visibility Important?

If you read reports regarding ransomware intrusions, they indicate that the common theme among them is a phishing attempt, using a malicious macro document. For example, the latest DFIR Report on the Bazar malware highlighted the use of a DocuSign themed, malicious Excel document to compromise targets:

In addition to phishing malware documents, business email compromise (BEC) is another extremely popular and effective attack vector. John Hencinksi of expel.io notes that sixty-percent of the incidents Expel detects are BEC attempts:

Given these two critical attack vectors, it stands to reason that an organization would want as much email and macro execution visibility as possible. Unfortunately, visibility into these two areas is difficult to acquire. However, the new Microsoft O365 Email Add-On from Splunk is, in our opinion, worth examining. More importantly, we recommend that you configure it in your environment if you utilize Splunk and Office 365 services.

What Does The Application Do?

The original blog post from Splunk (obviously) does a good job of outlining what the application does. In a nutshell, the application provides us with the ability to see full DKIM, SPF and Email header analysis for every email sent to the mailbox that you configure the Splunk app to monitor. In addition, the application can also collect portions or the full body text of the email itself (not just the subject lines) to be used for text-based analysis. Taking it to the next level, the application will also use OLETools to extract suspicious indicators of compromise (IOCs) from macro enabled documents attached to emails. The application also has other features like pixel tracking detections and the ability to extract non-password protected zip files. So, taking a pause, hopefully you are starting to sense why this application is so exciting and promising. It enhances visibility into malicious macros and phishing attacks, directly addressing ransomware and BEC threats.

What Do I Do With the Data?

The blog post from Splunk highlights some use cases for SPF/DKIM data, so we won’t focus on that in this post. Instead, we’d like to show how you can combine the extremely rich data made available through this application with your endpoint telemetry – in our case we’ll be using Sysmon (*free*). As mentioned previously, the application runs OLETools on all macro-enabled documents to extract IOCs. So, let’s build a quick Splunk dashboard to show these data to us:

We can see OLETools getting a work out with our test payloads, showing us all the suspicious macro functions it found, such as AutoOpen or CreateThread or Wscript.Shell. Cool! Now we see what kind of suspicious macros are making their way into our users mailboxes.

As a next step, we want to see what these macros are doing at the host level as well, and this is where Sysmon telemetry comes in handy. In our example, we’re building a drop-down list of all the suspicious macros inspected by OLETools. We then pass the value of our dropdown selection into a search that displays the command line values for this document. We can observe also DLLs the macro loaded and its associated parent process – All together, you get the resulting dashboard panel:

In this particular example, as a proof of concept, we are extracting the name of the document from host logs and are linking it to the attachment file name. In production, you may want to use a hash value to avoide the potential of duplicate file names that might occur in a real environment.

Next, and in a different panel, we want to graphically display what processes where spawned by the macro that we chose to investigate. Here is the resulting panel:

And finally, we populate another drop down list with the names of macros, this time looking for what functions these macros called. You can accomplish this by referencing our previous research: https://www.lares.com/blog/hunting-in-the-sysmon-call-trace/ – this panel looks like:

Putting it all together, our final proof of concept macro investigations dashboard will look something like the following:

It is interesting to point out here that OLETools picked up on the suspicious Wscript.Shell VBA call, which was also shown using our Sysmon CallTrace analysis. We cannot be overstate how powerful this type of end-to-end, mailbox-to-host level visibility is. Indeed, a threat hunters dream! Overall, the goal of this type of dashboard is to provide a high-level view of suspicious macros and to provide the functionality required to quickly investigate and triage these macros at the host level. This dashboard does not make use of File, DNS or Named Pipe telemetry provided by Sysmon. However, if you have those elements enabled, you can easily add them to this dashboard.

Conclusion

BEC and malicious Office macros are critical risk areas that organizations should proactively manage. During Purple Team engagements, we often watch EDRs struggle with malicious macro detections and find that teams often lack the required visibility to properly investigate these popular attack vectors. Ramping up email and malicious office macro visibility should be a target goal of all security teams. We are highly confident that this Splunk application is an extremely solid solution to enhance your detection capability in this critical area.

References

Appendix – Dashboard Code

Please note: this dashboard is provided as a proof of concept only, the regular expressions used to extract the relevant information required have not been tested in a production environment. Please think of this dashboard as a starting point only.

<form>
  <label>Macro Investigations</label>
  <fieldset submitButton="false">
    <input type="time" token="field1">
      <label></label>
      <default>
        <earliest>-24h@h</earliest>
        <latest>now</latest>
      </default>
    </input>
  </fieldset>
  <row>
    <panel>
      <title>Macros Incoming from Office 365</title>
      <table>
        <search>
          <query>index="o365_email" hasAttachments=true "attachments{}.macros_exist"=true
| spath output=macro_keyword path=attachments{}.macros_analysis{}{0}
| spath output=macro_action path=attachments{}.macros_analysis{}{1}
| spath output=macro_description path=attachments{}.macros_analysis{}{2}
| spath output=attachment_name path=attachments{}.name
| dedup attachment_name
| table attachment_name,macro_keyword,macro_action,macro_description</query>
          <earliest>$field1.earliest$</earliest>
          <latest>$field1.latest$</latest>
        </search>
        <option name="drilldown">none</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
  </row>
  <row>
    <panel>
      <title>Macro System Execution</title>
      <input type="dropdown" token="macro_name" searchWhenChanged="true">
        <label>Select The Macro You Want to Investigate</label>
        <fieldForLabel>attachment_name</fieldForLabel>
        <fieldForValue>attachment_name</fieldForValue>
        <search>
          <query>index="o365_email" hasAttachments=true "attachments{}.macros_exist"=true
| spath output=attachment_name path=attachments{}.name
| table attachment_name</query>
          <earliest>0</earliest>
          <latest></latest>
        </search>
      </input>
      <table>
        <search>
          <query>index=sysmon 
    [search index=sysmon
| rex field=CommandLine "(\\\\)(?!.*\\\\)(?<file_name>.+?(?=\"))"
| search file_name = *$macro_name$*
| table ProcessGuid]
| stats values(CommandLine),values(ImageLoaded),values(ParentImage)</query>
          <earliest>$field1.earliest$</earliest>
          <latest>$field1.latest$</latest>
        </search>
        <option name="drilldown">none</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
    <panel>
      <viz type="sankey_diagram_app.sankey_diagram">
        <title>Processes Spawned By $macro_name$</title>
        <search>
          <query>index=sysmon EventCode=1 ParentImage IN (*WINWORD*,*EXCEL*)
| rex field=ParentCommandLine "(\\\\)(?!.*\\\\)(?<file_name>.+?(?=\"))"
| search file_name = *$macro_name$*
 | stats count(Image) by Image,ParentImage</query>
          <earliest>$field1.earliest$</earliest>
          <latest>$field1.latest$</latest>
        </search>
        <option name="drilldown">none</option>
        <option name="refresh.display">progressbar</option>
      </viz>
    </panel>
  </row>
  <row>
    <panel>
      <input type="dropdown" token="source_guid" searchWhenChanged="true">
        <label>Select Document for Function Call Information</label>
        <fieldForLabel>file_name</fieldForLabel>
        <fieldForValue>ProcessGuid</fieldForValue>
        <search>
          <query>index=sysmon EventCode=1
| rex field=CommandLine "(\\\\)(?!.*\\\\)(?<file_name>.+?(?=\"))"
| dedup file_name
| table ProcessGuid,file_name</query>
          <earliest>0</earliest>
          <latest></latest>
        </search>
      </input>
      <table>
        <title>Macro Function Calls</title>
        <search>
          <query>index=sysmon EventCode=10 SourceProcessGUID = $source_guid$
| eval RuleNameSplit = split(RuleName,",")
| eval technique_name=mvindex(RuleNameSplit,2)
| eval function_name=split(technique_name,"=")
| eval function_name_only=mvindex(function_name,1)
| stats values(function_name_only) BY SourceImage,TargetImage</query>
          <earliest>$field1.earliest$</earliest>
          <latest>$field1.latest$</latest>
        </search>
        <option name="drilldown">none</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
  </row>
</form>