From d4a562a55ab25b1be68341b6485623da2c27ff5f Mon Sep 17 00:00:00 2001 From: Michel Oosterhof Date: Thu, 19 Feb 2015 12:27:30 +0000 Subject: [PATCH 1/5] they're instance variables, not class variables --- kippo/core/ssh.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kippo/core/ssh.py b/kippo/core/ssh.py index db54083..aebbfbf 100644 --- a/kippo/core/ssh.py +++ b/kippo/core/ssh.py @@ -171,14 +171,10 @@ class HoneyPotTransport(sshserver.KippoSSHServerTransport): @ivar _hadVersion: used so we only send key exchange after receive version info """ - _hadVersion = False - ttylog_open = False - interactors = [] - transportId = '' - def connectionMade(self): self.logintime = time.time() self.transportId = uuid.uuid4().hex[:8] + self.interactors = [] log.msg( 'New connection: %s:%s (%s:%s) [session: %d]' % \ (self.transport.getPeer().host, self.transport.getPeer().port, From c8824e94d81c4a5fb93ea7fe994aa5c9280674a6 Mon Sep 17 00:00:00 2001 From: Michel Oosterhof Date: Thu, 19 Feb 2015 19:47:40 +0000 Subject: [PATCH 2/5] ttylog handling is done from logtransport only now. reliably call logtransport on disconnect --- kippo/core/protocol.py | 21 ++++++++++++++------- kippo/core/ssh.py | 19 ++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/kippo/core/protocol.py b/kippo/core/protocol.py index a418257..91f1b20 100644 --- a/kippo/core/protocol.py +++ b/kippo/core/protocol.py @@ -230,17 +230,18 @@ class HoneyPotInteractiveProtocol(HoneyPotBaseProtocol, recvline.HistoricRecvLin self.lineBuffer = self.lineBuffer[self.lineBufferIndex:] self.lineBufferIndex = 0 - class LoggingServerProtocol(insults.ServerProtocol): + """ + Wrapper for ServerProtocol that implements TTY logging + """ def connectionMade(self): transport = self.transport.session.conn.transport - transport.ttylog_file = '%s/tty/%s-%s.log' % \ (config().get('honeypot', 'log_path'), time.strftime('%Y%m%d-%H%M%S'), transport.transportId ) log.msg( 'Opening TTY log: %s' % transport.ttylog_file ) ttylog.ttylog_open(transport.ttylog_file, time.time()) - transport.ttylog_open = True + self.ttylog_open = True transport.stdinlog_file = '%s/%s-%s-stdin.log' % \ (config().get('honeypot', 'download_path'), @@ -253,14 +254,14 @@ class LoggingServerProtocol(insults.ServerProtocol): transport = self.transport.session.conn.transport for i in transport.interactors: i.sessionWrite(bytes) - if transport.ttylog_open and not noLog: + if self.ttylog_open and not noLog: ttylog.ttylog_write(transport.ttylog_file, len(bytes), ttylog.TYPE_OUTPUT, time.time(), bytes) insults.ServerProtocol.write(self, bytes) def dataReceived(self, data, noLog = False): transport = self.transport.session.conn.transport - if transport.ttylog_open and not noLog: + if self.ttylog_open and not noLog: ttylog.ttylog_write(transport.ttylog_file, len(data), ttylog.TYPE_INPUT, time.time(), data) if transport.stdinlog_open and not noLog: @@ -269,9 +270,15 @@ class LoggingServerProtocol(insults.ServerProtocol): f.close insults.ServerProtocol.dataReceived(self, data) - # this doesn't seem to be called upon disconnect, so please use - # HoneyPotTransport.connectionLost instead + # FIXME: this method is called 4 times on logout.... + # it's called once from Avatar.closed() if disconnected def connectionLost(self, reason): + # log.msg( "received call to LSP.connectionLost" ) + transport = self.transport.session.conn.transport + if self.ttylog_open: + log.msg( 'Closing TTY log: %s' % transport.ttylog_file ) + ttylog.ttylog_close(transport.ttylog_file, time.time()) + self.ttylog_open = False insults.ServerProtocol.connectionLost(self, reason) # vim: set sw=4 et: diff --git a/kippo/core/ssh.py b/kippo/core/ssh.py index aebbfbf..45cd64c 100644 --- a/kippo/core/ssh.py +++ b/kippo/core/ssh.py @@ -21,7 +21,6 @@ from twisted.conch.ssh.common import NS, getNS import ConfigParser -import ttylog import utils import fs import sshserver @@ -164,8 +163,6 @@ class HoneyPotTransport(sshserver.KippoSSHServerTransport): @ivar interactors: interactors - @ivar ttylog_open: whether log is open - @ivar transportId: UUID of this transport @ivar _hadVersion: used so we only send key exchange after receive version info @@ -227,9 +224,6 @@ class HoneyPotTransport(sshserver.KippoSSHServerTransport): if self.transport.sessionno in self.factory.sessions: 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 sshserver.KippoSSHServerTransport.connectionLost(self, reason) class HoneyPotSSHSession(session.SSHSession): @@ -254,6 +248,10 @@ class HoneyPotSSHSession(session.SSHSession): log.msg('request_x11: %s' % repr(data) ) return 0 + # this is reliably called on session close/disconnect and calls the avatar + def closed(self): + session.SSHSession.closed(self) + def loseConnection(self): self.conn.sendRequest(self, 'exit-status', "\x00"*4) session.SSHSession.loseConnection(self) @@ -268,6 +266,7 @@ class HoneyPotAvatar(avatar.ConchUser): self.env = env self.fs = fs.HoneyPotFilesystem(copy.deepcopy(self.env.fs)) self.hostname = self.env.cfg.get('honeypot', 'hostname') + self.protocol = None self.channelLookup.update({'session': HoneyPotSSHSession}) self.channelLookup['direct-tcpip'] = KippoOpenConnectForwardingClient @@ -288,6 +287,8 @@ class HoneyPotAvatar(avatar.ConchUser): protocol.HoneyPotInteractiveProtocol, self, self.env) serverProtocol.makeConnection(proto) proto.makeConnection(session.wrapProtocol(serverProtocol)) + #self.protocol = serverProtocol + self.protocol = proto def getPty(self, terminal, windowSize, attrs): log.msg( 'Terminal size: %s %s' % windowSize[0:2] ) @@ -309,9 +310,13 @@ class HoneyPotAvatar(avatar.ConchUser): protocol.HoneyPotExecProtocol, self, self.env, cmd) serverProtocol.makeConnection(proto) proto.makeConnection(session.wrapProtocol(serverProtocol)) + self.protocol = serverProtocol + # this is reliably called on both logout and disconnect + # we notify the protocol here we lost the connection def closed(self): - pass + if self.protocol: + self.protocol.connectionLost("disconnected") def eofReceived(self): pass From 62697b967c25dfc96374cb00d8545cf9ca9b7cfb Mon Sep 17 00:00:00 2001 From: Michel Oosterhof Date: Thu, 19 Feb 2015 20:01:04 +0000 Subject: [PATCH 3/5] remove the screen clear/reset on logout --- kippo/core/protocol.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kippo/core/protocol.py b/kippo/core/protocol.py index 91f1b20..65d0d84 100644 --- a/kippo/core/protocol.py +++ b/kippo/core/protocol.py @@ -270,6 +270,10 @@ class LoggingServerProtocol(insults.ServerProtocol): f.close insults.ServerProtocol.dataReceived(self, data) + # override super to remove the terminal reset on logout + def loseConnection(self): + self.transport.loseConnection() + # FIXME: this method is called 4 times on logout.... # it's called once from Avatar.closed() if disconnected def connectionLost(self, reason): From e4cd5442aed88867c6c28a030ad40aef85a13826 Mon Sep 17 00:00:00 2001 From: Michel Oosterhof Date: Thu, 19 Feb 2015 20:03:44 +0000 Subject: [PATCH 4/5] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05683b1..9a6f445 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ +* 2015-02-20 Removed screen clear/reset on logout * 2015-02-19 Configuration directives have changed! ssh_addr has become listen_addr and ssh_port has become listen_port. The old keywords are still accepted for backwards compatibility * default behaviour is changed to disable the exit jail From a7f189eed1ca55d787dd96e17d2078892424f9a6 Mon Sep 17 00:00:00 2001 From: Michel Oosterhof Date: Thu, 19 Feb 2015 20:21:55 +0000 Subject: [PATCH 5/5] stdin log updates now give log message when writing and simplify variable storage --- kippo/core/protocol.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/kippo/core/protocol.py b/kippo/core/protocol.py index 65d0d84..e85b2d4 100644 --- a/kippo/core/protocol.py +++ b/kippo/core/protocol.py @@ -145,7 +145,7 @@ class HoneyPotExecProtocol(HoneyPotBaseProtocol): def connectionMade(self): HoneyPotBaseProtocol.connectionMade(self) - self.terminal.transport.session.conn.transport.stdinlog_open = True + self.terminal.stdinlog_open = True self.cmdstack = [honeypot.HoneyPotShell(self, interactive=False)] self.cmdstack[0].lineReceived(self.execcmd) @@ -243,10 +243,10 @@ class LoggingServerProtocol(insults.ServerProtocol): ttylog.ttylog_open(transport.ttylog_file, time.time()) self.ttylog_open = True - transport.stdinlog_file = '%s/%s-%s-stdin.log' % \ + self.stdinlog_file = '%s/%s-%s-stdin.log' % \ (config().get('honeypot', 'download_path'), time.strftime('%Y%m%d-%H%M%S'), transport.transportId ) - transport.stdinlog_open = False + self.stdinlog_open = False insults.ServerProtocol.connectionMade(self) @@ -264,8 +264,9 @@ class LoggingServerProtocol(insults.ServerProtocol): if self.ttylog_open and not noLog: ttylog.ttylog_write(transport.ttylog_file, len(data), ttylog.TYPE_INPUT, time.time(), data) - if transport.stdinlog_open and not noLog: - f = file( transport.stdinlog_file, 'ab' ) + if self.stdinlog_open and not noLog: + log.msg( "Saving stdin log: %s" % self.stdinlog_file ) + f = file( self.stdinlog_file, 'ab' ) f.write(data) f.close insults.ServerProtocol.dataReceived(self, data)