mirror of
https://github.com/aljazceru/cowrie.git
synced 2026-02-23 07:14:24 +01:00
Merge branch 'master' of https://github.com/micheloosterhof/cowrie
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
|
||||
* 2015-12-28 Interact port (default 5123) only listens on loopback interface now (127.0.0.1)
|
||||
* 2015-12-24 Redirect to file (>) now works for most commands and is logged in dl/ directory
|
||||
* 2015-12-06 UID information is now retrieved from honeyfs/etc/passwd. If you added additional users
|
||||
you will need to add these to the passwd file as well
|
||||
* 2015-12-04 New 'free' command with '-h' and '-m' options
|
||||
|
||||
@@ -7,7 +7,6 @@ __all__ = [
|
||||
'base',
|
||||
'busybox',
|
||||
'curl',
|
||||
'dice',
|
||||
'env',
|
||||
'ethtool',
|
||||
'free',
|
||||
@@ -17,7 +16,6 @@ __all__ = [
|
||||
'iptables',
|
||||
'last',
|
||||
'ls',
|
||||
'malware',
|
||||
'netstat',
|
||||
'nohup',
|
||||
'ping',
|
||||
|
||||
@@ -9,22 +9,9 @@ from twisted.python import log
|
||||
|
||||
from cowrie.core.honeypot import HoneyPotCommand
|
||||
from cowrie.core.fs import *
|
||||
from cowrie.commands import dice, malware
|
||||
|
||||
commands = {}
|
||||
|
||||
def pick_handler(cmd, size):
|
||||
"""
|
||||
"""
|
||||
if size in malware.slist:
|
||||
handler = malware.slist[size]
|
||||
elif cmd in malware.clist:
|
||||
handler = malware.clist[cmd]
|
||||
else:
|
||||
handler = random.choice(dice.clist)
|
||||
return handler
|
||||
|
||||
|
||||
|
||||
class command_tar(HoneyPotCommand):
|
||||
"""
|
||||
@@ -92,8 +79,6 @@ class command_tar(HoneyPotCommand):
|
||||
elif f.isfile():
|
||||
self.mkfullpath(os.path.dirname(dest), f)
|
||||
self.fs.mkfile(dest, 0, 0, f.size, f.mode, f.mtime)
|
||||
self.protocol.commands[dest] = \
|
||||
pick_handler(os.path.basename(dest), f.size)
|
||||
else:
|
||||
log.msg( 'tar: skipping [%s]' % f.name )
|
||||
|
||||
|
||||
@@ -25,4 +25,4 @@ class command_which(HoneyPotCommand):
|
||||
continue
|
||||
|
||||
# Definition
|
||||
commands['/bin/which'] = command_which
|
||||
commands['which'] = command_which
|
||||
|
||||
@@ -219,4 +219,3 @@ class AuthRandom(object):
|
||||
self.savevars()
|
||||
return auth
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
63
cowrie/core/avatar.py
Normal file
63
cowrie/core/avatar.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# Copyright (c) 2009-2014 Upi Tamminen <desaster@gmail.com>
|
||||
# See the COPYRIGHT file for more information
|
||||
|
||||
"""
|
||||
This module contains ...
|
||||
"""
|
||||
|
||||
from zope.interface import implementer
|
||||
|
||||
import twisted
|
||||
from twisted.conch import avatar
|
||||
from twisted.conch.interfaces import IConchUser, ISession, ISFTPServer
|
||||
from twisted.conch.ssh import filetransfer as conchfiletransfer
|
||||
from twisted.python import log, components
|
||||
|
||||
from cowrie.core import pwd
|
||||
from cowrie.ssh import session
|
||||
from cowrie.ssh import filetransfer
|
||||
from cowrie.ssh import forwarding
|
||||
|
||||
|
||||
@implementer(IConchUser)
|
||||
class CowrieUser(avatar.ConchUser):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, username, server):
|
||||
avatar.ConchUser.__init__(self)
|
||||
self.username = username
|
||||
self.server = server
|
||||
self.cfg = self.server.cfg
|
||||
|
||||
self.channelLookup.update(
|
||||
{"session": session.HoneyPotSSHSession,
|
||||
"direct-tcpip": forwarding.CowrieOpenConnectForwardingClient})
|
||||
|
||||
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'
|
||||
|
||||
# Sftp support enabled only when option is explicitly set
|
||||
try:
|
||||
if (self.cfg.get('honeypot', 'sftp_enabled') == "true"):
|
||||
self.subsystemLookup['sftp'] = conchfiletransfer.FileTransferServer
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def logout(self):
|
||||
"""
|
||||
"""
|
||||
log.msg('avatar {} logging out'.format(self.username))
|
||||
|
||||
|
||||
components.registerAdapter(filetransfer.SFTPServerForCowrieUser, CowrieUser, ISFTPServer)
|
||||
components.registerAdapter(session.SSHSessionForCowrieUser, CowrieUser, ISession)
|
||||
|
||||
@@ -130,4 +130,3 @@ class HoneypotPasswordChecker:
|
||||
username=theusername, password=thepassword)
|
||||
return False
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -12,4 +12,3 @@ def readConfigFile(cfgfile):
|
||||
cfg.readfp(open(cfgfile))
|
||||
return cfg
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -100,4 +100,3 @@ class UsernamePasswordIP:
|
||||
self.password = password
|
||||
self.ip = ip
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -195,4 +195,3 @@ class DBLogger(object):
|
||||
def handleFileDownload(self, session, args):
|
||||
pass
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -42,6 +42,7 @@ class TooManyLevels(Exception):
|
||||
|
||||
class FileNotFound(Exception):
|
||||
"""
|
||||
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -561,4 +562,3 @@ class _statobj:
|
||||
self.st_mtime = st_mtime
|
||||
self.st_ctime = st_ctime
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -31,7 +31,6 @@ class HoneyPotCommand(object):
|
||||
# MS-DOS style redirect handling, inside the command
|
||||
if '>' in self.args:
|
||||
self.writtenBytes = 0
|
||||
self.writeln = self.writeToFileLn
|
||||
self.write = self.writeToFile
|
||||
|
||||
index = self.args.index(">")
|
||||
@@ -45,7 +44,6 @@ class HoneyPotCommand(object):
|
||||
self.fs.update_realfile(self.fs.getfile(self.outfile), self.safeoutfile)
|
||||
else:
|
||||
self.write = self.protocol.terminal.write
|
||||
self.writeln = self.protocol.writeln
|
||||
|
||||
|
||||
def writeToFile(self, data):
|
||||
@@ -57,12 +55,6 @@ class HoneyPotCommand(object):
|
||||
self.fs.update_size(self.outfile, self.writtenBytes)
|
||||
|
||||
|
||||
def writeToFileLn(self, data):
|
||||
"""
|
||||
"""
|
||||
self.writeToFile(data+'\n')
|
||||
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
"""
|
||||
@@ -130,10 +122,11 @@ class HoneyPotShell(object):
|
||||
def __init__(self, protocol, interactive=True):
|
||||
self.protocol = protocol
|
||||
self.interactive = interactive
|
||||
self.showPrompt()
|
||||
self.cmdpending = []
|
||||
self.environ = protocol.environ
|
||||
|
||||
self.showPrompt()
|
||||
|
||||
|
||||
def lineReceived(self, line):
|
||||
"""
|
||||
@@ -260,6 +253,7 @@ class HoneyPotShell(object):
|
||||
|
||||
attrs = {'path': path}
|
||||
self.protocol.terminal.write(prompt % attrs)
|
||||
self.protocol.ps = (prompt % attrs , '> ')
|
||||
|
||||
|
||||
def handle_CTRL_C(self):
|
||||
|
||||
@@ -206,4 +206,3 @@ def makeInteractFactory(honeypotFactory):
|
||||
ifactory.honeypotFactory = honeypotFactory
|
||||
return ifactory
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -61,4 +61,3 @@ def getDSAKeys(cfg):
|
||||
privateKeyString = f.read()
|
||||
return publicKeyString, privateKeyString
|
||||
|
||||
|
||||
|
||||
@@ -169,4 +169,3 @@ class Output(object):
|
||||
del self.sessions[sessionno]
|
||||
del self.ips[sessionno]
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -91,7 +91,7 @@ class HoneyPotBaseProtocol(insults.TerminalProtocol, TimeoutMixin):
|
||||
"""
|
||||
this logs out when connection times out
|
||||
"""
|
||||
self.write( 'timed out waiting for input: auto-logout\n' )
|
||||
self.terminal.write( 'timed out waiting for input: auto-logout\n' )
|
||||
ret = failure.Failure(error.ProcessTerminated(exitCode=1))
|
||||
self.terminal.transport.processEnded(ret)
|
||||
|
||||
@@ -150,12 +150,15 @@ class HoneyPotBaseProtocol(insults.TerminalProtocol, TimeoutMixin):
|
||||
if self.fs.exists(i):
|
||||
path = i
|
||||
break
|
||||
|
||||
txt = os.path.normpath('%s/%s' % \
|
||||
(self.cfg.get('honeypot', 'txtcmds_path'), path))
|
||||
if os.path.exists(txt) and os.path.isfile(txt):
|
||||
return self.txtcmd(txt)
|
||||
|
||||
if path in self.commands:
|
||||
return self.commands[path]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -167,14 +170,6 @@ class HoneyPotBaseProtocol(insults.TerminalProtocol, TimeoutMixin):
|
||||
self.cmdstack[-1].lineReceived(line)
|
||||
|
||||
|
||||
def writeln(self, data):
|
||||
"""
|
||||
Sometimes still called after disconnect because of a deferred
|
||||
"""
|
||||
if self.terminal:
|
||||
self.terminal.write(data+'\n')
|
||||
|
||||
|
||||
def call_command(self, cmd, *args):
|
||||
"""
|
||||
"""
|
||||
@@ -246,6 +241,7 @@ class HoneyPotInteractiveProtocol(HoneyPotBaseProtocol, recvline.HistoricRecvLin
|
||||
'\x06': self.handle_RIGHT, # CTRL-F
|
||||
'\x09': self.handle_TAB,
|
||||
'\x0B': self.handle_CTRL_K, # CTRL-K
|
||||
'\x0C': self.handle_CTRL_L, # CTRL-L
|
||||
'\x0E': self.handle_DOWN, # CTRL-N
|
||||
'\x10': self.handle_UP, # CTRL-P
|
||||
'\x15': self.handle_CTRL_U, # CTRL-U
|
||||
@@ -256,7 +252,7 @@ class HoneyPotInteractiveProtocol(HoneyPotBaseProtocol, recvline.HistoricRecvLin
|
||||
"""
|
||||
"""
|
||||
try:
|
||||
self.write(self.fs.file_contents('/etc/motd')+'\n')
|
||||
self.terminal.write(self.fs.file_contents('/etc/motd')+'\n')
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -348,6 +344,16 @@ class HoneyPotInteractiveProtocol(HoneyPotBaseProtocol, recvline.HistoricRecvLin
|
||||
self.lineBuffer = self.lineBuffer[0:self.lineBufferIndex]
|
||||
|
||||
|
||||
def handle_CTRL_L(self):
|
||||
"""
|
||||
Handle a 'form feed' byte - generally used to request a screen
|
||||
refresh/redraw.
|
||||
"""
|
||||
self.terminal.eraseDisplay()
|
||||
self.terminal.cursorHome()
|
||||
self.drawInputLine()
|
||||
|
||||
|
||||
def handle_CTRL_U(self):
|
||||
"""
|
||||
"""
|
||||
@@ -357,152 +363,3 @@ 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 __init__(self, prot=None, *a, **kw):
|
||||
insults.ServerProtocol.__init__(self, prot, *a, **kw)
|
||||
self.cfg = a[0].cfg
|
||||
self.bytesReceived = 0
|
||||
self.interactors = []
|
||||
|
||||
try:
|
||||
self.bytesReceivedLimit = int(self.cfg.get('honeypot', 'download_limit_size'))
|
||||
except:
|
||||
self.bytesReceivedLimit = 0
|
||||
|
||||
if prot is HoneyPotExecProtocol:
|
||||
self.type = 'e' # execcmd
|
||||
else:
|
||||
self.type = 'i' # interactive
|
||||
|
||||
|
||||
def connectionMade(self):
|
||||
"""
|
||||
"""
|
||||
transportId = self.transport.session.conn.transport.transportId
|
||||
channelId = self.transport.session.id
|
||||
|
||||
self.ttylog_file = '%s/tty/%s-%s-%s%s.log' % \
|
||||
(self.cfg.get('honeypot', 'log_path'),
|
||||
time.strftime('%Y%m%d-%H%M%S'), transportId, channelId,
|
||||
self.type)
|
||||
ttylog.ttylog_open(self.ttylog_file, time.time())
|
||||
self.ttylog_open = True
|
||||
|
||||
log.msg(eventid='COW0004', ttylog=self.ttylog_file,
|
||||
format='Opening TTY Log: %(ttylog)s')
|
||||
|
||||
self.stdinlog_file = '%s/%s-%s-%s-stdin.log' % \
|
||||
(self.cfg.get('honeypot', 'download_path'),
|
||||
time.strftime('%Y%m%d-%H%M%S'), transportId, channelId)
|
||||
self.stdinlog_open = False
|
||||
|
||||
insults.ServerProtocol.connectionMade(self)
|
||||
|
||||
|
||||
def write(self, bytes):
|
||||
"""
|
||||
"""
|
||||
for i in self.interactors:
|
||||
i.sessionWrite(bytes)
|
||||
|
||||
if self.ttylog_open:
|
||||
ttylog.ttylog_write(self.ttylog_file, len(bytes),
|
||||
ttylog.TYPE_OUTPUT, time.time(), bytes)
|
||||
|
||||
insults.ServerProtocol.write(self, bytes)
|
||||
|
||||
|
||||
def dataReceived(self, data):
|
||||
"""
|
||||
"""
|
||||
self.bytesReceived += len(data)
|
||||
if self.bytesReceivedLimit and self.bytesReceived > self.bytesReceivedLimit:
|
||||
log.msg(eventid='COW0015', format='Data upload limit reached')
|
||||
#self.loseConnection()
|
||||
self.eofReceived()
|
||||
return
|
||||
|
||||
if self.stdinlog_open:
|
||||
with file(self.stdinlog_file, 'ab') as f:
|
||||
f.write(data)
|
||||
elif self.ttylog_open:
|
||||
ttylog.ttylog_write(self.ttylog_file, len(data),
|
||||
ttylog.TYPE_INPUT, time.time(), data)
|
||||
|
||||
insults.ServerProtocol.dataReceived(self, data)
|
||||
|
||||
|
||||
def eofReceived(self):
|
||||
"""
|
||||
"""
|
||||
if self.terminalProtocol:
|
||||
self.terminalProtocol.eofReceived()
|
||||
|
||||
|
||||
def addInteractor(self, interactor):
|
||||
"""
|
||||
"""
|
||||
self.interactors.append(interactor)
|
||||
|
||||
|
||||
def delInteractor(self, interactor):
|
||||
"""
|
||||
"""
|
||||
self.interactors.remove(interactor)
|
||||
|
||||
|
||||
def loseConnection(self):
|
||||
"""
|
||||
override super to remove the terminal reset on logout
|
||||
|
||||
"""
|
||||
self.transport.loseConnection()
|
||||
|
||||
|
||||
def connectionLost(self, reason):
|
||||
"""
|
||||
FIXME: this method is called 4 times on logout....
|
||||
it's called once from Avatar.closed() if disconnected
|
||||
"""
|
||||
log.msg("received call to LSP.connectionLost")
|
||||
|
||||
for i in self.interactors:
|
||||
i.sessionClosed()
|
||||
|
||||
transport = self.transport.session.conn.transport
|
||||
|
||||
if self.stdinlog_open:
|
||||
try:
|
||||
with open(self.stdinlog_file, 'rb') as f:
|
||||
shasum = hashlib.sha256(f.read()).hexdigest()
|
||||
shasumfile = self.cfg.get('honeypot',
|
||||
'download_path') + "/" + shasum
|
||||
if (os.path.exists(shasumfile)):
|
||||
os.remove(self.stdinlog_file)
|
||||
else:
|
||||
os.rename(self.stdinlog_file, shasumfile)
|
||||
os.symlink(shasum, self.stdinlog_file)
|
||||
log.msg(eventid='COW0007',
|
||||
format='Saved stdin contents to %(outfile)s',
|
||||
url='stdin', outfile=shasumfile, shasum=shasum)
|
||||
except IOError as e:
|
||||
pass
|
||||
finally:
|
||||
self.stdinlog_open = False
|
||||
|
||||
if self.ttylog_open:
|
||||
log.msg(eventid='COW0012', format='Closing TTY Log: %(ttylog)s',
|
||||
ttylog=self.ttylog_file)
|
||||
ttylog.ttylog_close(self.ttylog_file, time.time())
|
||||
self.ttylog_open = False
|
||||
|
||||
self.cfg = None
|
||||
insults.ServerProtocol.connectionLost(self, reason)
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -190,4 +190,3 @@ class Group(object):
|
||||
return _
|
||||
raise KeyError("getgruid(): uid not found in group file: " + uid)
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -38,7 +38,7 @@ from twisted.python import log
|
||||
|
||||
from cowrie.core import protocol
|
||||
from cowrie.core import server
|
||||
from cowrie.core import ssh
|
||||
from cowrie.core import avatar
|
||||
|
||||
import sys
|
||||
import gc
|
||||
@@ -71,8 +71,7 @@ class HoneyPotRealm:
|
||||
|
||||
if conchinterfaces.IConchUser in interfaces:
|
||||
return interfaces[0], \
|
||||
ssh.CowrieUser(avatarId, server.CowrieServer(self.cfg)), lambda:None
|
||||
avatar.CowrieUser(avatarId, server.CowrieServer(self.cfg)), lambda:None
|
||||
else:
|
||||
raise Exception("No supported interfaces found.")
|
||||
|
||||
|
||||
|
||||
@@ -38,4 +38,3 @@ def ttylog_close(logfile, stamp):
|
||||
sec, usec = int(stamp), int(1000000 * (stamp - int(stamp)))
|
||||
f.write(struct.pack('<iLiiLL', 2, 0, 0, 0, sec, usec))
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -87,5 +87,3 @@ def uptime(total_seconds):
|
||||
s += '%s min' % (str(minutes))
|
||||
return s
|
||||
|
||||
|
||||
# vim: set sw=4 et:
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
from twisted.words.xish import domish
|
||||
from twisted.python import log
|
||||
from wokkel.xmppim import AvailablePresence
|
||||
from twisted.words.protocols.jabber.jid import JID
|
||||
from wokkel import muc
|
||||
import uuid
|
||||
import json
|
||||
|
||||
class XMPPLoggerProtocol(muc.MUCClient):
|
||||
|
||||
def __init__(self, server, rooms, nick):
|
||||
def __init__(self, rooms, server, nick):
|
||||
muc.MUCClient.__init__(self)
|
||||
self.server = server
|
||||
self.jrooms = rooms
|
||||
self.server = rooms.host
|
||||
self.jrooms = rooms
|
||||
self._roomOccupantMap = {}
|
||||
log.msg(rooms.user)
|
||||
log.msg(rooms.host)
|
||||
self.nick = nick
|
||||
self.last = {}
|
||||
self.activity = None
|
||||
|
||||
def initialized(self):
|
||||
def connectionInitialized(self):
|
||||
"""The bot has connected to the xmpp server, now try to join the room.
|
||||
"""
|
||||
for i in self.jrooms:
|
||||
print(i)
|
||||
self.join(self.server, i, self.nick).addCallback(self.initRoom)
|
||||
self.join(self.jrooms, self.nick);
|
||||
|
||||
def initRoom(self, room):
|
||||
def joinedRoom(self, room):
|
||||
log.msg( 'Joined room %s' % room.name )
|
||||
|
||||
def connectionMade(self):
|
||||
@@ -31,7 +34,7 @@ class XMPPLoggerProtocol(muc.MUCClient):
|
||||
self.send(AvailablePresence())
|
||||
|
||||
def connectionLost(self, reason):
|
||||
logmsg( 'Disconnected!' )
|
||||
log.msg( 'Disconnected!' )
|
||||
|
||||
def onMessage(self, msg):
|
||||
pass
|
||||
@@ -69,10 +72,11 @@ class DBLogger(dblog.DBLogger):
|
||||
for i in range(8)])
|
||||
jid = user + '/' + resource
|
||||
application = service.Application('honeypot')
|
||||
self.run(application, jid, password, muc, channels)
|
||||
self.run(application, jid, password, JID(None,[muc,server,None]), channels)
|
||||
|
||||
def run(self, application, jidstr, password, muc, channels, anon=True):
|
||||
self.xmppclient = XMPPClient(jid.JID(jidstr), password)
|
||||
|
||||
self.xmppclient = XMPPClient(JID(jidstr), password)
|
||||
if self.cfg.has_option('database_xmpp', 'debug') and \
|
||||
self.cfg.get('database_xmpp', 'debug') in ('1', 'true', 'yes'):
|
||||
self.xmppclient.logTraffic = True # DEBUG HERE
|
||||
@@ -94,18 +98,16 @@ class DBLogger(dblog.DBLogger):
|
||||
(self.signals[msgtype], self.muc.server) , msg)
|
||||
|
||||
def report(self, msgtype, to, xmsg):
|
||||
body = domish.Element((None, 'body'))
|
||||
body.addContent('\n')
|
||||
msg = domish.Element(('http://github.com/micheloosterhof/cowrie', 'cowrie'))
|
||||
msg = {}
|
||||
msg['type'] = msgtype
|
||||
msg.addChild(xmsg)
|
||||
body.addChild(msg)
|
||||
self.muc.groupChat(jid.JID(to), body)
|
||||
msg['message'] = xmsg
|
||||
msgJson = json.dumps(msg,indent=5)
|
||||
self.muc.groupChat(self.muc.jrooms, msgJson)
|
||||
|
||||
# We have to return an unique ID
|
||||
def createSession(self, peerIP, peerPort, hostIP, hostPort):
|
||||
session = uuid.uuid4().hex
|
||||
ses = domish.Element((None, 'session'))
|
||||
ses = {}
|
||||
ses['session'] = session
|
||||
ses['remote_host'] = peerIP
|
||||
ses['remote_port'] = str(peerPort)
|
||||
@@ -122,50 +124,50 @@ class DBLogger(dblog.DBLogger):
|
||||
pass
|
||||
|
||||
def handleConnectionLost(self, session, args):
|
||||
ses = domish.Element((None, 'session'))
|
||||
ses = {}
|
||||
ses['session'] = session
|
||||
self.broadcast('connectionlost', ses)
|
||||
|
||||
def handleLoginFailed(self, session, args):
|
||||
ses = domish.Element((None, 'credentials'))
|
||||
ses = {}
|
||||
ses['session'] = session
|
||||
ses['username'] = args['username']
|
||||
ses['password'] = args['password']
|
||||
self.broadcast('loginfailed', ses)
|
||||
|
||||
def handleLoginSucceeded(self, session, args):
|
||||
ses = domish.Element((None, 'credentials'))
|
||||
ses = {}
|
||||
ses['session'] = session
|
||||
ses['username'] = args['username']
|
||||
ses['password'] = args['password']
|
||||
self.broadcast('loginsucceeded', ses)
|
||||
|
||||
def handleCommand(self, session, args):
|
||||
ses = domish.Element((None, 'command'))
|
||||
ses = {}
|
||||
ses['session'] = session
|
||||
ses['command'] = 'known'
|
||||
ses.addContent(args['input'])
|
||||
ses['input'] = args['input']
|
||||
self.broadcast('command', ses)
|
||||
|
||||
def handleUnknownCommand(self, session, args):
|
||||
ses = domish.Element((None, 'command'))
|
||||
ses = {}
|
||||
ses['session'] = session
|
||||
ses['command'] = 'unknown'
|
||||
ses.addContent(args['input'])
|
||||
ses['input'] = args['input']
|
||||
self.broadcast('command', ses)
|
||||
|
||||
def handleInput(self, session, args):
|
||||
ses = domish.Element((None, 'input'))
|
||||
ses = {}
|
||||
ses['session'] = session
|
||||
ses['realm'] = args['realm']
|
||||
ses.addContent(args['input'])
|
||||
ses['input'] = args['input']
|
||||
self.broadcast('input', ses)
|
||||
|
||||
def handleTerminalSize(self, session, args):
|
||||
pass
|
||||
|
||||
def handleClientVersion(self, session, args):
|
||||
ses = domish.Element((None, 'version'))
|
||||
ses = {}
|
||||
ses['session'] = session
|
||||
ses['version'] = args['version']
|
||||
self.broadcast('clientversion', ses)
|
||||
|
||||
0
cowrie/insults/__init__.py
Normal file
0
cowrie/insults/__init__.py
Normal file
164
cowrie/insults/insults.py
Normal file
164
cowrie/insults/insults.py
Normal file
@@ -0,0 +1,164 @@
|
||||
# Copyright (c) 2009-2014 Upi Tamminen <desaster@gmail.com>
|
||||
# See the COPYRIGHT file for more information
|
||||
|
||||
"""
|
||||
This module contains ...
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import hashlib
|
||||
|
||||
from twisted.python import log
|
||||
from twisted.conch.insults import insults
|
||||
|
||||
from cowrie.core import ttylog
|
||||
from cowrie.core import protocol
|
||||
|
||||
|
||||
class LoggingServerProtocol(insults.ServerProtocol):
|
||||
"""
|
||||
Wrapper for ServerProtocol that implements TTY logging
|
||||
"""
|
||||
|
||||
def __init__(self, prot=None, *a, **kw):
|
||||
insults.ServerProtocol.__init__(self, prot, *a, **kw)
|
||||
self.cfg = a[0].cfg
|
||||
self.bytesReceived = 0
|
||||
self.interactors = []
|
||||
|
||||
try:
|
||||
self.bytesReceivedLimit = int(self.cfg.get('honeypot', 'download_limit_size'))
|
||||
except:
|
||||
self.bytesReceivedLimit = 0
|
||||
|
||||
if prot is protocol.HoneyPotExecProtocol:
|
||||
self.type = 'e' # execcmd
|
||||
else:
|
||||
self.type = 'i' # interactive
|
||||
|
||||
|
||||
def connectionMade(self):
|
||||
"""
|
||||
"""
|
||||
transportId = self.transport.session.conn.transport.transportId
|
||||
channelId = self.transport.session.id
|
||||
|
||||
self.ttylog_file = '%s/tty/%s-%s-%s%s.log' % \
|
||||
(self.cfg.get('honeypot', 'log_path'),
|
||||
time.strftime('%Y%m%d-%H%M%S'), transportId, channelId,
|
||||
self.type)
|
||||
ttylog.ttylog_open(self.ttylog_file, time.time())
|
||||
self.ttylog_open = True
|
||||
|
||||
log.msg(eventid='COW0004', ttylog=self.ttylog_file,
|
||||
format='Opening TTY Log: %(ttylog)s')
|
||||
|
||||
self.stdinlog_file = '%s/%s-%s-%s-stdin.log' % \
|
||||
(self.cfg.get('honeypot', 'download_path'),
|
||||
time.strftime('%Y%m%d-%H%M%S'), transportId, channelId)
|
||||
self.stdinlog_open = False
|
||||
|
||||
insults.ServerProtocol.connectionMade(self)
|
||||
|
||||
|
||||
def write(self, bytes):
|
||||
"""
|
||||
"""
|
||||
for i in self.interactors:
|
||||
i.sessionWrite(bytes)
|
||||
|
||||
if self.ttylog_open:
|
||||
ttylog.ttylog_write(self.ttylog_file, len(bytes),
|
||||
ttylog.TYPE_OUTPUT, time.time(), bytes)
|
||||
|
||||
insults.ServerProtocol.write(self, bytes)
|
||||
|
||||
|
||||
def dataReceived(self, data):
|
||||
"""
|
||||
"""
|
||||
self.bytesReceived += len(data)
|
||||
if self.bytesReceivedLimit and self.bytesReceived > self.bytesReceivedLimit:
|
||||
log.msg(eventid='COW0015', format='Data upload limit reached')
|
||||
#self.loseConnection()
|
||||
self.eofReceived()
|
||||
return
|
||||
|
||||
if self.stdinlog_open:
|
||||
with file(self.stdinlog_file, 'ab') as f:
|
||||
f.write(data)
|
||||
elif self.ttylog_open:
|
||||
ttylog.ttylog_write(self.ttylog_file, len(data),
|
||||
ttylog.TYPE_INPUT, time.time(), data)
|
||||
|
||||
insults.ServerProtocol.dataReceived(self, data)
|
||||
|
||||
|
||||
def eofReceived(self):
|
||||
"""
|
||||
"""
|
||||
if self.terminalProtocol:
|
||||
self.terminalProtocol.eofReceived()
|
||||
|
||||
|
||||
def addInteractor(self, interactor):
|
||||
"""
|
||||
"""
|
||||
self.interactors.append(interactor)
|
||||
|
||||
|
||||
def delInteractor(self, interactor):
|
||||
"""
|
||||
"""
|
||||
self.interactors.remove(interactor)
|
||||
|
||||
|
||||
def loseConnection(self):
|
||||
"""
|
||||
override super to remove the terminal reset on logout
|
||||
|
||||
"""
|
||||
self.transport.loseConnection()
|
||||
|
||||
|
||||
def connectionLost(self, reason):
|
||||
"""
|
||||
FIXME: this method is called 4 times on logout....
|
||||
it's called once from Avatar.closed() if disconnected
|
||||
"""
|
||||
log.msg("received call to LSP.connectionLost")
|
||||
|
||||
for i in self.interactors:
|
||||
i.sessionClosed()
|
||||
|
||||
transport = self.transport.session.conn.transport
|
||||
|
||||
if self.stdinlog_open:
|
||||
try:
|
||||
with open(self.stdinlog_file, 'rb') as f:
|
||||
shasum = hashlib.sha256(f.read()).hexdigest()
|
||||
shasumfile = self.cfg.get('honeypot',
|
||||
'download_path') + "/" + shasum
|
||||
if (os.path.exists(shasumfile)):
|
||||
os.remove(self.stdinlog_file)
|
||||
else:
|
||||
os.rename(self.stdinlog_file, shasumfile)
|
||||
os.symlink(shasum, self.stdinlog_file)
|
||||
log.msg(eventid='COW0007',
|
||||
format='Saved stdin contents to %(outfile)s',
|
||||
url='stdin', outfile=shasumfile, shasum=shasum)
|
||||
except IOError as e:
|
||||
pass
|
||||
finally:
|
||||
self.stdinlog_open = False
|
||||
|
||||
if self.ttylog_open:
|
||||
log.msg(eventid='COW0012', format='Closing TTY Log: %(ttylog)s',
|
||||
ttylog=self.ttylog_file)
|
||||
ttylog.ttylog_close(self.ttylog_file, time.time())
|
||||
self.ttylog_open = False
|
||||
|
||||
self.cfg = None
|
||||
insults.ServerProtocol.connectionLost(self, reason)
|
||||
|
||||
0
cowrie/ssh/__init__.py
Normal file
0
cowrie/ssh/__init__.py
Normal file
@@ -10,209 +10,14 @@ import os
|
||||
from zope.interface import implementer
|
||||
|
||||
import twisted
|
||||
from twisted.conch import avatar, interfaces as conchinterfaces
|
||||
from twisted.conch.ssh import session
|
||||
from twisted.conch.interfaces import ISFTPFile, ISFTPServer
|
||||
from twisted.conch.ssh import filetransfer
|
||||
from twisted.conch.ssh import forwarding
|
||||
from twisted.conch.ssh.filetransfer import FXF_READ, FXF_WRITE, FXF_APPEND, FXF_CREAT, FXF_TRUNC, FXF_EXCL
|
||||
import twisted.conch.ls
|
||||
from twisted.python import log, components
|
||||
from twisted.conch.ssh.common import getNS
|
||||
|
||||
from cowrie.core import pwd
|
||||
from cowrie.core import protocol
|
||||
from twisted.python import log
|
||||
|
||||
|
||||
|
||||
class HoneyPotSSHSession(session.SSHSession):
|
||||
"""
|
||||
This is an SSH channel that's used for SSH sessions
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
session.SSHSession.__init__(self, *args, **kw)
|
||||
#self.__dict__['request_auth_agent_req@openssh.com'] = self.request_agent
|
||||
|
||||
|
||||
def request_env(self, data):
|
||||
"""
|
||||
"""
|
||||
name, rest = getNS(data)
|
||||
value, rest = getNS(rest)
|
||||
if rest:
|
||||
raise ValueError("Bad data given in env request")
|
||||
log.msg(eventid='COW0013', format='request_env: %(name)s=%(value)s',
|
||||
name=name, value=value)
|
||||
# Environment variables come after shell or before exec command
|
||||
if self.session:
|
||||
self.session.environ[name] = value
|
||||
return 0
|
||||
|
||||
|
||||
def request_agent(self, data):
|
||||
"""
|
||||
"""
|
||||
log.msg('request_agent: %s' % (repr(data),))
|
||||
return 0
|
||||
|
||||
|
||||
def request_x11_req(self, data):
|
||||
"""
|
||||
"""
|
||||
log.msg('request_x11: %s' % (repr(data),))
|
||||
return 0
|
||||
|
||||
|
||||
def closed(self):
|
||||
"""
|
||||
This is reliably called on session close/disconnect and calls the avatar
|
||||
"""
|
||||
session.SSHSession.closed(self)
|
||||
|
||||
|
||||
def sendEOF(self):
|
||||
"""
|
||||
Utility function to request to send EOF for this session
|
||||
"""
|
||||
self.conn.sendEOF(self)
|
||||
|
||||
|
||||
def sendClose(self):
|
||||
"""
|
||||
Utility function to request to send close for this session
|
||||
"""
|
||||
self.conn.sendClose(self)
|
||||
|
||||
|
||||
def channelClosed(self):
|
||||
"""
|
||||
"""
|
||||
log.msg("Called channelClosed in SSHSession")
|
||||
|
||||
|
||||
|
||||
@implementer(conchinterfaces.IConchUser)
|
||||
class CowrieUser(avatar.ConchUser):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, username, server):
|
||||
avatar.ConchUser.__init__(self)
|
||||
self.username = username
|
||||
self.server = server
|
||||
self.cfg = self.server.cfg
|
||||
|
||||
self.channelLookup.update(
|
||||
{"session": HoneyPotSSHSession,
|
||||
"direct-tcpip": CowrieOpenConnectForwardingClient})
|
||||
|
||||
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'
|
||||
|
||||
# Sftp support enabled only when option is explicitly set
|
||||
try:
|
||||
if (self.cfg.get('honeypot', 'sftp_enabled') == "true"):
|
||||
self.subsystemLookup['sftp'] = filetransfer.FileTransferServer
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def logout(self):
|
||||
"""
|
||||
"""
|
||||
log.msg('avatar {} logging out'.format(self.username))
|
||||
|
||||
|
||||
|
||||
@implementer(conchinterfaces.ISession)
|
||||
class SSHSessionForCowrieUser:
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, avatar, reactor=None):
|
||||
"""
|
||||
Construct an C{SSHSessionForCowrieUser}.
|
||||
|
||||
@param avatar: The L{CowrieUser} for whom this is an SSH session.
|
||||
@param reactor: An L{IReactorProcess} used to handle shell and exec
|
||||
requests. Uses the default reactor if None.
|
||||
"""
|
||||
self.protocol = None
|
||||
self.avatar = avatar
|
||||
self.server = avatar.server
|
||||
self.cfg = avatar.cfg
|
||||
self.uid = avatar.uid
|
||||
self.gid = avatar.gid
|
||||
self.username = avatar.username
|
||||
self.environ = {
|
||||
'LOGNAME': self.username,
|
||||
'USER': self.username,
|
||||
'HOME': self.avatar.home}
|
||||
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'
|
||||
|
||||
def openShell(self, processprotocol):
|
||||
"""
|
||||
"""
|
||||
self.protocol = protocol.LoggingServerProtocol(
|
||||
protocol.HoneyPotInteractiveProtocol, self)
|
||||
self.protocol.makeConnection(processprotocol)
|
||||
processprotocol.makeConnection(session.wrapProtocol(self.protocol))
|
||||
|
||||
|
||||
def getPty(self, terminal, windowSize, attrs):
|
||||
"""
|
||||
"""
|
||||
self.environ['TERM'] = terminal
|
||||
log.msg(eventid='COW0010', width=windowSize[0], height=windowSize[1],
|
||||
format='Terminal Size: %(width)s %(height)s')
|
||||
self.windowSize = windowSize
|
||||
return None
|
||||
|
||||
|
||||
def execCommand(self, processprotocol, cmd):
|
||||
"""
|
||||
"""
|
||||
self.protocol = protocol.LoggingServerProtocol(
|
||||
protocol.HoneyPotExecProtocol, self, cmd)
|
||||
self.protocol.makeConnection(processprotocol)
|
||||
processprotocol.makeConnection(session.wrapProtocol(self.protocol))
|
||||
|
||||
|
||||
def closed(self):
|
||||
"""
|
||||
this is reliably called on both logout and disconnect
|
||||
we notify the protocol here we lost the connection
|
||||
"""
|
||||
if self.protocol:
|
||||
self.protocol.connectionLost("disconnected")
|
||||
self.protocol = None
|
||||
|
||||
|
||||
def eofReceived(self):
|
||||
"""
|
||||
"""
|
||||
if self.protocol:
|
||||
self.protocol.eofReceived()
|
||||
|
||||
|
||||
def windowChanged(self, windowSize):
|
||||
"""
|
||||
"""
|
||||
self.windowSize = windowSize
|
||||
|
||||
|
||||
|
||||
@implementer(conchinterfaces.ISFTPFile)
|
||||
@implementer(ISFTPFile)
|
||||
class CowrieSFTPFile:
|
||||
"""
|
||||
"""
|
||||
@@ -335,7 +140,7 @@ class CowrieSFTPDirectory:
|
||||
|
||||
|
||||
|
||||
@implementer(conchinterfaces.ISFTPServer)
|
||||
@implementer(ISFTPServer)
|
||||
class SFTPServerForCowrieUser:
|
||||
"""
|
||||
"""
|
||||
@@ -476,39 +281,3 @@ class SFTPServerForCowrieUser:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
|
||||
components.registerAdapter(SFTPServerForCowrieUser, CowrieUser, conchinterfaces.ISFTPServer)
|
||||
components.registerAdapter(SSHSessionForCowrieUser, CowrieUser, session.ISession)
|
||||
|
||||
|
||||
def CowrieOpenConnectForwardingClient(remoteWindow, remoteMaxPacket, data, avatar):
|
||||
"""
|
||||
"""
|
||||
remoteHP, origHP = twisted.conch.ssh.forwarding.unpackOpen_direct_tcpip(data)
|
||||
log.msg(eventid='COW0014', format='direct-tcp connection request to %(dst_ip)s:%(dst_port)s',
|
||||
dst_ip=remoteHP[0], dst_port=remoteHP[1])
|
||||
return CowrieConnectForwardingChannel(remoteHP,
|
||||
remoteWindow=remoteWindow, remoteMaxPacket=remoteMaxPacket,
|
||||
avatar=avatar)
|
||||
|
||||
|
||||
|
||||
class CowrieConnectForwardingChannel(forwarding.SSHConnectForwardingChannel):
|
||||
"""
|
||||
"""
|
||||
def channelOpen(self, specificData):
|
||||
"""
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def dataReceived(self, data):
|
||||
"""
|
||||
"""
|
||||
log.msg(eventid='COW0015',
|
||||
format='direct-tcp forward to %(dst_ip)s:%(dst_port)s with data %(data)s',
|
||||
dst_ip=self.hostport[0], dst_port=self.hostport[1], data=repr(data))
|
||||
self._close("Connection refused")
|
||||
|
||||
# vim: set et sw=4 et:
|
||||
41
cowrie/ssh/forwarding.py
Normal file
41
cowrie/ssh/forwarding.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# Copyright (c) 2009-2014 Upi Tamminen <desaster@gmail.com>
|
||||
# See the COPYRIGHT file for more information
|
||||
|
||||
"""
|
||||
This module contains ...
|
||||
"""
|
||||
|
||||
import twisted
|
||||
from twisted.conch.ssh import forwarding
|
||||
from twisted.python import log
|
||||
|
||||
|
||||
def CowrieOpenConnectForwardingClient(remoteWindow, remoteMaxPacket, data, avatar):
|
||||
"""
|
||||
"""
|
||||
remoteHP, origHP = twisted.conch.ssh.forwarding.unpackOpen_direct_tcpip(data)
|
||||
log.msg(eventid='COW0014', format='direct-tcp connection request to %(dst_ip)s:%(dst_port)s',
|
||||
dst_ip=remoteHP[0], dst_port=remoteHP[1])
|
||||
return CowrieConnectForwardingChannel(remoteHP,
|
||||
remoteWindow=remoteWindow, remoteMaxPacket=remoteMaxPacket,
|
||||
avatar=avatar)
|
||||
|
||||
|
||||
|
||||
class CowrieConnectForwardingChannel(forwarding.SSHConnectForwardingChannel):
|
||||
"""
|
||||
"""
|
||||
def channelOpen(self, specificData):
|
||||
"""
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def dataReceived(self, data):
|
||||
"""
|
||||
"""
|
||||
log.msg(eventid='COW0015',
|
||||
format='direct-tcp forward to %(dst_ip)s:%(dst_port)s with data %(data)s',
|
||||
dst_ip=self.hostport[0], dst_port=self.hostport[1], data=repr(data))
|
||||
self._close("Connection refused")
|
||||
|
||||
169
cowrie/ssh/session.py
Normal file
169
cowrie/ssh/session.py
Normal file
@@ -0,0 +1,169 @@
|
||||
# Copyright (c) 2009-2014 Upi Tamminen <desaster@gmail.com>
|
||||
# See the COPYRIGHT file for more information
|
||||
|
||||
"""
|
||||
This module contains ...
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from zope.interface import implementer
|
||||
|
||||
import twisted
|
||||
from twisted.conch.interfaces import ISession
|
||||
from twisted.conch.ssh import session
|
||||
from twisted.python import log
|
||||
from twisted.conch.ssh.common import getNS
|
||||
|
||||
from cowrie.core import protocol
|
||||
from cowrie.core import pwd
|
||||
from cowrie.insults import insults
|
||||
|
||||
|
||||
class HoneyPotSSHSession(session.SSHSession):
|
||||
"""
|
||||
This is an SSH channel that's used for SSH sessions
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
session.SSHSession.__init__(self, *args, **kw)
|
||||
#self.__dict__['request_auth_agent_req@openssh.com'] = self.request_agent
|
||||
|
||||
|
||||
def request_env(self, data):
|
||||
"""
|
||||
"""
|
||||
name, rest = getNS(data)
|
||||
value, rest = getNS(rest)
|
||||
if rest:
|
||||
raise ValueError("Bad data given in env request")
|
||||
log.msg(eventid='COW0013', format='request_env: %(name)s=%(value)s',
|
||||
name=name, value=value)
|
||||
# FIXME: This only works for shell, not for exec command
|
||||
if self.session:
|
||||
self.session.environ[name] = value
|
||||
return 0
|
||||
|
||||
|
||||
def request_agent(self, data):
|
||||
"""
|
||||
"""
|
||||
log.msg('request_agent: %s' % (repr(data),))
|
||||
return 0
|
||||
|
||||
|
||||
def request_x11_req(self, data):
|
||||
"""
|
||||
"""
|
||||
log.msg('request_x11: %s' % (repr(data),))
|
||||
return 0
|
||||
|
||||
|
||||
def closed(self):
|
||||
"""
|
||||
This is reliably called on session close/disconnect and calls the avatar
|
||||
"""
|
||||
session.SSHSession.closed(self)
|
||||
|
||||
|
||||
def sendEOF(self):
|
||||
"""
|
||||
Utility function to request to send EOF for this session
|
||||
"""
|
||||
self.conn.sendEOF(self)
|
||||
|
||||
|
||||
def sendClose(self):
|
||||
"""
|
||||
Utility function to request to send close for this session
|
||||
"""
|
||||
self.conn.sendClose(self)
|
||||
|
||||
|
||||
def channelClosed(self):
|
||||
"""
|
||||
"""
|
||||
log.msg("Called channelClosed in SSHSession")
|
||||
|
||||
|
||||
|
||||
@implementer(ISession)
|
||||
class SSHSessionForCowrieUser:
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, avatar, reactor=None):
|
||||
"""
|
||||
Construct an C{SSHSessionForCowrieUser}.
|
||||
|
||||
@param avatar: The L{CowrieUser} for whom this is an SSH session.
|
||||
@param reactor: An L{IReactorProcess} used to handle shell and exec
|
||||
requests. Uses the default reactor if None.
|
||||
"""
|
||||
self.protocol = None
|
||||
self.avatar = avatar
|
||||
self.server = avatar.server
|
||||
self.cfg = avatar.cfg
|
||||
self.uid = avatar.uid
|
||||
self.gid = avatar.gid
|
||||
self.username = avatar.username
|
||||
self.environ = {
|
||||
'LOGNAME': self.username,
|
||||
'USER': self.username,
|
||||
'HOME': self.avatar.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'
|
||||
|
||||
def openShell(self, processprotocol):
|
||||
"""
|
||||
"""
|
||||
self.protocol = insults.LoggingServerProtocol(
|
||||
protocol.HoneyPotInteractiveProtocol, self)
|
||||
self.protocol.makeConnection(processprotocol)
|
||||
processprotocol.makeConnection(session.wrapProtocol(self.protocol))
|
||||
|
||||
|
||||
def getPty(self, terminal, windowSize, attrs):
|
||||
"""
|
||||
"""
|
||||
self.environ['TERM'] = terminal
|
||||
log.msg(eventid='COW0010', width=windowSize[0], height=windowSize[1],
|
||||
format='Terminal Size: %(width)s %(height)s')
|
||||
self.windowSize = windowSize
|
||||
return None
|
||||
|
||||
|
||||
def execCommand(self, processprotocol, cmd):
|
||||
"""
|
||||
"""
|
||||
self.protocol = insults.LoggingServerProtocol(
|
||||
protocol.HoneyPotExecProtocol, self, cmd)
|
||||
self.protocol.makeConnection(processprotocol)
|
||||
processprotocol.makeConnection(session.wrapProtocol(self.protocol))
|
||||
|
||||
|
||||
def closed(self):
|
||||
"""
|
||||
this is reliably called on both logout and disconnect
|
||||
we notify the protocol here we lost the connection
|
||||
"""
|
||||
if self.protocol:
|
||||
self.protocol.connectionLost("disconnected")
|
||||
self.protocol = None
|
||||
|
||||
|
||||
def eofReceived(self):
|
||||
"""
|
||||
"""
|
||||
if self.protocol:
|
||||
self.protocol.eofReceived()
|
||||
|
||||
|
||||
def windowChanged(self, windowSize):
|
||||
"""
|
||||
"""
|
||||
self.windowSize = windowSize
|
||||
|
||||
@@ -17,8 +17,8 @@ from twisted.conch.openssh_compat import primes
|
||||
from twisted.conch.ssh.common import getNS
|
||||
from twisted.protocols.policies import TimeoutMixin
|
||||
|
||||
from cowrie.core import connection
|
||||
from cowrie.core import userauth
|
||||
from cowrie.ssh import connection
|
||||
from cowrie.ssh import userauth
|
||||
from cowrie.core import keys as cowriekeys
|
||||
|
||||
|
||||
@@ -291,4 +291,3 @@ class HoneyPotTransport(transport.SSHServerTransport, TimeoutMixin):
|
||||
% (reason, desc))
|
||||
self.transport.loseConnection()
|
||||
|
||||
|
||||
@@ -45,10 +45,11 @@ from twisted.cred import portal
|
||||
|
||||
from cowrie.core.config import readConfigFile
|
||||
from cowrie import core
|
||||
import cowrie.core.transport
|
||||
import cowrie.core.realm
|
||||
import cowrie.core.checkers
|
||||
|
||||
import cowrie.ssh.transport
|
||||
|
||||
class Options(usage.Options):
|
||||
"""
|
||||
FIXME: Docstring
|
||||
@@ -80,6 +81,25 @@ class CowrieServiceMaker(object):
|
||||
|
||||
cfg = readConfigFile(options["config"])
|
||||
|
||||
top_service = service.MultiService()
|
||||
application = service.Application('cowrie')
|
||||
top_service.setServiceParent(application)
|
||||
|
||||
factory = cowrie.ssh.transport.HoneyPotSSHFactory(cfg)
|
||||
|
||||
factory.portal = portal.Portal(core.realm.HoneyPotRealm(cfg))
|
||||
factory.portal.registerChecker(
|
||||
core.checkers.HoneypotPublicKeyChecker())
|
||||
factory.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'):
|
||||
factory.portal.registerChecker(
|
||||
core.checkers.HoneypotNoneChecker())
|
||||
|
||||
|
||||
if cfg.has_option('honeypot', 'listen_addr'):
|
||||
listen_addr = cfg.get('honeypot', 'listen_addr')
|
||||
else:
|
||||
@@ -93,23 +113,9 @@ class CowrieServiceMaker(object):
|
||||
else:
|
||||
listen_port = 2222
|
||||
|
||||
factory = core.transport.HoneyPotSSHFactory(cfg)
|
||||
factory.portal = portal.Portal(core.realm.HoneyPotRealm(cfg))
|
||||
factory.portal.registerChecker(
|
||||
core.checkers.HoneypotPublicKeyChecker())
|
||||
factory.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'):
|
||||
factory.portal.registerChecker(
|
||||
core.checkers.HoneypotNoneChecker())
|
||||
|
||||
top_service = top_service = service.MultiService()
|
||||
|
||||
for i in listen_addr.split():
|
||||
svc = internet.TCPServer(listen_port, factory, interface=i)
|
||||
# FIXME: Use addService on top_service ?
|
||||
svc.setServiceParent(top_service)
|
||||
|
||||
if cfg.has_option('honeypot', 'interact_enabled') and \
|
||||
@@ -118,11 +124,10 @@ class CowrieServiceMaker(object):
|
||||
iport = int(cfg.get('honeypot', 'interact_port'))
|
||||
from cowrie.core import interact
|
||||
svc = internet.TCPServer(iport,
|
||||
interact.makeInteractFactory(factory))
|
||||
interact.makeInteractFactory(factory), interface='127.0.0.1')
|
||||
# FIXME: Use addService on top_service ?
|
||||
svc.setServiceParent(top_service)
|
||||
|
||||
application = service.Application('cowrie')
|
||||
top_service.setServiceParent(application)
|
||||
return top_service
|
||||
|
||||
# Now construct an object which *provides* the relevant interfaces
|
||||
|
||||
Reference in New Issue
Block a user