2015-02-19 05:48:33 +00:00
|
|
|
# Copyright (c) 2015 Michel Oosterhof <michel@oosterhof.net>
|
|
|
|
# All rights reserved.
|
|
|
|
#
|
|
|
|
# Redistribution and use in source and binary forms, with or without
|
|
|
|
# modification, are permitted provided that the following conditions
|
|
|
|
# are met:
|
|
|
|
#
|
|
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer.
|
|
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
|
|
# documentation and/or other materials provided with the distribution.
|
|
|
|
# 3. The names of the author(s) may not be used to endorse or promote
|
|
|
|
# products derived from this software without specific prior written
|
|
|
|
# permission.
|
|
|
|
#
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
# SUCH DAMAGE.
|
2015-02-18 14:23:20 +00:00
|
|
|
|
|
|
|
import abc
|
|
|
|
import datetime
|
|
|
|
import re
|
2015-02-25 19:27:15 +00:00
|
|
|
import copy
|
2015-02-18 14:23:20 +00:00
|
|
|
import socket
|
|
|
|
import uuid
|
|
|
|
|
|
|
|
# KIPP0001 : create session
|
|
|
|
# KIPP0002 : succesful login
|
|
|
|
# KIPP0003 : failed login
|
|
|
|
# KIPP0004 : TTY log opened
|
|
|
|
# KIPP0005 : handle command
|
|
|
|
# KIPP0006 : handle unknown command
|
|
|
|
# KIPP0007 : file download
|
|
|
|
# KIPP0008 : INPUT
|
|
|
|
# KIPP0009 : SSH Version
|
|
|
|
# KIPP0010 : Terminal Size
|
|
|
|
# KIPP0011 : Connection Lost
|
2015-02-25 18:17:55 +00:00
|
|
|
# KIPP0012 : TTY log closed
|
2015-02-18 14:23:20 +00:00
|
|
|
|
|
|
|
class Output(object):
|
2015-02-19 05:48:33 +00:00
|
|
|
"""
|
|
|
|
This is the abstract base class intended to be inherited by kippo output plugins
|
|
|
|
Plugins require the mandatory methods: stop, start and handleLog
|
|
|
|
"""
|
|
|
|
|
2015-02-18 14:23:20 +00:00
|
|
|
__metaclass__ = abc.ABCMeta
|
|
|
|
|
|
|
|
def __init__(self, cfg):
|
|
|
|
self.cfg = cfg
|
|
|
|
self.sessions = {}
|
|
|
|
self.re_sessionlog = re.compile(
|
|
|
|
'.*HoneyPotTransport,([0-9]+),[0-9.]+$')
|
|
|
|
if self.cfg.has_option('honeypot', 'sensor_name'):
|
|
|
|
self.sensor = self.cfg.get('honeypot', 'sensor_name')
|
|
|
|
else:
|
|
|
|
self.sensor = socket.gethostname()
|
|
|
|
|
|
|
|
self.start(cfg)
|
|
|
|
|
|
|
|
# use logDispatch when the HoneypotTransport prefix is not available.
|
|
|
|
# here you can explicitly set the sessionIds to tie the sessions together
|
2015-02-25 19:27:15 +00:00
|
|
|
#def logDispatch(self, sessionid, msg):
|
|
|
|
# if isinstance( msg, dict ):
|
|
|
|
# msg['sessionid'] = sessionid
|
|
|
|
# return self.emit( msg )
|
|
|
|
# elif isinstance( msg, str ):
|
|
|
|
# return self.emit( { 'message':msg, 'sessionid':sessionid } )
|
|
|
|
def logDispatch(self, *msg, **kw):
|
|
|
|
ev = kw
|
|
|
|
ev['message'] = msg
|
|
|
|
self.emit(ev)
|
2015-02-18 14:23:20 +00:00
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def start():
|
2015-02-25 18:17:55 +00:00
|
|
|
"""Abstract method to initialize output plugin"""
|
2015-02-18 14:23:20 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def stop():
|
2015-02-25 18:17:55 +00:00
|
|
|
"""Abstract method to shut down output plugin"""
|
2015-02-18 14:23:20 +00:00
|
|
|
pass
|
|
|
|
|
2015-03-10 09:40:18 +00:00
|
|
|
@abc.abstractmethod
|
|
|
|
def handleLog( self, session, event ):
|
|
|
|
"""Handle a general event within the output plugin"""
|
|
|
|
pass
|
|
|
|
|
2015-02-18 14:23:20 +00:00
|
|
|
# this is the main emit() hook that gets called by the the Twisted logging
|
2015-02-25 19:27:15 +00:00
|
|
|
def emit(self, event):
|
2015-02-18 14:23:20 +00:00
|
|
|
# ignore stdout and stderr in output plugins
|
2015-02-25 19:27:15 +00:00
|
|
|
if 'printed' in event:
|
2015-02-18 14:23:20 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
# ignore anything without eventid
|
2015-02-25 19:27:15 +00:00
|
|
|
if not 'eventid' in event:
|
2015-02-18 14:23:20 +00:00
|
|
|
return
|
|
|
|
|
2015-02-25 19:27:15 +00:00
|
|
|
ev = copy.copy(event)
|
|
|
|
|
2015-02-18 14:23:20 +00:00
|
|
|
# add ISO timestamp and sensor data
|
2015-02-25 19:27:15 +00:00
|
|
|
if not 'time' in ev:
|
|
|
|
ev['timestamp'] = datetime.datetime.today().isoformat() + 'Z'
|
|
|
|
else:
|
|
|
|
ev['timestamp'] = datetime.datetime.fromtimestamp(ev['time']).isoformat() + 'Z'
|
|
|
|
del ev['time']
|
2015-02-18 14:23:20 +00:00
|
|
|
|
2015-02-25 19:27:15 +00:00
|
|
|
ev['sensor'] = self.sensor
|
2015-02-18 14:23:20 +00:00
|
|
|
|
|
|
|
# disconnection is special, add the tty log
|
2015-02-25 19:27:15 +00:00
|
|
|
#if ev['eventid'] == 'KIPP0012':
|
2015-02-18 14:23:20 +00:00
|
|
|
# FIXME: file is read for each output plugin
|
2015-02-25 18:17:55 +00:00
|
|
|
#f = file(ev['ttylog'])
|
2015-02-18 14:23:20 +00:00
|
|
|
#ev['ttylog'] = f.read(10485760)
|
|
|
|
#f.close()
|
2015-02-25 19:27:15 +00:00
|
|
|
#pass
|
2015-02-18 14:23:20 +00:00
|
|
|
|
2015-02-25 19:27:15 +00:00
|
|
|
# explicit sessionno (from logDispatch) overrides from 'system'
|
|
|
|
if 'sessionno' in ev:
|
|
|
|
sessionno = ev['sessionno']
|
|
|
|
del ev['sessionno']
|
2015-02-18 14:23:20 +00:00
|
|
|
# extract session id from the twisted log prefix
|
|
|
|
elif 'system' in ev:
|
|
|
|
match = self.re_sessionlog.match(ev['system'])
|
|
|
|
if not match:
|
|
|
|
return
|
2015-02-25 19:27:15 +00:00
|
|
|
sessionno = int(match.groups()[0])
|
|
|
|
del ev['system']
|
|
|
|
|
|
|
|
# connection event is special. adds to session list
|
|
|
|
if ev['eventid'] == 'KIPP0001':
|
|
|
|
self.sessions[sessionno] = uuid.uuid4().hex
|
2015-02-18 14:23:20 +00:00
|
|
|
|
2015-02-25 19:27:15 +00:00
|
|
|
self.handleLog( self.sessions[sessionno], ev )
|
2015-02-18 14:23:20 +00:00
|
|
|
# print "error calling handleLog for event %s" % repr(ev)
|
|
|
|
|
|
|
|
# vim: set sw=4 et:
|