Tuesday, November 6, 2018

Monitoring USB Storage Activity with Splunk – Part 1 (Connectivity events)

By Tony Lee

Have you ever wanted to monitor what goes on with removable media in your environment, but maybe lack the money or man power to run a Data Loss Prevention (DLP) tool to monitor the USB devices? The good news is that you can do this on the cheap using Microsoft Windows Event logs and a bit of data crunching effort. In this article we will provide a few ways to collect the logs, but we will ultimately use Splunk to aggregate, process, and display the information. As a bonus, we will not only outline the steps to accomplish this task, but we will also provide working dashboard code at the end of the article.

Figure 1: Dashboard provided at the end of the article

High-level steps

There are two main steps needed to accomplish this task. We need to generate and collect the Windows event logs and then we need to process and display the logs within Splunk. Each is outlined below.

Windows Event Generation
Microsoft logs USB connect and disconnect actions in the following Windows Event Viewer location:  Application and Services Logs > Microsoft > Windows > DriverFrameworks-UserMode > Operational

Unfortunately, this log is disabled by default. Administrators can manually enable it per machine or take action on a larger scale using a login script or other mechanism outlined in the References section below. For this article, we will enable the logs manually by right clicking on “Operational” and selecting “Properties” to show that it is disabled. Check the box to enable these logs. After checking the box, we rebooted for good measure, because hey, this is Windows.

Figure 2:  DriverFrameworks-UserMode enablement and log path


Connect Event IDs
Now that USB connectivity logging is enabled, insert a USB drive and click the refresh button to see some events. You will notice that there are quite a few event IDs associated with connecting a USB device, but fortunately for our situation, not all of them are important. For example, some of the event IDs pertain to USB functions needed to ready the device. For the sake of completeness, the event IDs associated with connecting a device are the following:

  • 2003 – This is a unique event created upon connecting a USB device which contains helpful data
  • 2004
  • 2006
  • 2010
  • 2100
  • 2101
  • 2105
  • 2106


Disconnect Event IDs
Fortunately, there are far fewer event IDs associated with disconnecting a USB device.

  • 2100
  • 2102 – This is a unique event created upon disconnecting a USB device which contains helpful data


Feel free to explore the data within each event but note that we have called out two Event IDs that contain the most amount of data pertaining to connection (2003) and disconnection (2102).

Windows Event Collection
Now that the logs are being generated, they need to be forwarded from the endpoints to a central location—in this case Splunk. This task could be accomplished using a number of methods such as Windows Event Collector (WEC), a Splunk Universal Forwarder agent, or some other forwarding method. For this demo, we will use a Splunk Universal Forwarder shown in next section.

Splunk
While we are assuming a functional Splunk Enterprise installation exists, we still need to collect the logs. We provide a sample Splunk Universal Forwarder configuration file below to help those using the Splunk Universal Forwarder. Note: we will be placing the events into an index called wineventlog. If this index does not already exist, you will first need to create it.

inputs.conf 
Located on the Windows endpoint (Usually found here:  C:\Program Files\SplunkUniversalForwarder\etc\apps\SplunkUniversalForwarder\local\inputs.conf)

WinEventLog://Microsoft-Windows-DriverFrameworks-UserMode/Operational]
index = wineventlog
checkpointInterval = 5
current_only = 0
disabled = 0
start_from = oldest
whitelist = 2003, 2102


Once the inputs.conf file is properly configured (and the universal forwarder restarted) to collect these logs from the endpoint, we need to verify that the logs are reaching Splunk. Try running the following Splunk search:

index=wineventlog 

If you see results, try something more specific, such as either of the following:

index=wineventlog EventCode=2003
index=wineventlog EventCode=2102

Field Extraction

Now that we have the proper Windows Event IDs we need to make sure we can reference the fields. Unfortunately, Windows event logs are a hybrid between human readable and machine readable—which usually means that no one likes to read them. As a result, we need to perform some manual extraction within Splunk to pull out key information such as the USB vendor, product, serial number, and guid. Within Splunk (Settings -> Fields -> Fields extractions) we added the following regex string to enable this parsing:

.*?VEN_(?<vendor>.*?)\&PROD_(?<product>.*?)\&.*?#(?<serialNumber>.*?)&.*?{(?<guid>.*?)}


Figure 3:  Example Field Extraction

Figure 4:  Example Event ID 2003 showing fields are properly extracted


Conclusion

Now that we have the proper event IDs flowing into Splunk and the necessary fields extracted, we created a Removable Storage Connections dashboard. The dashboard provides statistical analysis for connects, disconnects, top vendors, products, serial numbers, and hosts.  It even includes events over time by action and serial number along with the details needed to investigate USB connections. For your convenience, we included the dashboard code below.

Caveats

Per Greg Shultz, “If you find an Event ID 2003 event record for a specific USB flash drive but don't find a corresponding Event ID 2102 event record, that either means that the USB flash drive is still attached to the system or the system was shut down before the device was removed.”

Acknowledgement and References

Big thanks to the following articles which were quite useful:
https://www.techrepublic.com/article/how-to-track-down-usb-flash-drive-usage-in-windows-10s-event-viewer/ 
https://df-stream.com/2014/01/the-windows-7-event-log-and-usb-device/

Dashboard Code

The following dashboard assumes that the appropriate logs are being collected and sent to Splunk. Additionally, the dashboard code assumes an index of wineventlog. Feel free to adjust as necessary. Splunk dashboard code provided below:


<form>
  <label>Removable Storage Connections</label>
  <description>index=wineventlog EventCode=2003 &amp; 2102 - Microsoft-Windows-DriverFrameworks-UserMode/Operational"</description>
  <fieldset autoRun="true" submitButton="true">
    <input type="time" token="time">
      <label>Time Range</label>
      <default>
        <earliest>0</earliest>
        <latest></latest>
      </default>
    </input>
    <input type="text" token="wild">
      <label>Wildcard Search</label>
      <default>*</default>
      <initialValue>*</initialValue>
    </input>
  </fieldset>
  <row>
    <panel>
      <single>
        <title>Number of Connect Events</title>
        <search>
          <query>index=wineventlog EventCode=2003 USBSTOR $wild$ | table _time, ComputerName, EventCode, User, vendor, product, serialNumber | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="drilldown">all</option>
        <option name="refresh.display">progressbar</option>
      </single>
    </panel>
    <panel>
      <single>
        <title>Number of Disconnect Events</title>
        <search>
          <query>index=wineventlog EventCode=2102 USBSTOR $wild$ | transaction maxspan=5s EventCode, ComputerName, serialNumber | dedup _time, ComputerName, serialNumber | table _time, ComputerName, EventCode, User, vendor, product, serialNumber | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="drilldown">all</option>
        <option name="refresh.display">progressbar</option>
      </single>
    </panel>
    <panel>
      <table>
        <title>Top Hosts with USB Activity</title>
        <search>
          <query>index=wineventlog (EventCode=2003 OR EventCode=2102) USBSTOR $wild$ | transaction maxspan=5s EventCode, ComputerName, serialNumber | table _time, ComputerName, EventCode, User, vendor, product, serialNumber | top limit=0 ComputerName</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="count">10</option>
        <option name="drilldown">cell</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
    <panel>
      <table>
        <title>Top Removable Storage Vendors</title>
        <search>
          <query>index=wineventlog (EventCode=2003 OR EventCode=2102) USBSTOR $wild$ | dedup serialNumber | table _time, ComputerName, EventCode, User, vendor, product, serialNumber | top limit=0 vendor</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="count">10</option>
        <option name="drilldown">cell</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
    <panel>
      <table>
        <title>Top Removable Storage Products</title>
        <search>
          <query>index=wineventlog (EventCode=2003 OR EventCode=2102) USBSTOR $wild$ | dedup serialNumber | table _time, ComputerName, EventCode, User, vendor, product, serialNumber | top limit=0 product</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="count">10</option>
        <option name="drilldown">cell</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
    <panel>
      <table>
        <title>Top Serial Numbers</title>
        <search>
          <query>index=wineventlog (EventCode=2003 OR EventCode=2102) USBSTOR $wild$ | dedup serialNumber | table _time, ComputerName, EventCode, User, vendor, product, serialNumber | top limit=0 serialNumber</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="count">10</option>
        <option name="drilldown">cell</option>
      </table>
    </panel>
  </row>
  <row>
    <panel>
      <chart>
        <title>Events Over Time</title>
        <search>
          <query>index=wineventlog (EventCode=2003 OR EventCode=2102) USBSTOR $wild$ | eval action=case(EventCode == 2003, "Connect", EventCode == 2102, "Disconnect") | table _time, ComputerName, action, EventCode, User, vendor, product, serialNumber | eval ActionSerial = action + ":" + serialNumber | timechart dc(serialNumber) by ActionSerial</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="charting.chart">column</option>
        <option name="charting.drilldown">none</option>
      </chart>
    </panel>
  </row>
  <row>
    <panel>
      <table>
        <title>Connect Events (EventCode=2003)</title>
        <search>
          <query>index=wineventlog EventCode=2003 USBSTOR $wild$ | table _time, ComputerName, EventCode, User, vendor, product, serialNumber</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
          <sampleRatio>1</sampleRatio>
        </search>
        <option name="dataOverlayMode">none</option>
        <option name="drilldown">cell</option>
        <option name="percentagesRow">false</option>
        <option name="refresh.display">progressbar</option>
        <option name="rowNumbers">false</option>
        <option name="totalsRow">false</option>
        <option name="wrap">true</option>
      </table>
    </panel>
    <panel>
      <table>
        <title>Disconnect Events (EventCode=2102)</title>
        <search>
          <query>index=wineventlog EventCode=2102 USBSTOR $wild$ | transaction maxspan=5s EventCode, ComputerName, serialNumber | dedup _time, ComputerName, serialNumber | table _time, ComputerName, EventCode, User, vendor, product, serialNumber</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="count">10</option>
        <option name="drilldown">cell</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
  </row>
</form>


2 comments: