From f1381d2e96c1bd9711e284a5439dd723164990fe Mon Sep 17 00:00:00 2001 From: desaster Date: Wed, 16 Jun 2010 14:51:26 +0000 Subject: [PATCH] Logging improvements: * redo the logger in a way that allows the host ip from the connection to be saved to the db * ignore mysql errors (such as connectivity problems) git-svn-id: https://kippo.googlecode.com/svn/trunk@123 951d7100-d841-11de-b865-b3884708a8e2 --- kippo/core/dblog.py | 47 +++++++++++++++++++++--------------------- kippo/core/honeypot.py | 12 ++++++++++- kippo/dblog/mysql.py | 41 +++++++++++++++++++++--------------- 3 files changed, 59 insertions(+), 41 deletions(-) diff --git a/kippo/core/dblog.py b/kippo/core/dblog.py index 706b484..32b0347 100644 --- a/kippo/core/dblog.py +++ b/kippo/core/dblog.py @@ -5,9 +5,13 @@ import re, time, datetime, socket class DBLogger(object): def __init__(self, cfg): + self.cfg = cfg self.sessions = {} self.ttylogs = {} - self.re_unique = re.compile('.*(SSHServerTransport,[0-9]+,[0-9.]+)$') + self.re_connected = re.compile( + '^New connection: ([0-9.]+):([0-9]+) \(([0-9.]+):([0-9]+)\) ' + \ + '\[session: ([0-9]+)\]$') + self.re_sessionlog = re.compile('.*HoneyPotTransport,([0-9]+),[0-9.]+$') self.re_map = [(re.compile(x[0]), x[1]) for x in ( ('^connection lost$', self._connectionLost), @@ -24,45 +28,42 @@ class DBLogger(object): ('^INPUT \((?P[a-zA-Z0-9]+)\): (?P.*)$', self.handleInput), )] - - if cfg.has_option('honeypot', 'sensor_name'): - self.sensor = cfg.get('honeypot', 'sensor_name') - else: - self.sensor = socket.gethostbyaddr(socket.gethostname())[2][0] - self.start(cfg) def start(): pass + def getSensor(self): + if self.cfg.has_option('honeypot', 'sensor_name'): + return self.cfg.get('honeypot', 'sensor_name') + return None + def nowUnix(self): """return the current UTC time as an UNIX timestamp""" return int(time.mktime(datetime.datetime.utcnow().utctimetuple())) - def uniqstr(self, system): - matches = self.re_unique.match(system) - return matches.groups()[0] - def emit(self, ev): - if ev['system'] == '-' or not len(ev['message']): + if not len(ev['message']): return - match = self.re_unique.match(ev['system']) + match = self.re_connected.match(ev['message'][0]) + if match: + sessionid = int(match.groups()[4]) + self.sessions[sessionid] = \ + self.createSession( + match.groups()[0], int(match.groups()[1]), + match.groups()[2], int(match.groups()[3])) + return + match = self.re_sessionlog.match(ev['system']) if not match: return - uniqstr = match.groups()[0] - if uniqstr not in self.sessions.keys(): - ip = uniqstr.split(',')[2] - session = self.createSession(ip) - self.sessions[uniqstr] = session - else: - session = self.sessions[uniqstr] - if session is None: + sessionid = int(match.groups()[0]) + if sessionid not in self.sessions.keys(): return message = ev['message'][0] for regex, func in self.re_map: match = regex.match(message) if match: - func(session, match.groupdict()) + func(self.sessions[sessionid], match.groupdict()) break def _connectionLost(self, session, args): @@ -81,7 +82,7 @@ class DBLogger(object): return ttylog # We have to return an unique ID - def createSession(self, ip): + def createSession(self, peerIP, peerPort, hostIP, hostPort): return 0 # args has: logfile diff --git a/kippo/core/honeypot.py b/kippo/core/honeypot.py index 2f1b4ea..95fae04 100644 --- a/kippo/core/honeypot.py +++ b/kippo/core/honeypot.py @@ -332,6 +332,15 @@ class HoneyPotRealm: else: raise Exception, "No supported interfaces found." +class HoneyPotTransport(transport.SSHServerTransport): + + def connectionMade(self): + print 'New connection: %s:%s (%s:%s) [session: %d]' % \ + (self.transport.getPeer().host, self.transport.getPeer().port, + self.transport.getHost().host, self.transport.getHost().port, + self.transport.sessionno) + transport.SSHServerTransport.connectionMade(self) + # As implemented by Kojoney class HoneyPotSSHFactory(factory.SSHFactory): #publicKeys = {'ssh-rsa': keys.getPublicKeyString(data=publicKey)} @@ -352,7 +361,8 @@ class HoneyPotSSHFactory(factory.SSHFactory): def buildProtocol(self, addr): # FIXME: try to mimic something real 100% - t = transport.SSHServerTransport() + t = HoneyPotTransport() + t.ourVersionString = 'SSH-2.0-OpenSSH_5.1p1 Debian-5' t.supportedPublicKeys = self.privateKeys.keys() if not self.primes: diff --git a/kippo/dblog/mysql.py b/kippo/dblog/mysql.py index f7c9a76..4b71f54 100644 --- a/kippo/dblog/mysql.py +++ b/kippo/dblog/mysql.py @@ -10,20 +10,32 @@ class DBLogger(dblog.DBLogger): passwd = cfg.get('database', 'password'), reconnect = True) - def createSession(self, ip): + def query(self, sql, params = None): + cursor = self.db.cursor() + try: + if params is None: + cursor.execute(sql) + else: + cursor.execute(sql, params) + return cursor + except MySQLdb.MySQLError: + return None + + def createSession(self, peerIP, peerPort, hostIP, hostPort): sql = 'INSERT INTO `session` (`starttime`, `sensor`, `ip`)' + \ ' VALUES (FROM_UNIXTIME(%s), %s, %s)' - params = (self.nowUnix(), self.sensor, ip) - cursor = self.db.cursor() - cursor.execute(sql, params) - return int(cursor.lastrowid) + params = (self.nowUnix(), self.getSensor() or hostIP, peerIP) + cursor = self.query(sql, params) + if cursor is not None: + return int(cursor.lastrowid) + else: + return None def handleConnectionLost(self, session, args): sql = 'UPDATE `session` SET `endtime` = FROM_UNIXTIME(%s)' + \ ', `ttylog` = %s WHERE `id` = %s' params = (self.nowUnix(), self.ttylog(session), session) - cursor = self.db.cursor() - cursor.execute(sql, params) + self.query(sql, params) def handleLoginFailed(self, session, args): sql = 'INSERT INTO `auth` (`session`, `success`' + \ @@ -31,8 +43,7 @@ class DBLogger(dblog.DBLogger): ' VALUES (%s, %s, %s, %s, FROM_UNIXTIME(%s))' params = (session, 0, args['username'], args['password'], self.nowUnix()) - cursor = self.db.cursor() - cursor.execute(sql, params) + self.query(sql, params) def handleLoginSucceeded(self, session, args): sql = 'INSERT INTO `auth` (`session`, `success`' + \ @@ -40,31 +51,27 @@ class DBLogger(dblog.DBLogger): ' VALUES (%s, %s, %s, %s, FROM_UNIXTIME(%s))' params = (session, 1, args['username'], args['password'], self.nowUnix()) - cursor = self.db.cursor() - cursor.execute(sql, params) + self.query(sql, params) def handleCommand(self, session, args): sql = 'INSERT INTO `input`' + \ ' (`session`, `timestamp`, `success`, `input`)' + \ ' VALUES (%s, FROM_UNIXTIME(%s), %s, %s)' params = (session, self.nowUnix(), 1, args['input']) - cursor = self.db.cursor() - cursor.execute(sql, params) + self.query(sql, params) def handleUnknownCommand(self, session, args): sql = 'INSERT INTO `input`' + \ ' (`session`, `timestamp`, `success`, `input`)' + \ ' VALUES (%s, FROM_UNIXTIME(%s), %s, %s)' params = (session, self.nowUnix(), 0, args['input']) - cursor = self.db.cursor() - cursor.execute(sql, params) + self.query(sql, params) def handleInput(self, session, args): sql = 'INSERT INTO `input`' + \ ' (`session`, `timestamp`, `realm`, `input`)' + \ ' VALUES (%s, FROM_UNIXTIME(%s), %s, %s)' params = (session, self.nowUnix(), args['realm'], args['input']) - cursor = self.db.cursor() - cursor.execute(sql, params) + self.query(sql, params) # vim: set sw=4 et: