mirror of
https://github.com/aljazceru/cowrie.git
synced 2025-12-17 05:54:21 +01:00
Merge branch 'master' of https://github.com/micheloosterhof/cowrie
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,4 +13,5 @@ __pycache__/
|
||||
*env/
|
||||
twisted/plugins/dropin.cache
|
||||
.DS_Store
|
||||
_trial_temp
|
||||
|
||||
|
||||
11
README.md
11
README.md
@@ -35,14 +35,9 @@ Additional functionality over standard kippo:
|
||||
Software required:
|
||||
|
||||
* Python 2.7+, (Python 3 not yet supported due to Twisted dependencies)
|
||||
* Zope Interface 3.6.0+
|
||||
* Twisted 12.0+
|
||||
* python-crypto
|
||||
* python-cryptography
|
||||
* python-pyasn1
|
||||
* python-gmpy2 (recommended)
|
||||
* python-mysqldb (for MySQL output)
|
||||
* python-OpenSSL
|
||||
* python-virtualenv
|
||||
|
||||
For Python dependencies, see requirements.txt
|
||||
|
||||
## Files of interest:
|
||||
|
||||
|
||||
@@ -385,6 +385,14 @@ logfile = log/cowrie.json
|
||||
#[output_sqlite]
|
||||
#db_file = cowrie.db
|
||||
|
||||
# MongoDB logging module
|
||||
#
|
||||
# MongoDB logging requires an extra Python module: pip install pymongo
|
||||
#
|
||||
#[output_mongodb]
|
||||
#connection_string = mongodb://username:password@host:port/database
|
||||
#database = dbname
|
||||
|
||||
|
||||
# Splunk SDK output module - Legacy. Requires Splunk API installed
|
||||
# This sends logs directly to Splunk using the Python REST SDK
|
||||
|
||||
@@ -92,10 +92,14 @@ class command_curl(HoneyPotCommand):
|
||||
|
||||
self.download_path = cfg.get('honeypot', 'download_path')
|
||||
|
||||
self.safeoutfile = '%s/%s_%s' % \
|
||||
(self.download_path,
|
||||
time.strftime('%Y%m%d%H%M%S'),
|
||||
re.sub('[^A-Za-z0-9]', '_', url))
|
||||
if not hasattr(self, 'safeoutfile'):
|
||||
tmp_fname = '%s_%s_%s_%s' % \
|
||||
(time.strftime('%Y%m%d%H%M%S'),
|
||||
self.protocol.getProtoTransport().transportId,
|
||||
self.protocol.terminal.transport.session.id,
|
||||
re.sub('[^A-Za-z0-9]', '_', url))
|
||||
self.safeoutfile = os.path.join(self.download_path, tmp_fname)
|
||||
|
||||
self.deferred = self.download(url, outfile, self.safeoutfile)
|
||||
if self.deferred:
|
||||
self.deferred.addCallback(self.success, outfile)
|
||||
@@ -311,7 +315,7 @@ Options: (H) means HTTP/HTTPS only, (F) means FTP only
|
||||
self.exit()
|
||||
|
||||
shasum = hashlib.sha256(open(self.safeoutfile, 'rb').read()).hexdigest()
|
||||
hashPath = '%s/%s' % (self.download_path, shasum)
|
||||
hashPath = os.path.join(self.download_path, shasum)
|
||||
|
||||
# If we have content already, delete temp file
|
||||
if not os.path.exists(hashPath):
|
||||
@@ -336,7 +340,7 @@ Options: (H) means HTTP/HTTPS only, (F) means FTP only
|
||||
os.symlink(shasum, self.safeoutfile)
|
||||
|
||||
# FIXME: is this necessary?
|
||||
self.safeoutfile = hashPath
|
||||
# self.safeoutfile = hashPath
|
||||
|
||||
# Update the honeyfs to point to downloaded file
|
||||
if outfile is not None:
|
||||
|
||||
@@ -124,9 +124,8 @@ class command_grep(HoneyPotCommand):
|
||||
|
||||
|
||||
commands['/bin/grep'] = command_grep
|
||||
commands['/usr/bin/grep'] = command_grep
|
||||
commands['/usr/bin/egrep'] = command_grep
|
||||
commands['/usr/bin/fgrep'] = command_grep
|
||||
commands['/bin/egrep'] = command_grep
|
||||
commands['/bin/fgrep'] = command_grep
|
||||
|
||||
|
||||
class command_tail(HoneyPotCommand):
|
||||
|
||||
@@ -93,10 +93,13 @@ Download a file via FTP
|
||||
cfg = self.protocol.cfg
|
||||
url = 'ftp://%s/%s' % (self.host, self.remote_path)
|
||||
self.download_path = cfg.get('honeypot', 'download_path')
|
||||
self.safeoutfile = '%s/%s_%s' % \
|
||||
(self.download_path,
|
||||
time.strftime('%Y%m%d%H%M%S'),
|
||||
re.sub('[^A-Za-z0-9]', '_', url))
|
||||
|
||||
tmp_fname = '%s_%s_%s_%s' % \
|
||||
(time.strftime('%Y%m%d%H%M%S'),
|
||||
self.protocol.getProtoTransport().transportId,
|
||||
self.protocol.terminal.transport.session.id,
|
||||
re.sub('[^A-Za-z0-9]', '_', url))
|
||||
self.safeoutfile = os.path.join(self.download_path, tmp_fname)
|
||||
|
||||
result = self.ftp_download(self.safeoutfile)
|
||||
|
||||
@@ -110,7 +113,7 @@ Download a file via FTP
|
||||
return
|
||||
|
||||
shasum = hashlib.sha256(open(self.safeoutfile, 'rb').read()).hexdigest()
|
||||
hash_path = '%s/%s' % (self.download_path, shasum)
|
||||
hash_path = os.path.join(self.download_path, shasum)
|
||||
|
||||
# If we have content already, delete temp file
|
||||
if not os.path.exists(hash_path):
|
||||
|
||||
@@ -4,6 +4,7 @@ import time
|
||||
import re
|
||||
import getopt
|
||||
import random
|
||||
import os
|
||||
|
||||
from twisted.internet import reactor
|
||||
|
||||
@@ -164,10 +165,12 @@ gcc version %s (Debian %s-5)""" % (version, version_short, version_short, versio
|
||||
def generate_file(self, outfile):
|
||||
data = ""
|
||||
# TODO: make sure it is written to temp file, not downloads
|
||||
safeoutfile = '%s/%s_%s' % \
|
||||
(self.protocol.cfg.get('honeypot', 'download_path'),
|
||||
time.strftime('%Y%m%d%H%M%S'),
|
||||
re.sub('[^A-Za-z0-9]', '_', outfile))
|
||||
tmp_fname = '%s_%s_%s_%s' % \
|
||||
(time.strftime('%Y%m%d%H%M%S'),
|
||||
self.protocol.getProtoTransport().transportId,
|
||||
self.protocol.terminal.transport.session.id,
|
||||
re.sub('[^A-Za-z0-9]', '_', outfile))
|
||||
safeoutfile = os.path.join(self.protocol.cfg.get('honeypot', 'download_path'), tmp_fname)
|
||||
|
||||
# Data contains random garbage from an actual file, so when
|
||||
# catting the file, you'll see some 'real' compiled data
|
||||
|
||||
@@ -56,10 +56,12 @@ class command_tftp(HoneyPotCommand):
|
||||
|
||||
self.download_path = cfg.get('honeypot', 'download_path')
|
||||
|
||||
self.safeoutfile = '%s/%s_%s' % \
|
||||
(self.download_path,
|
||||
time.strftime('%Y%m%d%H%M%S'),
|
||||
re.sub('[^A-Za-z0-9]', '_', self.file_to_get))
|
||||
tmp_fname = '%s_%s_%s_%s' % \
|
||||
(time.strftime('%Y%m%d%H%M%S'),
|
||||
self.protocol.getProtoTransport().transportId,
|
||||
self.protocol.terminal.transport.session.id,
|
||||
re.sub('[^A-Za-z0-9]', '_', self.file_to_get))
|
||||
self.safeoutfile = os.path.join(self.download_path, tmp_fname)
|
||||
|
||||
try:
|
||||
tclient.download(self.file_to_get, self.safeoutfile, progresshook)
|
||||
@@ -67,38 +69,41 @@ class command_tftp(HoneyPotCommand):
|
||||
self.fs.mkfile(self.file_to_get, 0, 0, tclient.context.metrics.bytes, 33188)
|
||||
self.fs.update_realfile(self.fs.getfile(self.file_to_get), self.safeoutfile)
|
||||
|
||||
shasum = hashlib.sha256(open(self.safeoutfile, 'rb').read()).hexdigest()
|
||||
hash_path = '%s/%s' % (self.download_path, shasum)
|
||||
if os.path.exists(self.safeoutfile):
|
||||
|
||||
# If we have content already, delete temp file
|
||||
if not os.path.exists(hash_path):
|
||||
os.rename(self.safeoutfile, hash_path)
|
||||
else:
|
||||
os.remove(self.safeoutfile)
|
||||
log.msg("Not storing duplicate content " + shasum)
|
||||
if os.path.getsize(self.safeoutfile) == 0:
|
||||
os.remove(self.safeoutfile)
|
||||
self.safeoutfile = None
|
||||
return
|
||||
|
||||
log.msg(eventid='cowrie.session.file_download',
|
||||
format='Downloaded tftpFile (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
|
||||
url=self.file_to_get,
|
||||
outfile=hash_path,
|
||||
shasum=shasum)
|
||||
with open(self.safeoutfile, 'rb') as f:
|
||||
shasum = hashlib.sha256(f.read()).hexdigest()
|
||||
hash_path = os.path.join(self.download_path, shasum)
|
||||
|
||||
# Link friendly name to hash
|
||||
os.symlink(shasum, self.safeoutfile)
|
||||
# If we have content already, delete temp file
|
||||
if not os.path.exists(hash_path):
|
||||
os.rename(self.safeoutfile, hash_path)
|
||||
else:
|
||||
os.remove(self.safeoutfile)
|
||||
log.msg("Not storing duplicate content " + shasum)
|
||||
|
||||
# FIXME: is this necessary?
|
||||
self.safeoutfile = hash_path
|
||||
log.msg(eventid='cowrie.session.file_download',
|
||||
format='Downloaded tftpFile (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
|
||||
url=self.file_to_get,
|
||||
outfile=hash_path,
|
||||
shasum=shasum)
|
||||
|
||||
# Update the honeyfs to point to downloaded file
|
||||
f = self.fs.getfile(self.file_to_get)
|
||||
f[A_REALFILE] = hash_path
|
||||
# Link friendly name to hash
|
||||
os.symlink(shasum, self.safeoutfile)
|
||||
|
||||
log.msg(eventid='cowrie.session.file_download',
|
||||
format='Downloaded tftpFile to %(outfile)s',
|
||||
outfile=self.safeoutfile
|
||||
)
|
||||
# Update the honeyfs to point to downloaded file
|
||||
f = self.fs.getfile(self.file_to_get)
|
||||
f[A_REALFILE] = hash_path
|
||||
|
||||
except tftpy.TftpException, err:
|
||||
if os.path.exists(self.safeoutfile):
|
||||
if os.path.getsize(self.safeoutfile) == 0:
|
||||
os.remove(self.safeoutfile)
|
||||
return
|
||||
|
||||
except KeyboardInterrupt:
|
||||
|
||||
@@ -121,10 +121,14 @@ class command_wget(HoneyPotCommand):
|
||||
|
||||
self.download_path = cfg.get('honeypot', 'download_path')
|
||||
|
||||
self.safeoutfile = '%s/%s_%s' % \
|
||||
(self.download_path,
|
||||
time.strftime('%Y%m%d%H%M%S'),
|
||||
re.sub('[^A-Za-z0-9]', '_', url))
|
||||
if not hasattr(self, 'safeoutfile'):
|
||||
tmp_fname = '%s_%s_%s_%s' % \
|
||||
(time.strftime('%Y%m%d%H%M%S'),
|
||||
self.protocol.getProtoTransport().transportId,
|
||||
self.protocol.terminal.transport.session.id,
|
||||
re.sub('[^A-Za-z0-9]', '_', url))
|
||||
self.safeoutfile = os.path.join(self.download_path, tmp_fname)
|
||||
|
||||
self.deferred = self.download(url, outfile, self.safeoutfile)
|
||||
if self.deferred:
|
||||
self.deferred.addCallback(self.success, outfile)
|
||||
@@ -142,6 +146,9 @@ class command_wget(HoneyPotCommand):
|
||||
path = parsed.path or '/'
|
||||
if scheme != 'http' and scheme != 'https':
|
||||
raise NotImplementedError
|
||||
if not host:
|
||||
self.exit()
|
||||
return None
|
||||
except:
|
||||
self.write('%s: Unsupported scheme.\n' % (url,))
|
||||
self.exit()
|
||||
@@ -185,8 +192,9 @@ class command_wget(HoneyPotCommand):
|
||||
log.msg("there's no file " + self.safeoutfile)
|
||||
self.exit()
|
||||
|
||||
shasum = hashlib.sha256(open(self.safeoutfile, 'rb').read()).hexdigest()
|
||||
hash_path = '%s/%s' % (self.download_path, shasum)
|
||||
with open(self.safeoutfile, 'rb') as f:
|
||||
shasum = hashlib.sha256(f.read()).hexdigest()
|
||||
hash_path = os.path.join(self.download_path, shasum)
|
||||
|
||||
# If we have content already, delete temp file
|
||||
if not os.path.exists(hash_path):
|
||||
@@ -208,10 +216,10 @@ class command_wget(HoneyPotCommand):
|
||||
shasum=shasum)
|
||||
|
||||
# Link friendly name to hash
|
||||
os.symlink( shasum, self.safeoutfile )
|
||||
os.symlink(shasum, self.safeoutfile)
|
||||
|
||||
# FIXME: is this necessary?
|
||||
self.safeoutfile = hash_path
|
||||
# self.safeoutfile = hash_path
|
||||
|
||||
# Update the honeyfs to point to downloaded file
|
||||
f = self.fs.getfile(outfile)
|
||||
|
||||
@@ -32,22 +32,40 @@ class HoneyPotCommand(object):
|
||||
self.errorWrite = self.protocol.pp.errReceived
|
||||
# MS-DOS style redirect handling, inside the command
|
||||
# TODO: handle >>, 2>, etc
|
||||
if '>' in self.args:
|
||||
if '>' in self.args or '>>' in self.args:
|
||||
self.writtenBytes = 0
|
||||
self.write = self.write_to_file
|
||||
index = self.args.index(">")
|
||||
if '>>' in self.args:
|
||||
index = self.args.index('>>')
|
||||
b_append = True
|
||||
else:
|
||||
index = self.args.index('>')
|
||||
b_append = False
|
||||
self.outfile = self.fs.resolve_path(str(self.args[(index + 1)]), self.protocol.cwd)
|
||||
del self.args[index:]
|
||||
self.safeoutfile = '%s/%s-%s-%s-redir_%s' % (
|
||||
self.protocol.cfg.get('honeypot', 'download_path'),
|
||||
time.strftime('%Y%m%d-%H%M%S'),
|
||||
self.protocol.getProtoTransport().transportId,
|
||||
self.protocol.terminal.transport.session.id,
|
||||
re.sub('[^A-Za-z0-9]', '_', self.outfile))
|
||||
perm = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
|
||||
self.fs.mkfile(self.outfile, 0, 0, 0, stat.S_IFREG | perm)
|
||||
with open(self.safeoutfile, 'a'):
|
||||
self.fs.update_realfile(self.fs.getfile(self.outfile), self.safeoutfile)
|
||||
p = self.fs.getfile(self.outfile)
|
||||
if not p or not p[fs.A_REALFILE] or p[fs.A_REALFILE].startswith('honeyfs') or not b_append:
|
||||
tmp_fname = '%s-%s-%s-redir_%s' % \
|
||||
(time.strftime('%Y%m%d-%H%M%S'),
|
||||
self.protocol.getProtoTransport().transportId,
|
||||
self.protocol.terminal.transport.session.id,
|
||||
re.sub('[^A-Za-z0-9]', '_', self.outfile))
|
||||
self.safeoutfile = os.path.join(self.protocol.cfg.get('honeypot', 'download_path'), tmp_fname)
|
||||
perm = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
|
||||
try:
|
||||
self.fs.mkfile(self.outfile, 0, 0, 0, stat.S_IFREG | perm)
|
||||
except fs.FileNotFound:
|
||||
# The outfile locates at a non-existing directory.
|
||||
self.protocol.pp.outReceived('-bash: %s: No such file or directory\n' % self.outfile)
|
||||
self.write = self.write_to_failed
|
||||
self.outfile = None
|
||||
self.safeoutfile = None
|
||||
|
||||
else:
|
||||
with open(self.safeoutfile, 'a'):
|
||||
self.fs.update_realfile(self.fs.getfile(self.outfile), self.safeoutfile)
|
||||
else:
|
||||
self.safeoutfile = p[fs.A_REALFILE]
|
||||
|
||||
|
||||
def check_arguments(self, application, args):
|
||||
@@ -78,10 +96,16 @@ class HoneyPotCommand(object):
|
||||
self.fs.update_size(self.outfile, self.writtenBytes)
|
||||
|
||||
|
||||
def write_to_failed(self, data):
|
||||
"""
|
||||
"""
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
"""
|
||||
self.call()
|
||||
if self.write != self.write_to_failed:
|
||||
self.call()
|
||||
self.exit()
|
||||
|
||||
|
||||
@@ -97,8 +121,9 @@ class HoneyPotCommand(object):
|
||||
"""
|
||||
try:
|
||||
self.protocol.cmdstack.pop()
|
||||
self.protocol.cmdstack[-1].resume()
|
||||
except AttributeError:
|
||||
if len(self.protocol.cmdstack):
|
||||
self.protocol.cmdstack[-1].resume()
|
||||
except (AttributeError, IndexError):
|
||||
# Cmdstack could be gone already (wget + disconnect)
|
||||
pass
|
||||
|
||||
@@ -165,6 +190,14 @@ class HoneyPotShell(object):
|
||||
try:
|
||||
tok = self.lexer.get_token()
|
||||
# log.msg( "tok: %s" % (repr(tok)) )
|
||||
|
||||
# Ignore parentheses
|
||||
tok_len = len(tok)
|
||||
tok = tok.strip('(')
|
||||
tok = tok.strip(')')
|
||||
if len(tok) != tok_len and tok == '':
|
||||
continue
|
||||
|
||||
if tok == self.lexer.eof:
|
||||
if len(tokens):
|
||||
self.cmdpending.append((tokens))
|
||||
|
||||
@@ -195,7 +195,11 @@ class HoneyPotBaseProtocol(insults.TerminalProtocol, TimeoutMixin):
|
||||
obj.set_input_data(pp.input_data)
|
||||
self.cmdstack.append(obj)
|
||||
obj.start()
|
||||
self.pp.outConnectionLost()
|
||||
if hasattr(obj, 'safeoutfile'):
|
||||
if obj.safeoutfile:
|
||||
self.terminal.redirFiles.add(obj.safeoutfile)
|
||||
if self.pp:
|
||||
self.pp.outConnectionLost()
|
||||
|
||||
|
||||
def uptime(self):
|
||||
@@ -352,19 +356,22 @@ class HoneyPotInteractiveProtocol(HoneyPotBaseProtocol, recvline.HistoricRecvLin
|
||||
def handle_CTRL_C(self):
|
||||
"""
|
||||
"""
|
||||
self.cmdstack[-1].handle_CTRL_C()
|
||||
if len(self.cmdstack):
|
||||
self.cmdstack[-1].handle_CTRL_C()
|
||||
|
||||
|
||||
def handle_CTRL_D(self):
|
||||
"""
|
||||
"""
|
||||
self.cmdstack[-1].handle_CTRL_D()
|
||||
if len(self.cmdstack):
|
||||
self.cmdstack[-1].handle_CTRL_D()
|
||||
|
||||
|
||||
def handle_TAB(self):
|
||||
"""
|
||||
"""
|
||||
self.cmdstack[-1].handle_TAB()
|
||||
if len(self.cmdstack):
|
||||
self.cmdstack[-1].handle_TAB()
|
||||
|
||||
|
||||
def handle_CTRL_K(self):
|
||||
|
||||
@@ -31,6 +31,8 @@ class LoggingServerProtocol(insults.ServerProtocol):
|
||||
self.ttylogPath = cfg.get('honeypot', 'log_path')
|
||||
self.downloadPath = cfg.get('honeypot', 'download_path')
|
||||
|
||||
self.redirFiles = set()
|
||||
|
||||
try:
|
||||
self.bytesReceivedLimit = int(cfg.get('honeypot',
|
||||
'download_limit_size'))
|
||||
@@ -134,14 +136,15 @@ class LoggingServerProtocol(insults.ServerProtocol):
|
||||
try:
|
||||
with open(self.stdinlogFile, 'rb') as f:
|
||||
shasum = hashlib.sha256(f.read()).hexdigest()
|
||||
shasumfile = self.downloadPath + "/" + shasum
|
||||
if (os.path.exists(shasumfile)):
|
||||
shasumfile = os.path.join(self.downloadPath, shasum)
|
||||
if os.path.exists(shasumfile):
|
||||
os.remove(self.stdinlogFile)
|
||||
log.msg("Not storing duplicate content " + shasum)
|
||||
else:
|
||||
os.rename(self.stdinlogFile, shasumfile)
|
||||
os.symlink(shasum, self.stdinlogFile)
|
||||
log.msg(eventid='cowrie.session.file_download',
|
||||
format='Saved stdin contents to %(outfile)s',
|
||||
format='Saved stdin contents with SHA-256 %(shasum)s to %(outfile)s',
|
||||
url='stdin',
|
||||
outfile=shasumfile,
|
||||
shasum=shasum)
|
||||
@@ -150,6 +153,34 @@ class LoggingServerProtocol(insults.ServerProtocol):
|
||||
finally:
|
||||
self.stdinlogOpen = False
|
||||
|
||||
if self.redirFiles:
|
||||
for rf in self.redirFiles:
|
||||
try:
|
||||
if not os.path.exists(rf):
|
||||
continue
|
||||
|
||||
if os.path.getsize(rf) == 0:
|
||||
os.remove(rf)
|
||||
continue
|
||||
|
||||
with open(rf, 'rb') as f:
|
||||
shasum = hashlib.sha256(f.read()).hexdigest()
|
||||
shasumfile = os.path.join(self.downloadPath, shasum)
|
||||
if os.path.exists(shasumfile):
|
||||
os.remove(rf)
|
||||
log.msg("Not storing duplicate content " + shasum)
|
||||
else:
|
||||
os.rename(rf, shasumfile)
|
||||
os.symlink(shasum, rf)
|
||||
log.msg(eventid='cowrie.session.file_download',
|
||||
format='Saved redir contents with SHA-256 %(shasum)s to %(outfile)s',
|
||||
url='redir',
|
||||
outfile=shasumfile,
|
||||
shasum=shasum)
|
||||
except IOError:
|
||||
pass
|
||||
self.redirFiles.clear()
|
||||
|
||||
if self.ttylogOpen:
|
||||
# TODO: Add session duration to this entry
|
||||
log.msg(eventid='cowrie.log.closed',
|
||||
|
||||
@@ -86,8 +86,7 @@ class Output(cowrie.core.output.Output):
|
||||
base64.b64decode(self.auth_key), hashlib.sha256).digest())
|
||||
auth_header = 'credentials={0} nonce={1} userid={2}'.format(digest, _nonceb64, self.userid)
|
||||
headers = {'X-ISC-Authorization': auth_header,
|
||||
'Content-Type':'text/plain',
|
||||
'Content-Length': len(log_output)}
|
||||
'Content-Type':'text/plain'}
|
||||
#log.msg(headers)
|
||||
|
||||
if self.debug:
|
||||
|
||||
136
cowrie/output/mongodb.py
Normal file
136
cowrie/output/mongodb.py
Normal file
@@ -0,0 +1,136 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pymongo
|
||||
|
||||
from twisted.python import log
|
||||
|
||||
import cowrie.core.output
|
||||
|
||||
|
||||
class Output(cowrie.core.output.Output):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, cfg):
|
||||
self.cfg = cfg
|
||||
cowrie.core.output.Output.__init__(self, cfg)
|
||||
|
||||
def insert_one(self, collection, event):
|
||||
try:
|
||||
object_id = collection.insert_one(event).inserted_id
|
||||
return object_id
|
||||
except Exception as e:
|
||||
log.msg('mongo error - {0}'.format(e))
|
||||
|
||||
def update_one(self, collection, session, doc):
|
||||
try:
|
||||
object_id = collection.update({'session': session}, doc)
|
||||
return object_id
|
||||
except Exception as e:
|
||||
log.msg('mongo error - {0}'.format(e))
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
"""
|
||||
db_addr = self.cfg.get('output_mongodb', 'connection_string')
|
||||
db_name = self.cfg.get('output_mongodb', 'database')
|
||||
|
||||
try:
|
||||
self.mongo_client = pymongo.MongoClient(db_addr)
|
||||
self.mongo_db = self.mongo_client[db_name]
|
||||
# Define Collections.
|
||||
self.col_sensors = self.mongo_db['sensors']
|
||||
self.col_sessions = self.mongo_db['sessions']
|
||||
self.col_auth = self.mongo_db['auth']
|
||||
self.col_input = self.mongo_db['input']
|
||||
self.col_downloads = self.mongo_db['downloads']
|
||||
self.col_input = self.mongo_db['input']
|
||||
self.col_clients = self.mongo_db['clients']
|
||||
self.col_ttylog = self.mongo_db['ttylog']
|
||||
self.col_keyfingerprints = self.mongo_db['keyfingerprints']
|
||||
self.col_event = self.mongo_db['event']
|
||||
except Exception, e:
|
||||
log.msg('output_mongodb: Error: %s' % str(e))
|
||||
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
"""
|
||||
self.mongo_client.close()
|
||||
|
||||
|
||||
def write(self, entry):
|
||||
"""
|
||||
"""
|
||||
for i in list(entry.keys()):
|
||||
# Remove twisted 15 legacy keys
|
||||
if i.startswith('log_'):
|
||||
del entry[i]
|
||||
|
||||
eventid = entry["eventid"]
|
||||
|
||||
if eventid == 'cowrie.session.connect':
|
||||
# Check if sensor exists, else add it.
|
||||
doc = self.col_sensors.find_one({'sensor': self.sensor})
|
||||
if doc:
|
||||
sensorid = doc['sensor']
|
||||
else:
|
||||
sensorid = self.insert_one(self.col_sensors, entry)
|
||||
|
||||
# Prep extra elements just to make django happy later on
|
||||
entry['starttime'] = entry['timestamp']
|
||||
entry['endtime'] = None
|
||||
entry['sshversion'] = None
|
||||
entry['termsize'] = None
|
||||
log.msg('Session Created')
|
||||
self.insert_one(self.col_sessions, entry)
|
||||
|
||||
elif eventid in ['cowrie.login.success', 'cowrie.login.failed']:
|
||||
self.insert_one(self.col_auth, entry)
|
||||
|
||||
elif eventid in ['cowrie.command.success', 'cowrie.command.failed']:
|
||||
self.insert_one(self.col_input, entry)
|
||||
|
||||
elif eventid == 'cowrie.session.file_download':
|
||||
# ToDo add a config section and offer to store the file in the db - useful for central logging
|
||||
# we will add an option to set max size, if its 16mb or less we can store as normal,
|
||||
# If over 16 either fail or we just use gridfs both are simple enough.
|
||||
self.insert_one(self.col_downloads, entry)
|
||||
|
||||
elif eventid == 'cowrie.client.version':
|
||||
doc = self.col_sessions.find_one({'session': entry['session']})
|
||||
if doc:
|
||||
doc['sshversion'] = entry['version']
|
||||
self.update_one(self.col_sessions, entry['session'], doc)
|
||||
else:
|
||||
pass
|
||||
|
||||
elif eventid == 'cowrie.client.size':
|
||||
doc = self.col_sessions.find_one({'session': entry['session']})
|
||||
if doc:
|
||||
doc['termsize'] = '{0}x{1}'.format(entry['width'], entry['height'])
|
||||
self.update_one(self.col_sessions, entry['session'], doc)
|
||||
else:
|
||||
pass
|
||||
|
||||
elif eventid == 'cowrie.session.closed':
|
||||
doc = self.col_sessions.find_one({'session': entry['session']})
|
||||
if doc:
|
||||
doc['endtime'] = entry['timestamp']
|
||||
self.update_one(self.col_sessions, entry['session'], doc)
|
||||
else:
|
||||
pass
|
||||
|
||||
elif eventid == 'cowrie.log.closed':
|
||||
# ToDo Compress to opimise the space and if your sending to remote db
|
||||
with open(entry["ttylog"]) as ttylog:
|
||||
entry['ttylogpath'] = entry['ttylog']
|
||||
entry['ttylog'] = ttylog.read().encode('hex')
|
||||
self.insert_one(self.col_ttylog, entry)
|
||||
|
||||
elif eventid == 'cowrie.client.fingerprint':
|
||||
self.insert_one(self.col_keyfingerprints, entry)
|
||||
|
||||
# Catch any other event types
|
||||
else:
|
||||
self.insert_one(self.col_event, entry)
|
||||
@@ -138,6 +138,10 @@ class HoneyPotTelnetAuthProtocol(AuthenticatingTelnetProtocol):
|
||||
|
||||
return 'Discard'
|
||||
|
||||
def telnet_Command(self, command):
|
||||
self.transport.protocol.dataReceived(command+'\r')
|
||||
return "Command"
|
||||
|
||||
def _cbLogin(self, ial):
|
||||
"""
|
||||
Fired on a successful login
|
||||
@@ -176,15 +180,17 @@ class HoneyPotTelnetAuthProtocol(AuthenticatingTelnetProtocol):
|
||||
if opt == ECHO:
|
||||
return True
|
||||
elif opt == SGA:
|
||||
return True
|
||||
return False
|
||||
#return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def enableRemote(self, opt):
|
||||
if opt == LINEMODE:
|
||||
self.transport.requestNegotiation(LINEMODE, MODE + chr(TRAPSIG))
|
||||
return True
|
||||
return False
|
||||
#self.transport.requestNegotiation(LINEMODE, MODE + chr(TRAPSIG))
|
||||
#return True
|
||||
elif opt == NAWS:
|
||||
return True
|
||||
elif opt == SGA:
|
||||
|
||||
@@ -343,6 +343,14 @@ logfile = log/cowrie.json
|
||||
#[output_sqlite]
|
||||
#db_file = cowrie.db
|
||||
|
||||
# MongoDB logging module
|
||||
#
|
||||
# MongoDB logging requires an extra Python module: pip install pymongo
|
||||
#
|
||||
#[output_mongodb]
|
||||
#connection_string = mongodb://username:password@host:port/database
|
||||
#database = dbname
|
||||
|
||||
|
||||
# Splunk SDK output module - EARLY RELEASE NOT RECOMMENDED
|
||||
# This sends logs directly to Splunk using the Python REST SDK
|
||||
|
||||
@@ -7,35 +7,64 @@
|
||||
|
||||
* Working Cowrie installation
|
||||
* Cowrie JSON log file (enable database json in cowrie.cfg)
|
||||
* Java 8
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
We'll examine simple installation, when we install ELK stack on the same machine that used for cowrie.
|
||||
|
||||
* Add Elastic's repository and key
|
||||
```
|
||||
wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
|
||||
echo "deb https://artifacts.elastic.co/packages/5.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-5.x.list
|
||||
apt-get update
|
||||
```
|
||||
|
||||
* Install logstash, elasticsearch and kibana
|
||||
|
||||
```
|
||||
apt-get install logstash
|
||||
apt-get install elasticsearch
|
||||
````
|
||||
|
||||
* Install Kibana
|
||||
|
||||
This may be different depending on your operating system. Kibana will need additional components such as a web server
|
||||
apt-get install elasticsearch logstash kibana
|
||||
```
|
||||
|
||||
* Set them to autostart
|
||||
```
|
||||
update-rc.d elasticsearch defaults 95 10
|
||||
update-rc.d kibana defaults 95 10
|
||||
```
|
||||
|
||||
## ElasticSearch Configuration
|
||||
|
||||
TBD
|
||||
|
||||
## Kibana Configuration
|
||||
|
||||
* Make a folder for logs
|
||||
|
||||
```
|
||||
mkdir /var/log/kibana
|
||||
chown kibana:kibana /var/log/kibana
|
||||
```
|
||||
|
||||
* Change the following parameters in /etc/kibana/kibana.yml to reflect your server setup:
|
||||
|
||||
```
|
||||
"server.host" - set it to "localhost" if you use nginx for basic authentication or external interface if you use XPack (see below)
|
||||
"server.name" - name of the server
|
||||
"elasticsearch.url" - address of the elasticsearch
|
||||
"elasticsearch.username", "elasticsearch.password" - needed only if you use XPack (see below)
|
||||
"logging.dest" - set path to logs (/var/log/kibana/kibana.log)
|
||||
```
|
||||
|
||||
## Logstash Configuration
|
||||
|
||||
* Download GeoIP data
|
||||
|
||||
```
|
||||
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
|
||||
wget http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
|
||||
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
|
||||
```
|
||||
|
||||
* Place these somewhere in your filesystem.
|
||||
* Place these somewhere in your filesystem and make sure that "logstash" user can read it
|
||||
|
||||
* Configure logstash
|
||||
|
||||
@@ -65,3 +94,59 @@ http://<hostname>:9200/_search?q=cowrie&size=5
|
||||
|
||||
* If this gives output, your data is correctly loaded into ElasticSearch
|
||||
|
||||
* When you successfully configured logstash, remove "file" and "stdout" blocks from output section of logstash configuration.
|
||||
|
||||
## Distributed setup of sensors or multiple sensors on the same host
|
||||
|
||||
If you have multiple sensors, you will need to setup up FileBeat to feed logstash with logs from all sensors
|
||||
|
||||
On the logstash server:
|
||||
|
||||
* Change "input" section of the logstash to the following:
|
||||
|
||||
```
|
||||
input {
|
||||
beats {
|
||||
port => 5044
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
On the sensor servers:
|
||||
|
||||
* Install filebeat
|
||||
```
|
||||
wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
|
||||
echo "deb https://artifacts.elastic.co/packages/5.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-5.x.list
|
||||
apt-get update
|
||||
apt-get install filebeat
|
||||
```
|
||||
|
||||
* Enable autorun for it
|
||||
```
|
||||
update-rc.d filebeat defaults 95 10
|
||||
```
|
||||
|
||||
* Configure filebeat
|
||||
|
||||
```
|
||||
cp filebeat-cowrie.conf /etc/filebeat/filebeat.yml
|
||||
```
|
||||
|
||||
* Check the following parameters
|
||||
```
|
||||
paths - path to cowrie's json logs
|
||||
logstash - check ip of the logstash host
|
||||
```
|
||||
|
||||
* Start filebeat
|
||||
|
||||
```
|
||||
service filebeat start
|
||||
```
|
||||
|
||||
## Tuning ELK stack
|
||||
|
||||
* Refer to elastic's documentation about proper configuration of the system for the best elasticsearch's performance
|
||||
|
||||
* You may avoid installing nginx for restricting access to the kibana by installing official elastic's plugin called "X-Pack" (https://www.elastic.co/products/x-pack)
|
||||
22
doc/elk/filebeat-cowrie.conf
Normal file
22
doc/elk/filebeat-cowrie.conf
Normal file
@@ -0,0 +1,22 @@
|
||||
filebeat:
|
||||
prospectors:
|
||||
-
|
||||
paths:
|
||||
- /home/cowrie/cowrie/log/cowrie.json*
|
||||
encoding: plain
|
||||
input_type: log
|
||||
document_type: cowrie
|
||||
registry_file: /var/lib/filebeat/registry
|
||||
output:
|
||||
logstash:
|
||||
hosts: ["10.10.0.11:5044"]
|
||||
shipper:
|
||||
logging:
|
||||
to_syslog: false
|
||||
to_files: true
|
||||
files:
|
||||
path: /var/log/filebeat/
|
||||
name: mybeat
|
||||
rotateeverybytes: 10485760 # = 10MB
|
||||
keepfiles: 7
|
||||
level: info
|
||||
@@ -1,675 +0,0 @@
|
||||
{
|
||||
"title": "Cowrie2ElasticSearch",
|
||||
"services": {
|
||||
"query": {
|
||||
"list": {
|
||||
"0": {
|
||||
"query": "*",
|
||||
"alias": "",
|
||||
"color": "#7EB26D",
|
||||
"id": 0,
|
||||
"pin": false,
|
||||
"type": "lucene",
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"list": {
|
||||
"0": {
|
||||
"type": "terms",
|
||||
"field": "_type",
|
||||
"value": "cowrie",
|
||||
"mandate": "must",
|
||||
"active": true,
|
||||
"alias": "",
|
||||
"id": 0
|
||||
},
|
||||
"1": {
|
||||
"type": "time",
|
||||
"field": "@timestamp",
|
||||
"from": "now-30d",
|
||||
"to": "now",
|
||||
"mandate": "must",
|
||||
"active": true,
|
||||
"alias": "",
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
"ids": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"rows": [
|
||||
{
|
||||
"title": "Graph",
|
||||
"height": "250px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"error": false,
|
||||
"span": 3,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "sensor",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": false,
|
||||
"size": 5,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "table",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "Sensors"
|
||||
},
|
||||
{
|
||||
"error": false,
|
||||
"span": 3,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "success",
|
||||
"exclude": [],
|
||||
"missing": true,
|
||||
"other": true,
|
||||
"size": 5,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "table",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "Successes"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
},
|
||||
{
|
||||
"title": "Histogram",
|
||||
"height": "300px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"span": 12,
|
||||
"editable": true,
|
||||
"type": "histogram",
|
||||
"loadingEditor": false,
|
||||
"mode": "count",
|
||||
"time_field": "timestamp",
|
||||
"value_field": null,
|
||||
"x-axis": true,
|
||||
"y-axis": true,
|
||||
"scale": 1,
|
||||
"y_format": "none",
|
||||
"grid": {
|
||||
"max": null,
|
||||
"min": 0
|
||||
},
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"annotate": {
|
||||
"enable": false,
|
||||
"query": "*",
|
||||
"size": 20,
|
||||
"field": "_type",
|
||||
"sort": [
|
||||
"_score",
|
||||
"desc"
|
||||
]
|
||||
},
|
||||
"auto_int": false,
|
||||
"resolution": 100,
|
||||
"interval": "1d",
|
||||
"intervals": [
|
||||
"auto",
|
||||
"1s",
|
||||
"1m",
|
||||
"5m",
|
||||
"10m",
|
||||
"30m",
|
||||
"1h",
|
||||
"3h",
|
||||
"12h",
|
||||
"1d",
|
||||
"1w",
|
||||
"1y"
|
||||
],
|
||||
"lines": true,
|
||||
"fill": 0,
|
||||
"linewidth": 3,
|
||||
"points": false,
|
||||
"pointradius": 5,
|
||||
"bars": false,
|
||||
"stack": true,
|
||||
"spyable": true,
|
||||
"zoomlinks": true,
|
||||
"options": true,
|
||||
"legend": true,
|
||||
"show_query": true,
|
||||
"interactive": true,
|
||||
"legend_counts": true,
|
||||
"timezone": "browser",
|
||||
"percentage": false,
|
||||
"zerofill": true,
|
||||
"derivative": false,
|
||||
"tooltip": {
|
||||
"value_type": "cumulative",
|
||||
"query_as_alias": true
|
||||
},
|
||||
"title": "Histogram",
|
||||
"scaleSeconds": false
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
},
|
||||
{
|
||||
"title": "Usernames",
|
||||
"height": "300px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"error": false,
|
||||
"span": 6,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "username.raw",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": false,
|
||||
"size": 20,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "bar",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "Usernames (top 20)"
|
||||
},
|
||||
{
|
||||
"error": false,
|
||||
"span": 6,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "username.raw",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": false,
|
||||
"size": 20,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "pie",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "Usernames (top 20)"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
},
|
||||
{
|
||||
"title": "Passwords",
|
||||
"height": "300px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"error": false,
|
||||
"span": 6,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "password.raw",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": false,
|
||||
"size": 20,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "bar",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "Passwords (top 20)"
|
||||
},
|
||||
{
|
||||
"error": false,
|
||||
"span": 6,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "password.raw",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": false,
|
||||
"size": 20,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "pie",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "Passwords (top 20)"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
},
|
||||
{
|
||||
"title": "Clients",
|
||||
"height": "300px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"error": false,
|
||||
"span": 6,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "client.raw",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": false,
|
||||
"size": 20,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "bar",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "SSH clients (top 20)"
|
||||
},
|
||||
{
|
||||
"error": false,
|
||||
"span": 6,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "client.raw",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": false,
|
||||
"size": 20,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "pie",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "SSH clients (top 20)"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
},
|
||||
{
|
||||
"title": "Maps",
|
||||
"height": "450px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"error": false,
|
||||
"span": 8,
|
||||
"editable": true,
|
||||
"type": "map",
|
||||
"loadingEditor": false,
|
||||
"map": "world",
|
||||
"colors": [
|
||||
"#A0E2E2",
|
||||
"#265656"
|
||||
],
|
||||
"size": 100,
|
||||
"exclude": [],
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"title": "Attack map (world)",
|
||||
"field": "country_code2"
|
||||
},
|
||||
{
|
||||
"error": false,
|
||||
"span": 4,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "geoip.country_name.raw",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": true,
|
||||
"size": 13,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "table",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "count",
|
||||
"valuefield": "",
|
||||
"title": "Countries"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
},
|
||||
{
|
||||
"title": "ASN",
|
||||
"height": "150px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"error": false,
|
||||
"span": 4,
|
||||
"editable": true,
|
||||
"type": "terms",
|
||||
"loadingEditor": false,
|
||||
"field": "geoip.asn.raw",
|
||||
"exclude": [],
|
||||
"missing": false,
|
||||
"other": true,
|
||||
"size": 20,
|
||||
"order": "count",
|
||||
"style": {
|
||||
"font-size": "10pt"
|
||||
},
|
||||
"donut": false,
|
||||
"tilt": false,
|
||||
"labels": true,
|
||||
"arrangement": "horizontal",
|
||||
"chart": "table",
|
||||
"counter_pos": "above",
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"tmode": "terms",
|
||||
"tstat": "total",
|
||||
"valuefield": "",
|
||||
"title": "ASN"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
},
|
||||
{
|
||||
"title": "Events",
|
||||
"height": "650px",
|
||||
"editable": true,
|
||||
"collapse": true,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"error": false,
|
||||
"span": 12,
|
||||
"editable": true,
|
||||
"group": [
|
||||
"default"
|
||||
],
|
||||
"type": "table",
|
||||
"size": 100,
|
||||
"pages": 5,
|
||||
"offset": 0,
|
||||
"sort": [
|
||||
"_score",
|
||||
"desc"
|
||||
],
|
||||
"style": {
|
||||
"font-size": "9pt"
|
||||
},
|
||||
"overflow": "min-height",
|
||||
"fields": [],
|
||||
"highlight": [],
|
||||
"sortable": true,
|
||||
"header": true,
|
||||
"paging": true,
|
||||
"spyable": true,
|
||||
"queries": {
|
||||
"mode": "all",
|
||||
"ids": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"field_list": true,
|
||||
"status": "Stable",
|
||||
"trimFactor": 300,
|
||||
"normTimes": true,
|
||||
"title": "Documents",
|
||||
"all_fields": false,
|
||||
"localTime": false,
|
||||
"timeField": "@timestamp"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
}
|
||||
],
|
||||
"editable": true,
|
||||
"index": {
|
||||
"interval": "day",
|
||||
"pattern": "[logstash-]YYYY.MM.DD",
|
||||
"default": "_all",
|
||||
"warm_fields": false
|
||||
},
|
||||
"style": "dark",
|
||||
"failover": false,
|
||||
"panel_hints": true,
|
||||
"loader": {
|
||||
"save_gist": false,
|
||||
"save_elasticsearch": true,
|
||||
"save_local": true,
|
||||
"save_default": true,
|
||||
"save_temp": true,
|
||||
"save_temp_ttl_enable": true,
|
||||
"save_temp_ttl": "30d",
|
||||
"load_gist": true,
|
||||
"load_elasticsearch": true,
|
||||
"load_elasticsearch_size": 20,
|
||||
"load_local": true,
|
||||
"hide": false
|
||||
},
|
||||
"pulldowns": [
|
||||
{
|
||||
"type": "query",
|
||||
"collapse": false,
|
||||
"notice": false,
|
||||
"query": "*",
|
||||
"pinned": true,
|
||||
"history": [],
|
||||
"remember": 10,
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"type": "filtering",
|
||||
"collapse": false,
|
||||
"notice": true,
|
||||
"enable": true
|
||||
}
|
||||
],
|
||||
"nav": [
|
||||
{
|
||||
"type": "timepicker",
|
||||
"collapse": false,
|
||||
"notice": false,
|
||||
"status": "Stable",
|
||||
"time_options": [
|
||||
"5m",
|
||||
"15m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"24h",
|
||||
"2d",
|
||||
"7d",
|
||||
"30d"
|
||||
],
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"timefield": "@timestamp",
|
||||
"enable": true,
|
||||
"now": true,
|
||||
"filter_id": 1
|
||||
}
|
||||
],
|
||||
"refresh": false
|
||||
}
|
||||
@@ -33,18 +33,7 @@ filter {
|
||||
geoip {
|
||||
source => "src_ip"
|
||||
target => "geoip"
|
||||
database => "/opt/logstash/vendor/geoip/GeoLiteCity.dat"
|
||||
add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ]
|
||||
add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ]
|
||||
}
|
||||
|
||||
geoip {
|
||||
source => "src_ip"
|
||||
database => "/opt/logstash/vendor/geoip/GeoIPASNum.dat"
|
||||
}
|
||||
|
||||
mutate {
|
||||
convert => [ "[geoip][coordinates]", "float" ]
|
||||
database => "/opt/logstash/vendor/geoip/GeoLite2-City.dat"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ Wants=mysql.service
|
||||
Type=forking
|
||||
User=cowrie
|
||||
Group=cowrie
|
||||
PIDFile=var/run/cowrie.pid
|
||||
PIDFile=/home/cowrie/cowrie/var/run/cowrie.pid
|
||||
ExecStart=/home/cowrie/cowrie/start.sh cowrie-env
|
||||
ExecStop=/home/cowrie/cowrie/stop.sh
|
||||
ExecReload=/home/cowrie/cowrie/stop.sh && sleep 10 && /home/cowrie/cowrie/start.sh cowrie-env
|
||||
|
||||
@@ -5,25 +5,10 @@ udev /dev devtmpfs rw,relatime,size=10240k,nr_inodes=997843,mode=755 0 0
|
||||
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
|
||||
tmpfs /run tmpfs rw,nosuid,relatime,size=1613336k,mode=755 0 0
|
||||
/dev/dm-0 / ext3 rw,relatime,errors=remount-ro,data=ordered 0 0
|
||||
securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
|
||||
tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0
|
||||
tmpfs /run/lock tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k 0 0
|
||||
tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec,mode=755 0 0
|
||||
cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd 0 0
|
||||
pstore /sys/fs/pstore pstore rw,nosuid,nodev,noexec,relatime 0 0
|
||||
cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
|
||||
cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0
|
||||
cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
|
||||
cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
|
||||
cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0
|
||||
cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
|
||||
cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
|
||||
systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=22,pgrp=1,timeout=300,minproto=5,maxproto=5,direct 0 0
|
||||
mqueue /dev/mqueue mqueue rw,relatime 0 0
|
||||
hugetlbfs /dev/hugepages hugetlbfs rw,relatime 0 0
|
||||
debugfs /sys/kernel/debug debugfs rw,relatime 0 0
|
||||
fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0
|
||||
/dev/sda1 /boot ext2 rw,relatime 0 0
|
||||
/dev/mapper/home /home ext3 rw,relatime,data=ordered 0 0
|
||||
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
|
||||
tmpfs /run/user/1000 tmpfs rw,nosuid,nodev,relatime,size=806668k,mode=700,uid=1000,gid=1000 0 0
|
||||
|
||||
@@ -10,6 +10,9 @@ pyes
|
||||
# mysql
|
||||
MySQL-python
|
||||
|
||||
# mongodb
|
||||
pymongo
|
||||
|
||||
# rethinkdblog
|
||||
rethinkdb
|
||||
|
||||
|
||||
Reference in New Issue
Block a user