mirror of
https://github.com/aljazceru/cowrie.git
synced 2026-01-31 12:04:24 +01:00
Merge branch 'master' of https://github.com/micheloosterhof/cowrie
This commit is contained in:
13
bin/cowrie
13
bin/cowrie
@@ -59,15 +59,18 @@ cowrie_stop () {
|
||||
fi
|
||||
}
|
||||
|
||||
cowrie_usage() {
|
||||
echo "usage: $0 <start|stop>"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## Main script
|
||||
################################################################################
|
||||
|
||||
if [ "$#" = 0 ]
|
||||
then
|
||||
echo "Usage: $0 <command>"
|
||||
echo 'Command can be "start" or "stop"'
|
||||
exit 0
|
||||
cowrie_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
find_cowrie_directory $0
|
||||
@@ -89,5 +92,9 @@ do
|
||||
status)
|
||||
cowrie_status
|
||||
;;
|
||||
*)
|
||||
cowrie_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -51,7 +51,7 @@ data_path = data
|
||||
contents_path = honeyfs
|
||||
|
||||
|
||||
# File in the python pickle format containing the virtual filesystem.
|
||||
# File in the Python pickle format containing the virtual filesystem.
|
||||
#
|
||||
# This includes the filenames, paths, permissions for the Cowrie filesystem,
|
||||
# but not the file contents. This is created by the bin/createfs utility from
|
||||
@@ -358,9 +358,11 @@ logfile = log/cowrie.json
|
||||
|
||||
|
||||
# MySQL logging module
|
||||
# Identical functionality as [database_mysql] but with different internals
|
||||
# Database structure for this module is supplied in doc/sql/mysql.sql
|
||||
#
|
||||
# MySQL logging requires extra software: sudo apt-get install libmysqlclient-dev
|
||||
# MySQL logging requires an extra Python module: pip install mysql-python
|
||||
#
|
||||
#[output_mysql]
|
||||
#host = localhost
|
||||
#database = cowrie
|
||||
|
||||
@@ -30,5 +30,6 @@ __all__ = [
|
||||
'which',
|
||||
'perl',
|
||||
'uptime',
|
||||
'python'
|
||||
'python',
|
||||
'tftp'
|
||||
]
|
||||
|
||||
@@ -139,7 +139,8 @@ class command_echo(HoneyPotCommand):
|
||||
|
||||
# FIXME: Wrap in exception, Python escape cannot handle single digit \x codes (e.g. \x1)
|
||||
try:
|
||||
self.write(escape_fn(re.sub('(?<=\\\\)x([0-9a-fA-F]{1})(?=\\\\|\"|\s|$)', 'x0\g<1>', ' '.join(args))))
|
||||
self.write(escape_fn(re.sub('(?<=\\\\)x([0-9a-fA-F]{1})(?=\\\\|\"|\'|\s|$)', 'x0\g<1>',
|
||||
' '.join(args))).strip('\"\''))
|
||||
except ValueError as e:
|
||||
log.msg("echo command received Python incorrect hex escape")
|
||||
|
||||
|
||||
128
cowrie/commands/tftp.py
Normal file
128
cowrie/commands/tftp.py
Normal file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import time
|
||||
import re
|
||||
import tftpy
|
||||
import os
|
||||
from cowrie.core.customparser import CustomParser
|
||||
from cowrie.core.customparser import OptionNotFound
|
||||
from cowrie.core.customparser import ExitException
|
||||
from cowrie.core.honeypot import HoneyPotCommand
|
||||
from cowrie.core.fs import *
|
||||
|
||||
|
||||
commands = {}
|
||||
|
||||
|
||||
class Progress(object):
|
||||
|
||||
def __init__(self, protocol):
|
||||
|
||||
self.progress = 0
|
||||
self.out = protocol
|
||||
|
||||
|
||||
def progresshook(self, pkt):
|
||||
|
||||
if isinstance(pkt, tftpy.TftpPacketDAT):
|
||||
self.progress += len(pkt.data)
|
||||
self.out.write("Transferred %d bytes" % self.progress + "\n")
|
||||
elif isinstance(pkt, tftpy.TftpPacketOACK):
|
||||
self.out.write("Received OACK, options are: %s" % pkt.options + "\n")
|
||||
|
||||
|
||||
class command_tftp(HoneyPotCommand):
|
||||
|
||||
port = 69
|
||||
|
||||
hostname = None
|
||||
file_to_get = None
|
||||
|
||||
def makeTftpRetrieval(self):
|
||||
|
||||
progresshook = Progress(self).progresshook
|
||||
|
||||
tclient = tftpy.TftpClient(self.hostname,
|
||||
int(self.port))
|
||||
cfg = self.protocol.cfg
|
||||
if cfg.has_option('honeypot', 'download_limit_size'):
|
||||
self.limit_size = int(cfg.get('honeypot', 'download_limit_size'))
|
||||
|
||||
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))
|
||||
|
||||
self.protocol.logDispatch(eventid='cowrie.session.file_download',
|
||||
format='Downloaded tftpFile to %(outfile)s',
|
||||
outfile=self.safeoutfile
|
||||
)
|
||||
|
||||
log.msg(eventid='cowrie.session.file_download',
|
||||
format='Downloaded tftpFile to %(outfile)s',
|
||||
outfile=self.safeoutfile
|
||||
)
|
||||
|
||||
try:
|
||||
tclient.download(self.file_to_get, self.safeoutfile, progresshook)
|
||||
self.file_to_get = self.fs.resolve_path(self.file_to_get, self.protocol.cwd)
|
||||
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)
|
||||
f = self.fs.getfile(self.file_to_get)
|
||||
f[A_REALFILE] = self.safeoutfile
|
||||
|
||||
except tftpy.TftpException, err:
|
||||
return
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
def start(self):
|
||||
|
||||
parser = CustomParser(self)
|
||||
parser.prog = "tftp"
|
||||
parser.add_argument("hostname", nargs='?', default=None)
|
||||
parser.add_argument("-c", nargs=2)
|
||||
parser.add_argument("-l")
|
||||
parser.add_argument("-g")
|
||||
parser.add_argument("-p")
|
||||
parser.add_argument("-r")
|
||||
|
||||
try:
|
||||
args = parser.parse_args(self.args)
|
||||
if args.c:
|
||||
if len(args.c) > 1:
|
||||
command = args.c[0]
|
||||
self.file_to_get = args.c[1]
|
||||
if args.hostname is None:
|
||||
raise OptionNotFound("Hostname is invalid")
|
||||
self.hostname = args.hostname
|
||||
|
||||
elif args.r:
|
||||
self.file_to_get = args.r
|
||||
self.hostname = args.g
|
||||
else:
|
||||
parser.print_usage()
|
||||
raise OptionNotFound("Missing!!")
|
||||
|
||||
if self.hostname is None:
|
||||
raise OptionNotFound("Hostname is invalid")
|
||||
|
||||
self.makeTftpRetrieval()
|
||||
|
||||
except OptionNotFound:
|
||||
self.exit()
|
||||
return
|
||||
except ExitException:
|
||||
self.exit()
|
||||
return
|
||||
except Exception:
|
||||
self.exit()
|
||||
return
|
||||
|
||||
self.exit()
|
||||
|
||||
commands['/usr/bin/tftp'] = command_tftp
|
||||
@@ -256,8 +256,11 @@ class HTTPProgressDownloader(client.HTTPDownloader):
|
||||
if self.status == '304':
|
||||
client.HTTPDownloader.page(self, '')
|
||||
else:
|
||||
reason.webStatus = self.status
|
||||
reason.webMessage = self.message
|
||||
if hasattr(self, 'status'):
|
||||
reason.webStatus = self.status
|
||||
if hasattr(self, 'message'):
|
||||
reason.webMessage = self.message
|
||||
|
||||
client.HTTPDownloader.noPage(self, reason)
|
||||
|
||||
|
||||
|
||||
93
cowrie/core/artifact.py
Normal file
93
cowrie/core/artifact.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# Copyright (c) 2016 Michel Oosterhof <michel@oosterhof.net>
|
||||
|
||||
"""
|
||||
This module contains code to handling saving of honeypot artifacts
|
||||
These will typically be files uploaded to the honeypot and files
|
||||
downloaded inside the honeypot, or input being piped in.
|
||||
|
||||
Code behaves like a normal Python file handle.
|
||||
|
||||
Example:
|
||||
|
||||
with Artifact(name) as f:
|
||||
f.write("abc")
|
||||
|
||||
or:
|
||||
|
||||
g = Artifact("testme2")
|
||||
g.write( "def" )
|
||||
g.close()
|
||||
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import tempfile
|
||||
|
||||
from twisted.python import log
|
||||
|
||||
class Artifact:
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, cfg, label):
|
||||
"""
|
||||
"""
|
||||
self.label = label
|
||||
self.artifactDir = cfg.get('honeypot', 'download_path')
|
||||
|
||||
self.fp = tempfile.NamedTemporaryFile(dir=self.artifactDir, delete=False)
|
||||
self.tempFilename = self.fp.name
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
"""
|
||||
return self.fp
|
||||
|
||||
|
||||
def __exit__(self, exception_type, exception_value, trace):
|
||||
"""
|
||||
"""
|
||||
self.close()
|
||||
|
||||
|
||||
def write(self, bytes):
|
||||
"""
|
||||
"""
|
||||
self.fp.write(bytes)
|
||||
|
||||
|
||||
def fileno(self):
|
||||
"""
|
||||
"""
|
||||
return self.fp.fileno()
|
||||
|
||||
|
||||
def close(self, keepEmpty=True):
|
||||
"""
|
||||
"""
|
||||
size = self.fp.tell()
|
||||
self.fp.seek(0)
|
||||
shasum = hashlib.sha256(self.fp.read()).hexdigest()
|
||||
self.fp.close()
|
||||
shasumFilename = self.artifactDir + "/" + shasum
|
||||
|
||||
if size == 0 and keepEmpty == False:
|
||||
os.remove(self.fp.name)
|
||||
elif os.path.exists(shasumFilename):
|
||||
os.remove(self.fp.name)
|
||||
else:
|
||||
os.rename(self.fp.name, shasumFilename)
|
||||
|
||||
if size>0:
|
||||
linkName = self.artifactDir + "/" \
|
||||
+ time.strftime('%Y%m%dT%H%M%S') \
|
||||
+ "_" + re.sub('[^-A-Za-z0-9]', '_', self.label)
|
||||
os.symlink(shasum, linkName)
|
||||
|
||||
return shasum, shasumFilename
|
||||
|
||||
|
||||
59
cowrie/core/customparser.py
Normal file
59
cowrie/core/customparser.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import argparse
|
||||
|
||||
|
||||
class OptionNotFound(Exception):
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
|
||||
class ExitException(Exception):
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
|
||||
class CustomParser(argparse.ArgumentParser):
|
||||
def __init__(self, protocol,
|
||||
prog=None,
|
||||
usage=None,
|
||||
description=None,
|
||||
epilog=None,
|
||||
version=None,
|
||||
parents=[],
|
||||
formatter_class=argparse.HelpFormatter,
|
||||
prefix_chars='-',
|
||||
fromfile_prefix_chars=None,
|
||||
argument_default=None,
|
||||
conflict_handler='error',
|
||||
add_help=True):
|
||||
self.protocol = protocol
|
||||
super(CustomParser, self).__init__(prog,
|
||||
usage,
|
||||
description,
|
||||
epilog,
|
||||
version,
|
||||
parents,
|
||||
formatter_class,
|
||||
prefix_chars,
|
||||
fromfile_prefix_chars,
|
||||
argument_default,
|
||||
conflict_handler,
|
||||
add_help)
|
||||
|
||||
def exit(self, status=0, message=None):
|
||||
raise ExitException("Exiting...")
|
||||
|
||||
|
||||
def _print_message(self, message, file=None):
|
||||
super(CustomParser,self)._print_message(message, self.protocol)
|
||||
|
||||
def error(self, message):
|
||||
self.print_usage(self.protocol)
|
||||
raise OptionNotFound("Sorry no option found")
|
||||
@@ -222,8 +222,6 @@ class HoneyPotExecProtocol(HoneyPotBaseProtocol):
|
||||
"""
|
||||
HoneyPotBaseProtocol.connectionMade(self)
|
||||
self.setTimeout(60)
|
||||
self.terminal.stdinlog_open = True
|
||||
|
||||
self.cmdstack = [honeypot.HoneyPotShell(self, interactive=False)]
|
||||
self.cmdstack[0].lineReceived(self.execcmd)
|
||||
|
||||
|
||||
@@ -68,7 +68,11 @@ class LoggingServerProtocol(insults.ServerProtocol):
|
||||
self.stdinlogFile = '%s/%s-%s-%s-stdin.log' % \
|
||||
(self.downloadPath,
|
||||
time.strftime('%Y%m%d-%H%M%S'), transportId, channelId)
|
||||
self.stdinlogOpen = False
|
||||
|
||||
if self.type == 'e':
|
||||
self.stdinlogOpen = True
|
||||
else: #i
|
||||
self.stdinlogOpen = False
|
||||
|
||||
insults.ServerProtocol.connectionMade(self)
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
"root@unitTest:~# "
|
||||
],
|
||||
"echo": [
|
||||
"\"test worked correctly\"",
|
||||
"test worked correctly",
|
||||
"root@unitTest:~# "
|
||||
],
|
||||
"hostname": [
|
||||
|
||||
215122
data/fs.pickle
215122
data/fs.pickle
File diff suppressed because it is too large
Load Diff
@@ -6,3 +6,4 @@ gmpy2
|
||||
service_identity
|
||||
pycrypto
|
||||
python-dateutil
|
||||
tftpy
|
||||
|
||||
0
share/.gitignore
vendored
Normal file
0
share/.gitignore
vendored
Normal file
0
share/cowrie/.gitignore
vendored
Normal file
0
share/cowrie/.gitignore
vendored
Normal file
58
txtcmds/bin/enable
Normal file
58
txtcmds/bin/enable
Normal file
@@ -0,0 +1,58 @@
|
||||
enable .
|
||||
enable :
|
||||
enable [
|
||||
enable alias
|
||||
enable bg
|
||||
enable bind
|
||||
enable break
|
||||
enable builtin
|
||||
enable caller
|
||||
enable cd
|
||||
enable command
|
||||
enable compgen
|
||||
enable complete
|
||||
enable continue
|
||||
enable declare
|
||||
enable dirs
|
||||
enable disown
|
||||
enable echo
|
||||
enable enable
|
||||
enable eval
|
||||
enable exec
|
||||
enable exit
|
||||
enable export
|
||||
enable false
|
||||
enable fc
|
||||
enable fg
|
||||
enable getopts
|
||||
enable hash
|
||||
enable help
|
||||
enable history
|
||||
enable jobs
|
||||
enable kill
|
||||
enable let
|
||||
enable local
|
||||
enable logout
|
||||
enable popd
|
||||
enable printf
|
||||
enable pushd
|
||||
enable pwd
|
||||
enable read
|
||||
enable readonly
|
||||
enable return
|
||||
enable set
|
||||
enable shift
|
||||
enable shopt
|
||||
enable source
|
||||
enable suspend
|
||||
enable test
|
||||
enable times
|
||||
enable trap
|
||||
enable true
|
||||
enable type
|
||||
enable typeset
|
||||
enable ulimit
|
||||
enable umask
|
||||
enable unalias
|
||||
enable unset
|
||||
enable wait
|
||||
Reference in New Issue
Block a user