Groundspeed Violation/Improbable Access

Oftentimes we are required to determine impossible or improbably access events. Typically, this is a relatively simple thing to do in a modern SIEM, however Splunk, without ESS, does not have a “great” way to handle this type of temporal correlation aside from appends or joins back to the original data. I constructed the following search parameters, but feel free to modify based on any log source you’d like to validate authentication probability for.Use Case:

Use Case: A user logs in from Canada at 1300 and the same user authenticates from another country at 1305. This is typically indicative of a hijacked session, leaked credentials, etc.


index= sourcetype= (typically network)
| eventstats dc(src) as src_count by user
| search src_count>1
| sort 0 + _time
| iplocation src
| where isnotnull(lat) AND isnotnull(lon)
| streamstats window=2 earliest(lat) as prev_lat, earliest(lon) as prev_lon, earliest(_time) as prev_time, earliest(src) as prev_src, earliest(City) as prev_city, earliest(Country) as prev_country, earliest(app) as prev_app by user
| where (src != prev_src)
| eval lat1_r=((lat * 3.14159265358) / 180), lat2_r=((prev_lat * 3.14159265358) / 180), delta=(((prev_lon - lon) * 3.14159265358) / 180), distance=(3959 * acos(((sin(lat1_r) * sin(lat2_r)) + ((cos(lat1_r) * cos(lat2_r)) * cos(delta))))), distance=round(distance,2)
| fields - lat1_r, lat2_r, long1_r, long2_r, delta
| eval time_diff=if((('_time' - prev_time) == 0),1,('_time' - prev_time)), speed=round(((distance * 3600) / time_diff),2)
| where (speed > 500)
| eval prev_time=strftime(prev_time,"%Y-%m-%d %H:%M:%S")
| table user, src, _time, City, Country, app, prev_src, prev_time, prev_city, prev_country, prev_app, distance, speed

Share This:

Leave A Comment?