Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
User logon today and history monitor

This plug-in to monitor user registration in controlled systems. It collects data saved in alienvault-siem database from cisco-asa and ossec plugins. Controlled events are Windows logon success (both domain and local), pam unix logon, cisco remote access (AnyConnect) ip to user assined.

The plugin uses my own Python script user-logon-monitor that creates two work files /var/cache/logon-monitor/logon-history.list and /var/cache/logon-monitor/logon-<today_date>.list and also write in /var/log/user-logon-monitor.log 5 types of evants:

1 - Hello! If a user is logged the first time today and is already registered in the past 5 days

2 - Wellcome back! If a user is logged the first time today and has last recorded more than 5 but less than 20 days ago

3 - Wow... Last time I saw you NN days ago! If a user last recorded more then 20 days ago

4 - New kid in town! If a user never been regestered before

5 - Error! if a script has stoped by error when.

The corresponded plugin read this log and put messages in OSSIM.

Files in /var/cache/logon-monitor are also usefull. These files have csv format (user@domain;time) for using in Excel. History file contain records abaut last user logon, today file - about first user logon today.

In user@domain 'domain' meens 'host' for Linux or Windows local logon or keyword 'Remote' for Cisco AnyConnect, or dns domain for Windows AD logon.

Russian text in user@domain supported especialy for Russian Windows users :)

# Alienvault plugin
# Author: Eugene Sokolov at esguardian@outlook.com
# Plugin user-logon-monitor id:9006 version: 0.0.2
# Last modification: 2015-07-02 16:10
# use my user-logon-monitor.py http://gist.github.com/esguardian
#
[DEFAULT]
plugin_id=9006
[config]
type=detector
enable=yes
source=log
location=/var/log/user-logon-monitor.log
# create log file if it does not exists,
# otherwise stop processing this plugin
create_file=false
process=user-logon-monitor.py
start=yes ; launch plugin process when agent starts
stop=no ; shutdown plugin process when agent stops
restart=yes ; restart plugin process after each interval
restart_interval=300
startup=/usr/local/bin/user-logon-monitor.py
shutdown=
[user-logon-monitor]
event_type=event
regexp="=(?P<p_sid>.*?);\s(?P<mess>.*?)!\s(?P<user>.*?)\sat\s(?P<time>.*?);\ssrc\sip:\s(?P<src_ip>.*?);\sdst\sip:\s(?P<dst_ip>.*?)\s"
plugin_sid={$p_sid}
username={$user}
date={normalize_date($time)}
src_ip={$src_ip}
dst_ip={$dst_ip}
#! /usr/bin/python
# -*- coding: cp1251 -*-
# author Eugene Sokolov esguardian@outlook.com
# version 0.0.3
#
# create two work files /var/cache/logon-monitor/logon-history.list and /var/cache/logon-monitor/logon-<today_date>.list
# and also write in /var/log/user-logon-monitor.log 5 types of evants:
# 1 - Hello! If a user is logged the first time today and is already registered in the past 5 days
# 2 - Wellcome back! If a user is logged the first time today and has last recorded more than 5 but less than 20 days ago
# 3 - Wow... Last time I saw you NN days ago! If a user last recorded more then 20 days ago
# 4 - New kid in town! If a user never been regestered before
# 5 - Error! if a script has stoped by error when.
# The corresponded plugin read this log and put messages in OSSIM.
# Files in /var/cache/logon-monitor are also usefull. These files have csv format (user@domain;time)
# for using in Excel. History file contain records abaut last user logon, today file - about first user logon today.
# In user@domain 'domain' meens 'host' for Linux or Windows local logon
# or keyword 'Remote' for Cisco AnyConnect, or dns domain for Windows AD logon.
#
# Russian text in user@domain supported especialy for Russian Windows users :)
# Controlled events are Windows logon success (both domain and local), pam unix logon,
# cisco remote access (AnyConnect) ip to user assined.
#
import sys
import MySQLdb
import codecs
import subprocess
import os
# import syslog
from datetime import *
# I don'n know wich encoding used for source string but one of these three
def str_decode(str):
try:
s=codecs.decode(str, 'cp1251')
except:
try:
s=codecs.decode(str, 'utf8')
except:
s=str
return s
# Datababe connection config. Use your own data
dbuser='<db_username>'
dbpass='<db_userpassword>'
dbhost='127.0.0.1'
dbschema='alienvault_siem'
asset_dbschema='alienvault'
# --- End of Database config
# ---- Init
mytz="'+03:00'"
mycharset='cp1251'
mylogpath='/var/log/user-logon-monitor.log'
# list of tuple my domain names synonims (netbios and dns)
# first element of tuple is "canonical" name for use in
# logon and logon_history.list,
# then two variants of domain names which may be in event record in database
# must be lowercase
my_doms_list = [('mydom.com','mynetbios','mydom.com')]
today=date.today()
log_cache_fullpath='/var/cache/logon-monitor/logon-' + today.strftime('%Y-%m-%d') + '.list'
log_history_fullpath='/var/cache/logon-monitor/logon-history.list'
# read today logon hash
logon_dict={}
if os.path.isfile(log_cache_fullpath):
with codecs.open(log_cache_fullpath, 'r', encoding=mycharset) as f:
for line in f:
(user,ltime) = line.strip().split(';')
logon_dict[user] = ltime
f.close()
else:
if not os.path.exists('/var/cache/logon-monitor'):
os.makedirs('/var/cache/logon-monitor')
open(log_cache_fullpath,'a').close()
# read logon history hash
logon_history_dict={}
if os.path.isfile(log_history_fullpath):
with codecs.open(log_history_fullpath, 'r', encoding=mycharset) as f:
for line in f:
(user,ltime) = line.strip().split(';')
logon_history_dict[user] = ltime
f.close()
else:
open(log_history_fullpath,'a').close()
#
#
# set time interval for mySQL Select 8 minutes
period = 8
end_time=datetime.utcnow().strftime('%Y:%m:%d %H:%M:%S')
start_time=(datetime.utcnow() - timedelta(minutes=period)).strftime('%Y:%m:%d %H:%M:%S')
conn = MySQLdb.connect(host=dbhost, user=dbuser, passwd=dbpass, db=dbschema, charset='utf8')
cursor = conn.cursor()
when = "timestamp between '" + start_time + "' and '" + end_time + "'"
# ---- End of Init
# now start
mylog = codecs.open(mylogpath, 'a', encoding=mycharset)
# collect usernames in format username@domain (username@host) from siem database:
# ossec windows logon events, osses pam.unix logon, cisco-asa remote coonection (ip to user assign)
what = "username, case plugin_sid when 18107 then userdata6 when 5501 then substring_index(substring_index(data_payload,'HOSTNAME: ',-1),';',1) when 722051 then 'remote' end as udom, convert_tz(timestamp,'+00:00'," + mytz +") as time, inet_ntoa(conv(HEX(ip_src), 16, 10)), inet_ntoa(conv(HEX(ip_dst), 16, 10)) from acid_event join extra_data on id=extra_data.event_id"
where = "(plugin_id=7009 and (plugin_sid=18107 or plugin_sid=5501) or plugin_id=1636 and plugin_sid=722051) and not username='' and not userdata6='NT AUTHORITY' and locate('$',username)=0"
select="select " + what + " where " + where + " and " + when + " order by time"
cursor.execute(select)
row=cursor.fetchone()
try:
while row:
uname = str_decode(row[0])
uname = uname.strip().lower()
udom = str_decode(row[1])
udom = udom.strip().strip('"').lower()
syslog_message = ' at ' + str(row[2]).strip() + '; src ip: ' + str(row[3]).strip() + '; dst ip: ' + str(row[4]).strip() + '\n'
if not '@' in uname:
for i in my_doms_list:
if i[1] == udom or i[2] == udom:
udom = i[0]
break
uname = uname + '@' + udom
if uname in logon_dict:
logon_history_dict[uname] = str(row[2]).strip()
else:
logon_dict[uname] = str(row[2]).strip()
with codecs.open(log_cache_fullpath, 'a', encoding=mycharset) as out:
out.write(str_decode(uname + ';' + logon_dict[uname] + '\n'))
out.close()
if uname in logon_history_dict:
dt = datetime.strptime(logon_history_dict[uname],'%Y-%m-%d %H:%M:%S')
dd = (row[2] - dt).days
if dd <5:
mylog.write(str_decode('=1; Hello! ' + uname + syslog_message))
elif dd < 20:
mylog.write(str_decode('=2; Wellcome back! ' + uname + syslog_message))
else:
mylog.write(str_decode('=3; Wow ... Last time I saw you ' + str(dd) + ' days ago! ' + uname + syslog_message))
logon_history_dict[uname] = str(row[2]).strip()
else:
mylog.write(str_decode('=4; New kid in town! ' + uname + syslog_message))
logon_history_dict[uname] = str(row[2]).strip()
row=cursor.fetchone()
with codecs.open(log_history_fullpath, 'w', encoding=mycharset) as out:
for key in logon_history_dict.keys():
out.write(str_decode(key + ';' + logon_history_dict[key] + '\n'))
out.close()
except Exception:
mylog.write('=100;Error! no_user at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S') + '; src ip 0.0.0.0; dst ip 0.0.0.0 '+ str(sys.exc_info()[0]))
# raise
mylog.close()
conn.close()
-- user-logon-monitor
-- plugin_id: 9006
DELETE FROM plugin WHERE id = "9006";
DELETE FROM plugin_sid where plugin_id = "9006";
INSERT IGNORE INTO plugin (id, type, name, description) VALUES (9006, 1, 'user-logon-minitor', 'Logon and remote access monitor');
INSERT IGNORE INTO plugin_sid (plugin_id, sid, category_id, class_id, name, priority, reliability) VALUES (9006, 1, NULL, NULL, 'Hello!',1, 3);
INSERT IGNORE INTO plugin_sid (plugin_id, sid, category_id, class_id, name, priority, reliability) VALUES (9006, 2, NULL, NULL, 'Wellcome back!',1, 3);
INSERT IGNORE INTO plugin_sid (plugin_id, sid, category_id, class_id, name, priority, reliability) VALUES (9006, 3, NULL, NULL, 'Old friend come back!',1, 3);
INSERT IGNORE INTO plugin_sid (plugin_id, sid, category_id, class_id, name, priority, reliability) VALUES (9006, 4, NULL, NULL, 'New kid in town!',1, 3);
INSERT IGNORE INTO plugin_sid (plugin_id, sid, category_id, class_id, name, priority, reliability) VALUES (9006, 100, NULL, NULL, 'Error!',1, 3);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.