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
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/

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

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

View File

@@ -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 = {}

View File

@@ -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 = {}

View File

@@ -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 = {}

View File

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

View File

@@ -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 = {}

View File

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

View File

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

View File

@@ -1,10 +1,10 @@
# Copyright (c) 2009 Upi Tamminen <desaster@gmail.com>
# 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 = {}

View File

@@ -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 = {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 = {}

View File

@@ -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 = {}

View File

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

View File

@@ -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 = {}

View File

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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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(

View File

@@ -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):

View File

@@ -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
"""

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -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):

View File

@@ -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):

View File

@@ -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)

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
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

View File

@@ -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

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)
## 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://<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

View File

@@ -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": "",

View File

@@ -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 {

View File

@@ -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"