Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement to unswf #98

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions unswf_service/DEPENDENCIES
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Dependencies for unswf (is/are):

pylzma (https://pypi.python.org/pypi/pylzma)
Flare (http://www.nowrap.de/flare.html) - you need to put the flare binary in /usr/local/bin/
4 changes: 2 additions & 2 deletions unswf_service/README
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
unswf_service 0.0.2
unswf_service 0.0.5
-------------

Decompress Flash files.
Decompress Flash files and estract some ActionScript with Flare.



122 changes: 115 additions & 7 deletions unswf_service/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
# (c) 2015, Adam Polkosnik <[email protected]>
# (c) 2015, Adam Polkosnik <[email protected]> <[email protected]>
#
import logging
import os
import io
import tempfile
import shutil
import zlib
import pylzma
from datetime import datetime

import subprocess

# for computing the MD5
from hashlib import md5

# for adding the extracted files
from crits.samples.handlers import handle_file
# for adding the actionscript
from crits.raw_data.handlers import handle_raw_data_file

from crits.core.class_mapper import class_from_id

from django.conf import settings
from django.template.loader import render_to_string
from crits.services.core import Service, ServiceConfigError

#from . import forms
from . import forms

logger = logging.getLogger(__name__)
class unswfService(Service):
Expand All @@ -26,10 +35,57 @@ class unswfService(Service):
"""

name = "unswf"
version = '0.0.2'
version = '0.0.6'
supported_types = ['Sample']
description = "Uncompress flash files."



@staticmethod
def parse_config(config):
flare_path = config.get("flare_path", "")
if not flare_path:
raise ServiceConfigError("Must specify Flare path.")

if not os.path.isfile(flare_path):
raise ServiceConfigError("Flare path does not exist.")

if not os.access(flare_path, os.X_OK):
raise ServiceConfigError("Flare path is not executable.")

if not 'flare' in flare_path.lower():
raise ServiceConfigError("Executable does not appear to be Flare.")

@staticmethod
def get_config(existing_config):
# Generate default config from form and initial values.
config = {}
fields = forms.UnswfConfigForm().fields
for name, field in fields.iteritems():
config[name] = field.initial

# If there is a config in the database, use values from that.
if existing_config:
for key, value in existing_config.iteritems():
config[key] = value
return config

@staticmethod
def get_config_details(config):
return {'flare_path': config['flare_path']}

@classmethod
def generate_config_form(self, config):
html = render_to_string('services_config_form.html',
{'name': self.name,
'form': forms.UnswfConfigForm(initial=config),
'config_error': None})
form = forms.UnswfConfigForm
return form, html




@staticmethod
def valid_for(obj):
if obj.filedata.grid_id == None:
Expand All @@ -39,9 +95,9 @@ def valid_for(obj):
raise ServiceConfigError("Need at least 4 bytes.")
# Reset the read pointer.
obj.filedata.seek(0)
'We only care about the compressed flash files'
if not data[:3] in ['CWS','ZWS']:
raise ServiceConfigError("Not a valid compressed Flash file.")
'We only care about the flash files'
if not data[:3] in ['FWS','CWS','ZWS']:
raise ServiceConfigError("Not a valid Flash file.")


def run(self, obj, config):
Expand All @@ -57,10 +113,62 @@ def run(self, obj, config):
if comp == 'ZWS':
data.seek(12) # seek to LZMA props
swf = 'FWS' + header + pylzma.decompress(data.read())
if comp == 'FWS':
data.seek(0)
flare_path = config.get("flare_path", "")
# Needed some special temp file, since Flare only
# accepts files with swf file extension
tempdir = tempfile.mkdtemp()
self.directory = tempdir
tfile = os.path.join(tempdir, str(obj.id)+'.swf')
rfile = os.path.join(tempdir, str(obj.id)+'.flr')
(working_dir, filename) = os.path.split(tfile)
with open(tfile, "wb") as f:
f.write(data.read())

if os.path.isfile(tfile):
data.seek(0)
self._warning("data md5: %s "% md5(data.read()).hexdigest())
args = [flare_path, filename]
# Flare does not generate a lot of output, so we should not have to
# worry about this hanging because the buffer is full
proc = subprocess.Popen(args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, cwd=working_dir)
# Note that we are redirecting STDERR to STDOUT, so we can ignore
# the second element of the tuple returned by communicate().
output = proc.communicate()[0]
self._warning("Flare output: %s" % output)
if proc.returncode:
msg = ("Flare could not process the file.")
self._warning(msg)
return
with open(rfile, "rb") as newfile:
ac3 = newfile.read()
h3 = md5(ac3).hexdigest()
# clean up the temp files and folders
if os.path.isdir(self.directory):
shutil.rmtree(self.directory)
res = handle_raw_data_file(ac3, self.obj.source, self.current_task.username,
title="Flare", data_type='text',
tool_name='Flare', tool_version='0.6', tool_details='http://www.nowrap.de/flare.html',
method=self.name,
copy_rels=True)
raw_obj = class_from_id("RawData", res["_id"])
self._warning("obj.id: %s, raw_id:%s, suc: %s" % (str(obj.id), str(raw_obj.id), repr(res['success']) ) )
# update relationship if a related top-level object is supplied
rel_type = "Related_To"
if obj.id != raw_obj.id: #don't form relationship to itself
resy = obj.add_relationship(rel_item=raw_obj,
rel_type=rel_type,
rel_date=datetime.now(),
analyst=self.current_task.username)
obj.save(username=self.current_task.username)
raw_obj.save(username=self.current_task.username)
self._warning("resy: %s" % (str(resy)) )
self._add_result("file_added", rfile, {'md5': h3})
except Exception as exc:
self._error("unswf: (%s)." % exc)
return

if swf:
h = md5(str(swf)).hexdigest()
name = h
Expand Down
13 changes: 13 additions & 0 deletions unswf_service/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django import forms

class UnswfConfigForm(forms.Form):
error_css_class = 'error'
required_css_class = 'required'
flare_path = forms.CharField(required=True,
label="Flare Binary",
initial='/usr/local/bin/flare',
widget=forms.TextInput(),
help_text="Full path to Flare binary.")

def __init__(self, *args, **kwargs):
super(UnswfConfigForm, self).__init__(*args, **kwargs)