command_wget: fix artifacts (#693)

* command_wget: fix artifacts
This commit is contained in:
fe7ch
2018-03-15 07:54:03 +03:00
committed by Michel Oosterhof
parent f549510c14
commit 49be876532
2 changed files with 53 additions and 57 deletions

View File

@ -19,6 +19,7 @@ from twisted.python import log, compat
from cowrie.shell.honeypot import HoneyPotCommand from cowrie.shell.honeypot import HoneyPotCommand
from cowrie.shell.fs import * from cowrie.shell.fs import *
from cowrie.core.artifact import Artifact
from cowrie.core.config import CONFIG from cowrie.core.config import CONFIG
""" """
@ -120,6 +121,7 @@ class command_wget(HoneyPotCommand):
if not path or not self.fs.exists(path) or not self.fs.isdir(path): if not path or not self.fs.exists(path) or not self.fs.isdir(path):
self.errorWrite('wget: %s: Cannot open: No such file or directory\n' % outfile) self.errorWrite('wget: %s: Cannot open: No such file or directory\n' % outfile)
self.exit() self.exit()
return
self.url = url self.url = url
@ -128,9 +130,8 @@ class command_wget(HoneyPotCommand):
self.limit_size = CONFIG.getint('honeypot', 'download_limit_size') self.limit_size = CONFIG.getint('honeypot', 'download_limit_size')
self.downloadPath = CONFIG.get('honeypot', 'download_path') self.downloadPath = CONFIG.get('honeypot', 'download_path')
self.artifactFile = tempfile.NamedTemporaryFile(dir=self.downloadPath, delete=False) self.artifactFile = Artifact(outfile)
# HTTPDownloader will close() the file object so need to preserve the name # HTTPDownloader will close() the file object so need to preserve the name
self.artifactName = self.artifactFile.name
d = self.download(url, outfile, self.artifactFile) d = self.download(url, outfile, self.artifactFile)
if d: if d:
@ -139,7 +140,6 @@ class command_wget(HoneyPotCommand):
else: else:
self.exit() self.exit()
def download(self, url, fakeoutfile, outputfile, *args, **kwargs): def download(self, url, fakeoutfile, outputfile, *args, **kwargs):
""" """
url - URL to download url - URL to download
@ -182,49 +182,42 @@ class command_wget(HoneyPotCommand):
return factory.deferred return factory.deferred
def handle_CTRL_C(self): def handle_CTRL_C(self):
""" """
""" """
self.errorWrite('^C\n') self.errorWrite('^C\n')
self.connection.transport.loseConnection() self.connection.transport.loseConnection()
def success(self, data, outfile): def success(self, data, outfile):
""" """
""" """
if not os.path.isfile(self.artifactName): if not os.path.isfile(self.artifactFile.shasumFilename):
log.msg("there's no file " + self.artifactName) log.msg("there's no file " + self.artifactFile.shasumFilename)
self.exit() self.exit()
with open(self.artifactName, 'rb') as f: # log to cowrie.log
filedata = f.read() log.msg(format='Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
shasum = hashlib.sha256(filedata).hexdigest() url=self.url,
hash_path = os.path.join(self.downloadPath, shasum) outfile=self.artifactFile.shasumFilename,
shasum=self.artifactFile.shasum)
# Rename temp file to the hash
if not os.path.exists(hash_path):
os.rename(self.artifactName, hash_path)
unique = True
else:
os.remove(self.artifactName)
log.msg("Not storing duplicate content " + shasum)
unique = False
# log to output modules
self.protocol.logDispatch(eventid='cowrie.session.file_download', self.protocol.logDispatch(eventid='cowrie.session.file_download',
format='Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s', format='Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
url=self.url, outfile=hash_path, shasum=shasum, unique=unique) url=self.url,
outfile=self.artifactFile.shasumFilename,
shasum=self.artifactFile.shasum)
# Update honeyfs to point to downloaded file or write to screen # Update honeyfs to point to downloaded file or write to screen
if outfile != '-': if outfile != '-':
self.fs.update_realfile(self.fs.getfile(outfile), hash_path) self.fs.update_realfile(self.fs.getfile(outfile), self.artifactFile.shasumFilename)
self.fs.chown(outfile, self.protocol.user.uid, self.protocol.user.gid) self.fs.chown(outfile, self.protocol.user.uid, self.protocol.user.gid)
else: else:
self.write(filedata) with open(self.artifactFile.shasumFilename, 'rb') as f:
self.write(f.read())
self.exit() self.exit()
def error(self, error, url): def error(self, error, url):
""" """
""" """
@ -233,14 +226,22 @@ class command_wget(HoneyPotCommand):
self.errorWrite(errorMessage + '\n') self.errorWrite(errorMessage + '\n')
# Real wget also adds this: # Real wget also adds this:
if hasattr(error, 'webStatus') and hasattr(error, 'webMessage'): # exceptions if hasattr(error, 'webStatus') and hasattr(error, 'webMessage'): # exceptions
self.errorWrite('{} ERROR {}: {}\n'.format(time.strftime('%Y-%m-%d %T'), error.webStatus.decode(), error.webMessage.decode())) self.errorWrite('{} ERROR {}: {}\n'.format(time.strftime('%Y-%m-%d %T'), error.webStatus.decode(),
error.webMessage.decode()))
else: else:
self.errorWrite('{} ERROR 404: Not Found.\n'.format(time.strftime('%Y-%m-%d %T'))) self.errorWrite('{} ERROR 404: Not Found.\n'.format(time.strftime('%Y-%m-%d %T')))
self.protocol.logDispatch(eventid='cowrie.session.file_download.failed',
format='Attempt to download file(s) from URL (%(url)s) failed', # prevent cowrie from crashing if the terminal have been already destroyed
url=self.url) try:
self.protocol.logDispatch(eventid='cowrie.session.file_download.failed',
format='Attempt to download file(s) from URL (%(url)s) failed',
url=self.url)
except:
pass
self.exit() self.exit()
commands['/usr/bin/wget'] = command_wget commands['/usr/bin/wget'] = command_wget
commands['/usr/bin/dget'] = command_wget commands['/usr/bin/dget'] = command_wget
@ -258,7 +259,6 @@ class HTTPProgressDownloader(client.HTTPDownloader):
self.nomore = False self.nomore = False
self.quiet = self.wget.quiet self.quiet = self.wget.quiet
def noPage(self, reason): # Called for non-200 responses def noPage(self, reason): # Called for non-200 responses
""" """
""" """
@ -272,7 +272,6 @@ class HTTPProgressDownloader(client.HTTPDownloader):
client.HTTPDownloader.noPage(self, reason) client.HTTPDownloader.noPage(self, reason)
def gotHeaders(self, headers): def gotHeaders(self, headers):
""" """
""" """
@ -292,9 +291,9 @@ class HTTPProgressDownloader(client.HTTPDownloader):
if self.totallength > 0: if self.totallength > 0:
if not self.quiet: if not self.quiet:
self.wget.errorWrite('Length: %d (%s) [%s]\n' % \ self.wget.errorWrite('Length: %d (%s) [%s]\n' % \
(self.totallength, (self.totallength,
sizeof_fmt(self.totallength), sizeof_fmt(self.totallength),
self.contenttype)) self.contenttype))
else: else:
if not self.quiet: if not self.quiet:
self.wget.errorWrite('Length: unspecified [{}]\n'.format(self.contenttype)) self.wget.errorWrite('Length: unspecified [{}]\n'.format(self.contenttype))
@ -309,7 +308,6 @@ class HTTPProgressDownloader(client.HTTPDownloader):
return client.HTTPDownloader.gotHeaders(self, headers) return client.HTTPDownloader.gotHeaders(self, headers)
def pagePart(self, data): def pagePart(self, data):
""" """
""" """
@ -348,17 +346,17 @@ class HTTPProgressDownloader(client.HTTPDownloader):
if self.totallength != 0 and self.currentlength != self.totallength: if self.totallength != 0 and self.currentlength != self.totallength:
return client.HTTPDownloader.pageEnd(self) return client.HTTPDownloader.pageEnd(self)
if not self.quiet: if not self.quiet:
self.wget.errorWrite('\r100%%[%s] %s %dK/s' % \ self.wget.errorWrite('\r100%%[%s] %s %dK/s' %
('%s>' % (38 * '='), ('%s>' % (38 * '='),
splitthousands(str(int(self.totallength))).ljust(12), splitthousands(str(int(self.totallength))).ljust(12),
self.speed / 1000)) self.speed / 1000))
self.wget.errorWrite('\n\n') self.wget.errorWrite('\n\n')
self.wget.errorWrite( self.wget.errorWrite(
'%s (%d KB/s) - `%s\' saved [%d/%d]\n\n' % \ '%s (%d KB/s) - `%s\' saved [%d/%d]\n\n' %
(time.strftime('%Y-%m-%d %H:%M:%S'), (time.strftime('%Y-%m-%d %H:%M:%S'),
self.speed / 1000, self.speed / 1000,
self.fakeoutfile, self.currentlength, self.totallength)) self.fakeoutfile, self.currentlength, self.totallength))
if self.fakeoutfile != '-':
self.wget.fs.mkfile(self.fakeoutfile, 0, 0, self.totallength, 33188) self.wget.fs.mkfile(self.fakeoutfile, 0, 0, self.totallength, 33188)
return client.HTTPDownloader.pageEnd(self) return client.HTTPDownloader.pageEnd(self)

View File

@ -24,14 +24,13 @@ from __future__ import division, absolute_import
import hashlib import hashlib
import os import os
import re
import time
import tempfile import tempfile
from twisted.python import log from twisted.python import log
from cowrie.core.config import CONFIG from cowrie.core.config import CONFIG
class Artifact: class Artifact:
""" """
""" """
@ -45,6 +44,8 @@ class Artifact:
self.fp = tempfile.NamedTemporaryFile(dir=self.artifactDir, delete=False) self.fp = tempfile.NamedTemporaryFile(dir=self.artifactDir, delete=False)
self.tempFilename = self.fp.name self.tempFilename = self.fp.name
self.shasum = ''
self.shasumFilename = ''
def __enter__(self): def __enter__(self):
""" """
@ -75,26 +76,23 @@ class Artifact:
""" """
size = self.fp.tell() size = self.fp.tell()
self.fp.seek(0) self.fp.seek(0)
shasum = hashlib.sha256(self.fp.read()).hexdigest() data = self.fp.read()
self.fp.close() self.fp.close()
shasumFilename = self.artifactDir + "/" + shasum self.shasum = hashlib.sha256(data).hexdigest()
self.shasumFilename = os.path.join(self.artifactDir, self.shasum)
if size == 0 and keepEmpty == False: if size == 0 and not keepEmpty:
log.msg("Not storing empty file")
os.remove(self.fp.name) os.remove(self.fp.name)
elif os.path.exists(shasumFilename): elif os.path.exists(self.shasumFilename):
log.msg("Not storing duplicate content " + self.shasum)
os.remove(self.fp.name) os.remove(self.fp.name)
else: else:
os.rename(self.fp.name, shasumFilename) os.rename(self.fp.name, self.shasumFilename)
umask = os.umask(0) umask = os.umask(0)
os.umask(umask) os.umask(umask)
os.chmod(shasumFilename, 0o666 & ~umask) os.chmod(self.shasumFilename, 0o666 & ~umask)
# if size>0: return self.shasum, self.shasumFilename
# 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