mirror of
https://github.com/aljazceru/cowrie.git
synced 2026-02-11 17:34:27 +01:00
Added a telnet based session management interface for interacting with active
sessions git-svn-id: https://kippo.googlecode.com/svn/trunk@209 951d7100-d841-11de-b865-b3884708a8e2
This commit is contained in:
@@ -108,6 +108,16 @@ private_key = private.key
|
||||
# (default: not specified)
|
||||
#banner_file =
|
||||
|
||||
# Session management interface.
|
||||
#
|
||||
# This is a telnet based service that can be used to interact with active
|
||||
# sessions. Disabled by default.
|
||||
#
|
||||
# (default: false)
|
||||
interact_enable = false
|
||||
# (default: 5123)
|
||||
interact_port = 5123
|
||||
|
||||
# MySQL logging module
|
||||
#
|
||||
# Database structure for this module is supplied in doc/sql/mysql.sql
|
||||
|
||||
@@ -46,4 +46,13 @@ for i in ssh_addr.split():
|
||||
interface=i)
|
||||
service.setServiceParent(application)
|
||||
|
||||
if cfg.has_option('honeypot', 'interact_enabled') and \
|
||||
cfg.get('honeypot', 'interact_enabled').lower() in \
|
||||
('yes', 'true', 'on'):
|
||||
iport = int(cfg.get('honeypot', 'interact_port'))
|
||||
from kippo.core import interact
|
||||
from twisted.internet import protocol
|
||||
service = internet.TCPServer(iport, interact.makeInteractFactory(factory))
|
||||
service.setServiceParent(application)
|
||||
|
||||
# vim: set ft=python sw=4 et:
|
||||
|
||||
@@ -254,6 +254,7 @@ class HoneyPotProtocol(recvline.HistoricRecvLine):
|
||||
self.cmdstack = [HoneyPotShell(self)]
|
||||
|
||||
transport = self.terminal.transport.session.conn.transport
|
||||
transport.factory.sessions.append(self) # this is for the interactors
|
||||
|
||||
# You are in a maze of twisty little passages, all alike
|
||||
p = transport.transport.getPeer()
|
||||
@@ -296,6 +297,8 @@ class HoneyPotProtocol(recvline.HistoricRecvLine):
|
||||
|
||||
def 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:
|
||||
@@ -392,6 +395,12 @@ class HoneyPotProtocol(recvline.HistoricRecvLine):
|
||||
def handle_TAB(self):
|
||||
self.cmdstack[-1].handle_TAB()
|
||||
|
||||
def addInteractor(self, interactor):
|
||||
self.terminal.interactors.append(interactor)
|
||||
|
||||
def delInteractor(self, interactor):
|
||||
self.terminal.interactors.remove(interactor)
|
||||
|
||||
class LoggingServerProtocol(insults.ServerProtocol):
|
||||
def connectionMade(self):
|
||||
self.ttylog_file = '%s/tty/%s-%s.log' % \
|
||||
@@ -401,15 +410,20 @@ class LoggingServerProtocol(insults.ServerProtocol):
|
||||
print 'Opening TTY log: %s' % self.ttylog_file
|
||||
ttylog.ttylog_open(self.ttylog_file, time.time())
|
||||
self.ttylog_open = True
|
||||
self.interactors = []
|
||||
insults.ServerProtocol.connectionMade(self)
|
||||
|
||||
def write(self, bytes, noLog = False):
|
||||
for i in self.interactors:
|
||||
i.sessionWrite(bytes)
|
||||
if self.ttylog_open and not noLog:
|
||||
ttylog.ttylog_write(self.ttylog_file, len(bytes),
|
||||
ttylog.DIR_WRITE, time.time(), bytes)
|
||||
insults.ServerProtocol.write(self, bytes)
|
||||
|
||||
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
|
||||
@@ -532,6 +546,9 @@ class HoneyPotSSHFactory(factory.SSHFactory):
|
||||
def __init__(self):
|
||||
cfg = config()
|
||||
|
||||
# protocol instances are kept here for use by the interact feature
|
||||
self.sessions = []
|
||||
|
||||
# convert old pass.db root passwords
|
||||
passdb_file = '%s/pass.db' % (cfg.get('honeypot', 'data_path'),)
|
||||
if os.path.exists(passdb_file):
|
||||
|
||||
153
kippo/core/interact.py
Normal file
153
kippo/core/interact.py
Normal file
@@ -0,0 +1,153 @@
|
||||
from twisted.internet import protocol
|
||||
from twisted.conch import telnet
|
||||
|
||||
class Interact(telnet.Telnet):
|
||||
|
||||
def connectionMade(self):
|
||||
print 'Connected'
|
||||
self.interacting = None
|
||||
self.cmdbuf = ''
|
||||
self.honeypotFactory = self.factory.honeypotFactory
|
||||
|
||||
# someone tell me if i'm doing this wrong?
|
||||
d = self.do(telnet.LINEMODE)
|
||||
self.requestNegotiation(telnet.LINEMODE, telnet.LINEMODE_EDIT + '\0')
|
||||
self.will(telnet.ECHO)
|
||||
|
||||
self.transport.write('*** kippo session management console ***\r\n')
|
||||
self.cmd_help()
|
||||
|
||||
def connectionLost(self, reason):
|
||||
print 'Connection lost'
|
||||
if self.interacting != None:
|
||||
self.interacting.delInteractor(self)
|
||||
|
||||
def enableRemote(self, option):
|
||||
print 'enableRemote', repr(option)
|
||||
return option == telnet.LINEMODE
|
||||
|
||||
def disableRemote(self, option):
|
||||
print 'disableRemote', repr(option)
|
||||
|
||||
def applicationDataReceived(self, bytes):
|
||||
# in command mode, we want to echo characters and buffer the input
|
||||
if not self.interacting:
|
||||
self.transport.write(bytes)
|
||||
if bytes == '\r':
|
||||
self.transport.write('\n')
|
||||
pieces = self.cmdbuf.split(' ', 1)
|
||||
self.cmdbuf = ''
|
||||
cmd, args = pieces[0], ''
|
||||
if len(pieces) > 1:
|
||||
args = pieces[1]
|
||||
try:
|
||||
func = getattr(self, 'cmd_' + cmd)
|
||||
except AttributeError:
|
||||
print 'Unknown command: %s' % (cmd,)
|
||||
self.transport.write('** Unknown command.\r\n')
|
||||
return
|
||||
func(args)
|
||||
else:
|
||||
self.cmdbuf += bytes
|
||||
|
||||
# in non-command mode we are passing input to the session we are
|
||||
# watching
|
||||
else:
|
||||
for c in bytes:
|
||||
if ord(c) == 27: # escape
|
||||
self.interacting.delInteractor(self)
|
||||
self.interacting = None
|
||||
self.transport.write(
|
||||
'\r\n** Interactive session closed.\r\n')
|
||||
return
|
||||
if not self.readonly:
|
||||
self.interacting.keystrokeReceived(bytes, None)
|
||||
|
||||
def sessionWrite(self, data):
|
||||
buf, prev = '', ''
|
||||
for c in data:
|
||||
if c == '\n' and prev != '\r':
|
||||
buf += '\r\n'
|
||||
else:
|
||||
buf += c
|
||||
prev = c
|
||||
self.transport.write(buf)
|
||||
|
||||
def sessionClosed(self):
|
||||
self.interacting.delInteractor(self)
|
||||
self.interacting = None
|
||||
self.transport.write('\r\n** Interactive session disconnected.\r\n')
|
||||
|
||||
def cmd_hijack(self, args):
|
||||
self.cmd_view(args)
|
||||
self.readonly = False
|
||||
|
||||
def cmd_view(self, args):
|
||||
self.readonly = True
|
||||
try:
|
||||
sessionno = int(args)
|
||||
except ValueError:
|
||||
self.transport.write('** Invalid session ID.\r\n')
|
||||
return
|
||||
for s in self.honeypotFactory.sessions:
|
||||
transport = s.terminal.transport.session.conn.transport
|
||||
if sessionno == transport.transport.sessionno:
|
||||
self.view(s)
|
||||
return
|
||||
self.transport.write('** No such session found.\r\n')
|
||||
|
||||
def view(self, session):
|
||||
transport = session.terminal.transport.session.conn.transport
|
||||
sessionno = transport.transport.sessionno
|
||||
self.transport.write(
|
||||
'** Attaching to #%d, hit ESC to return\r\n' % sessionno)
|
||||
session.addInteractor(self)
|
||||
self.interacting = session
|
||||
|
||||
def cmd_list(self, args):
|
||||
self.transport.write('ID clientIP clientVersion\r\n')
|
||||
for s in self.honeypotFactory.sessions:
|
||||
transport = s.terminal.transport.session.conn.transport
|
||||
sessionno = transport.transport.sessionno
|
||||
self.transport.write('%s %s %s\r\n' % \
|
||||
(str(sessionno).ljust(4),
|
||||
s.realClientIP.ljust(15),
|
||||
s.clientVersion))
|
||||
|
||||
def cmd_help(self, args = ''):
|
||||
self.transport.write('List of commands:\r\n')
|
||||
self.transport.write(' list - list all active sessions\r\n')
|
||||
self.transport.write(
|
||||
' view - attach to a session in read-only mode\r\n')
|
||||
self.transport.write(
|
||||
' hijack - attach to a session in interactive mode\r\n')
|
||||
self.transport.write(
|
||||
' disconnect - disconnect a session\r\n')
|
||||
self.transport.write(' help - this help\r\n')
|
||||
self.transport.write(' exit - disconnect the console\r\n')
|
||||
|
||||
def cmd_disconnect(self, args):
|
||||
try:
|
||||
sessionno = int(args)
|
||||
except ValueError:
|
||||
self.transport.write('** Invalid session ID.\r\n')
|
||||
return
|
||||
for s in self.honeypotFactory.sessions:
|
||||
transport = s.terminal.transport.session.conn.transport
|
||||
if sessionno == transport.transport.sessionno:
|
||||
self.transport.write(
|
||||
'** Disconnecting session #%d\r\n' % sessionno)
|
||||
transport.loseConnection()
|
||||
return
|
||||
self.transport.write('** No such session found.\r\n')
|
||||
|
||||
def cmd_exit(self, args = ''):
|
||||
self.transport.loseConnection()
|
||||
|
||||
def makeInteractFactory(honeypotFactory):
|
||||
ifactory = protocol.Factory()
|
||||
ifactory.protocol = Interact
|
||||
ifactory.honeypotFactory = honeypotFactory
|
||||
return ifactory
|
||||
|
||||
# vim: set sw=4 et:
|
||||
Reference in New Issue
Block a user