mirror of https://github.com/cowrie/cowrie.git
Basic Telnet support implemented
A squash merge of GoSecure/cowrie telnet-poc branch: https://github.com/GoSecure/cowrie/tree/telnet-poc Rebased on current upstream master. August 2016 update: Resolved several conflicts when rebasing
This commit is contained in:
parent
bae58890f5
commit
640652207d
|
@ -1,6 +1,6 @@
|
|||
# Cowrie
|
||||
|
||||
Cowrie is a medium interaction SSH honeypot designed to log brute force attacks and the shell interaction performed by the attacker.
|
||||
Cowrie is a medium interaction SSH and Telnet honeypot designed to log brute force attacks and the shell interaction performed by the attacker.
|
||||
|
||||
[Cowrie](http://github.com/micheloosterhof/cowrie/) is developed by Michel Oosterhof and is based on [Kippo](http://github.com/desaster/kippo/) by Upi Tamminen (desaster).
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
# (default: not specified)
|
||||
#sensor_name=myhostname
|
||||
|
||||
|
||||
# Hostname for the honeypot. Displayed by the shell prompt of the virtual
|
||||
# environment
|
||||
#
|
||||
|
@ -174,15 +173,15 @@ auth_class = UserDB
|
|||
# IP addresses to listen for incoming SSH connections.
|
||||
#
|
||||
# (default: 0.0.0.0) = any IPv4 address
|
||||
#listen_addr = 0.0.0.0
|
||||
#listen_ssh_addr = 0.0.0.0
|
||||
# (use :: for listen to all IPv6 and IPv4 addresses)
|
||||
#listen_addr = ::
|
||||
#listen_ssh_addr = ::
|
||||
|
||||
|
||||
# Port to listen for incoming SSH connections.
|
||||
#
|
||||
# (default: 2222)
|
||||
#listen_port = 2222
|
||||
#listen_ssh_port = 2222
|
||||
|
||||
|
||||
# SSH Version String
|
||||
|
@ -245,6 +244,28 @@ forward_redirect_443 = 127.0.0.1:8443
|
|||
forward_redirect_25 = 127.0.0.1:12525
|
||||
forward_redirect_587 = 127.0.0.1:12525
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Telnet Specific Options
|
||||
# ============================================================================
|
||||
|
||||
# IP addresses to listen for incoming Telnet connections.
|
||||
#
|
||||
# (default: 0.0.0.0) = any IPv4 address
|
||||
#listen_telnet_addr = 0.0.0.0
|
||||
# (use :: for listen to all IPv6 and IPv4 addresses)
|
||||
#listen_telnet_addr = ::
|
||||
|
||||
|
||||
# Port to listen for incoming Telnet connections.
|
||||
#
|
||||
# (default: 2223)
|
||||
#listen_telnet_port = 2223
|
||||
|
||||
# Source Port to report in logs (useful if you use iptables to forward ports to Cowrie)
|
||||
#reported_telnet_port = 23
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Database logging Specific Options
|
||||
# ============================================================================
|
||||
|
|
|
@ -19,9 +19,11 @@ class DBLogger(object):
|
|||
self.cfg = cfg
|
||||
self.sessions = {}
|
||||
self.ttylogs = {}
|
||||
# FIXME figure out what needs to be done here regarding
|
||||
# HoneyPotTransport renamed to HoneyPotSSHTransport
|
||||
#:* Handles ipv6
|
||||
self.re_sessionlog = re.compile(
|
||||
r'.*HoneyPotTransport,([0-9]+),[:a-f0-9.]+$')
|
||||
r'.*HoneyPotSSHTransport,([0-9]+),[:a-f0-9.]+$')
|
||||
|
||||
# cowrie.session.connect is special since it kicks off new logging session,
|
||||
# and is not handled here
|
||||
|
|
|
@ -67,8 +67,10 @@ class Output(object):
|
|||
self.cfg = cfg
|
||||
self.sessions = {}
|
||||
self.ips = {}
|
||||
# FIXME figure out what needs to be done here regarding
|
||||
# HoneyPotTransport renamed to HoneyPotSSHTransport
|
||||
self.re_sessionlog = re.compile(
|
||||
'.*HoneyPotTransport,([0-9]+),[0-9a-f:.]+$')
|
||||
'.*HoneyPotSSHTransport,([0-9]+),[0-9a-f:.]+$')
|
||||
try:
|
||||
self.sensor = self.cfg.get('honeypot', 'sensor_name')
|
||||
except:
|
||||
|
|
|
@ -53,24 +53,32 @@ class HoneyPotBaseProtocol(insults.TerminalProtocol, TimeoutMixin):
|
|||
self.password_input = False
|
||||
self.cmdstack = []
|
||||
|
||||
def getProtoTransport(self):
|
||||
"""
|
||||
Due to protocol nesting differences, we need provide how we grab
|
||||
the proper transport to access underlying SSH information. Meant to be
|
||||
overridden for other protocols.
|
||||
"""
|
||||
return self.terminal.transport.session.conn.transport
|
||||
|
||||
|
||||
def logDispatch(self, *msg, **args):
|
||||
"""
|
||||
Send log directly to factory, avoiding normal log dispatch
|
||||
"""
|
||||
transport = self.terminal.transport.session.conn.transport
|
||||
args['sessionno'] = transport.transport.sessionno
|
||||
transport.factory.logDispatch(*msg, **args)
|
||||
pt = self.getProtoTransport()
|
||||
args['sessionno'] = pt.transport.sessionno
|
||||
pt.factory.logDispatch(*msg, **args)
|
||||
|
||||
|
||||
def connectionMade(self):
|
||||
"""
|
||||
"""
|
||||
transport = self.terminal.transport.session.conn.transport
|
||||
pt = self.getProtoTransport()
|
||||
|
||||
self.realClientIP = transport.transport.getPeer().host
|
||||
self.realClientPort = transport.transport.getPeer().port
|
||||
self.clientVersion = transport.otherVersionString
|
||||
self.realClientIP = pt.transport.getPeer().host
|
||||
self.realClientPort = pt.transport.getPeer().port
|
||||
self.clientVersion = self.getClientVersion()
|
||||
self.logintime = time.time()
|
||||
self.setTimeout(1800)
|
||||
|
||||
|
@ -189,10 +197,15 @@ class HoneyPotBaseProtocol(insults.TerminalProtocol, TimeoutMixin):
|
|||
"""
|
||||
Uptime
|
||||
"""
|
||||
transport = self.terminal.transport.session.conn.transport
|
||||
r = time.time() - transport.factory.starttime
|
||||
pt = self.getProtoTransport()
|
||||
r = time.time() - pt.factory.starttime
|
||||
if reset:
|
||||
pt.factory.starttime = reset
|
||||
return r
|
||||
|
||||
def getClientVersion(self):
|
||||
pt = self.getProtoTransport()
|
||||
return pt.otherVersionString
|
||||
|
||||
|
||||
class HoneyPotExecProtocol(HoneyPotBaseProtocol):
|
||||
|
@ -235,8 +248,8 @@ class HoneyPotInteractiveProtocol(HoneyPotBaseProtocol, recvline.HistoricRecvLin
|
|||
|
||||
self.cmdstack = [honeypot.HoneyPotShell(self)]
|
||||
|
||||
transport = self.terminal.transport.session.conn.transport
|
||||
transport.factory.sessions[transport.transport.sessionno] = self
|
||||
pt = self.getProtoTransport()
|
||||
pt.factory.sessions[pt.transport.sessionno] = self
|
||||
|
||||
self.keyHandlers.update({
|
||||
'\x01': self.handle_HOME, # CTRL-A
|
||||
|
@ -292,9 +305,9 @@ class HoneyPotInteractiveProtocol(HoneyPotBaseProtocol, recvline.HistoricRecvLin
|
|||
def connectionLost(self, reason):
|
||||
"""
|
||||
"""
|
||||
transport = self.terminal.transport.session.conn.transport
|
||||
if transport.transport.sessionno in transport.factory.sessions:
|
||||
del transport.factory.sessions[transport.transport.sessionno]
|
||||
pt = self.getProtoTransport()
|
||||
if pt.transport.sessionno in pt.factory.sessions:
|
||||
del pt.factory.sessions[pt.transport.sessionno]
|
||||
|
||||
self.lastlogExit()
|
||||
HoneyPotBaseProtocol.connectionLost(self, reason)
|
||||
|
@ -396,3 +409,23 @@ class HoneyPotInteractiveProtocol(HoneyPotBaseProtocol, recvline.HistoricRecvLin
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class HoneyPotInteractiveTelnetProtocol(HoneyPotInteractiveProtocol):
|
||||
"""
|
||||
Specialized HoneyPotInteractiveProtocol that provides Telnet specific
|
||||
overrides.
|
||||
"""
|
||||
|
||||
def __init__(self, avatar):
|
||||
recvline.HistoricRecvLine.__init__(self)
|
||||
HoneyPotInteractiveProtocol.__init__(self, avatar)
|
||||
|
||||
def getProtoTransport(self):
|
||||
"""
|
||||
Due to protocol nesting differences, we need to override how we grab
|
||||
the proper transport to access underlying Telnet information.
|
||||
"""
|
||||
return self.terminal.transport.session.transport
|
||||
|
||||
def getClientVersion(self):
|
||||
return 'Telnet'
|
||||
|
|
|
@ -38,12 +38,14 @@ import pickle
|
|||
|
||||
import twisted
|
||||
from twisted.conch import interfaces as conchinterfaces
|
||||
from twisted.conch.telnet import ITelnetProtocol
|
||||
from twisted.python import log
|
||||
|
||||
from cowrie.core import protocol
|
||||
from cowrie.core import server
|
||||
from cowrie.core import avatar
|
||||
from cowrie.core import fs
|
||||
from cowrie.telnet import session
|
||||
|
||||
|
||||
@implementer(twisted.cred.portal.IRealm)
|
||||
|
@ -78,6 +80,11 @@ class HoneyPotRealm(object):
|
|||
serv = server.CowrieServer(self)
|
||||
user = avatar.CowrieUser(avatarId, serv)
|
||||
return interfaces[0], user, user.logout
|
||||
else:
|
||||
raise Exception("No supported interfaces found.")
|
||||
elif ITelnetProtocol in interfaces:
|
||||
cs = server.CowrieServer(self)
|
||||
av = session.HoneyPotTelnetSession(avatarId, cs)
|
||||
return interfaces[0], av, lambda:None
|
||||
|
||||
log.msg('No supported interfaces found.')
|
||||
# TODO: this exception doesn't raise for a reason I don't understand
|
||||
raise NotImplementedError("No supported interfaces found.")
|
||||
|
|
|
@ -41,12 +41,15 @@ class LoggingServerProtocol(insults.ServerProtocol):
|
|||
else:
|
||||
self.type = 'i' # Interactive
|
||||
|
||||
def getSessionId(self):
|
||||
transportId = self.transport.session.conn.transport.transportId
|
||||
channelId = self.transport.session.id
|
||||
return (transportId, channelId)
|
||||
|
||||
def connectionMade(self):
|
||||
"""
|
||||
"""
|
||||
transportId = self.transport.session.conn.transport.transportId
|
||||
channelId = self.transport.session.id
|
||||
transportId, channelId = self.getSessionId()
|
||||
|
||||
self.startTime = time.time()
|
||||
self.ttylogFile = '%s/tty/%s-%s-%s%s.log' % \
|
||||
|
@ -176,3 +179,12 @@ class LoggingServerProtocol(insults.ServerProtocol):
|
|||
|
||||
insults.ServerProtocol.connectionLost(self, reason)
|
||||
|
||||
class LoggingTelnetServerProtocol(LoggingServerProtocol):
|
||||
"""
|
||||
Wrap LoggingServerProtocol with single method to fetch session id for Telnet
|
||||
"""
|
||||
|
||||
def getSessionId(self):
|
||||
transportId = self.transport.session.transportId
|
||||
sn = self.transport.session.transport.transport.sessionno
|
||||
return (transportId, sn)
|
||||
|
|
|
@ -26,7 +26,7 @@ from cowrie.core import keys as cowriekeys
|
|||
|
||||
class HoneyPotSSHFactory(factory.SSHFactory):
|
||||
"""
|
||||
This factory creates HoneyPotTransport instances
|
||||
This factory creates HoneyPotSSHTransport instances
|
||||
They listen directly to the TCP port
|
||||
"""
|
||||
|
||||
|
@ -119,13 +119,13 @@ class HoneyPotSSHFactory(factory.SSHFactory):
|
|||
@type addr: L{twisted.internet.interfaces.IAddress} provider
|
||||
@param addr: The address at which the server will listen.
|
||||
|
||||
@rtype: L{cowrie.core.HoneyPotTransport}
|
||||
@rtype: L{cowrie.ssh.transport.HoneyPotSSHTransport}
|
||||
@return: The built transport.
|
||||
"""
|
||||
|
||||
_modulis = '/etc/ssh/moduli', '/private/etc/moduli'
|
||||
|
||||
t = HoneyPotTransport()
|
||||
t = HoneyPotSSHTransport()
|
||||
|
||||
try:
|
||||
t.ourVersionString = self.cfg.get('honeypot', 'ssh_version_string')
|
||||
|
@ -164,7 +164,7 @@ class HoneyPotSSHFactory(factory.SSHFactory):
|
|||
|
||||
|
||||
|
||||
class HoneyPotTransport(transport.SSHServerTransport, TimeoutMixin):
|
||||
class HoneyPotSSHTransport(transport.SSHServerTransport, TimeoutMixin):
|
||||
"""
|
||||
"""
|
||||
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
# Copyright (C) 2015, 2016 GoSecure Inc.
|
||||
"""
|
||||
Telnet User Session management for the Honeypot
|
||||
|
||||
@author: Olivier Bilodeau <obilodeau@gosecure.ca>
|
||||
"""
|
||||
|
||||
from zope.interface import implementer
|
||||
|
||||
from twisted.internet import interfaces, protocol
|
||||
from twisted.python import log
|
||||
from twisted.conch.ssh import session
|
||||
from twisted.conch.telnet import StatefulTelnetProtocol, TelnetBootstrapProtocol
|
||||
|
||||
from cowrie.core import pwd
|
||||
from cowrie.core import protocol as cproto
|
||||
from cowrie.insults import insults
|
||||
|
||||
class HoneyPotTelnetSession(TelnetBootstrapProtocol):
|
||||
|
||||
def __init__(self, username, server):
|
||||
self.username = username
|
||||
self.server = server
|
||||
self.cfg = self.server.cfg
|
||||
|
||||
try:
|
||||
pwentry = pwd.Passwd(self.cfg).getpwnam(self.username)
|
||||
self.uid = pwentry["pw_uid"]
|
||||
self.gid = pwentry["pw_gid"]
|
||||
self.home = pwentry["pw_dir"]
|
||||
except:
|
||||
self.uid = 1001
|
||||
self.gid = 1001
|
||||
self.home = '/home'
|
||||
|
||||
self.environ = {
|
||||
'LOGNAME': self.username,
|
||||
'USER': self.username,
|
||||
'HOME': self.home,
|
||||
'TMOUT': '1800'}
|
||||
|
||||
if self.uid==0:
|
||||
self.environ['PATH']='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
|
||||
else:
|
||||
self.environ['PATH']='/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games'
|
||||
|
||||
# required because HoneyPotBaseProtocol relies on avatar.avatar.home
|
||||
self.avatar = self
|
||||
|
||||
# to be populated by HoneyPotTelnetAuthTransport after auth
|
||||
self.transportId = None
|
||||
|
||||
def connectionMade(self):
|
||||
processprotocol = TelnetSessionProcessProtocol(self)
|
||||
|
||||
self.protocol = insults.LoggingTelnetServerProtocol(
|
||||
cproto.HoneyPotInteractiveTelnetProtocol, self)
|
||||
self.protocol.makeConnection(processprotocol)
|
||||
processprotocol.makeConnection(session.wrapProtocol(self.protocol))
|
||||
|
||||
# TODO do I need to implement connectionLost?
|
||||
# XXX verify if HoneyPotTelnetAuthTransport's connectionLost fires otherwise
|
||||
# we'll have to reimplement some of the stuff here
|
||||
#def connectionLost(self, reason):
|
||||
# pt = self.transport
|
||||
# if pt.transport.sessionno in pt.factory.sessions:
|
||||
# del pt.factory.sessions[pt.transport.sessionno]
|
||||
# pt.connectionLost(reason)
|
||||
|
||||
# def lineReceived(self, line):
|
||||
# self.transport.write("I received %r from you\r\n" % (line,))
|
||||
|
||||
|
||||
def logout(self):
|
||||
"""
|
||||
"""
|
||||
log.msg('avatar {} logging out'.format(self.username))
|
||||
|
||||
# Taken and adapted from
|
||||
# https://github.com/twisted/twisted/blob/26ad16ab41db5f0f6d2526a891e81bbd3e260247/twisted/conch/ssh/session.py#L186
|
||||
@implementer(interfaces.ITransport)
|
||||
class TelnetSessionProcessProtocol(protocol.ProcessProtocol):
|
||||
"""I am both an L{IProcessProtocol} and an L{ITransport}.
|
||||
I am a transport to the remote endpoint and a process protocol to the
|
||||
local subsystem.
|
||||
"""
|
||||
|
||||
def __init__(self, sess):
|
||||
self.session = sess
|
||||
self.lostOutOrErrFlag = False
|
||||
|
||||
# FIXME probably no such thing such as buffering in Telnet protocol
|
||||
#def connectionMade(self):
|
||||
# if self.session.buf:
|
||||
# self.session.write(self.session.buf)
|
||||
# self.session.buf = None
|
||||
|
||||
def outReceived(self, data):
|
||||
self.session.write(data)
|
||||
|
||||
def errReceived(self, err):
|
||||
self.session.writeExtended(connection.EXTENDED_DATA_STDERR, err)
|
||||
|
||||
def outConnectionLost(self):
|
||||
"""
|
||||
EOF should only be sent when both STDOUT and STDERR have been closed.
|
||||
"""
|
||||
if self.lostOutOrErrFlag:
|
||||
self.session.conn.sendEOF(self.session)
|
||||
else:
|
||||
self.lostOutOrErrFlag = True
|
||||
|
||||
def errConnectionLost(self):
|
||||
"""
|
||||
See outConnectionLost().
|
||||
"""
|
||||
self.outConnectionLost()
|
||||
|
||||
def connectionLost(self, reason = None):
|
||||
self.session.loseConnection()
|
||||
|
||||
|
||||
# here SSH is doing signal handling, I don't think telnet supports that so
|
||||
# I'm simply going to bail out
|
||||
def processEnded(self, reason=None):
|
||||
# TODO: log reason maybe?
|
||||
log.msg("Process ended. Telnet Session disconnected")
|
||||
self.session.loseConnection()
|
||||
|
||||
|
||||
def getHost(self):
|
||||
"""
|
||||
Return the host from my session's transport.
|
||||
"""
|
||||
return self.session.transport.getHost()
|
||||
|
||||
|
||||
def getPeer(self):
|
||||
"""
|
||||
Return the peer from my session's transport.
|
||||
"""
|
||||
return self.session.transport.getPeer()
|
||||
|
||||
|
||||
def write(self, data):
|
||||
self.session.write(data)
|
||||
|
||||
|
||||
def writeSequence(self, seq):
|
||||
self.session.write(''.join(seq))
|
||||
|
||||
|
||||
def loseConnection(self):
|
||||
self.session.loseConnection()
|
|
@ -0,0 +1,164 @@
|
|||
# Copyright (C) 2015, 2016 GoSecure Inc.
|
||||
"""
|
||||
Telnet Transport and Authentication for the Honeypot
|
||||
|
||||
@author: Olivier Bilodeau <obilodeau@gosecure.ca>
|
||||
"""
|
||||
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from twisted.python import log
|
||||
from twisted.internet import protocol
|
||||
from twisted.conch.telnet import AuthenticatingTelnetProtocol, ECHO, \
|
||||
ITelnetProtocol, ProtocolTransportMixin, \
|
||||
TelnetTransport
|
||||
from twisted.protocols.policies import TimeoutMixin
|
||||
|
||||
from cowrie.core.credentials import UsernamePasswordIP
|
||||
|
||||
class HoneyPotTelnetFactory(protocol.ServerFactory):
|
||||
"""
|
||||
This factory creates HoneyPotTelnetAuthTransport instances
|
||||
They listen directly to the TCP port
|
||||
"""
|
||||
|
||||
def __init__(self, cfg):
|
||||
self.cfg = cfg
|
||||
|
||||
def logDispatch(self, *msg, **args):
|
||||
"""
|
||||
Special delivery to the loggers to avoid scope problems
|
||||
"""
|
||||
for dblog in self.dbloggers:
|
||||
dblog.logDispatch(*msg, **args)
|
||||
for output in self.output_plugins:
|
||||
output.logDispatch(*msg, **args)
|
||||
|
||||
def startFactory(self):
|
||||
"""
|
||||
"""
|
||||
# The banner to serve
|
||||
honeyfs = self.portal.realm.cfg.get('honeypot', 'contents_path')
|
||||
issuefile = honeyfs + "/etc/issue.net"
|
||||
self.banner = file(issuefile).read()
|
||||
|
||||
# Interactive protocols are kept here for the interact feature
|
||||
self.sessions = {}
|
||||
|
||||
# For use by the uptime command
|
||||
self.starttime = time.time()
|
||||
|
||||
# Load db loggers
|
||||
self.dbloggers = []
|
||||
for x in self.cfg.sections():
|
||||
if not x.startswith('database_'):
|
||||
continue
|
||||
engine = x.split('_')[1]
|
||||
try:
|
||||
dblogger = __import__( 'cowrie.dblog.{}'.format(engine),
|
||||
globals(), locals(), ['dblog']).DBLogger(self.cfg)
|
||||
log.addObserver(dblogger.emit)
|
||||
self.dbloggers.append(dblogger)
|
||||
log.msg("Loaded dblog engine: {}".format(engine))
|
||||
except:
|
||||
log.err()
|
||||
log.msg("Failed to load dblog engine: {}".format(engine))
|
||||
|
||||
# Load output modules
|
||||
self.output_plugins = []
|
||||
for x in self.cfg.sections():
|
||||
if not x.startswith('output_'):
|
||||
continue
|
||||
engine = x.split('_')[1]
|
||||
try:
|
||||
output = __import__( 'cowrie.output.{}'.format(engine),
|
||||
globals(), locals(), ['output']).Output(self.cfg)
|
||||
log.addObserver(output.emit)
|
||||
self.output_plugins.append(output)
|
||||
log.msg("Loaded output engine: {}".format(engine))
|
||||
except:
|
||||
log.err()
|
||||
log.msg("Failed to load output engine: {}".format(engine))
|
||||
|
||||
# hook protocol
|
||||
self.protocol = lambda: TelnetTransport(HoneyPotTelnetAuthTransport,
|
||||
self.portal)
|
||||
|
||||
protocol.ServerFactory.startFactory(self)
|
||||
|
||||
def stopFactory(self):
|
||||
"""
|
||||
Stop output plugins
|
||||
"""
|
||||
for output in self.output_plugins:
|
||||
output.stop()
|
||||
protocol.ServerFactory.stopFactory(self)
|
||||
|
||||
|
||||
class HoneyPotTelnetAuthTransport(AuthenticatingTelnetProtocol, ProtocolTransportMixin, TimeoutMixin):
|
||||
"""
|
||||
Telnet Transport that takes care of Authentication. Once authenticated this
|
||||
transport is replaced with HoneyPotTelnetSession.
|
||||
"""
|
||||
|
||||
def connectionMade(self):
|
||||
|
||||
self.transportId = uuid.uuid4().hex[:8]
|
||||
sessionno = self.transport.transport.sessionno
|
||||
self.factory.sessions[sessionno] = self.transportId
|
||||
|
||||
log.msg(eventid='cowrie.session.connect',
|
||||
format='New connection: %(src_ip)s:%(src_port)s (%(dst_ip)s:%(dst_port)s) [session: %(sessionno)s]',
|
||||
src_ip=self.transport.getPeer().host, src_port=self.transport.getPeer().port,
|
||||
dst_ip=self.transport.getHost().host, dst_port=self.transport.getHost().port,
|
||||
session=self.transportId, sessionno=sessionno)
|
||||
|
||||
# p/Cisco telnetd/ d/router/ o/IOS/ cpe:/a:cisco:telnet/ cpe:/o:cisco:ios/a
|
||||
# NB _write() is for raw data and write() handles telnet special bytes
|
||||
self.transport._write("\xff\xfb\x01\xff\xfb\x03\xff\xfb\0\xff\xfd\0\xff\xfd\x1f\r\n")
|
||||
self.transport.write(self.factory.banner)
|
||||
self.transport._write("User Access Verification\r\n\r\nUsername: ")
|
||||
|
||||
self.setTimeout(120)
|
||||
|
||||
# FIXME TelnetTransport is throwing an exception when client disconnects
|
||||
# Not sure if this is true anymore
|
||||
def connectionLost(self, reason):
|
||||
"""
|
||||
This seems to be the only reliable place of catching lost connection
|
||||
"""
|
||||
self.setTimeout(None)
|
||||
if self.transport.transport.sessionno in self.factory.sessions:
|
||||
del self.factory.sessions[self.transport.transport.sessionno]
|
||||
self.transport.connectionLost(reason)
|
||||
self.transport = None
|
||||
log.msg(eventid='cowrie.session.closed', format='Connection lost')
|
||||
|
||||
def telnet_Password(self, line):
|
||||
username, password = self.username, line
|
||||
del self.username
|
||||
def login(ignored):
|
||||
self.src_ip = self.transport.getPeer().host
|
||||
creds = UsernamePasswordIP(username, password, self.src_ip)
|
||||
d = self.portal.login(creds, self.src_ip, ITelnetProtocol)
|
||||
d.addCallback(self._cbLogin)
|
||||
d.addErrback(self._ebLogin)
|
||||
self.transport.wont(ECHO).addCallback(login)
|
||||
|
||||
return 'Discard'
|
||||
|
||||
def _cbLogin(self, ial):
|
||||
"""
|
||||
"""
|
||||
interface, protocol, logout = ial
|
||||
self.protocol = protocol
|
||||
self.logout = logout
|
||||
self.state = 'Command'
|
||||
|
||||
# transfer important state info to new transport
|
||||
protocol.transportId = self.transportId
|
||||
|
||||
# replace myself with avatar protocol
|
||||
protocol.makeConnection(self.transport)
|
||||
self.transport.protocol = protocol
|
|
@ -0,0 +1,2 @@
|
|||
Debian GNU/Linux 7
|
||||
|
|
@ -48,6 +48,7 @@ from cowrie import core
|
|||
import cowrie.core.realm
|
||||
import cowrie.core.checkers
|
||||
|
||||
import cowrie.telnet.transport
|
||||
import cowrie.ssh.transport
|
||||
|
||||
class Options(usage.Options):
|
||||
|
@ -99,28 +100,53 @@ class CowrieServiceMaker(object):
|
|||
factory.portal.registerChecker(
|
||||
core.checkers.HoneypotNoneChecker())
|
||||
|
||||
if cfg.has_option('honeypot', 'listen_addr'):
|
||||
listenAddr = cfg.get('honeypot', 'listen_addr')
|
||||
if cfg.has_option('honeypot', 'listen_ssh_addr'):
|
||||
listen_ssh_addr = cfg.get('honeypot', 'listen_ssh_addr')
|
||||
else:
|
||||
listenAddr = '0.0.0.0'
|
||||
listen_ssh_addr = '0.0.0.0'
|
||||
|
||||
# Preference: 1, option, 2, config, 3, default of 2222
|
||||
if options['port'] != 0:
|
||||
listenPort = int(options["port"])
|
||||
elif cfg.has_option('honeypot', 'listen_port'):
|
||||
listenPort = int(cfg.get('honeypot', 'listen_port'))
|
||||
listen_ssh_port = int(options["port"])
|
||||
elif cfg.has_option('honeypot', 'listen_ssh_port'):
|
||||
listen_ssh_port = int(cfg.get('honeypot', 'listen_ssh_port'))
|
||||
else:
|
||||
listenPort = 2222
|
||||
listen_ssh_port = 2222
|
||||
|
||||
for i in listenAddr.split():
|
||||
svc = internet.TCPServer(listenPort, factory, interface=i)
|
||||
for i in listen_ssh_addr.split():
|
||||
svc = internet.TCPServer(listen_ssh_port, factory, interface=i)
|
||||
# FIXME: Use addService on topService ?
|
||||
svc.setServiceParent(topService)
|
||||
|
||||
# TODO deduplicate telnet and ssh into a generic loop for each service
|
||||
if cfg.has_option('honeypot', 'listen_telnet_addr'):
|
||||
listen_telnet_addr = cfg.get('honeypot', 'listen_telnet_addr')
|
||||
else:
|
||||
listen_telnet_addr = '0.0.0.0'
|
||||
|
||||
# Preference: 1, config, 2, default of 2223
|
||||
if cfg.has_option('honeypot', 'listen_telnet_port'):
|
||||
listen_telnet_port = int(cfg.get('honeypot', 'listen_telnet_port'))
|
||||
else:
|
||||
listen_telnet_port = 2223
|
||||
|
||||
f = cowrie.telnet.transport.HoneyPotTelnetFactory(cfg)
|
||||
f.portal = portal.Portal(core.realm.HoneyPotRealm(cfg))
|
||||
f.portal.registerChecker(core.checkers.HoneypotPasswordChecker(cfg))
|
||||
if cfg.has_option('honeypot', 'auth_none_enabled') and \
|
||||
cfg.get('honeypot', 'auth_none_enabled').lower() in \
|
||||
('yes', 'true', 'on'):
|
||||
f.portal.registerChecker(core.checkers.HoneypotNoneChecker())
|
||||
for i in listen_telnet_addr.split():
|
||||
tsvc = internet.TCPServer(listen_telnet_port, f, interface=i)
|
||||
# FIXME: Use addService on topService ?
|
||||
tsvc.setServiceParent(topService)
|
||||
|
||||
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'))
|
||||
# FIXME this doesn't support checking both Telnet and SSH sessions
|
||||
from cowrie.core import interact
|
||||
svc = internet.TCPServer(iport,
|
||||
interact.makeInteractFactory(factory), interface='127.0.0.1')
|
||||
|
|
Loading…
Reference in New Issue