cowrie rename

This commit is contained in:
Michel Oosterhof
2015-05-12 14:57:29 +00:00
parent a6e64f29e5
commit e6c3e71dc2
59 changed files with 136 additions and 243 deletions

2
.gitattributes vendored
View File

@@ -1 +1 @@
fs.pickle -diff binary data/fs.pickle -diff binary

8
.gitignore vendored
View File

@@ -1,5 +1,5 @@
kippo.cfg cowrie.cfg
kippo.pid cowrie.pid
data/lastlog.txt data/lastlog.txt
data/ssh_host_dsa_key data/ssh_host_dsa_key
data/ssh_host_dsa_key.pub data/ssh_host_dsa_key.pub
@@ -8,13 +8,11 @@ data/ssh_host_rsa_key.pub
dl/* dl/*
log/* log/*
log/tty/* log/tty/*
kippo-textlog.log cowrie-textlog.log
private.key private.key
public.key public.key
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
env/ env/
env1/ env1/
env2/ env2/

View File

@@ -13,7 +13,7 @@
* stdin is saved as a file in dl/ when using exec commands * stdin is saved as a file in dl/ when using exec commands
to support commands like 'cat >file; ./file' to support commands like 'cat >file; ./file'
* allow wget download over non-80 port * allow wget download over non-80 port
* simple JSON logging to kippo.json * simple JSON logging added
* accept log and deny publickey authentication * accept log and deny publickey authentication
* add uname -r, -m flags * add uname -r, -m flags
* add working sleep command * add working sleep command

View File

@@ -1,7 +1,8 @@
# Kippo # 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/). Kippo is inspired, but not based on [Kojoney](http://kojoney.sourceforge.net/).
## Features ## 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 * 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 * 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 * 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 ## Requirements
@@ -27,24 +28,25 @@ See Wiki for some installation instructions.
## How to run it? ## 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`
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: Files of interest:
* dl/ - files downloaded with wget are stored here * 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 * log/tty/ - session logs
* utils/playlog.py - utility to replay session logs * utils/playlog.py - utility to replay session logs
* utils/createfs.py - used to create fs.pickle * 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 * honeyfs/ - file contents for the fake filesystem - feel free to copy a real system here
## Is it secure? ## Is it secure?
@@ -53,4 +55,4 @@ Maybe. See [FAQ](https://github.com/desaster/kippo/wiki/FAQ)
## I have some questions! ## I have some questions!
Please visit https://github.com/micheloosterhof/kippo/issues Please visit https://github.com/micheloosterhof/cowrie/issues

View File

@@ -1,10 +1,10 @@
# #
# Kippo configuration file (kippo.cfg) # Cowrie configuration file (cowrie.cfg)
# #
[honeypot] [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. # logging modules such as mysql.
# #
# If not specified, the logging modules will instead use the IP address of the # 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 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. # Default is the 'UserDB' class which uses the password database.
# #
# Alternatively the 'AuthRandom' class can be used, which will let # Alternatively the 'AuthRandom' class can be used, which will let
@@ -134,7 +134,7 @@ sftp_enabled = true
#fake_addr = 192.168.66.254 #fake_addr = 192.168.66.254
# The IP address on which this machine reachable on from the internet. # 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 # will determine by itself. Used in 'netstat' output
#internet_facing_ip = 9.9.9.9 #internet_facing_ip = 9.9.9.9
@@ -195,8 +195,8 @@ interact_port = 5123
#[database_mysql] #[database_mysql]
#host = localhost #host = localhost
#database = kippo #database = cowrie
#username = kippo #username = cowrie
#password = secret #password = secret
#port = 3306 #port = 3306
@@ -213,33 +213,28 @@ interact_port = 5123
#user = anonymous@sensors.carnivore.it #user = anonymous@sensors.carnivore.it
#password = anonymous #password = anonymous
#muc = dionaea.sensors.carnivore.it #muc = dionaea.sensors.carnivore.it
#signal_createsession = kippo-events #signal_createsession = cowrie-events
#signal_connectionlost = kippo-events #signal_connectionlost = cowrie-events
#signal_loginfailed = kippo-events #signal_loginfailed = cowrie-events
#signal_loginsucceeded = kippo-events #signal_loginsucceeded = cowrie-events
#signal_command = kippo-events #signal_command = cowrie-events
#signal_clientversion = kippo-events #signal_clientversion = cowrie-events
#debug=true #debug=true
# Text based logging module # Text based logging module
# #
# While this is a database logging module, it actually just creates a simple # 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 # 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 # To enable this module, remove the comments below, including the
# [database_textlog] line. # [database_textlog] line.
#[database_textlog] #[database_textlog]
#logfile = log/kippo-textlog.log #logfile = log/cowrie-textlog.log
# deprecated JSON based logging module # JSON output module [output_jsonlog]
#[database_jsonlog] logfile = log/cowrie.json
#logfile = log/kippolog.json
# new default output module
[output_jsonlog]
logfile = log/kippo.json
#[database_hpfeeds] #[database_hpfeeds]
#server = hpfeeds.mysite.org #server = hpfeeds.mysite.org

View File

@@ -13,17 +13,17 @@ from twisted.cred import portal
from twisted.conch.ssh import factory, keys from twisted.conch.ssh import factory, keys
if os.name == 'posix' and os.getuid() == 0: 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) sys.exit(1)
if not os.path.exists('kippo.cfg'): if not os.path.exists('cowrie.cfg'):
print 'ERROR: kippo.cfg is missing!' print 'ERROR: cowrie.cfg is missing!'
sys.exit(1) sys.exit(1)
from kippo.core.config import config from cowrie.core.config import config
import kippo.core.honeypot import cowrie.core.honeypot
import kippo.core.ssh import cowrie.core.ssh
from kippo import core from cowrie import core
factory = core.ssh.HoneyPotSSHFactory() factory = core.ssh.HoneyPotSSHFactory()
factory.portal = portal.Portal(core.ssh.HoneyPotRealm()) 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 \ cfg.get('honeypot', 'interact_enabled').lower() in \
('yes', 'true', 'on'): ('yes', 'true', 'on'):
iport = int(cfg.get('honeypot', 'interact_port')) 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 = internet.TCPServer(iport, interact.makeInteractFactory(factory))
service.setServiceParent(application) service.setServiceParent(application)

View File

@@ -5,7 +5,7 @@ import random
from twisted.internet import reactor from twisted.internet import reactor
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -7,7 +7,7 @@ import re
from twisted.internet import reactor, defer from twisted.internet import reactor, defer
from twisted.internet.defer import inlineCallbacks from twisted.internet.defer import inlineCallbacks
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -7,10 +7,10 @@ import datetime
from twisted.internet import reactor from twisted.internet import reactor
from twisted.python import log from twisted.python import log
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
from kippo.core.config import config from cowrie.core.config import config
from kippo.core.auth import UserDB from cowrie.core.auth import UserDB
from kippo.core import utils from cowrie.core import utils
commands = {} commands = {}

View File

@@ -15,8 +15,8 @@ from twisted.web import client
from twisted.internet import reactor from twisted.internet import reactor
from twisted.python import log from twisted.python import log
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
from kippo.core.fs import * from cowrie.core.fs import *
commands = {} commands = {}

View File

@@ -3,7 +3,7 @@
# Random commands when running new executables # Random commands when running new executables
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}
clist = [] clist = []

View File

@@ -5,8 +5,8 @@ import os
import getopt import getopt
import copy import copy
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
from kippo.core.fs import * from cowrie.core.fs import *
commands = {} commands = {}

View File

@@ -7,7 +7,7 @@ import random
from twisted.internet import reactor from twisted.internet import reactor
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -2,7 +2,7 @@
import optparse import optparse
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -1,10 +1,10 @@
# Copyright (c) 2009 Upi Tamminen <desaster@gmail.com> # Copyright (c) 2009 Upi Tamminen <desaster@gmail.com>
# See the COPYRIGHT file for more information # See the COPYRIGHT file for more information
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
from kippo.core.fs import * from cowrie.core.fs import *
from kippo.core.config import config from cowrie.core.config import config
from kippo.core import utils from cowrie.core import utils
commands = {} commands = {}

View File

@@ -4,8 +4,8 @@
import stat import stat
import time import time
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
from kippo.core.fs import * from cowrie.core.fs import *
commands = {} commands = {}

View File

@@ -3,7 +3,7 @@
# Commands mapped to common malware # Commands mapped to common malware
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}
clist = {} # names clist = {} # names

View File

@@ -2,7 +2,7 @@
import socket import socket
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -8,7 +8,7 @@ import socket
from twisted.internet import reactor from twisted.internet import reactor
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -28,7 +28,7 @@
import getopt import getopt
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -1,7 +1,7 @@
from twisted.internet import reactor from twisted.internet import reactor
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -10,7 +10,7 @@ import socket
from twisted.python import log from twisted.python import log
from twisted.internet import reactor from twisted.internet import reactor
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -7,9 +7,9 @@ import os
from twisted.python import log from twisted.python import log
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
from kippo.core.fs import * from cowrie.core.fs import *
from kippo.commands import dice, malware from cowrie.commands import dice, malware
commands = {} commands = {}

View File

@@ -1,6 +1,6 @@
# #
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -13,8 +13,8 @@ from twisted.web import client
from twisted.internet import reactor from twisted.internet import reactor
from twisted.python import log from twisted.python import log
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
from kippo.core.fs import * from cowrie.core.fs import *
commands = {} commands = {}

View File

@@ -1,6 +1,6 @@
# Copyright (c) 2013 Bas Stottelaar <basstottelaar [AT] gmail [DOT] com> # Copyright (c) 2013 Bas Stottelaar <basstottelaar [AT] gmail [DOT] com>
from kippo.core.honeypot import HoneyPotCommand from cowrie.core.honeypot import HoneyPotCommand
commands = {} commands = {}

View File

@@ -64,7 +64,7 @@ class UserDB(object):
save the user db 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') f = open(self.userdb_file, 'w')
for (login, uid, passwd) in self.userdb: for (login, uid, passwd) in self.userdb:
f.write('%s:%d:%s\n' % (login, uid, passwd)) f.write('%s:%d:%s\n' % (login, uid, passwd))
@@ -154,7 +154,7 @@ class AuthRandom(object):
def savevars(self): def savevars(self):
# Save the user vars to json file # Save the user vars to json file
data = self.uservar 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: with open(self.uservar_file, 'wb') as fp:
json.dump(data, fp) json.dump(data, fp)

View File

@@ -6,7 +6,7 @@ import ConfigParser
def config(): def config():
cfg = ConfigParser.ConfigParser() 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): if os.path.exists(f):
cfg.read(f) cfg.read(f)
return cfg return cfg

View File

@@ -34,7 +34,7 @@ from twisted.internet import defer
MSG_CHANNEL_SUCCESS = 99 MSG_CHANNEL_SUCCESS = 99
class KippoSSHConnection(connection.SSHConnection): class CowrieSSHConnection(connection.SSHConnection):
""" """
Subclass this for a workaround for the Granados SSH library. Subclass this for a workaround for the Granados SSH library.
Channel request for openshell needs to return success immediatly Channel request for openshell needs to return success immediatly

View File

@@ -256,9 +256,9 @@ class HoneyPotEnvironment(object):
def __init__(self): def __init__(self):
self.cfg = config() self.cfg = config()
self.commands = {} self.commands = {}
import kippo.commands import cowrie.commands
for c in kippo.commands.__all__: for c in cowrie.commands.__all__:
module = __import__('kippo.commands.%s' % c, module = __import__('cowrie.commands.%s' % c,
globals(), locals(), ['commands']) globals(), locals(), ['commands'])
self.commands.update(module.commands) self.commands.update(module.commands)
self.fs = pickle.load(file( self.fs = pickle.load(file(

View File

@@ -20,7 +20,7 @@ class Interact(telnet.Telnet):
self.requestNegotiation(telnet.LINEMODE, telnet.LINEMODE_EDIT + '\0') self.requestNegotiation(telnet.LINEMODE, telnet.LINEMODE_EDIT + '\0')
self.will(telnet.ECHO) 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() self.cmd_help()
def connectionLost(self, reason): def connectionLost(self, reason):

View File

@@ -49,7 +49,7 @@ import uuid
class Output(object): 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 Plugins require the mandatory methods: stop, start and write
""" """

View File

@@ -78,7 +78,7 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
class HoneyPotSSHFactory(factory.SSHFactory): class HoneyPotSSHFactory(factory.SSHFactory):
services = { services = {
'ssh-userauth': HoneyPotSSHUserAuthServer, 'ssh-userauth': HoneyPotSSHUserAuthServer,
'ssh-connection': connection.KippoSSHConnection, 'ssh-connection': connection.CowrieSSHConnection,
} }
# Special delivery to the loggers to avoid scope problems # 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)) lcfg.set('honeypot', i, cfg.get('honeypot', i))
log.msg('Loading dblog engine: %s' % (engine,)) log.msg('Loading dblog engine: %s' % (engine,))
dblogger = __import__( dblogger = __import__(
'kippo.dblog.%s' % (engine,), 'cowrie.dblog.%s' % (engine,),
globals(), locals(), ['dblog']).DBLogger(lcfg) globals(), locals(), ['dblog']).DBLogger(lcfg)
log.startLoggingWithObserver(dblogger.emit, setStdout=False) log.startLoggingWithObserver(dblogger.emit, setStdout=False)
self.dbloggers.append(dblogger) self.dbloggers.append(dblogger)
@@ -134,7 +134,7 @@ class HoneyPotSSHFactory(factory.SSHFactory):
lcfg.set('honeypot', i, cfg.get('honeypot', i)) lcfg.set('honeypot', i, cfg.get('honeypot', i))
log.msg('Loading output engine: %s' % (engine,)) log.msg('Loading output engine: %s' % (engine,))
output = __import__( output = __import__(
'kippo.output.%s' % (engine,) 'cowrie.output.%s' % (engine,)
,globals(), locals(), ['output']).Output(lcfg) ,globals(), locals(), ['output']).Output(lcfg)
log.startLoggingWithObserver(output.emit, setStdout=False) log.startLoggingWithObserver(output.emit, setStdout=False)
self.output_plugins.append(output) self.output_plugins.append(output)
@@ -196,7 +196,7 @@ class HoneyPotRealm:
else: else:
raise Exception("No supported interfaces found.") 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, dst_ip=self.transport.getHost().host, dst_port=self.transport.getHost().port,
sessionno=self.transport.sessionno) sessionno=self.transport.sessionno)
sshserver.KippoSSHServerTransport.connectionMade(self) sshserver.CowrieSSHServerTransport.connectionMade(self)
def sendKexInit(self): def sendKexInit(self):
# Don't send key exchange prematurely # Don't send key exchange prematurely
if not self.gotVersion: if not self.gotVersion:
return return
sshserver.KippoSSHServerTransport.sendKexInit(self) sshserver.CowrieSSHServerTransport.sendKexInit(self)
def dataReceived(self, data): def dataReceived(self, data):
sshserver.KippoSSHServerTransport.dataReceived(self, data) sshserver.CowrieSSHServerTransport.dataReceived(self, data)
# later versions seem to call sendKexInit again on their own # later versions seem to call sendKexInit again on their own
if twisted.version.major < 11 and \ if twisted.version.major < 11 and \
not self._hadVersion and self.gotVersion: not self._hadVersion and self.gotVersion:
@@ -241,7 +241,7 @@ class HoneyPotTransport(sshserver.KippoSSHServerTransport):
kexAlgs=kexAlgs, keyAlgs=keyAlgs, encCS=encCS, macCS=macCS, kexAlgs=kexAlgs, keyAlgs=keyAlgs, encCS=encCS, macCS=macCS,
compCS=compCS, format='Remote SSH version: %(version)s') 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 # this seems to be the only reliable place of catching lost connection
def connectionLost(self, reason): def connectionLost(self, reason):
@@ -249,7 +249,7 @@ class HoneyPotTransport(sshserver.KippoSSHServerTransport):
i.sessionClosed() i.sessionClosed()
if self.transport.sessionno in self.factory.sessions: if self.transport.sessionno in self.factory.sessions:
del self.factory.sessions[self.transport.sessionno] del self.factory.sessions[self.transport.sessionno]
sshserver.KippoSSHServerTransport.connectionLost(self, reason) sshserver.CowrieSSHServerTransport.connectionLost(self, reason)
log.msg(eventid='KIPP0011', format='Connection lost') log.msg(eventid='KIPP0011', format='Connection lost')
class HoneyPotSSHSession(session.SSHSession): class HoneyPotSSHSession(session.SSHSession):
@@ -310,7 +310,7 @@ class HoneyPotAvatar(avatar.ConchUser):
self.protocol = None self.protocol = None
self.channelLookup.update({'session': HoneyPotSSHSession}) self.channelLookup.update({'session': HoneyPotSSHSession})
self.channelLookup['direct-tcpip'] = KippoOpenConnectForwardingClient self.channelLookup['direct-tcpip'] = CowrieOpenConnectForwardingClient
# sftp support enabled only when option is explicitly set # sftp support enabled only when option is explicitly set
if self.env.cfg.has_option('honeypot', 'sftp_enabled'): if self.env.cfg.has_option('honeypot', 'sftp_enabled'):
@@ -416,7 +416,7 @@ def getDSAKeys():
return publicKeyString, privateKeyString return publicKeyString, privateKeyString
@implementer(conchinterfaces.ISFTPFile) @implementer(conchinterfaces.ISFTPFile)
class KippoSFTPFile: class CowrieSFTPFile:
def __init__(self, server, filename, flags, attrs): def __init__(self, server, filename, flags, attrs):
self.server = server self.server = server
@@ -472,7 +472,7 @@ class KippoSFTPFile:
def setAttrs(self, attrs): def setAttrs(self, attrs):
raise NotImplementedError raise NotImplementedError
class KippoSFTPDirectory: class CowrieSFTPDirectory:
def __init__(self, server, directory): def __init__(self, server, directory):
self.server = server self.server = server
@@ -497,7 +497,7 @@ class KippoSFTPDirectory:
self.files = [] self.files = []
@implementer(conchinterfaces.ISFTPServer) @implementer(conchinterfaces.ISFTPServer)
class KippoSFTPServer: class CowrieSFTPServer:
def __init__(self, avatar): def __init__(self, avatar):
self.avatar = avatar self.avatar = avatar
@@ -530,7 +530,7 @@ class KippoSFTPServer:
def openFile(self, filename, flags, attrs): def openFile(self, filename, flags, attrs):
log.msg("SFTP openFile: %s" % filename) 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): def removeFile(self, filename):
log.msg("SFTP removeFile: %s" % filename) log.msg("SFTP removeFile: %s" % filename)
@@ -553,7 +553,7 @@ class KippoSFTPServer:
def openDirectory(self, path): def openDirectory(self, path):
log.msg("SFTP OpenDirectory: %s" % path) log.msg("SFTP OpenDirectory: %s" % path)
return KippoSFTPDirectory(self, self._absPath(path)) return CowrieSFTPDirectory(self, self._absPath(path))
def getAttrs(self, path, followLinks): def getAttrs(self, path, followLinks):
log.msg("SFTP getAttrs: %s" % path) log.msg("SFTP getAttrs: %s" % path)
@@ -587,17 +587,17 @@ class KippoSFTPServer:
def extendedRequest(self, extName, extData): def extendedRequest(self, extName, extData):
raise NotImplementedError 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) remoteHP, origHP = twisted.conch.ssh.forwarding.unpackOpen_direct_tcpip(data)
log.msg("direct-tcp connection attempt to %s:%i" % remoteHP) log.msg("direct-tcp connection attempt to %s:%i" % remoteHP)
return KippoConnectForwardingChannel(remoteHP, return CowrieConnectForwardingChannel(remoteHP,
remoteWindow=remoteWindow, remoteWindow=remoteWindow,
remoteMaxPacket=remoteMaxPacket, remoteMaxPacket=remoteMaxPacket,
avatar=avatar) avatar=avatar)
class KippoConnectForwardingChannel(forwarding.SSHConnectForwardingChannel): class CowrieConnectForwardingChannel(forwarding.SSHConnectForwardingChannel):
def channelOpen(self, specificData): def channelOpen(self, specificData):
log.msg("Faking channel open %s:%i" % self.hostport) log.msg("Faking channel open %s:%i" % self.hostport)

View File

@@ -29,7 +29,7 @@
from twisted.conch.ssh import transport from twisted.conch.ssh import transport
from twisted.python import log from twisted.python import log
class KippoSSHServerTransport(transport.SSHServerTransport): class CowrieSSHServerTransport(transport.SSHServerTransport):
def connectionMade(self): def connectionMade(self):
""" """
Called when the connection is made to the other side. We sent our Called when the connection is made to the other side. We sent our

View File

@@ -1,6 +1,6 @@
## From https://github.com/threatstream/kippo/blob/master/kippo/dblog/hpfeeds.py ## 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 twisted.python import log
from datetime import datetime from datetime import datetime
@@ -28,7 +28,7 @@ SIZES = {
OP_SUBSCRIBE: 5+256*2, OP_SUBSCRIBE: 5+256*2,
} }
KIPPOCHAN = 'kippo.sessions' KIPPOCHAN = 'cowrie.sessions'
class BadClient(Exception): class BadClient(Exception):
pass pass

View File

@@ -1,4 +1,4 @@
from kippo.core import dblog from cowrie.core import dblog
from twisted.enterprise import adbapi from twisted.enterprise import adbapi
from twisted.internet import defer from twisted.internet import defer
from twisted.python import log from twisted.python import log

View File

@@ -3,7 +3,7 @@
# ..so not exactly a dblog. # ..so not exactly a dblog.
# #
from kippo.core import dblog from cowrie.core import dblog
import time import time
import uuid import uuid

View File

@@ -45,7 +45,7 @@ class XMPPLoggerProtocol(muc.MUCClient):
from twisted.application import service from twisted.application import service
from twisted.words.protocols.jabber import jid from twisted.words.protocols.jabber import jid
from wokkel.client import XMPPClient from wokkel.client import XMPPClient
from kippo.core import dblog from cowrie.core import dblog
from twisted.words.xish import domish from twisted.words.xish import domish
class DBLogger(dblog.DBLogger): class DBLogger(dblog.DBLogger):

View File

@@ -1,11 +1,11 @@
To create additional output plugins, place Python modules in this directory. 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' 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): def start(self, cfg):

View File

@@ -31,12 +31,12 @@ import os
import twisted.python.logfile 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): def __init__(self, cfg):
kippo.core.output.Output.__init__(self, cfg) cowrie.core.output.Output.__init__(self, cfg)
fn = cfg.get('output_jsonlog', 'logfile') fn = cfg.get('output_jsonlog', 'logfile')
dirs = os.path.dirname(fn) dirs = os.path.dirname(fn)
base = os.path.basename(fn) base = os.path.basename(fn)

View File

@@ -1,102 +0,0 @@
# Copyright (c) 2015 Michel Oosterhof <michel@oosterhof.net>
# 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:

View File

@@ -24,5 +24,5 @@ then
. $VENV/bin/activate . $VENV/bin/activate
fi fi
echo "Starting kippo in the background..." echo "Starting cowrie in the background..."
twistd -y kippo.tac -l log/kippo.log --pidfile kippo.pid twistd -y cowrie.tac -l log/cowrie.log --pidfile cowrie.pid

View File

@@ -1,12 +1,12 @@
#!/bin/sh #!/bin/sh
PIDFILE=kippo.pid PIDFILE=cowrie.pid
cd $(dirname $0) cd $(dirname $0)
PID=$(cat $PIDFILE 2>/dev/null) PID=$(cat $PIDFILE 2>/dev/null)
if [ -n "$PID" ]; then if [ -n "$PID" ]; then
echo "Stopping kippo...\n" echo "Stopping cowrie...\n"
kill -TERM $PID kill -TERM $PID
fi fi

View File

@@ -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) (Note: work in progress, instructions are not verified)
## Prerequisites ## Prerequisites
* Working Kippo installation * Working Cowrie installation
* Kippo JSON log file (enable database json in kippo.cfg) * Cowrie JSON log file (enable database json in cowrie.cfg)
## Installation ## Installation
@@ -40,7 +40,7 @@ wget http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
* Configure logstash * 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) * 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 * 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: * To test whether data is loaded into ElasticSearch, run the following query:
``` ```
http://<hostname>:9200/_search?q=kippo&size=5 http://<hostname>:9200/_search?q=cowrie&size=5
``` ```
* If this gives output, your data is correctly loaded into ElasticSearch * If this gives output, your data is correctly loaded into ElasticSearch

View File

@@ -1,5 +1,5 @@
{ {
"title": "Kippo2ElasticSearch", "title": "Cowrie2ElasticSearch",
"services": { "services": {
"query": { "query": {
"list": { "list": {
@@ -22,7 +22,7 @@
"0": { "0": {
"type": "terms", "type": "terms",
"field": "_type", "field": "_type",
"value": "kippo", "value": "cowrie",
"mandate": "must", "mandate": "must",
"active": true, "active": true,
"alias": "", "alias": "",

View File

@@ -1,19 +1,19 @@
input { input {
# this is the actual live log file to monitor # this is the actual live log file to monitor
file { file {
path => ["/home/kippo/kippo-git/log/kippo.json"] path => ["/home/cowrie/cowrie-git/log/cowrie.json"]
codec => json_lines codec => json_lines
type => "kippo" type => "cowrie"
} }
# this is to send old logs to for reprocessing # this is to send old logs to for reprocessing
tcp { tcp {
port => 3333 port => 3333
type => "kippo" type => "cowrie"
} }
} }
filter { filter {
if [type] == "kippo" { if [type] == "cowrie" {
json { json {
source => message source => message
@@ -51,13 +51,13 @@ filter {
} }
output { output {
if [type] == "kippo" { if [type] == "cowrie" {
elasticsearch { elasticsearch {
host => helium host => helium
protocol => http protocol => http
} }
file { file {
path => "/tmp/kippo-logstash.log" path => "/tmp/cowrie-logstash.log"
codec => json codec => json
} }
stdout { stdout {

View File

@@ -2,14 +2,14 @@
############################################################### ###############################################################
# This program creates a command line interpreter used to edit # 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 # It is intended to mimic a basic bash shell and supports relative
# file references. # file references.
# #
# This isn't meant to build a brand new filesystem. Instead it # This isn't meant to build a brand new filesystem. Instead it
# should be used to edit existing filesystems such as the default # should be used to edit existing filesystems such as the default
# /opt/kippo/fs.pickle. # /opt/cowrie/data/fs.pickle.
# #
# Donovan Hubbard # Donovan Hubbard
# Douglas Hubbard # Douglas Hubbard
@@ -555,18 +555,18 @@ class fseditCmd(cmd.Cmd):
def help_about(self): def help_about(self):
print "Kippo stores information about its file systems in a " + \ print "Kippo stores information about its file systems in a " + \
"series of nested lists. Once the lists are made, they are " + \ "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 " + \ "gets a new client, it reads from the pickle file and loads " + \
"the fake filesystem into memory. By default this file " + \ "the fake filesystem into memory. By default this file " + \
"is /opt/kippo/fs.pickle. Originally the script " + \ "is /opt/cowrie/data/fs.pickle. Originally the script " + \
"/opt/kippo/createfs.py was used to copy the filesystem " + \ "/opt/cowrie/createfs.py was used to copy the filesystem " + \
"of the existing computer. However, it quite difficult to " + \ "of the existing computer. However, it quite difficult to " + \
"edit the pickle file by hand.\n\nThis script strives to be " + \ "edit the pickle file by hand.\n\nThis script strives to be " + \
"a bash-like interface that allows users to modify " + \ "a bash-like interface that allows users to modify " + \
"existing fs pickle files. It supports many of the " + \ "existing fs pickle files. It supports many of the " + \
"common bash commands and even handles relative file " + \ "common bash commands and even handles relative file " + \
"paths. Keep in mind that you need to restart the " + \ "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, " + \ "reloaded into memory.\n\nDonovan Hubbard, Douglas Hubbard, " + \
"March 2013\nVersion 1.0" "March 2013\nVersion 1.0"