diff --git a/.gitattributes b/.gitattributes index c193e24..75e0ec9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -fs.pickle -diff binary +data/fs.pickle -diff binary diff --git a/.gitignore b/.gitignore index c0b8620..02df6d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -kippo.cfg -kippo.pid +cowrie.cfg +cowrie.pid data/lastlog.txt data/ssh_host_dsa_key data/ssh_host_dsa_key.pub @@ -8,13 +8,11 @@ data/ssh_host_rsa_key.pub dl/* log/* log/tty/* -kippo-textlog.log +cowrie-textlog.log private.key public.key - __pycache__/ *.py[cod] - env/ env1/ env2/ diff --git a/CHANGELOG.md b/CHANGELOG.md index f2e0f87..48adcd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ * stdin is saved as a file in dl/ when using exec commands to support commands like 'cat >file; ./file' * allow wget download over non-80 port -* simple JSON logging to kippo.json +* simple JSON logging added * accept log and deny publickey authentication * add uname -r, -m flags * add working sleep command diff --git a/README.md b/README.md index efb80c4..31e1b13 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Kippo -Kippo is a medium interaction SSH honeypot designed to log brute force attacks and, most importantly, the entire shell interaction performed by the attacker. +Cowrie is a medium interaction SSH honeypot designed to log brute force attacks and, most importantly, the entire shell interaction performed by the attacker. +Kippo is directly based on [Kippo] by desaster (http://github.com/desaster/kippo/). Kippo is inspired, but not based on [Kojoney](http://kojoney.sourceforge.net/). ## Features @@ -10,7 +11,7 @@ Some interesting features: * Fake filesystem with the ability to add/remove files. A full fake filesystem resembling a Debian 5.0 installation is included * Possibility of adding fake file contents so the attacker can 'cat' files such as /etc/passwd. Only minimal file contents are included * Session logs stored in an [UML Compatible](http://user-mode-linux.sourceforge.net/) format for easy replay with original timings -* Kippo saves files downloaded with wget or uploaded with SFTP for later inspection +* Kippo saves files downloaded with wget/curl or uploaded with SFTP and scp for later inspection ## Requirements @@ -27,24 +28,25 @@ See Wiki for some installation instructions. ## How to run it? -Edit kippo.cfg to your liking and start the honeypot by running: +Edit cowrie.cfg to your liking and start the honeypot by running: `./start.sh` -start.sh is a simple shell script that runs Kippo in the background using twistd. Detailed startup options can be given by running twistd manually. For example, to run Kippo in foreground: +start.sh is a simple shell script that runs Cowrie in the background using twistd. Detailed startup options can be given by running twistd manually. For example, to run Cowrie in foreground: -`twistd -y kippo.tac -n` +`twistd -y cowrie.tac -n` -By default Kippo listens for ssh connections on port 2222. You can change this, but do not change it to 22 as it requires root privileges. Use port forwarding instead. (More info: [MakingKippoReachable](https://github.com/desaster/kippo/wiki/Making-Kippo-Reachable)). +By default Cowrie listens for ssh connections on port 2222. You can change this, but do not change it to 22 as it requires root privileges. Use port forwarding instead. (More info: [MakingKippoReachable](https://github.com/desaster/kippo/wiki/Making-Kippo-Reachable)). Files of interest: * dl/ - files downloaded with wget are stored here -* log/kippo.log - log/debug output +* log/cowrie.log - log/debug output +* log/cowrie.json - transaction output in JSON format * log/tty/ - session logs * utils/playlog.py - utility to replay session logs * utils/createfs.py - used to create fs.pickle -* fs.pickle - fake filesystem +* data/fs.pickle - fake filesystem * honeyfs/ - file contents for the fake filesystem - feel free to copy a real system here ## Is it secure? @@ -53,4 +55,4 @@ Maybe. See [FAQ](https://github.com/desaster/kippo/wiki/FAQ) ## I have some questions! -Please visit https://github.com/micheloosterhof/kippo/issues +Please visit https://github.com/micheloosterhof/cowrie/issues diff --git a/kippo.cfg.dist b/cowrie.cfg.dist similarity index 90% rename from kippo.cfg.dist rename to cowrie.cfg.dist index cfe20b0..468cc8a 100644 --- a/kippo.cfg.dist +++ b/cowrie.cfg.dist @@ -1,10 +1,10 @@ # -# Kippo configuration file (kippo.cfg) +# Cowrie configuration file (cowrie.cfg) # [honeypot] -# Sensor name use to identify this kippo instance. Used by the database +# Sensor name use to identify this cowrie instance. Used by the database # logging modules such as mysql. # # If not specified, the logging modules will instead use the IP address of the @@ -71,7 +71,7 @@ data_path = data # Class that implements the checklogin() method. # -# Class must be defined in kippo/core/auth.py +# Class must be defined in cowrie/core/auth.py # Default is the 'UserDB' class which uses the password database. # # Alternatively the 'AuthRandom' class can be used, which will let @@ -134,7 +134,7 @@ sftp_enabled = true #fake_addr = 192.168.66.254 # The IP address on which this machine reachable on from the internet. -# Useful if you use portforwarding or other mechanisms. If empty, the kippo +# Useful if you use portforwarding or other mechanisms. If empty, the cowrie # will determine by itself. Used in 'netstat' output #internet_facing_ip = 9.9.9.9 @@ -195,8 +195,8 @@ interact_port = 5123 #[database_mysql] #host = localhost -#database = kippo -#username = kippo +#database = cowrie +#username = cowrie #password = secret #port = 3306 @@ -213,33 +213,28 @@ interact_port = 5123 #user = anonymous@sensors.carnivore.it #password = anonymous #muc = dionaea.sensors.carnivore.it -#signal_createsession = kippo-events -#signal_connectionlost = kippo-events -#signal_loginfailed = kippo-events -#signal_loginsucceeded = kippo-events -#signal_command = kippo-events -#signal_clientversion = kippo-events +#signal_createsession = cowrie-events +#signal_connectionlost = cowrie-events +#signal_loginfailed = cowrie-events +#signal_loginsucceeded = cowrie-events +#signal_command = cowrie-events +#signal_clientversion = cowrie-events #debug=true # Text based logging module # # While this is a database logging module, it actually just creates a simple # text based log. This may not have much purpose, if you're fine with the -# default text based logs generated by kippo in log/ +# default text based logs generated by cowrie in log/ # # To enable this module, remove the comments below, including the # [database_textlog] line. #[database_textlog] -#logfile = log/kippo-textlog.log +#logfile = log/cowrie-textlog.log -# deprecated JSON based logging module -#[database_jsonlog] -#logfile = log/kippolog.json - -# new default output module -[output_jsonlog] -logfile = log/kippo.json +# JSON output module [output_jsonlog] +logfile = log/cowrie.json #[database_hpfeeds] #server = hpfeeds.mysite.org diff --git a/kippo.tac b/cowrie.tac similarity index 89% rename from kippo.tac rename to cowrie.tac index b92bbc9..00641d9 100644 --- a/kippo.tac +++ b/cowrie.tac @@ -13,17 +13,17 @@ from twisted.cred import portal from twisted.conch.ssh import factory, keys if os.name == 'posix' and os.getuid() == 0: - print 'ERROR: You must not run kippo as root!' + print 'ERROR: You must not run cowrie as root!' sys.exit(1) -if not os.path.exists('kippo.cfg'): - print 'ERROR: kippo.cfg is missing!' +if not os.path.exists('cowrie.cfg'): + print 'ERROR: cowrie.cfg is missing!' sys.exit(1) -from kippo.core.config import config -import kippo.core.honeypot -import kippo.core.ssh -from kippo import core +from cowrie.core.config import config +import cowrie.core.honeypot +import cowrie.core.ssh +from cowrie import core factory = core.ssh.HoneyPotSSHFactory() factory.portal = portal.Portal(core.ssh.HoneyPotRealm()) @@ -66,7 +66,7 @@ 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 cowrie.core import interact service = internet.TCPServer(iport, interact.makeInteractFactory(factory)) service.setServiceParent(application) diff --git a/kippo/__init__.py b/cowrie/__init__.py similarity index 100% rename from kippo/__init__.py rename to cowrie/__init__.py diff --git a/kippo/commands/__init__.py b/cowrie/commands/__init__.py similarity index 100% rename from kippo/commands/__init__.py rename to cowrie/commands/__init__.py diff --git a/kippo/commands/adduser.py b/cowrie/commands/adduser.py similarity index 98% rename from kippo/commands/adduser.py rename to cowrie/commands/adduser.py index ced34fd..bd980e6 100644 --- a/kippo/commands/adduser.py +++ b/cowrie/commands/adduser.py @@ -5,7 +5,7 @@ import random from twisted.internet import reactor -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/apt.py b/cowrie/commands/apt.py similarity index 98% rename from kippo/commands/apt.py rename to cowrie/commands/apt.py index f213949..a434300 100644 --- a/kippo/commands/apt.py +++ b/cowrie/commands/apt.py @@ -7,7 +7,7 @@ import re from twisted.internet import reactor, defer from twisted.internet.defer import inlineCallbacks -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/base.py b/cowrie/commands/base.py similarity index 99% rename from kippo/commands/base.py rename to cowrie/commands/base.py index 38930ae..8c0cb00 100644 --- a/kippo/commands/base.py +++ b/cowrie/commands/base.py @@ -7,10 +7,10 @@ import datetime from twisted.internet import reactor from twisted.python import log -from kippo.core.honeypot import HoneyPotCommand -from kippo.core.config import config -from kippo.core.auth import UserDB -from kippo.core import utils +from cowrie.core.honeypot import HoneyPotCommand +from cowrie.core.config import config +from cowrie.core.auth import UserDB +from cowrie.core import utils commands = {} diff --git a/kippo/commands/curl.py b/cowrie/commands/curl.py similarity index 99% rename from kippo/commands/curl.py rename to cowrie/commands/curl.py index 8f55364..a7cd919 100644 --- a/kippo/commands/curl.py +++ b/cowrie/commands/curl.py @@ -15,8 +15,8 @@ from twisted.web import client from twisted.internet import reactor from twisted.python import log -from kippo.core.honeypot import HoneyPotCommand -from kippo.core.fs import * +from cowrie.core.honeypot import HoneyPotCommand +from cowrie.core.fs import * commands = {} diff --git a/kippo/commands/dice.py b/cowrie/commands/dice.py similarity index 96% rename from kippo/commands/dice.py rename to cowrie/commands/dice.py index dd1de70..ec52d7f 100644 --- a/kippo/commands/dice.py +++ b/cowrie/commands/dice.py @@ -3,7 +3,7 @@ # Random commands when running new executables -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} clist = [] diff --git a/kippo/commands/fs.py b/cowrie/commands/fs.py similarity index 99% rename from kippo/commands/fs.py rename to cowrie/commands/fs.py index b27518b..700b617 100644 --- a/kippo/commands/fs.py +++ b/cowrie/commands/fs.py @@ -5,8 +5,8 @@ import os import getopt import copy -from kippo.core.honeypot import HoneyPotCommand -from kippo.core.fs import * +from cowrie.core.honeypot import HoneyPotCommand +from cowrie.core.fs import * commands = {} diff --git a/kippo/commands/gcc.py b/cowrie/commands/gcc.py similarity index 99% rename from kippo/commands/gcc.py rename to cowrie/commands/gcc.py index d3f55a4..50a2cd2 100644 --- a/kippo/commands/gcc.py +++ b/cowrie/commands/gcc.py @@ -7,7 +7,7 @@ import random from twisted.internet import reactor -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/iptables.py b/cowrie/commands/iptables.py similarity index 99% rename from kippo/commands/iptables.py rename to cowrie/commands/iptables.py index 3952d91..503fdd9 100644 --- a/kippo/commands/iptables.py +++ b/cowrie/commands/iptables.py @@ -2,7 +2,7 @@ import optparse -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/last.py b/cowrie/commands/last.py similarity index 84% rename from kippo/commands/last.py rename to cowrie/commands/last.py index 98ff92c..7026f15 100644 --- a/kippo/commands/last.py +++ b/cowrie/commands/last.py @@ -1,10 +1,10 @@ # Copyright (c) 2009 Upi Tamminen # See the COPYRIGHT file for more information -from kippo.core.honeypot import HoneyPotCommand -from kippo.core.fs import * -from kippo.core.config import config -from kippo.core import utils +from cowrie.core.honeypot import HoneyPotCommand +from cowrie.core.fs import * +from cowrie.core.config import config +from cowrie.core import utils commands = {} diff --git a/kippo/commands/ls.py b/cowrie/commands/ls.py similarity index 98% rename from kippo/commands/ls.py rename to cowrie/commands/ls.py index c093bed..2ae1176 100644 --- a/kippo/commands/ls.py +++ b/cowrie/commands/ls.py @@ -4,8 +4,8 @@ import stat import time -from kippo.core.honeypot import HoneyPotCommand -from kippo.core.fs import * +from cowrie.core.honeypot import HoneyPotCommand +from cowrie.core.fs import * commands = {} diff --git a/kippo/commands/malware.py b/cowrie/commands/malware.py similarity index 98% rename from kippo/commands/malware.py rename to cowrie/commands/malware.py index e82aecc..447e6b6 100644 --- a/kippo/commands/malware.py +++ b/cowrie/commands/malware.py @@ -3,7 +3,7 @@ # Commands mapped to common malware -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} clist = {} # names diff --git a/kippo/commands/netstat.py b/cowrie/commands/netstat.py similarity index 99% rename from kippo/commands/netstat.py rename to cowrie/commands/netstat.py index 727f8bb..d646856 100644 --- a/kippo/commands/netstat.py +++ b/cowrie/commands/netstat.py @@ -2,7 +2,7 @@ import socket -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/ping.py b/cowrie/commands/ping.py similarity index 97% rename from kippo/commands/ping.py rename to cowrie/commands/ping.py index 4ba3cec..7e7ea21 100644 --- a/kippo/commands/ping.py +++ b/cowrie/commands/ping.py @@ -8,7 +8,7 @@ import socket from twisted.internet import reactor -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/scp.py b/cowrie/commands/scp.py similarity index 98% rename from kippo/commands/scp.py rename to cowrie/commands/scp.py index 22aeb34..3cd041d 100644 --- a/kippo/commands/scp.py +++ b/cowrie/commands/scp.py @@ -28,7 +28,7 @@ import getopt -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/sleep.py b/cowrie/commands/sleep.py similarity index 90% rename from kippo/commands/sleep.py rename to cowrie/commands/sleep.py index 2e43dd5..2880b28 100644 --- a/kippo/commands/sleep.py +++ b/cowrie/commands/sleep.py @@ -1,7 +1,7 @@ from twisted.internet import reactor -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/ssh.py b/cowrie/commands/ssh.py similarity index 98% rename from kippo/commands/ssh.py rename to cowrie/commands/ssh.py index 6cc6264..0340353 100644 --- a/kippo/commands/ssh.py +++ b/cowrie/commands/ssh.py @@ -10,7 +10,7 @@ import socket from twisted.python import log from twisted.internet import reactor -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/tar.py b/cowrie/commands/tar.py similarity index 96% rename from kippo/commands/tar.py rename to cowrie/commands/tar.py index 3e4a84d..e88cb45 100644 --- a/kippo/commands/tar.py +++ b/cowrie/commands/tar.py @@ -7,9 +7,9 @@ import os from twisted.python import log -from kippo.core.honeypot import HoneyPotCommand -from kippo.core.fs import * -from kippo.commands import dice, malware +from cowrie.core.honeypot import HoneyPotCommand +from cowrie.core.fs import * +from cowrie.commands import dice, malware commands = {} diff --git a/kippo/commands/uname.py b/cowrie/commands/uname.py similarity index 92% rename from kippo/commands/uname.py rename to cowrie/commands/uname.py index 5070fa4..9b8b3c9 100644 --- a/kippo/commands/uname.py +++ b/cowrie/commands/uname.py @@ -1,6 +1,6 @@ # -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/commands/wget.py b/cowrie/commands/wget.py similarity index 99% rename from kippo/commands/wget.py rename to cowrie/commands/wget.py index dc8cd45..8a5de10 100644 --- a/kippo/commands/wget.py +++ b/cowrie/commands/wget.py @@ -13,8 +13,8 @@ from twisted.web import client from twisted.internet import reactor from twisted.python import log -from kippo.core.honeypot import HoneyPotCommand -from kippo.core.fs import * +from cowrie.core.honeypot import HoneyPotCommand +from cowrie.core.fs import * commands = {} diff --git a/kippo/commands/which.py b/cowrie/commands/which.py similarity index 93% rename from kippo/commands/which.py rename to cowrie/commands/which.py index a9c3412..fedf421 100644 --- a/kippo/commands/which.py +++ b/cowrie/commands/which.py @@ -1,6 +1,6 @@ # Copyright (c) 2013 Bas Stottelaar -from kippo.core.honeypot import HoneyPotCommand +from cowrie.core.honeypot import HoneyPotCommand commands = {} diff --git a/kippo/core/__init__.py b/cowrie/core/__init__.py similarity index 100% rename from kippo/core/__init__.py rename to cowrie/core/__init__.py diff --git a/kippo/core/auth.py b/cowrie/core/auth.py similarity index 98% rename from kippo/core/auth.py rename to cowrie/core/auth.py index 4c5af88..f84597e 100644 --- a/kippo/core/auth.py +++ b/cowrie/core/auth.py @@ -64,7 +64,7 @@ class UserDB(object): save the user db """ - # Note: this is subject to races between kippo instances, but hey ... + # Note: this is subject to races between cowrie instances, but hey ... f = open(self.userdb_file, 'w') for (login, uid, passwd) in self.userdb: f.write('%s:%d:%s\n' % (login, uid, passwd)) @@ -154,7 +154,7 @@ class AuthRandom(object): def savevars(self): # Save the user vars to json file data = self.uservar - # Note: this is subject to races between kippo logins + # Note: this is subject to races between cowrie logins with open(self.uservar_file, 'wb') as fp: json.dump(data, fp) diff --git a/kippo/core/config.py b/cowrie/core/config.py similarity index 80% rename from kippo/core/config.py rename to cowrie/core/config.py index 6c92629..b670555 100644 --- a/kippo/core/config.py +++ b/cowrie/core/config.py @@ -6,7 +6,7 @@ import ConfigParser def config(): cfg = ConfigParser.ConfigParser() - for f in ('kippo.cfg', '/etc/kippo/kippo.cfg', '/etc/kippo.cfg'): + for f in ('cowrie.cfg', '/etc/cowrie/cowrie.cfg', '/etc/cowrie.cfg'): if os.path.exists(f): cfg.read(f) return cfg diff --git a/kippo/core/connection.py b/cowrie/core/connection.py similarity index 97% rename from kippo/core/connection.py rename to cowrie/core/connection.py index 24fade6..acee9f3 100644 --- a/kippo/core/connection.py +++ b/cowrie/core/connection.py @@ -34,7 +34,7 @@ from twisted.internet import defer MSG_CHANNEL_SUCCESS = 99 -class KippoSSHConnection(connection.SSHConnection): +class CowrieSSHConnection(connection.SSHConnection): """ Subclass this for a workaround for the Granados SSH library. Channel request for openshell needs to return success immediatly diff --git a/kippo/core/dblog.py b/cowrie/core/dblog.py similarity index 100% rename from kippo/core/dblog.py rename to cowrie/core/dblog.py diff --git a/kippo/core/exceptions.py b/cowrie/core/exceptions.py similarity index 100% rename from kippo/core/exceptions.py rename to cowrie/core/exceptions.py diff --git a/kippo/core/fs.py b/cowrie/core/fs.py similarity index 100% rename from kippo/core/fs.py rename to cowrie/core/fs.py diff --git a/kippo/core/honeypot.py b/cowrie/core/honeypot.py similarity index 98% rename from kippo/core/honeypot.py rename to cowrie/core/honeypot.py index b2d93fa..1028dbc 100644 --- a/kippo/core/honeypot.py +++ b/cowrie/core/honeypot.py @@ -256,9 +256,9 @@ class HoneyPotEnvironment(object): def __init__(self): self.cfg = config() self.commands = {} - import kippo.commands - for c in kippo.commands.__all__: - module = __import__('kippo.commands.%s' % c, + import cowrie.commands + for c in cowrie.commands.__all__: + module = __import__('cowrie.commands.%s' % c, globals(), locals(), ['commands']) self.commands.update(module.commands) self.fs = pickle.load(file( diff --git a/kippo/core/interact.py b/cowrie/core/interact.py similarity index 98% rename from kippo/core/interact.py rename to cowrie/core/interact.py index 61c2ea7..5d8ca32 100644 --- a/kippo/core/interact.py +++ b/cowrie/core/interact.py @@ -20,7 +20,7 @@ class Interact(telnet.Telnet): self.requestNegotiation(telnet.LINEMODE, telnet.LINEMODE_EDIT + '\0') self.will(telnet.ECHO) - self.transport.write('*** kippo session management console ***\r\n') + self.transport.write('*** cowrie session management console ***\r\n') self.cmd_help() def connectionLost(self, reason): diff --git a/kippo/core/output.py b/cowrie/core/output.py similarity index 99% rename from kippo/core/output.py rename to cowrie/core/output.py index 6a92414..aeff758 100644 --- a/kippo/core/output.py +++ b/cowrie/core/output.py @@ -49,7 +49,7 @@ import uuid class Output(object): """ - This is the abstract base class intended to be inherited by kippo output plugins + This is the abstract base class intended to be inherited by cowrie output plugins Plugins require the mandatory methods: stop, start and write """ diff --git a/kippo/core/protocol.py b/cowrie/core/protocol.py similarity index 100% rename from kippo/core/protocol.py rename to cowrie/core/protocol.py diff --git a/kippo/core/ssh.py b/cowrie/core/ssh.py similarity index 94% rename from kippo/core/ssh.py rename to cowrie/core/ssh.py index 92e4d61..932fc14 100644 --- a/kippo/core/ssh.py +++ b/cowrie/core/ssh.py @@ -78,7 +78,7 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer): class HoneyPotSSHFactory(factory.SSHFactory): services = { 'ssh-userauth': HoneyPotSSHUserAuthServer, - 'ssh-connection': connection.KippoSSHConnection, + 'ssh-connection': connection.CowrieSSHConnection, } # Special delivery to the loggers to avoid scope problems @@ -113,7 +113,7 @@ class HoneyPotSSHFactory(factory.SSHFactory): lcfg.set('honeypot', i, cfg.get('honeypot', i)) log.msg('Loading dblog engine: %s' % (engine,)) dblogger = __import__( - 'kippo.dblog.%s' % (engine,), + 'cowrie.dblog.%s' % (engine,), globals(), locals(), ['dblog']).DBLogger(lcfg) log.startLoggingWithObserver(dblogger.emit, setStdout=False) self.dbloggers.append(dblogger) @@ -134,7 +134,7 @@ class HoneyPotSSHFactory(factory.SSHFactory): lcfg.set('honeypot', i, cfg.get('honeypot', i)) log.msg('Loading output engine: %s' % (engine,)) output = __import__( - 'kippo.output.%s' % (engine,) + 'cowrie.output.%s' % (engine,) ,globals(), locals(), ['output']).Output(lcfg) log.startLoggingWithObserver(output.emit, setStdout=False) self.output_plugins.append(output) @@ -196,7 +196,7 @@ class HoneyPotRealm: else: raise Exception("No supported interfaces found.") -class HoneyPotTransport(sshserver.KippoSSHServerTransport): +class HoneyPotTransport(sshserver.CowrieSSHServerTransport): """ """ @@ -210,16 +210,16 @@ class HoneyPotTransport(sshserver.KippoSSHServerTransport): dst_ip=self.transport.getHost().host, dst_port=self.transport.getHost().port, sessionno=self.transport.sessionno) - sshserver.KippoSSHServerTransport.connectionMade(self) + sshserver.CowrieSSHServerTransport.connectionMade(self) def sendKexInit(self): # Don't send key exchange prematurely if not self.gotVersion: return - sshserver.KippoSSHServerTransport.sendKexInit(self) + sshserver.CowrieSSHServerTransport.sendKexInit(self) def dataReceived(self, data): - sshserver.KippoSSHServerTransport.dataReceived(self, data) + sshserver.CowrieSSHServerTransport.dataReceived(self, data) # later versions seem to call sendKexInit again on their own if twisted.version.major < 11 and \ not self._hadVersion and self.gotVersion: @@ -241,7 +241,7 @@ class HoneyPotTransport(sshserver.KippoSSHServerTransport): kexAlgs=kexAlgs, keyAlgs=keyAlgs, encCS=encCS, macCS=macCS, compCS=compCS, format='Remote SSH version: %(version)s') - return sshserver.KippoSSHServerTransport.ssh_KEXINIT(self, packet) + return sshserver.CowrieSSHServerTransport.ssh_KEXINIT(self, packet) # this seems to be the only reliable place of catching lost connection def connectionLost(self, reason): @@ -249,7 +249,7 @@ class HoneyPotTransport(sshserver.KippoSSHServerTransport): i.sessionClosed() if self.transport.sessionno in self.factory.sessions: del self.factory.sessions[self.transport.sessionno] - sshserver.KippoSSHServerTransport.connectionLost(self, reason) + sshserver.CowrieSSHServerTransport.connectionLost(self, reason) log.msg(eventid='KIPP0011', format='Connection lost') class HoneyPotSSHSession(session.SSHSession): @@ -310,7 +310,7 @@ class HoneyPotAvatar(avatar.ConchUser): self.protocol = None self.channelLookup.update({'session': HoneyPotSSHSession}) - self.channelLookup['direct-tcpip'] = KippoOpenConnectForwardingClient + self.channelLookup['direct-tcpip'] = CowrieOpenConnectForwardingClient # sftp support enabled only when option is explicitly set if self.env.cfg.has_option('honeypot', 'sftp_enabled'): @@ -416,7 +416,7 @@ def getDSAKeys(): return publicKeyString, privateKeyString @implementer(conchinterfaces.ISFTPFile) -class KippoSFTPFile: +class CowrieSFTPFile: def __init__(self, server, filename, flags, attrs): self.server = server @@ -472,7 +472,7 @@ class KippoSFTPFile: def setAttrs(self, attrs): raise NotImplementedError -class KippoSFTPDirectory: +class CowrieSFTPDirectory: def __init__(self, server, directory): self.server = server @@ -497,7 +497,7 @@ class KippoSFTPDirectory: self.files = [] @implementer(conchinterfaces.ISFTPServer) -class KippoSFTPServer: +class CowrieSFTPServer: def __init__(self, avatar): self.avatar = avatar @@ -530,7 +530,7 @@ class KippoSFTPServer: def openFile(self, filename, flags, attrs): log.msg("SFTP openFile: %s" % filename) - return KippoSFTPFile(self, self._absPath(filename), flags, attrs) + return CowrieSFTPFile(self, self._absPath(filename), flags, attrs) def removeFile(self, filename): log.msg("SFTP removeFile: %s" % filename) @@ -553,7 +553,7 @@ class KippoSFTPServer: def openDirectory(self, path): log.msg("SFTP OpenDirectory: %s" % path) - return KippoSFTPDirectory(self, self._absPath(path)) + return CowrieSFTPDirectory(self, self._absPath(path)) def getAttrs(self, path, followLinks): log.msg("SFTP getAttrs: %s" % path) @@ -587,17 +587,17 @@ class KippoSFTPServer: def extendedRequest(self, extName, extData): raise NotImplementedError -components.registerAdapter(KippoSFTPServer, HoneyPotAvatar, conchinterfaces.ISFTPServer) +components.registerAdapter(CowrieSFTPServer, HoneyPotAvatar, conchinterfaces.ISFTPServer) -def KippoOpenConnectForwardingClient(remoteWindow, remoteMaxPacket, data, avatar): +def CowrieOpenConnectForwardingClient(remoteWindow, remoteMaxPacket, data, avatar): remoteHP, origHP = twisted.conch.ssh.forwarding.unpackOpen_direct_tcpip(data) log.msg("direct-tcp connection attempt to %s:%i" % remoteHP) - return KippoConnectForwardingChannel(remoteHP, + return CowrieConnectForwardingChannel(remoteHP, remoteWindow=remoteWindow, remoteMaxPacket=remoteMaxPacket, avatar=avatar) -class KippoConnectForwardingChannel(forwarding.SSHConnectForwardingChannel): +class CowrieConnectForwardingChannel(forwarding.SSHConnectForwardingChannel): def channelOpen(self, specificData): log.msg("Faking channel open %s:%i" % self.hostport) diff --git a/kippo/core/sshserver.py b/cowrie/core/sshserver.py similarity index 98% rename from kippo/core/sshserver.py rename to cowrie/core/sshserver.py index 2a9c6c5..484cc87 100644 --- a/kippo/core/sshserver.py +++ b/cowrie/core/sshserver.py @@ -29,7 +29,7 @@ from twisted.conch.ssh import transport from twisted.python import log -class KippoSSHServerTransport(transport.SSHServerTransport): +class CowrieSSHServerTransport(transport.SSHServerTransport): def connectionMade(self): """ Called when the connection is made to the other side. We sent our diff --git a/kippo/core/ttylog.py b/cowrie/core/ttylog.py similarity index 100% rename from kippo/core/ttylog.py rename to cowrie/core/ttylog.py diff --git a/kippo/core/utils.py b/cowrie/core/utils.py similarity index 100% rename from kippo/core/utils.py rename to cowrie/core/utils.py diff --git a/kippo/dblog/__init__.py b/cowrie/dblog/__init__.py similarity index 100% rename from kippo/dblog/__init__.py rename to cowrie/dblog/__init__.py diff --git a/kippo/dblog/hpfeeds.py b/cowrie/dblog/hpfeeds.py similarity index 99% rename from kippo/dblog/hpfeeds.py rename to cowrie/dblog/hpfeeds.py index e34d6a8..59ea12d 100644 --- a/kippo/dblog/hpfeeds.py +++ b/cowrie/dblog/hpfeeds.py @@ -1,6 +1,6 @@ ## From https://github.com/threatstream/kippo/blob/master/kippo/dblog/hpfeeds.py -from kippo.core import dblog +from cowrie.core import dblog from twisted.python import log from datetime import datetime @@ -28,7 +28,7 @@ SIZES = { OP_SUBSCRIBE: 5+256*2, } -KIPPOCHAN = 'kippo.sessions' +KIPPOCHAN = 'cowrie.sessions' class BadClient(Exception): pass diff --git a/kippo/dblog/mysql.py b/cowrie/dblog/mysql.py similarity index 99% rename from kippo/dblog/mysql.py rename to cowrie/dblog/mysql.py index ac9a8f6..212cde7 100644 --- a/kippo/dblog/mysql.py +++ b/cowrie/dblog/mysql.py @@ -1,4 +1,4 @@ -from kippo.core import dblog +from cowrie.core import dblog from twisted.enterprise import adbapi from twisted.internet import defer from twisted.python import log diff --git a/kippo/dblog/textlog.py b/cowrie/dblog/textlog.py similarity index 98% rename from kippo/dblog/textlog.py rename to cowrie/dblog/textlog.py index 9f8169c..15d1733 100644 --- a/kippo/dblog/textlog.py +++ b/cowrie/dblog/textlog.py @@ -3,7 +3,7 @@ # ..so not exactly a dblog. # -from kippo.core import dblog +from cowrie.core import dblog import time import uuid diff --git a/kippo/dblog/xmpp.py b/cowrie/dblog/xmpp.py similarity index 99% rename from kippo/dblog/xmpp.py rename to cowrie/dblog/xmpp.py index 1549734..f9899a0 100644 --- a/kippo/dblog/xmpp.py +++ b/cowrie/dblog/xmpp.py @@ -45,7 +45,7 @@ class XMPPLoggerProtocol(muc.MUCClient): from twisted.application import service from twisted.words.protocols.jabber import jid from wokkel.client import XMPPClient -from kippo.core import dblog +from cowrie.core import dblog from twisted.words.xish import domish class DBLogger(dblog.DBLogger): diff --git a/kippo/output/README.md b/cowrie/output/README.md similarity index 59% rename from kippo/output/README.md rename to cowrie/output/README.md index dbdfdeb..3915002 100644 --- a/kippo/output/README.md +++ b/cowrie/output/README.md @@ -1,11 +1,11 @@ To create additional output plugins, place Python modules in this directory. -Plugins need to subclass kippo.core.output.Output and define at least the +Plugins need to subclass cowrie.core.output.Output and define at least the methods 'start', 'stop' and 'handleLog' - import kippo.core.output + import cowrie.core.output - class Output(kippo.core.output.Output): + class Output(cowrie.core.output.Output): def start(self, cfg): diff --git a/kippo/output/__init__.py b/cowrie/output/__init__.py similarity index 100% rename from kippo/output/__init__.py rename to cowrie/output/__init__.py diff --git a/kippo/output/jsonlog.py b/cowrie/output/jsonlog.py similarity index 94% rename from kippo/output/jsonlog.py rename to cowrie/output/jsonlog.py index f86f13f..1bb900b 100644 --- a/kippo/output/jsonlog.py +++ b/cowrie/output/jsonlog.py @@ -31,12 +31,12 @@ import os import twisted.python.logfile -import kippo.core.output +import cowrie.core.output -class Output(kippo.core.output.Output): +class Output(cowrie.core.output.Output): def __init__(self, cfg): - kippo.core.output.Output.__init__(self, cfg) + cowrie.core.output.Output.__init__(self, cfg) fn = cfg.get('output_jsonlog', 'logfile') dirs = os.path.dirname(fn) base = os.path.basename(fn) diff --git a/fs.pickle b/data/fs.pickle similarity index 100% rename from fs.pickle rename to data/fs.pickle diff --git a/kippo/dblog/jsonlog.py b/kippo/dblog/jsonlog.py deleted file mode 100644 index 7d70b6b..0000000 --- a/kippo/dblog/jsonlog.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) 2015 Michel Oosterhof -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. The names of the author(s) may not be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. - -import datetime -import uuid -import json - -from ..core import dblog - -class DBLogger(dblog.DBLogger): - - def __init__(self, cfg): - self.sensor = "" - self.outfile = "" - dblog.DBLogger.__init__(self, cfg) - - def start(self, cfg): - self.outfile = file(cfg.get('database_jsonlog', 'logfile'), 'a') - - def write(self, session, logentry): - _meta = { - 'session' : session, - 'sensor' : self.sensor, - 'timestamp' : datetime.datetime.utcnow().isoformat() + 'Z' - } - logentry.update( _meta ) - json.dump( logentry, self.outfile ) - self.outfile.write( '\n' ) - self.outfile.flush() - - def createSession(self, peerIP, peerPort, hostIP, hostPort): - sid = uuid.uuid4().hex - logentry = { 'message' : 'New connection: %s:%s' % (peerIP, peerPort), 'src_ip' : peerIP } - self.sensor = self.getSensor() or hostIP - self.write(sid, logentry ) - return sid - - def handleConnectionLost(self, session, args): - logentry = { 'message': 'Connection lost' } - self.write( session, logentry ) - #ttylog = self.ttylog(session) - #if ttylog: - # self.write( session, { 'message': repr(ttylog) } ) - - def handleLoginFailed(self, session, args): - logentry = { 'message' : 'Login failed [%s/%s]' % (args['username'], args['password']), 'username' : args['username'], 'password' : args['password'] } - self.write( session, logentry ) - - def handleLoginSucceeded(self, session, args): - logentry = { 'message' : 'Login succeeded [%s/%s]' % (args['username'], args['password']), 'username' : args['username'], 'password' : args['password'] } - self.write( session, logentry ) - - def handleCommand(self, session, args): - logentry = { 'message' : 'command [%s]' % (args['input'],), 'command' : args['input'] } - self.write( session, logentry ) - - def handleUnknownCommand(self, session, args): - logentry = { 'message' : 'unknown command [%s]' % (args['input'],), 'command' : args['input'] } - self.write( session, logentry ) - - def handleInput(self, session, args): - logentry = { 'message' : 'input [%s] @%s' % (args['input'], args['realm']), 'command' : args['input'] } - self.write( session, logentry ) - - def handleTerminalSize(self, session, args): - logentry = { 'message' : 'Terminal size: %sx%s' % (args['width'], args['height']) } - self.write( session, logentry ) - - def handleClientVersion(self, session, args): - logentry = { 'message' : 'Client version: [%s]' % (args['version']), 'client' : args['version'] } - self.write( session, logentry ) - - def handleFileDownload(self, session, args): - logentry = { 'message' : 'File download: [%s] -> %s' % (args['url'], args['outfile']), 'url' : args['url'], 'shasum' : args['shasum'] } - self.write( session, logentry ) - -# vim: set sw=4 et: diff --git a/start.sh b/start.sh index 8a0289e..4b4841f 100755 --- a/start.sh +++ b/start.sh @@ -24,5 +24,5 @@ then . $VENV/bin/activate fi -echo "Starting kippo in the background..." -twistd -y kippo.tac -l log/kippo.log --pidfile kippo.pid +echo "Starting cowrie in the background..." +twistd -y cowrie.tac -l log/cowrie.log --pidfile cowrie.pid diff --git a/stop.sh b/stop.sh index ab2747f..37c49f3 100755 --- a/stop.sh +++ b/stop.sh @@ -1,12 +1,12 @@ #!/bin/sh -PIDFILE=kippo.pid +PIDFILE=cowrie.pid cd $(dirname $0) PID=$(cat $PIDFILE 2>/dev/null) if [ -n "$PID" ]; then - echo "Stopping kippo...\n" + echo "Stopping cowrie...\n" kill -TERM $PID fi diff --git a/utils/elk/README.md b/utils/elk/README.md index 0a65d8c..e930e23 100644 --- a/utils/elk/README.md +++ b/utils/elk/README.md @@ -1,12 +1,12 @@ -# How to process Kippo output in an ELK stack +# How to process Cowrie output in an ELK stack (Note: work in progress, instructions are not verified) ## Prerequisites -* Working Kippo installation -* Kippo JSON log file (enable database json in kippo.cfg) +* Working Cowrie installation +* Cowrie JSON log file (enable database json in cowrie.cfg) ## Installation @@ -40,7 +40,7 @@ wget http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz * Configure logstash ``` -cp logstash-kippo.conf /etc/logstash/conf.d +cp logstash-cowrie.conf /etc/logstash/conf.d ``` * Make sure the configuration file is correct. Check the input section (path), filter (geoip databases) and output (elasticsearch hostname) @@ -54,13 +54,13 @@ service logstash restart * To test whether logstash is working correctly, check the file in /tmp ``` -tail /tmp/kippo-logstash.log +tail /tmp/cowrie-logstash.log ``` * To test whether data is loaded into ElasticSearch, run the following query: ``` -http://:9200/_search?q=kippo&size=5 +http://:9200/_search?q=cowrie&size=5 ``` * If this gives output, your data is correctly loaded into ElasticSearch diff --git a/utils/elk/kibana-kippo.conf b/utils/elk/kibana-cowrie.conf similarity index 99% rename from utils/elk/kibana-kippo.conf rename to utils/elk/kibana-cowrie.conf index 68c083c..d8d6017 100644 --- a/utils/elk/kibana-kippo.conf +++ b/utils/elk/kibana-cowrie.conf @@ -1,5 +1,5 @@ { - "title": "Kippo2ElasticSearch", + "title": "Cowrie2ElasticSearch", "services": { "query": { "list": { @@ -22,7 +22,7 @@ "0": { "type": "terms", "field": "_type", - "value": "kippo", + "value": "cowrie", "mandate": "must", "active": true, "alias": "", diff --git a/utils/elk/logstash-kippo.conf b/utils/elk/logstash-cowrie.conf similarity index 85% rename from utils/elk/logstash-kippo.conf rename to utils/elk/logstash-cowrie.conf index 5533ac3..45503eb 100644 --- a/utils/elk/logstash-kippo.conf +++ b/utils/elk/logstash-cowrie.conf @@ -1,19 +1,19 @@ input { # this is the actual live log file to monitor file { - path => ["/home/kippo/kippo-git/log/kippo.json"] + path => ["/home/cowrie/cowrie-git/log/cowrie.json"] codec => json_lines - type => "kippo" + type => "cowrie" } # this is to send old logs to for reprocessing tcp { port => 3333 - type => "kippo" + type => "cowrie" } } filter { - if [type] == "kippo" { + if [type] == "cowrie" { json { source => message @@ -51,13 +51,13 @@ filter { } output { - if [type] == "kippo" { + if [type] == "cowrie" { elasticsearch { host => helium protocol => http } file { - path => "/tmp/kippo-logstash.log" + path => "/tmp/cowrie-logstash.log" codec => json } stdout { diff --git a/utils/fsctl.py b/utils/fsctl.py index 008a3a8..a8ac93b 100755 --- a/utils/fsctl.py +++ b/utils/fsctl.py @@ -2,14 +2,14 @@ ############################################################### # This program creates a command line interpreter used to edit -# kippo file system pickle files. +# cowrie file system pickle files. # # It is intended to mimic a basic bash shell and supports relative # file references. # # This isn't meant to build a brand new filesystem. Instead it # should be used to edit existing filesystems such as the default -# /opt/kippo/fs.pickle. +# /opt/cowrie/data/fs.pickle. # # Donovan Hubbard # Douglas Hubbard @@ -555,18 +555,18 @@ class fseditCmd(cmd.Cmd): def help_about(self): print "Kippo stores information about its file systems in a " + \ "series of nested lists. Once the lists are made, they are " + \ - "stored in a pickle file on the hard drive. Every time kippo " + \ + "stored in a pickle file on the hard drive. Every time cowrie " + \ "gets a new client, it reads from the pickle file and loads " + \ "the fake filesystem into memory. By default this file " + \ - "is /opt/kippo/fs.pickle. Originally the script " + \ - "/opt/kippo/createfs.py was used to copy the filesystem " + \ + "is /opt/cowrie/data/fs.pickle. Originally the script " + \ + "/opt/cowrie/createfs.py was used to copy the filesystem " + \ "of the existing computer. However, it quite difficult to " + \ "edit the pickle file by hand.\n\nThis script strives to be " + \ "a bash-like interface that allows users to modify " + \ "existing fs pickle files. It supports many of the " + \ "common bash commands and even handles relative file " + \ "paths. Keep in mind that you need to restart the " + \ - "kippo process in order for the new file system to be " + \ + "cowrie process in order for the new file system to be " + \ "reloaded into memory.\n\nDonovan Hubbard, Douglas Hubbard, " + \ "March 2013\nVersion 1.0"