All Apps and Add-ons

Anomalous Exchange sender daily_bytes dashboard?

Motivator

Does anyone have a dashboard that displays anomalies for Exchange daily_bytes by sender? Looking for possible exfil through Exchange.

0 Karma
1 Solution

Motivator

Yes. This is a run anywhere dashboard if you have Exchange set up; just replace MYDOMAIN

<dashboard script="button_submit_mail_anomalies.js">
  <label>Anomalies</label>

    <row>
    <panel>
      <html depends="$hide$">
        <style>
          #submit_button{
            width:80px !important;
          }
          #submit_button div[data-component="splunk-core:/splunkjs/mvc/components/LinkList"]{
            width:80px !important;
          }
          #submit_button  button{
            padding: 6px 15px !important;
            border-radius: 3px !important;
            font-weight: 500 !important;
            background-color: #5cc05c !important;
            border: transparent !important;
            color: #fff !important;
          }
          #submit_button  button:hover{
            background-color: #40a540 !important;
            border-color: transparent !important;
          }
        </style>
      </html>
      <input type="time" token="TIMERANGE1">
        <label>Time Range (STDEV Baseline):</label>
        <default>
          <earliest>-30d</earliest>
        </default>
        <change>
          <eval token="earliest_epoch_onChange">case(isnum($TIMERANGE1.earliest$), $TIMERANGE1.earliest$, $TIMERANGE1.earliest$=="now", time(), $TIMERANGE1.earliest$="", 0, true(), relative_time(time(), $TIMERANGE1.earliest$))</eval>
          <eval token="latest_epoch_onChange">case(isnum($TIMERANGE1.latest$), $TIMERANGE1.latest$, $TIMERANGE1.latest$=="now", time(), true(), relative_time(time(), $TIMERANGE1.latest$))</eval>
        </change>
      </input>
      <input type="time" token="TIMERANGE2">
        <label>Time Range (Results Filter):</label>
        <default>
          <earliest>@w0</earliest>
        </default>
        <change>
          <eval token="earliest_epoch_FILTER_onChange">case(isnum($TIMERANGE2.earliest$), $TIMERANGE2.earliest$, $TIMERANGE2.earliest$=="now", time(), $TIMERANGE2.earliest$="", 0, true(), relative_time(time(), $TIMERANGE2.earliest$))</eval>
          <eval token="latest_epoch_FILTER_onChange">case(isnum($TIMERANGE2.latest$), $TIMERANGE2.latest$, $TIMERANGE2.latest$=="now", time(), true(), relative_time(time(), $TIMERANGE2.latest$))</eval>
        </change>
      </input>-->
      <input type="link" id="submit_button">
        <label></label>
        <choice value="submit">Submit</choice>
      </input>
    </panel>
  </row>

  <search id="base">
    <query>
index=msexchange event_id=AGENTINFO sender_domain=MYDOMAIN.com | stats sum(total_bytes) as daily_bytes by sender,date_mday,date_month,date_year | eventstats avg(daily_bytes) as average stdev(daily_bytes) as sdev by sender | eval num_sdevs=(daily_bytes-average)/sdev | eval trigger="$submit_trigger$"
    </query>
    <earliest>$earliest_epoch$</earliest>
    <latest>$latest_epoch$</latest>
  </search>

  <row>
    <panel>        
      <input type="text" token="search">
        <label>Filter results by email:</label>
        <default>*</default>
      </input>
      <table>
        <title>Top 100 Anomalous Senders by Daily Bytes</title>
        <search base="base" id="base2">
          <query>
eval time=strptime(date_mday." ".date_month." ".date_year,"%d %B %Y") | where time >="$earliest_epoch_FILTER$" AND time <="$latest_epoch_FILTER$" |
sort 0 - num_sdevs | head 100 | search sender="$search$" | table sender date_mday date_month date_year daily_bytes average sdev num_sdevs
          </query>
        </search>
        <option name="wrap">true</option>
        <option name="rowNumbers">false</option>
        <option name="drilldown">none</option>
        <option name="dataOverlayMode">none</option>
        <option name="count">25</option>
      </table>
    </panel>
  </row>
  <row>
    <panel>        
      <table>
        <title>Repeat Senders in Top 100</title>
        <search base="base2">
          <query>
eventstats count by sender | where count >1 | table sender date_mday date_month date_year daily_bytes average sdev num_sdevs
          </query>
        </search>
        <option name="wrap">true</option>
        <option name="rowNumbers">false</option>
        <option name="drilldown">none</option>
        <option name="dataOverlayMode">none</option>
        <option name="count">5</option>
      </table>
    </panel>
  </row>

</dashboard>

JS:

 require([
     'jquery',
     'splunkjs/mvc',
     'splunkjs/mvc/simplexml/ready!'
 ], function($,mvc){
     var submittedTokens = mvc.Components.get("submitted");
     $("#submit_button").click(function(){
         submittedTokens.set("submit_trigger", ""+Math.random());
         submittedTokens.set("earliest_epoch",submittedTokens.get("earliest_epoch_onChange"));
         submittedTokens.set("latest_epoch",submittedTokens.get("latest_epoch_onChange"));
         submittedTokens.set("earliest_epoch_FILTER",submittedTokens.get("earliest_epoch_FILTER_onChange"));
         submittedTokens.set("latest_epoch_FILTER",submittedTokens.get("latest_epoch_FILTER_onChange"));
     });
 });

View solution in original post

0 Karma

Motivator

Yes. This is a run anywhere dashboard if you have Exchange set up; just replace MYDOMAIN

<dashboard script="button_submit_mail_anomalies.js">
  <label>Anomalies</label>

    <row>
    <panel>
      <html depends="$hide$">
        <style>
          #submit_button{
            width:80px !important;
          }
          #submit_button div[data-component="splunk-core:/splunkjs/mvc/components/LinkList"]{
            width:80px !important;
          }
          #submit_button  button{
            padding: 6px 15px !important;
            border-radius: 3px !important;
            font-weight: 500 !important;
            background-color: #5cc05c !important;
            border: transparent !important;
            color: #fff !important;
          }
          #submit_button  button:hover{
            background-color: #40a540 !important;
            border-color: transparent !important;
          }
        </style>
      </html>
      <input type="time" token="TIMERANGE1">
        <label>Time Range (STDEV Baseline):</label>
        <default>
          <earliest>-30d</earliest>
        </default>
        <change>
          <eval token="earliest_epoch_onChange">case(isnum($TIMERANGE1.earliest$), $TIMERANGE1.earliest$, $TIMERANGE1.earliest$=="now", time(), $TIMERANGE1.earliest$="", 0, true(), relative_time(time(), $TIMERANGE1.earliest$))</eval>
          <eval token="latest_epoch_onChange">case(isnum($TIMERANGE1.latest$), $TIMERANGE1.latest$, $TIMERANGE1.latest$=="now", time(), true(), relative_time(time(), $TIMERANGE1.latest$))</eval>
        </change>
      </input>
      <input type="time" token="TIMERANGE2">
        <label>Time Range (Results Filter):</label>
        <default>
          <earliest>@w0</earliest>
        </default>
        <change>
          <eval token="earliest_epoch_FILTER_onChange">case(isnum($TIMERANGE2.earliest$), $TIMERANGE2.earliest$, $TIMERANGE2.earliest$=="now", time(), $TIMERANGE2.earliest$="", 0, true(), relative_time(time(), $TIMERANGE2.earliest$))</eval>
          <eval token="latest_epoch_FILTER_onChange">case(isnum($TIMERANGE2.latest$), $TIMERANGE2.latest$, $TIMERANGE2.latest$=="now", time(), true(), relative_time(time(), $TIMERANGE2.latest$))</eval>
        </change>
      </input>-->
      <input type="link" id="submit_button">
        <label></label>
        <choice value="submit">Submit</choice>
      </input>
    </panel>
  </row>

  <search id="base">
    <query>
index=msexchange event_id=AGENTINFO sender_domain=MYDOMAIN.com | stats sum(total_bytes) as daily_bytes by sender,date_mday,date_month,date_year | eventstats avg(daily_bytes) as average stdev(daily_bytes) as sdev by sender | eval num_sdevs=(daily_bytes-average)/sdev | eval trigger="$submit_trigger$"
    </query>
    <earliest>$earliest_epoch$</earliest>
    <latest>$latest_epoch$</latest>
  </search>

  <row>
    <panel>        
      <input type="text" token="search">
        <label>Filter results by email:</label>
        <default>*</default>
      </input>
      <table>
        <title>Top 100 Anomalous Senders by Daily Bytes</title>
        <search base="base" id="base2">
          <query>
eval time=strptime(date_mday." ".date_month." ".date_year,"%d %B %Y") | where time >="$earliest_epoch_FILTER$" AND time <="$latest_epoch_FILTER$" |
sort 0 - num_sdevs | head 100 | search sender="$search$" | table sender date_mday date_month date_year daily_bytes average sdev num_sdevs
          </query>
        </search>
        <option name="wrap">true</option>
        <option name="rowNumbers">false</option>
        <option name="drilldown">none</option>
        <option name="dataOverlayMode">none</option>
        <option name="count">25</option>
      </table>
    </panel>
  </row>
  <row>
    <panel>        
      <table>
        <title>Repeat Senders in Top 100</title>
        <search base="base2">
          <query>
eventstats count by sender | where count >1 | table sender date_mday date_month date_year daily_bytes average sdev num_sdevs
          </query>
        </search>
        <option name="wrap">true</option>
        <option name="rowNumbers">false</option>
        <option name="drilldown">none</option>
        <option name="dataOverlayMode">none</option>
        <option name="count">5</option>
      </table>
    </panel>
  </row>

</dashboard>

JS:

 require([
     'jquery',
     'splunkjs/mvc',
     'splunkjs/mvc/simplexml/ready!'
 ], function($,mvc){
     var submittedTokens = mvc.Components.get("submitted");
     $("#submit_button").click(function(){
         submittedTokens.set("submit_trigger", ""+Math.random());
         submittedTokens.set("earliest_epoch",submittedTokens.get("earliest_epoch_onChange"));
         submittedTokens.set("latest_epoch",submittedTokens.get("latest_epoch_onChange"));
         submittedTokens.set("earliest_epoch_FILTER",submittedTokens.get("earliest_epoch_FILTER_onChange"));
         submittedTokens.set("latest_epoch_FILTER",submittedTokens.get("latest_epoch_FILTER_onChange"));
     });
 });

View solution in original post

0 Karma

Motivator

P.S. I also have an alert for this:

[bytes_anomalies]
action.email = 1
action.email.cc = DELETED
action.email.include.search = 1
action.email.include.trigger = 1
action.email.include.trigger_time = 1
action.email.inline = 1
action.email.message.alert = Machine learning algorithm monitoring possible Exchange data exfil by internal senders.\
\
This alert is ran twice daily at 5AM (producing results since 12AM the previous day) and 5PM PST (producing results since 12AM the current day) with a STDEV baseline of 30 days. Total_bytes over 200MB AND num_sdevs over 4.0 alerted on only.
action.email.sendcsv = 1
action.email.sendresults = 1
action.email.subject = Splunk Alert: Exchange daily_bytes Anomaly Detection ($result.spl_id$)
action.email.to = DELETED
alert.suppress = 0
alert.track = 0
counttype = number of events
cron_schedule = 0 5,17 * * *
dispatch.earliest_time = -30d@d
dispatch.latest_time = now
display.general.type = statistics
display.page.search.tab = statistics
enableSched = 1
quantity = 0
relation = greater than
request.ui_dispatch_app = DELETED
request.ui_dispatch_view = search
search = index=msexchange event_id=AGENTINFO sender_domain=DELETED.com | stats sum(total_bytes) as daily_bytes by sender,date_mday,date_month,date_year | eventstats avg(daily_bytes) as average stdev(daily_bytes) as sdev by sender | eval num_sdevs=(daily_bytes-average)/sdev | \
eval time=strptime(date_mday." ".date_month." ".date_year,"%d %B %Y")  | where time >= relative_time(now(),"-12h@d") AND daily_bytes >= 200000000 AND num_sdevs >= 4.0 | sort 0 - num_sdevs | eval spl_id=strftime(now(),"SPL%m%d%y_%H%M") | table spl_id sender date_mday date_month date_year daily_bytes average sdev num_sdevs
0 Karma