* load pickle from scratch, don't deepcopy
* allow output module `import` without side effects
* set up intersphinx for py3 and twisted
This commit is contained in:
Michel Oosterhof
2019-05-21 01:00:49 +04:00
committed by GitHub
parent c0217d3ef4
commit f551b249f0
28 changed files with 80 additions and 87 deletions

View File

@ -189,3 +189,8 @@ epub_exclude_files = ['search.html']
# If true, `todo` and `todoList` produce output, else they produce nothing. # If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True todo_include_todos = True
# -- Options for intersphinx extension ---------------------------------------
intersphinx_mapping = {'python': ('https://docs.python.org/3', None),
'twisted': ('https://twistedmatrix.com/documents/current/api/', None)}

View File

@ -2,7 +2,7 @@
# See the COPYRIGHT file for more information # See the COPYRIGHT file for more information
""" """
This module contains ... This module contains code to deal with Cowrie's configuration
""" """
from __future__ import absolute_import, division from __future__ import absolute_import, division
@ -31,7 +31,9 @@ class CowrieConfig(object):
class EnvironmentConfigParser(configparser.ConfigParser): class EnvironmentConfigParser(configparser.ConfigParser):
"""
ConfigParser with additional option to read from environment variables
"""
def has_option(self, section, option): def has_option(self, section, option):
if to_environ_key('_'.join((section, option))) in environ: if to_environ_key('_'.join((section, option))) in environ:
return True return True
@ -41,8 +43,7 @@ class EnvironmentConfigParser(configparser.ConfigParser):
key = to_environ_key('_'.join((section, option))) key = to_environ_key('_'.join((section, option)))
if key in environ: if key in environ:
return environ[key] return environ[key]
return super(EnvironmentConfigParser, self).get( return super(EnvironmentConfigParser, self).get(section, option, **kwargs)
section, option, **kwargs)
def readConfigFile(cfgfile): def readConfigFile(cfgfile):

View File

@ -28,9 +28,9 @@
from __future__ import absolute_import, division from __future__ import absolute_import, division
import twisted
from twisted.conch import interfaces as conchinterfaces from twisted.conch import interfaces as conchinterfaces
from twisted.conch.telnet import ITelnetProtocol from twisted.conch.telnet import ITelnetProtocol
from twisted.cred.portal import IRealm
from twisted.python import log from twisted.python import log
from zope.interface import implementer from zope.interface import implementer
@ -43,7 +43,7 @@ from cowrie.shell import server as shellserver
from cowrie.telnet import session from cowrie.telnet import session
@implementer(twisted.cred.portal.IRealm) @implementer(IRealm)
class HoneyPotRealm(object): class HoneyPotRealm(object):
def __init__(self): def __init__(self):

View File

@ -21,12 +21,12 @@ class Output(cowrie.core.output.Output):
""" """
csirtg output csirtg output
""" """
user = CowrieConfig().get('output_csirtg', 'username') or USERNAME
feed = CowrieConfig().get('output_csirtg', 'feed') or FEED
token = CowrieConfig().get('output_csirtg', 'token') or TOKEN
description = CowrieConfig().get('output_csirtg', 'description', fallback=DESCRIPTION)
def start(self, ): def start(self, ):
self.user = CowrieConfig().get('output_csirtg', 'username') or USERNAME
self.feed = CowrieConfig().get('output_csirtg', 'feed') or FEED
self.token = CowrieConfig().get('output_csirtg', 'token') or TOKEN
self.description = CowrieConfig().get('output_csirtg', 'description', fallback=DESCRIPTION)
self.context = {} self.context = {}
self.client = Client(token=self.token) self.client = Client(token=self.token)

View File

@ -50,16 +50,15 @@ class Output(cowrie.core.output.Output):
""" """
cuckoo output cuckoo output
""" """
url_base = CowrieConfig().get('output_cuckoo', 'url_base').encode('utf-8')
api_user = CowrieConfig().get('output_cuckoo', 'user')
api_passwd = CowrieConfig().get('output_cuckoo', 'passwd', raw=True)
cuckoo_force = int(CowrieConfig().getboolean('output_cuckoo', 'force'))
def start(self): def start(self):
""" """
Start output plugin Start output plugin
""" """
pass self.url_base = CowrieConfig().get('output_cuckoo', 'url_base').encode('utf-8')
self.api_user = CowrieConfig().get('output_cuckoo', 'user')
self.api_passwd = CowrieConfig().get('output_cuckoo', 'passwd', raw=True)
self.cuckoo_force = int(CowrieConfig().getboolean('output_cuckoo', 'force'))
def stop(self): def stop(self):
""" """

View File

@ -26,12 +26,12 @@ class Output(cowrie.core.output.Output):
""" """
dshield output dshield output
""" """
auth_key = CowrieConfig().get('output_dshield', 'auth_key')
userid = CowrieConfig().get('output_dshield', 'userid')
batch_size = CowrieConfig().getint('output_dshield', 'batch_size')
debug = CowrieConfig().getboolean('output_dshield', 'debug', fallback=False)
def start(self): def start(self):
self.auth_key = CowrieConfig().get('output_dshield', 'auth_key')
self.userid = CowrieConfig().get('output_dshield', 'userid')
self.batch_size = CowrieConfig().getint('output_dshield', 'batch_size')
self.debug = CowrieConfig().getboolean('output_dshield', 'debug', fallback=False)
self.batch = [] # This is used to store login attempts in batches self.batch = [] # This is used to store login attempts in batches
def stop(self): def stop(self):

View File

@ -12,13 +12,13 @@ class Output(cowrie.core.output.Output):
""" """
elasticsearch output elasticsearch output
""" """
host = CowrieConfig().get('output_elasticsearch', 'host')
port = CowrieConfig().get('output_elasticsearch', 'port')
index = CowrieConfig().get('output_elasticsearch', 'index')
type = CowrieConfig().get('output_elasticsearch', 'type')
pipeline = CowrieConfig().get('output_elasticsearch', 'pipeline')
def start(self): def start(self):
self.host = CowrieConfig().get('output_elasticsearch', 'host')
self.port = CowrieConfig().get('output_elasticsearch', 'port')
self.index = CowrieConfig().get('output_elasticsearch', 'index')
self.type = CowrieConfig().get('output_elasticsearch', 'type')
self.pipeline = CowrieConfig().get('output_elasticsearch', 'pipeline')
self.es = Elasticsearch('{0}:{1}'.format(self.host, self.port)) self.es = Elasticsearch('{0}:{1}'.format(self.host, self.port))
def stop(self): def stop(self):

View File

@ -20,14 +20,14 @@ class Output(cowrie.core.output.Output):
""" """
greynoise output greynoise output
""" """
apiKey = CowrieConfig().get('output_greynoise', 'api_key', fallback=None)
tags = CowrieConfig().get('output_greynoise', 'tags', fallback="all").split(",")
debug = CowrieConfig().getboolean('output_greynoise', 'debug', fallback=False)
def start(self): def start(self):
""" """
Start output plugin Start output plugin
""" """
self.apiKey = CowrieConfig().get('output_greynoise', 'api_key', fallback=None)
self.tags = CowrieConfig().get('output_greynoise', 'tags', fallback="all").split(",")
self.debug = CowrieConfig().getboolean('output_greynoise', 'debug', fallback=False)
def stop(self): def stop(self):
""" """

View File

@ -40,9 +40,9 @@ class Output(cowrie.core.output.Output):
""" """
jsonlog output jsonlog output
""" """
epoch_timestamp = CowrieConfig().getboolean('output_jsonlog', 'epoch_timestamp', fallback=False)
def start(self): def start(self):
self.epoch_timestamp = CowrieConfig().getboolean('output_jsonlog', 'epoch_timestamp', fallback=False)
fn = CowrieConfig().get('output_jsonlog', 'logfile') fn = CowrieConfig().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

@ -41,9 +41,9 @@ class Output(cowrie.core.output.Output):
""" """
localsyslog output localsyslog output
""" """
format = CowrieConfig().get('output_localsyslog', 'format')
def start(self): def start(self):
self.format = CowrieConfig().get('output_localsyslog', 'format')
facilityString = CowrieConfig().get('output_localsyslog', 'facility') facilityString = CowrieConfig().get('output_localsyslog', 'facility')
self.facility = vars(syslog)['LOG_' + facilityString] self.facility = vars(syslog)['LOG_' + facilityString]
self.syslog = twisted.python.syslog.SyslogObserver(prefix='cowrie', facility=self.facility) self.syslog = twisted.python.syslog.SyslogObserver(prefix='cowrie', facility=self.facility)

View File

@ -47,9 +47,9 @@ class Output(cowrie.core.output.Output):
mysql output mysql output
""" """
db = None db = None
debug = CowrieConfig().getboolean('output_mysql', 'debug', fallback=False)
def start(self): def start(self):
self.debug = CowrieConfig().getboolean('output_mysql', 'debug', fallback=False)
port = CowrieConfig().getint('output_mysql', 'port', fallback=3306) port = CowrieConfig().getint('output_mysql', 'port', fallback=3306)
try: try:
self.db = ReconnectingConnectionPool( self.db = ReconnectingConnectionPool(

View File

@ -1,7 +1,7 @@
from __future__ import absolute_import, division from __future__ import absolute_import, division
import json import json
from ConfigParser import NoOptionError from configparser import NoOptionError
import redis import redis

View File

@ -17,14 +17,14 @@ RETHINK_DB_SEGMENT = 'output_rethinkdblog'
class Output(cowrie.core.output.Output): class Output(cowrie.core.output.Output):
host = CowrieConfig().get(RETHINK_DB_SEGMENT, 'host')
port = CowrieConfig().getint(RETHINK_DB_SEGMENT, 'port')
db = CowrieConfig().get(RETHINK_DB_SEGMENT, 'db')
table = CowrieConfig().get(RETHINK_DB_SEGMENT, 'table')
password = CowrieConfig().get(RETHINK_DB_SEGMENT, 'password', raw=True)
# noinspection PyAttributeOutsideInit # noinspection PyAttributeOutsideInit
def start(self): def start(self):
self.host = CowrieConfig().get(RETHINK_DB_SEGMENT, 'host')
self.port = CowrieConfig().getint(RETHINK_DB_SEGMENT, 'port')
self.db = CowrieConfig().get(RETHINK_DB_SEGMENT, 'db')
self.table = CowrieConfig().get(RETHINK_DB_SEGMENT, 'table')
self.password = CowrieConfig().get(RETHINK_DB_SEGMENT, 'password', raw=True)
self.connection = r.connect( self.connection = r.connect(
host=self.host, host=self.host,
port=self.port, port=self.port,

View File

@ -15,14 +15,13 @@ class Output(cowrie.core.output.Output):
""" """
Output plugin used for reverse DNS lookup Output plugin used for reverse DNS lookup
""" """
timeout = [CowrieConfig().getint(
'output_reversedns', 'timeout', fallback=3)]
def start(self): def start(self):
""" """
Start Output Plugin Start Output Plugin
""" """
pass self.timeout = [CowrieConfig().getint(
'output_reversedns', 'timeout', fallback=3)]
def stop(self): def stop(self):
""" """

View File

@ -20,9 +20,9 @@ class Output(cowrie.core.output.Output):
""" """
s3 output s3 output
""" """
bucket = CowrieConfig().get("output_s3", "bucket")
def start(self): def start(self):
self.bucket = CowrieConfig().get("output_s3", "bucket")
self.seen = set() self.seen = set()
self.session = get_session() self.session = get_session()

View File

@ -41,10 +41,10 @@ class Output(cowrie.core.output.Output):
""" """
slack output slack output
""" """
slack_channel = CowrieConfig().get('output_slack', 'channel')
slack_token = CowrieConfig().get('output_slack', 'token')
def start(self): def start(self):
self.slack_channel = CowrieConfig().get('output_slack', 'channel')
self.slack_token = CowrieConfig().get('output_slack', 'token')
pass pass
def stop(self): def stop(self):

View File

@ -13,9 +13,9 @@ class Output(cowrie.core.output.Output):
""" """
socketlog output socketlog output
""" """
timeout = CowrieConfig().getint('output_socketlog', 'timeout')
def start(self): def start(self):
self.timeout = CowrieConfig().getint('output_socketlog', 'timeout')
addr = CowrieConfig().get('output_socketlog', 'address') addr = CowrieConfig().get('output_socketlog', 'address')
self.host = addr.split(':')[0] self.host = addr.split(':')[0]
self.port = int(addr.split(':')[1]) self.port = int(addr.split(':')[1])

View File

@ -29,14 +29,14 @@ class Output(cowrie.core.output.Output):
""" """
Splunk HEC output Splunk HEC output
""" """
token = CowrieConfig().get('output_splunk', 'token')
url = CowrieConfig().get('output_splunk', 'url').encode('utf8')
index = CowrieConfig().get('output_splunk', 'index', fallback=None)
source = CowrieConfig().get('output_splunk', 'source', fallback=None)
sourcetype = CowrieConfig().get('output_splunk', 'sourcetype', fallback=None)
host = CowrieConfig().get('output_splunk', 'host', fallback=None)
def start(self): def start(self):
self.token = CowrieConfig().get('output_splunk', 'token')
self.url = CowrieConfig().get('output_splunk', 'url').encode('utf8')
self.index = CowrieConfig().get('output_splunk', 'index', fallback=None)
self.source = CowrieConfig().get('output_splunk', 'source', fallback=None)
self.sourcetype = CowrieConfig().get('output_splunk', 'sourcetype', fallback=None)
self.host = CowrieConfig().get('output_splunk', 'host', fallback=None)
contextFactory = WebClientContextFactory() contextFactory = WebClientContextFactory()
# contextFactory.method = TLSv1_METHOD # contextFactory.method = TLSv1_METHOD
self.agent = client.Agent(reactor, contextFactory) self.agent = client.Agent(reactor, contextFactory)

View File

@ -37,10 +37,10 @@ class Output(cowrie.core.output.Output):
""" """
textlog output textlog output
""" """
format = CowrieConfig().get('output_textlog', 'format')
outfile = open(CowrieConfig().get('output_textlog', 'logfile'), 'a')
def start(self): def start(self):
self.format = CowrieConfig().get('output_textlog', 'format')
self.outfile = open(CowrieConfig().get('output_textlog', 'logfile'), 'a')
pass pass
def stop(self): def stop(self):

View File

@ -63,18 +63,18 @@ class Output(cowrie.core.output.Output):
""" """
virustotal output virustotal output
""" """
apiKey = CowrieConfig().get('output_virustotal', 'api_key')
debug = CowrieConfig().getboolean('output_virustotal', 'debug', fallback=False)
upload = CowrieConfig().getboolean('output_virustotal', 'upload', fallback=True)
comment = CowrieConfig().getboolean('output_virustotal', 'comment', fallback=True)
scan_file = CowrieConfig().getboolean('output_virustotal', 'scan_file', fallback=True)
scan_url = CowrieConfig().getboolean('output_virustotal', 'scan_url', fallback=False)
commenttext = CowrieConfig().get('output_virustotal', 'commenttext', fallback=COMMENT)
def start(self): def start(self):
""" """
Start output plugin Start output plugin
""" """
self.apiKey = CowrieConfig().get('output_virustotal', 'api_key')
self.debug = CowrieConfig().getboolean('output_virustotal', 'debug', fallback=False)
self.upload = CowrieConfig().getboolean('output_virustotal', 'upload', fallback=True)
self.comment = CowrieConfig().getboolean('output_virustotal', 'comment', fallback=True)
self.scan_file = CowrieConfig().getboolean('output_virustotal', 'scan_file', fallback=True)
self.scan_url = CowrieConfig().getboolean('output_virustotal', 'scan_url', fallback=False)
self.commenttext = CowrieConfig().get('output_virustotal', 'commenttext', fallback=COMMENT)
self.agent = client.Agent(reactor, WebClientContextFactory()) self.agent = client.Agent(reactor, WebClientContextFactory())
def stop(self): def stop(self):

View File

@ -20,18 +20,6 @@ from twisted.python import log
from cowrie.core.config import CowrieConfig from cowrie.core.config import CowrieConfig
# At the moment this is the first place a config file is used
# Put extra help here in case it goes wrong
try:
with open(CowrieConfig().get('shell', 'filesystem'), 'rb') as f:
PICKLE = pickle.load(f)
except UnicodeDecodeError:
with open(CowrieConfig().get('shell', 'filesystem'), 'rb') as f:
PICKLE = pickle.load(f, encoding='utf8')
except Exception as e:
log.err(e, "ERROR: Failed to load filesystem")
exit(2)
A_NAME, A_TYPE, A_UID, A_GID, A_SIZE, A_MODE, A_CTIME, A_CONTENTS, A_TARGET, A_REALFILE = list(range(0, 10)) A_NAME, A_TYPE, A_UID, A_GID, A_SIZE, A_MODE, A_CTIME, A_CONTENTS, A_TARGET, A_REALFILE = list(range(0, 10))
T_LINK, T_DIR, T_FILE, T_BLK, T_CHR, T_SOCK, T_FIFO = list(range(0, 7)) T_LINK, T_DIR, T_FILE, T_BLK, T_CHR, T_SOCK, T_FIFO = list(range(0, 7))
@ -85,7 +73,16 @@ class PermissionDenied(Exception):
class HoneyPotFilesystem(object): class HoneyPotFilesystem(object):
def __init__(self, fs, arch): def __init__(self, fs, arch):
self.fs = fs
try:
with open(CowrieConfig().get('shell', 'filesystem'), 'rb') as f:
self.fs = pickle.load(f)
except UnicodeDecodeError:
with open(CowrieConfig().get('shell', 'filesystem'), 'rb') as f:
self.fs = pickle.load(f, encoding='utf8')
except Exception as e:
log.err(e, "ERROR: Failed to load filesystem")
exit(2)
# Keep track of arch so we can return appropriate binary # Keep track of arch so we can return appropriate binary
self.arch = arch self.arch = arch

View File

@ -28,7 +28,6 @@
from __future__ import absolute_import, division from __future__ import absolute_import, division
import copy
import json import json
import random import random
from configparser import NoOptionError from configparser import NoOptionError
@ -74,7 +73,7 @@ class CowrieServer(object):
""" """
Do this so we can trigger it later. Not all sessions need file system Do this so we can trigger it later. Not all sessions need file system
""" """
self.fs = fs.HoneyPotFilesystem(copy.deepcopy(fs.PICKLE), self.arch) self.fs = fs.HoneyPotFilesystem(None, self.arch)
try: try:
self.process = self.getCommandOutput(CowrieConfig().get('shell', 'processes'))['command']['ps'] self.process = self.getCommandOutput(CowrieConfig().get('shell', 'processes'))['command']['ps']

View File

@ -231,7 +231,7 @@ class HoneyPotSSHTransport(transport.SSHServerTransport, TimeoutMixin):
@param reason: the reason for the disconnect. Should be one of the @param reason: the reason for the disconnect. Should be one of the
DISCONNECT_* values. DISCONNECT_* values.
@type reason: C{int} @type reason: C{int}
@param desc: a descrption of the reason for the disconnection. @param desc: a description of the reason for the disconnection.
@type desc: C{str} @type desc: C{str}
""" """
if b'bad packet length' not in desc: if b'bad packet length' not in desc:
@ -243,8 +243,7 @@ class HoneyPotSSHTransport(transport.SSHServerTransport, TimeoutMixin):
def receiveError(self, reasonCode, description): def receiveError(self, reasonCode, description):
""" """
Called when we receive a disconnect error message from the other Called when we receive a disconnect error message from the other side.
side.
@param reasonCode: the reason for the disconnect, one of the @param reasonCode: the reason for the disconnect, one of the
DISCONNECT_ values. DISCONNECT_ values.

View File

@ -5,10 +5,6 @@
from __future__ import absolute_import, division from __future__ import absolute_import, division
import copy
import pickle
from cowrie.core.config import CowrieConfig
from cowrie.shell import fs from cowrie.shell import fs
@ -22,9 +18,7 @@ class FakeServer:
self.arch = 'linux-x64-lsb' self.arch = 'linux-x64-lsb'
self.hostname = "unitTest" self.hostname = "unitTest"
self.pckl = pickle.load( self.fs = fs.HoneyPotFilesystem(None, 'arch')
open(CowrieConfig().get('honeypot', 'filesystem_file'), 'rb'))
self.fs = fs.HoneyPotFilesystem(copy.deepcopy(self.pckl), 'arch')
self.process = None self.process = None

View File

@ -13,7 +13,7 @@ from cowrie.shell import protocol
from cowrie.test import fake_server, fake_transport from cowrie.test import fake_server, fake_transport
os.environ["HONEYPOT_DATA_PATH"] = "../data" os.environ["HONEYPOT_DATA_PATH"] = "../data"
os.environ["HONEYPOT_FILESYSTEM_FILE"] = "../share/cowrie/fs.pickle" os.environ["SHELL_FILESYSTEM"] = "../share/cowrie/fs.pickle"
PROMPT = b"root@unitTest:~# " PROMPT = b"root@unitTest:~# "

View File

@ -18,7 +18,7 @@ from cowrie.test import fake_server, fake_transport
os.environ["HONEYPOT_DATA_PATH"] = "../data" os.environ["HONEYPOT_DATA_PATH"] = "../data"
os.environ["HONEYPOT_DOWNLOAD_PATH"] = "/tmp" os.environ["HONEYPOT_DOWNLOAD_PATH"] = "/tmp"
os.environ["HONEYPOT_FILESYSTEM_FILE"] = "../share/cowrie/fs.pickle" os.environ["SHELL_FILESYSTEM"] = "../share/cowrie/fs.pickle"
PROMPT = b"root@unitTest:~# " PROMPT = b"root@unitTest:~# "

View File

@ -15,7 +15,7 @@ from cowrie.test import fake_server, fake_transport
os.environ["HONEYPOT_DATA_PATH"] = "../data" os.environ["HONEYPOT_DATA_PATH"] = "../data"
os.environ["HONEYPOT_DOWNLOAD_PATH"] = "/tmp" os.environ["HONEYPOT_DOWNLOAD_PATH"] = "/tmp"
os.environ["HONEYPOT_FILESYSTEM_FILE"] = "../share/cowrie/fs.pickle" os.environ["SHELL_FILESYSTEM"] = "../share/cowrie/fs.pickle"
PROMPT = b"root@unitTest:~# " PROMPT = b"root@unitTest:~# "

View File

@ -18,7 +18,7 @@ from cowrie.test import fake_server, fake_transport
os.environ["HONEYPOT_DATA_PATH"] = "../data" os.environ["HONEYPOT_DATA_PATH"] = "../data"
os.environ["HONEYPOT_DOWNLOAD_PATH"] = "/tmp" os.environ["HONEYPOT_DOWNLOAD_PATH"] = "/tmp"
os.environ["HONEYPOT_FILESYSTEM_FILE"] = "../share/cowrie/fs.pickle" os.environ["SHELL_FILESYSTEM"] = "../share/cowrie/fs.pickle"
PROMPT = b"root@unitTest:~# " PROMPT = b"root@unitTest:~# "