CEF / textlog output module

This commit is contained in:
Michel Oosterhof
2016-02-16 18:42:40 +04:00
parent 457603c59c
commit 90cfee5ee5
6 changed files with 200 additions and 7 deletions

View File

@ -288,8 +288,24 @@ logfile = log/cowrie.json
# Facility can be:
# KERN, USER, MAIL, DAEMON, AUTH, LPR, NEWS, UUCP, CRON, SYSLOG and LOCAL0 to LOCAL7.
#
# Format can be:
# text, cef
#
#[output_localsyslog]
#facility = USER
#format = text
# Text output
#
# This writes log entries to a text file
#
# Format can be:
# text, cef
#
#[output_textlog]
#logfile = log/cowrie.textlog
#format = text
# MySQL logging module (output)

111
cowrie/core/cef.py Normal file
View File

@ -0,0 +1,111 @@
# 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.
"""
This module contains ...
"""
from twisted.python import log
# cowrie.client.fingerprint
# cowrie.client.size
# cowrie.client.var
# cowrie.client.version
# cowrie.command.failed
# cowrie.command.success
# cowrie.direct-tcpip.data
# cowrie.direct-tcpip.request
# cowrie.log.closed
# cowrie.log.open
# cowrie.login.failed
# cowrie.login.success
# cowrie.session.closed
# cowrie.session.connect
# cowrie.session.file_download
# cowrie.session.file_upload
def formatCef(logentry):
"""
Take logentry and turn into CEF string
"""
# Jan 18 11:07:53 host CEF:Version|Device Vendor|Device Product|Device Version|Signature ID|Name|Severity|[Extension]
cefVendor = "Cowrie"
cefProduct = "Cowrie"
cefVersion = "1.0"
cefSignature = logentry["eventid"]
cefName = logentry["eventid"]
cefSeverity = "5"
cefExtensions = {
'app': 'SSHv2',
'destinationServicename': 'sshd',
'deviceExternalId': logentry['sensor'],
'msg': log.textFromEventDict(logentry),
'src' : logentry['src_ip'],
'proto': 'tcp'
}
if logentry['eventid'] == 'cowrie.session.connect':
cefExtensions['spt'] = logentry['src_port']
cefExtensions['dpt'] = logentry['dst_port']
cefExtensions['src'] = logentry['src_ip']
cefExtensions['dst'] = logentry['dst_ip']
elif logentry['eventid'] == 'cowrie.login.success':
cefExtensions['duser'] = logentry['username']
cefExtensions['outcome'] = 'success'
elif logentry['eventid'] == 'cowrie.login.failed':
cefExtensions['duser'] = logentry['username']
cefExtensions['outcome'] = 'failed'
elif logentry['eventid'] == 'cowrie.file.file_download':
cefExtensions['filehash'] = logentry['filehash']
cefExtensions['filePath'] = logentry['filename']
cefExtensions['fsize'] = logentry['size']
elif logentry['eventid'] == 'cowrie.file.file_upload':
cefExtensions['filehash'] = logentry['filehash']
cefExtensions['filePath'] = logentry['filename']
cefExtensions['fsize'] = logentry['size']
# 'out' 'outcome' request, rt
cefList = []
for key in cefExtensions.keys():
value = str(cefExtensions[key]).replace(' ', '\ ')
cefList.append(key+"="+value)
cefExtension = ' '.join(cefList)
cefString = "CEF:0|" + \
cefVendor + "|" + \
cefProduct + "|" + \
cefVersion + "|" + \
cefSignature + "|" + \
cefName + "|" + \
cefSeverity + "|" + \
cefExtension
return cefString

View File

@ -158,11 +158,10 @@ class Output(object):
# Connection event is special. adds to session list
if ev['eventid'] == 'cowrie.session.connect':
self.sessions[sessionno] = ev['id']
self.sessions[sessionno] = ev['session']
self.ips[sessionno] = ev['src_ip']
del ev['id']
ev['session'] = self.sessions[sessionno]
else:
ev['session'] = self.sessions[sessionno]
self.write(ev)

View File

@ -30,6 +30,7 @@ import syslog
import twisted.python.syslog
import cowrie.core.output
import cowrie.core.cef
class Output(cowrie.core.output.Output):
@ -38,6 +39,7 @@ class Output(cowrie.core.output.Output):
"""
cowrie.core.output.Output.__init__(self, cfg)
facilityString = cfg.get('output_localsyslog', 'facility')
self.format = cfg.get('output_localsyslog', 'format')
self.facility = vars(syslog)['LOG_' + facilityString]
self.syslog = twisted.python.syslog.SyslogObserver(prefix='cowrie', facility=self.facility)
@ -57,5 +59,8 @@ class Output(cowrie.core.output.Output):
def write(self, logentry):
"""
"""
self.syslog.emit(logentry)
if self.format == 'cef':
self.syslog.emit(cowrie.core.cef.formatCef(logentry))
else:
self.syslog.emit(logentry)

62
cowrie/output/textlog.py Normal file
View File

@ -0,0 +1,62 @@
# 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 cowrie.core.output
import cowrie.core.cef
class Output(cowrie.core.output.Output):
def __init__(self, cfg):
"""
"""
cowrie.core.output.Output.__init__(self, cfg)
self.format = cfg.get('output_textlog', 'format')
self.outfile = file(cfg.get('output_textlog', 'logfile'), 'a')
def start(self):
"""
"""
pass
def stop(self):
"""
"""
pass
def write(self, logentry):
"""
"""
if self.format == 'cef':
self.outfile.write(cowrie.core.cef.formatCef(logentry)+'\n')
self.outfile.flush()
else:
self.outfile.write(logentry["message"])

View File

@ -171,10 +171,10 @@ class HoneyPotTransport(transport.SSHServerTransport, TimeoutMixin):
self.transportId = uuid.uuid4().hex[:8]
log.msg(eventid='cowrie.session.connect',
format='New connection: %(src_ip)s:%(src_port)s (%(dst_ip)s:%(dst_port)s) [session: %(sessionno)s]',
format='New connection: %(src_ip)s:%(src_port)s (%(dst_ip)s:%(dst_port)s) [session: %(session)s]',
src_ip=self.transport.getPeer().host, src_port=self.transport.getPeer().port,
dst_ip=self.transport.getHost().host, dst_port=self.transport.getHost().port,
id=self.transportId, sessionno=self.transport.sessionno)
session=self.transportId, sessionno=self.transport.sessionno)
self.transport.write('{}\r\n'.format(self.ourVersionString))
self.currentEncryptions = transport.SSHCiphers('none', 'none', 'none', 'none')