Fixes and restructuring for the session management code, as well as

disconnect handling in general


git-svn-id: https://kippo.googlecode.com/svn/trunk@212 951d7100-d841-11de-b865-b3884708a8e2
This commit is contained in:
desaster
2011-10-23 12:27:01 +00:00
parent f2488b4173
commit 8845b2b0eb
2 changed files with 65 additions and 55 deletions

View File

@@ -254,15 +254,12 @@ class HoneyPotProtocol(recvline.HistoricRecvLine):
self.cmdstack = [HoneyPotShell(self)] self.cmdstack = [HoneyPotShell(self)]
transport = self.terminal.transport.session.conn.transport transport = self.terminal.transport.session.conn.transport
transport.factory.sessions.append(self) # this is for the interactors transport.factory.sessions[transport.transport.sessionno] = self
# You are in a maze of twisty little passages, all alike
p = transport.transport.getPeer()
# real source IP of client
self.realClientIP = p.host
self.realClientIP = transport.transport.getPeer().host
self.clientVersion = transport.otherVersionString self.clientVersion = transport.otherVersionString
self.logintime = transport.logintime
self.ttylog_file = transport.ttylog_file
# source IP of client in user visible reports (can be fake or real) # source IP of client in user visible reports (can be fake or real)
cfg = config() cfg = config()
@@ -271,8 +268,6 @@ class HoneyPotProtocol(recvline.HistoricRecvLine):
else: else:
self.clientIP = self.realClientIP self.clientIP = self.realClientIP
self.logintime = time.time()
self.keyHandlers.update({ self.keyHandlers.update({
'\x04': self.handle_CTRL_D, '\x04': self.handle_CTRL_D,
'\x15': self.handle_CTRL_U, '\x15': self.handle_CTRL_U,
@@ -286,24 +281,15 @@ class HoneyPotProtocol(recvline.HistoricRecvLine):
except: except:
pass pass
def lastlogExit(self): # this doesn't seem to be called upon disconnect, so please use
starttime = time.strftime('%a %b %d %H:%M', # HoneyPotTransport.connectionLost instead
time.localtime(self.logintime))
endtime = time.strftime('%H:%M',
time.localtime(time.time()))
duration = utils.durationHuman(time.time() - self.logintime)
utils.addToLastlog('root\tpts/0\t%s\t%s - %s (%s)' % \
(self.clientIP, starttime, endtime, duration))
def connectionLost(self, reason): def connectionLost(self, reason):
recvline.HistoricRecvLine.connectionLost(self, reason) recvline.HistoricRecvLine.connectionLost(self, reason)
transport = self.terminal.transport.session.conn.transport
transport.factory.sessions.remove(self)
self.lastlogExit()
# not sure why i need to do this: # not sure why i need to do this:
del self.fs # scratch that, these don't seem to be necessary anymore:
del self.commands #del self.fs
#del self.commands
# Overriding to prevent terminal.reset() # Overriding to prevent terminal.reset()
def initializeScreen(self): def initializeScreen(self):
@@ -347,8 +333,9 @@ class HoneyPotProtocol(recvline.HistoricRecvLine):
self.cmdstack[-1].lineReceived(line) self.cmdstack[-1].lineReceived(line)
def keystrokeReceived(self, keyID, modifier): def keystrokeReceived(self, keyID, modifier):
transport = self.terminal.transport.session.conn.transport
if type(keyID) == type(''): if type(keyID) == type(''):
ttylog.ttylog_write(self.terminal.ttylog_file, len(keyID), ttylog.ttylog_write(transport.ttylog_file, len(keyID),
ttylog.TYPE_INPUT, time.time(), keyID) ttylog.TYPE_INPUT, time.time(), keyID)
recvline.HistoricRecvLine.keystrokeReceived(self, keyID, modifier) recvline.HistoricRecvLine.keystrokeReceived(self, keyID, modifier)
@@ -396,37 +383,40 @@ class HoneyPotProtocol(recvline.HistoricRecvLine):
self.cmdstack[-1].handle_TAB() self.cmdstack[-1].handle_TAB()
def addInteractor(self, interactor): def addInteractor(self, interactor):
self.terminal.interactors.append(interactor) transport = self.terminal.transport.session.conn.transport
transport.interactors.append(interactor)
def delInteractor(self, interactor): def delInteractor(self, interactor):
self.terminal.interactors.remove(interactor) transport = self.terminal.transport.session.conn.transport
transport.interactors.remove(interactor)
class LoggingServerProtocol(insults.ServerProtocol): class LoggingServerProtocol(insults.ServerProtocol):
def connectionMade(self): def connectionMade(self):
self.ttylog_file = '%s/tty/%s-%s.log' % \ transport = self.transport.session.conn.transport
transport.ttylog_file = '%s/tty/%s-%s.log' % \
(config().get('honeypot', 'log_path'), (config().get('honeypot', 'log_path'),
time.strftime('%Y%m%d-%H%M%S'), time.strftime('%Y%m%d-%H%M%S'),
int(random.random() * 10000)) int(random.random() * 10000))
print 'Opening TTY log: %s' % self.ttylog_file print 'Opening TTY log: %s' % transport.ttylog_file
ttylog.ttylog_open(self.ttylog_file, time.time()) ttylog.ttylog_open(transport.ttylog_file, time.time())
self.ttylog_open = True
self.interactors = [] transport.ttylog_open = True
insults.ServerProtocol.connectionMade(self) insults.ServerProtocol.connectionMade(self)
def write(self, bytes, noLog = False): def write(self, bytes, noLog = False):
for i in self.interactors: transport = self.transport.session.conn.transport
for i in transport.interactors:
i.sessionWrite(bytes) i.sessionWrite(bytes)
if self.ttylog_open and not noLog: if transport.ttylog_open and not noLog:
ttylog.ttylog_write(self.ttylog_file, len(bytes), ttylog.ttylog_write(transport.ttylog_file, len(bytes),
ttylog.TYPE_OUTPUT, time.time(), bytes) ttylog.TYPE_OUTPUT, time.time(), bytes)
insults.ServerProtocol.write(self, bytes) insults.ServerProtocol.write(self, bytes)
# this doesn't seem to be called upon disconnect, so please use
# HoneyPotTransport.connectionLost instead
def connectionLost(self, reason): def connectionLost(self, reason):
for i in self.interactors:
i.sessionClosed()
if self.ttylog_open:
ttylog.ttylog_close(self.ttylog_file, time.time())
self.ttylog_open = False
insults.ServerProtocol.connectionLost(self, reason) insults.ServerProtocol.connectionLost(self, reason)
class HoneyPotAvatar(avatar.ConchUser): class HoneyPotAvatar(avatar.ConchUser):
@@ -501,12 +491,36 @@ class HoneyPotTransport(transport.SSHServerTransport):
(self.transport.getPeer().host, self.transport.getPeer().port, (self.transport.getPeer().host, self.transport.getPeer().port,
self.transport.getHost().host, self.transport.getHost().port, self.transport.getHost().host, self.transport.getHost().port,
self.transport.sessionno) self.transport.sessionno)
self.interactors = []
self.logintime = time.time()
self.ttylog_open = False
transport.SSHServerTransport.connectionMade(self) transport.SSHServerTransport.connectionMade(self)
def ssh_KEXINIT(self, packet): def ssh_KEXINIT(self, packet):
print 'Remote SSH version: %s' % (self.otherVersionString,) print 'Remote SSH version: %s' % (self.otherVersionString,)
return transport.SSHServerTransport.ssh_KEXINIT(self, packet) return transport.SSHServerTransport.ssh_KEXINIT(self, packet)
def lastlogExit(self):
starttime = time.strftime('%a %b %d %H:%M',
time.localtime(self.logintime))
endtime = time.strftime('%H:%M',
time.localtime(time.time()))
duration = utils.durationHuman(time.time() - self.logintime)
clientIP = self.transport.getPeer().host
utils.addToLastlog('root\tpts/0\t%s\t%s - %s (%s)' % \
(clientIP, starttime, endtime, duration))
# this seems to be the only reliable place of catching lost connection
def connectionLost(self, reason):
for i in self.interactors:
i.sessionClosed()
del self.factory.sessions[self.transport.sessionno]
self.lastlogExit()
if self.ttylog_open:
ttylog.ttylog_close(self.ttylog_file, time.time())
self.ttylog_open = False
transport.SSHServerTransport.connectionLost(self, reason)
from twisted.conch.ssh.common import NS, getNS from twisted.conch.ssh.common import NS, getNS
class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer): class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
def serviceStarted(self): def serviceStarted(self):
@@ -546,8 +560,8 @@ class HoneyPotSSHFactory(factory.SSHFactory):
def __init__(self): def __init__(self):
cfg = config() cfg = config()
# protocol instances are kept here for use by the interact feature # protocol^Wwhatever instances are kept here for the interact feature
self.sessions = [] self.sessions = {}
# convert old pass.db root passwords # convert old pass.db root passwords
passdb_file = '%s/pass.db' % (cfg.get('honeypot', 'data_path'),) passdb_file = '%s/pass.db' % (cfg.get('honeypot', 'data_path'),)

View File

@@ -65,7 +65,7 @@ class Interact(telnet.Telnet):
if not self.readonly: if not self.readonly:
if type(bytes) == type(''): if type(bytes) == type(''):
ttylog.ttylog_write( ttylog.ttylog_write(
self.interacting.terminal.ttylog_file, self.interacting.ttylog_file,
len(bytes), ttylog.TYPE_INTERACT, time.time(), bytes) len(bytes), ttylog.TYPE_INTERACT, time.time(), bytes)
recvline.HistoricRecvLine.keystrokeReceived( recvline.HistoricRecvLine.keystrokeReceived(
self.interacting, bytes, None) self.interacting, bytes, None)
@@ -97,15 +97,13 @@ class Interact(telnet.Telnet):
self.transport.write('** Invalid session ID.\r\n') self.transport.write('** Invalid session ID.\r\n')
return return
for s in self.honeypotFactory.sessions: for s in self.honeypotFactory.sessions:
transport = s.terminal.transport.session.conn.transport if sessionno == s:
if sessionno == transport.transport.sessionno:
self.view(s) self.view(s)
return return
self.transport.write('** No such session found.\r\n') self.transport.write('** No such session found.\r\n')
def view(self, session): def view(self, sessionno):
transport = session.terminal.transport.session.conn.transport session = self.honeypotFactory.sessions[sessionno]
sessionno = transport.transport.sessionno
self.transport.write( self.transport.write(
'** Attaching to #%d, hit ESC to return\r\n' % sessionno) '** Attaching to #%d, hit ESC to return\r\n' % sessionno)
session.addInteractor(self) session.addInteractor(self)
@@ -114,12 +112,11 @@ class Interact(telnet.Telnet):
def cmd_list(self, args): def cmd_list(self, args):
self.transport.write('ID clientIP clientVersion\r\n') self.transport.write('ID clientIP clientVersion\r\n')
for s in self.honeypotFactory.sessions: for s in self.honeypotFactory.sessions:
transport = s.terminal.transport.session.conn.transport session = self.honeypotFactory.sessions[s]
sessionno = transport.transport.sessionno
self.transport.write('%s %s %s\r\n' % \ self.transport.write('%s %s %s\r\n' % \
(str(sessionno).ljust(4), (str(s).ljust(4),
s.realClientIP.ljust(15), session.realClientIP.ljust(15),
s.clientVersion)) session.clientVersion))
def cmd_help(self, args = ''): def cmd_help(self, args = ''):
self.transport.write('List of commands:\r\n') self.transport.write('List of commands:\r\n')
@@ -140,11 +137,10 @@ class Interact(telnet.Telnet):
self.transport.write('** Invalid session ID.\r\n') self.transport.write('** Invalid session ID.\r\n')
return return
for s in self.honeypotFactory.sessions: for s in self.honeypotFactory.sessions:
transport = s.terminal.transport.session.conn.transport if sessionno == s:
if sessionno == transport.transport.sessionno:
self.transport.write( self.transport.write(
'** Disconnecting session #%d\r\n' % sessionno) '** Disconnecting session #%d\r\n' % sessionno)
transport.loseConnection() self.honeypotFactory.sessions[s].terminal.loseConnection()
return return
self.transport.write('** No such session found.\r\n') self.transport.write('** No such session found.\r\n')