Beispiel #1
0
    class UploadSchema(schema.FileSchema):
        """Extends `FileSchema`."""

        args = fields.Dict(required=False, default={}, missing={})
        extract = fields.Bool(missing=False)
        name = fields.Str(missing=None)  # Override name
        password = fields.Str(missing=None)
Beispiel #2
0
class CommandSchema(Schema):
    """The command schema.

    This is the base schema for the command document stored within the mongo
    database.

    Note:
        Scales are allowed to embed additional information into this document
        but it will be ignored.
    """

    _id = fields.ObjectId(load_only=True)
    _output_id = fields.ObjectId(load_only=True, missing=None)  # GridFS

    sha256_digest = fields.Str(required=True)
    scale = fields.Str(required=True)
    command = fields.Str(required=True)

    args = fields.Dict(default={}, missing={})
    asynchronous = fields.Boolean(default=False)
    timeout = fields.Int(default=600)

    format = fields.Str(type=enums.Format, missing=enums.Format.JSON)
    output = fields.Raw(dump_only=True, default=None, missing=None)
    status = fields.Str(type=enums.Status, missing=enums.Status.PENDING, default=enums.Status.PENDING)

    timestamp = fields.DateTime("%Y-%m-%dT%H:%M:%S.%f")
    start_time = fields.DateTime("%Y-%m-%dT%H:%M:%S.%f")
    end_time = fields.DateTime("%Y-%m-%dT%H:%M:%S.%f")
Beispiel #3
0
    class InterfaceSchema(schema.Schema):
        """Extends `Schema`.

        Create schema for interface requests.
        """
        args = fields.Dict(required=False, default={}, missing={})
        command = fields.Str(required=True)
        format = fields.Str(type=enums.Format, missing=enums.Format.JSON)
        sha256_digest = fields.Str(required=True)
        type = fields.Str(type=enums.InterfaceType,
                          missing=enums.InterfaceType.PULL)
Beispiel #4
0
    class CommandsSchema(schema.Schema):
        """Extends `Schema`.

        Defines the valid schema for post request.
        """
        args = fields.Dict(required=False, default={}, missing={})
        command = fields.Str(required=True)
        format = fields.Str(type=enums.Format, missing=enums.Format.JSON)
        sha256_digests = fields.List(fields.Str(), required=True)
        scale = fields.Str(required=True)
        timeout = fields.Int(required=False)
Beispiel #5
0
class NoteSchema(Schema):
    """The note schema.

    This is the schema for the note document stored within the mongo database.
    """

    _id = fields.ObjectId(load_only=True)
    sha256_digest = fields.Str(required=True)

    body = fields.Str(required=True)

    timestamp = fields.DateTime("%Y-%m-%dT%H:%M:%S.%f")
    updated_time = fields.DateTime("%Y-%m-%dT%H:%M:%S.%f")
Beispiel #6
0
class StoreHandler(snake_handler.SnakeHandler):
    """Extends `SnakeHandler`."""
    @tornadoparser.use_args({
        # filter[field]: str
        'file_type':
        fields.Enum(type=enums.FileType, required=False, missing=None),
        'from':
        fields.Int(required=False, missing=0),
        'limit':
        fields.Int(required=False, missing=10),
        'operator':
        fields.Str(required=False, missing='and'),
        'order':
        fields.Int(required=False, missing=-1),
        'sort':
        fields.Str(required=False, missing=None)
    })
    async def get(self, data):
        documents = []
        filter_ = self.create_filter(self.request.arguments, data['operator'])
        if filter_:
            filter_ = {'$and': [filter_]}
            if data['file_type']:
                filter_['$and'] += [{'file_type': data['file_type']}]
        elif data['file_type']:
            filter_ = {'file_type': data['file_type']}
        # NOTE: With async (motor) there is no count() on cursor so we have to work around that
        total = await db.async_file_collection.db.files.count_documents(
            filter_ if filter_ else {})
        cursor = db.async_file_collection.select_all(filter_, data['order'],
                                                     data['sort'],
                                                     data['limit'],
                                                     data['from'])
        while await cursor.fetch_next:
            documents += [cursor.next_object()]

        documents = schema.FileSchema(many=True).dump(
            schema.FileSchema(many=True).load(documents))
        self.jsonify({'samples': documents, 'total': total})
        self.finish()
Beispiel #7
0
class FilesHandler(snake_handler.SnakeHandler):
    """Extends `SnakeHandler`."""
    @tornadoparser.use_args({
        'limit':
        fields.Str(required=False),
        'operator':
        fields.Str(required=False, missing='and'),
        'order':
        fields.Int(required=False, missing=-1),
        'sort':
        fields.Str(required=False)
    })
    async def get(self, data):
        documents = []
        sort = None
        if 'sort' in data.keys():
            sort = data['sort']
        filter_ = self.create_filter(self.request.arguments, data['operator'])
        if filter_:
            filter_ = {'$and': [{'file_type': enums.FileType.FILE}, filter_]}
        else:
            filter_ = {'file_type': enums.FileType.FILE}
        cursor = db.async_file_collection.select_all(filter_, data['order'],
                                                     sort)
        index = 0
        while await cursor.fetch_next:
            if 'limit' in data.keys():
                if index >= int(data['limit']):
                    break
                index += 1
            documents += [cursor.next_object()]

        documents = schema.FileSchema(many=True).dump(
            schema.FileSchema(many=True).load(documents))
        self.jsonify({'files': documents})
        self.finish()
Beispiel #8
0
class Commands(scale.Commands):
    def _decompile(self, kwargs):
        # NOTE: Using kwargs is lazy but it just makes life easier!
        # Online
        if self.decomp:
            try:
                decompilation = self.decomp.start_decompilation(**kwargs)
                decompilation.wait_until_finished()
            except exceptions.RetdecError as err:
                raise error.CommandError("retdec-python error: {}".format(err))

            return decompilation.get_hll_code()
        # Local
        else:
            with tempfile.NamedTemporaryFile('rb') as fp:
                cmd = [
                    path.join(self.retdec_dir, 'bin/retdec-decompiler.sh'),
                    '-o', fp.name
                ]
                if 'sel_decomp_funcs' in kwargs:
                    cmd += ['--select-functions', kwargs['sel_decomp_funcs']]
                if 'sel_decomp_ranges' in kwargs:
                    cmd += ['--select-ranges', kwargs['sel_decomp_ranges']]
                cmd += [kwargs['input_file']]
                proc = subprocess.run(cmd,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE)
                if proc.returncode:
                    raise error.CommandError("retdec error: {}".format(
                        proc.stderr.decode()))
                return fp.read().decode()

    def check(self):
        self.decomp = None
        self.retdec_dir = None
        if not shutil.which('radare2'):
            raise error.CommandError("binary 'radare2' not found")
        if config.scale_configs['retdec']['online']:
            if not config.scale_configs['retdec']['api_key']:
                raise error.CommandError(
                    "config variable 'api_key' has not been set and is required to query the online retdec"
                )
            self.decomp = decompiler.Decompiler(
                api_key=config.scale_configs['retdec']['api_key'])
        else:
            if not config.scale_configs['retdec']['retdec_dir']:
                raise error.CommandError(
                    "config variable 'retdec_dir' has not been set and is required to use a local retdec instance"
                )
            self.retdec_dir = config.scale_configs['retdec']['retdec_dir']

    @scale.command({
        'args': {
            'address_range': fields.Str(),
            'function_name': fields.Str(),
            'mode': fields.Str(default='bin', missing='bin')
        },
        'info': 'decompile a function with retdec'
    })
    def decompile(self, args, file, opts):
        kwargs = {'input_file': file.file_path}

        name = ''

        # Check the mode and ensure the options
        if args['mode'] == 'bin':
            if 'address_range' in args and args['address_range'] == '':
                del args['address_range']
            if 'function_name' in args and args['function_name'] == '':
                del args['function_name']

            if 'address_range' not in args and 'function_name' not in args:
                raise error.CommandError(
                    "'address_range' or 'function_name' must be set")
            if 'address_range' in args and 'function_name' in args:
                raise error.CommandError(
                    "'address_range' and 'function_name' are mutually exclusive"
                )

            if 'address_range' in args:
                name = '{}'.format(args['address_range'].strip())
                kwargs['sel_decomp_ranges'] = name.strip()
            elif 'function_name' in args:
                name = '{}'.format(args['function_name'].strip())
                kwargs['sel_decomp_funcs'] = name.strip()
        else:
            raise error.CommandError(
                "incorrect mode specified '{}' the following are supported: 'bin'"
                .format(args['mode']))

        return {'code': self._decompile(kwargs), 'name': name}

    def decompile_markdown(self, json):
        output = md.h3(json['name'])
        output += md.code(json['code'], lang='c')
        return output

    @scale.command({'info': 'returns a list of functions using radare2'})
    def functions(self, args, file, opts):
        r2 = r2pipe.open(file.file_path, ['-2'])  # pylint: disable=invalid-name

        output = {}
        output['exports'] = r2.cmdj('iEj')
        output['functions'] = []
        r2.cmd('aaa')
        funcs = r2.cmdj('aflj')
        if funcs:
            for i in funcs:
                i['address_range'] = '0x%08x-0x%08x' % (
                    i['offset'], i['offset'] + i['size'])
                output['functions'] += [i]

        return output

    def functions_markdown(self, json):
        output = md.h3('Exports')
        output += md.table_header(('Virtual Address', 'Size', 'Type', 'Name'))
        if not json['exports']:
            output += md.table_row(('-', '-', '-', '-'))
        else:
            for row in json['exports']:
                output += md.table_row(
                    ('0x%08x' % row['vaddr'], '%u' % row['size'], row['type'],
                     md.bold(row['name'])))
        output += md.newline()
        output += md.h3('Functions')
        output += md.table_header(('Address Range', 'Offset', 'Size', 'Name'))
        if not json['functions']:
            output += md.table_row(('-', '-', '-'))
        else:
            for row in json['functions']:
                output += md.table_row(
                    (md.bold(row['address_range']), '0x%08x' % row['offset'],
                     '%u' % row['size'], row['name']))
        return output
Beispiel #9
0
 def arguments(self):
     return {'url': fields.Str(required=True)}
Beispiel #10
0
class Interface(scale.Interface):
    def check(self):
        if CUCKOO_API is None or CUCKOO_API == '':
            raise error.InterfaceError(
                "config variable 'cuckoo_api' has not been set")

    @scale.pull({'info': 'summary of scores for the sample'})
    def info(self, args, file, opts):
        try:
            j = requests.get(CUCKOO_API + '/files/view/sha256/' +
                             file.sha256_digest,
                             verify=VERIFY).json()
        except requests.exceptions.RequestException:
            raise error.InterfaceError("failed to connect to Cuckoo")

        if 'sample' not in j:
            raise error.InterfaceWarning(
                "file has never been submitted to Cuckoo")
        s_id = j['sample']['id']
        r = requests.get(CUCKOO_API + '/tasks/list', verify=VERIFY)
        if not r.status_code == requests.codes.ok:  # pylint: disable=no-member
            return "No reports, sample must be pending/running", "pending"
        j = r.json()
        output = []
        for t in j['tasks']:
            if t['sample_id'] == s_id:
                r = requests.get(CUCKOO_API + '/tasks/report/' + str(t['id']),
                                 verify=VERIFY)
                if r.status_code == requests.codes.ok:  # pylint: disable=no-member
                    j = r.json()
                    output += [{
                        'score': j['info']['score'],
                        'name': j['info']['machine']['name']
                    }]
        if not output:
            return error.InterfaceWarning("no information available!")
        return {'info': output}

    def info_markdown(self, json):
        output = md.table_header(('Machine', 'Score'))
        for j in json['info']:
            score = j['score']
            if score > 5:
                s = "%red " + str(score) + " %"
            elif score > 3:
                s = "%yellow " + str(score) + " %"
            else:
                s = str(score)
            output += md.table_row((j['name'], s))
        return output

    @scale.pull({
        'args': {
            'id': fields.Str(required=True)
        },
        'info': 'view report summary'
    })
    def report(self, args, file, opts):
        # TODO: Hash match!
        try:
            r = requests.get(CUCKOO_API + '/tasks/report/' + args['id'],
                             verify=VERIFY)
        except requests.exceptions.RequestException:
            raise error.InterfaceError("failed to connect to Cuckoo")
        if not r.status_code == requests.codes.ok:  # pylint: disable=no-member
            return "No task for given id"
        j = r.json()
        output = {
            'score':
            j['info']['score'],
            'platform':
            j['info']['platform'],
            'analysis': {
                'category': j['info']['category'],
                'started': j['info']['started'],
                'ended': j['info']['ended'],
                'duration': j['info']['duration']
            },
            'machine': {
                'name': j['info']['machine']['name'],
                'manager': j['info']['machine']['manager']
            },
            'signatures': [{
                'severity': x['severity'],
                'description': x['description']
            } for x in j['signatures']]
        }
        return output

    def report_markdown(self, json):
        output = md.h4('General')
        output += md.paragraph(md.bold('Score: ') + str(json['score']))
        output += md.cr()
        output += md.paragraph(md.bold('Platform: ') + json['platform'])
        output += md.h4('Analysis')
        output += md.table_header(('Category', 'Started', 'Ended', 'Duration'))
        output += md.table_row(
            (json['analysis']['category'], str(json['analysis']['started']),
             str(json['analysis']['ended']),
             str(json['analysis']['duration'])))
        output += md.h4('Machines')
        output += md.table_header(('Name', 'Manager'))
        output += md.table_row(
            (json['machine']['name'], json['machine']['manager']))
        output += md.h4('Signatures')
        output += md.table_header(('Severity', 'Description'))
        for s in json['signatures']:
            if s['severity'] > 2:
                output += md.table_row(
                    ('%red ' + str(s['severity']) + ' %', s['description']))
            elif s['severity'] > 1:
                output += md.table_row(
                    ('%orange ' + str(s['severity']) + ' %', s['description']))
            else:
                output += md.table_row(
                    ('%blue ' + str(s['severity']) + ' %', s['description']))
        return output

    @scale.pull({'info': 'view reports for sample'})
    def reports(self, args, file, opts):
        try:
            j = requests.get(CUCKOO_API + '/files/view/sha256/' +
                             file.sha256_digest,
                             verify=VERIFY).json()
        except requests.exceptions.RequestException:
            raise error.InterfaceError("failed to connect to Cuckoo")

        if 'sample' not in j:
            raise error.InterfaceWarning(
                "file has never been submitted to Cuckoo")
        s_id = j['sample']['id']
        r = requests.get(CUCKOO_API + '/tasks/list', verify=VERIFY)
        if not r.status_code == requests.codes.ok:  # pylint: disable=no-member
            return "No reports, sample must be pending/running", "pending"
        j = r.json()
        output = {'reports': []}
        for t in j['tasks']:
            if t['sample_id'] == s_id:
                output['reports'] += [{
                    'id':
                    str(t['id']),
                    'url':
                    config.scale_configs['cuckoo']['cuckoo_url'] +
                    str(t['id']),
                    'timestamp':
                    str(t['added_on']),
                    'status':
                    str(t['status'])
                }]
        return output

    def reports_markdown(self, json):
        output = md.table_header(('ID', 'URL', 'Timestamp', 'Status'))
        for r in json['reports']:
            output += md.table_row(
                (r['id'], r['url'], r['timestamp'], r['status']))
        return output

    @scale.push({
        'args': {
            'machine': fields.Str(required=False),
            'priority': fields.Int(required=False),
            'timeout': fields.Int(required=False)
        },
        'info': 'submit sample to cuckoo'
    })
    def submit(self, args, file, opts):
        document = db.file_collection.select(file.sha256_digest)
        with open(file.file_path, "rb") as f:
            try:
                r = requests.post(CUCKOO_API + '/tasks/create/file',
                                  files={"file": (document['name'], f)},
                                  verify=VERIFY)
            except requests.exceptions.RequestException:
                raise error.InterfaceError("failed to connect to Cuckoo")

        if not r.status_code == requests.codes.ok:  # pylint: disable=no-member
            raise error.InterfaceError('failed to submit sample to Cuckoo')

        j = r.json()

        if not j["task_id"]:
            raise error.InterfaceError('failed to submit sample to Cuckoo')

        return j
Beispiel #11
0
class Commands(scale.Commands):  # pylint: disable=too-many-lines, too-many-public-methods
    def check(self):
        if not shutil.which('rekall'):
            raise error.CommandError("binary 'rekall' not found")

    # Generic run a command, useful for most commands
    def run_command(self, file, args, vol_cmd):
        if isinstance(vol_cmd, list):
            cmd = ['rekall', '-f', file.file_path]
            cmd += vol_cmd
        else:
            cmd = ['rekall', '-f', file.file_path, '%s' % (vol_cmd)]
        if config.scale_configs['rekall']['repository_path']:
            cmd += [
                '--repository_path',
                config.scale_configs['rekall']['repository_path']
            ]
        if config.scale_configs['rekall']['cache_dir']:
            cmd += ['--cache_dir', config.scale_configs['rekall']['cache_dir']]
        env = environ.copy()
        if 'http_proxy' in config.snake_config.keys():
            env['http_proxy'] = config.snake_config['http_proxy']
            env['HTTP_PROXY'] = config.snake_config['http_proxy']
            env['https_proxy'] = config.snake_config['https_proxy']
            env['HTTPS_PROXY'] = config.snake_config['https_proxy']
        proc = subprocess.run(cmd,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              env=env)
        if proc.returncode != 0:
            raise error.CommandError(proc.stderr)
        return str(proc.stdout, encoding="utf-8")

    @scale.command({
        'args': {
            'hive_offset': fields.Str(required=True),
        },
        'info': 'prints out a hive'
    })
    def hivedump(self, args, file, opts):
        cmd = [
            'rekall', '-f', file.file_path, 'hivedump', '--hive-offset',
            '%s' % (args['hive_offset'])
        ]
        if config.scale_configs['rekall']['repository_path']:
            cmd += [
                '--repository_path',
                config.scale_configs['rekall']['repository_path']
            ]
        if config.scale_configs['rekall']['cache_dir']:
            cmd += ['--cache_dir', config.scale_configs['rekall']['cache_dir']]
        env = environ.copy()
        if 'http_proxy' in config.snake_config.keys():
            env['http_proxy'] = config.snake_config['http_proxy']
            env['HTTP_PROXY'] = config.snake_config['http_proxy']
            env['https_proxy'] = config.snake_config['https_proxy']
            env['HTTPS_PROXY'] = config.snake_config['https_proxy']
        proc = subprocess.run(cmd,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              env=env)
        if proc.returncode != 0:
            raise error.CommandError(proc.stderr)
        return {'hivedump': str(proc.stdout, encoding="utf-8")}

    def hivedump_plaintext(self, json):
        return json['hivedump']

    @scale.command({'info': 'scan for possible _KDDEBUGGER_DATA64 structures'})
    def kdbgscan(self, args, file, opts):
        return {'kdbgscan': self.run_command(file, args, 'kdbgscan')}

    def kdbgscan_plaintext(self, json):
        return json['kdbgscan']

    @scale.command({'info': 'list overview information about this image'})
    def imageinfo(self, args, file, opts):
        return {'imageinfo': self.run_command(file, args, 'imageinfo')}

    def imageinfo_plaintext(self, json):
        return json['imageinfo']

    @scale.command({
        'args': {
            'offset': fields.Str(required=True),
            'profile': fields.Str(required=False)
        },
        'info': 'a plugin to analyze a memory location'
    })
    def analyze_struct(self, args, file, opts):
        return {
            'analyze_struct': self.run_command(file, args, 'analyze_struct')
        }

    def analyze_struct_plaintext(self, json):
        return json['analyze_struct']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print session and window station atom tables'
    })
    def atoms(self, args, file, opts):
        return {'atoms': self.run_command(file, args, 'atoms')}

    def atoms_plaintext(self, json):
        return json['atoms']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for _RTL_ATOM_TABLE'
    })
    def atomscan(self, args, file, opts):
        return {'atomscan': self.run_command(file, args, 'atomscan')}

    def atomscan_plaintext(self, json):
        return json['atomscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'enumerate callback routines'
    })
    def callbacks(self, args, file, opts):
        return {'callback': self.run_command(file, args, 'callbacks')}

    def callbacks_plaintext(self, json):
        return json['callback']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'a cc plugin for windows'
    })
    def cc(self, args, file, opts):
        return {'cc': self.run_command(file, args, 'cc')}

    def cc_plaintext(self, json):
        return json['cc']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'checks a pe file mapped into memory for hooks'
    })
    def check_pehooks(self, args, file, opts):
        return {'check_pehook': self.run_command(file, args, 'check_pehooks')}

    def check_pehooks_plaintext(self, json):
        return json['check_pehooks']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'extract the contents of the windows clipboard'
    })
    def clipboard(self, args, file, opts):
        return {'clipboard': self.run_command(file, args, 'clipboard')}

    def clipboard_plaintext(self, json):
        return json['clipboard']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'extract command history by scanning for _COMMAND_HISTORY'
    })
    def cmdscan(self, args, file, opts):
        return {'cmdscan': self.run_command(file, args, 'cmdscan')}

    def cmdscan_plaintext(self, json):
        return json['cmdscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'print list of open connections [Windows XP and 2003 Only]'
    })
    def connections(self, args, file, opts):
        return {'connection': self.run_command(file, args, 'connections')}

    def connections_plaintext(self, json):
        return json['connection']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for tcp connections'
    })
    def connscan(self, args, file, opts):
        return {'connscan': self.run_command(file, args, 'connscan')}

    def connscan_plaintext(self, json):
        return json['connscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'enumerate command consoles'
    })
    def consoles(self, args, file, opts):
        return {'consoles': self.run_command(file, args, 'consoles')}

    def consoles_plaintext(self, json):
        return json['consoles']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print information on each desktop'
    })
    def desktops(self, args, file, opts):
        return {'desktops': self.run_command(file, args, 'desktops')}

    def desktops_plaintext(self, json):
        return json['desktops']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'show device tree'
    })
    def devicetree(self, args, file, opts):
        return {'devicetree': self.run_command(file, args, 'devicetree')}

    def devicetree_plaintext(self, json):
        return json['devicetree']

    @scale.command({
        'args': {
            'offset': fields.Str(required=False),
            'profile': fields.Str(required=False)
        },
        'info': 'disassemble the given offset'
    })
    def dis(self, args, file, opts):
        return {'dis': self.run_command(file, args, 'dis')}

    def dis_plaintext(self, json):
        return json['dis']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'prints a list of dll modules mapped into each process'
    })
    def dlllist(self, args, file, opts):
        return {'dlllist': self.run_command(file, args, 'dlllist')}

    def dlllist_plaintext(self, json):
        return json['dlllist']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump the windows DNS resolver cache'
    })
    def dns_cache(self, args, file, opts):
        return {'dns_cache': self.run_command(file, args, 'dns_cache')}

    def dns_cache_plaintext(self, json):
        return json['dns_cache']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'driver IRP hook detection'
    })
    def driverirp(self, args, file, opts):
        return {'driverirp': self.run_command(file, args, 'driverirp')}

    def driverirp_plaintext(self, json):
        return json['driverirp']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan for driver objects _DRIVER_OBJECT'
    })
    def driverscan(self, args, file, opts):
        return {'driverscan': self.run_command(file, args, 'driverscan')}

    def driverscan_plaintext(self, json):
        return json['driverscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scans the physical memory for DTB values'
    })
    def dtbscan(self, args, file, opts):
        return {'dtbscan': self.run_command(file, args, 'dtbscan')}

    def dtbscan_plaintext(self, json):
        return json['dtbscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print details on windows event hooks'
    })
    def eventhooks(self, args, file, opts):
        return {'eventhook': self.run_command(file, args, 'eventhooks')}

    def eventhooks_plaintext(self, json):
        return json['eventhooks']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'extract Windows Event Logs (XP/2003 only)'
    })
    def evtlogs(self, args, file, opts):
        return {'evtlog': self.run_command(file, args, 'evtlogs')}

    def evtlogs_plaintext(self, json):
        return json['evtlogs']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'scan Physical memory for _FILE_OBJECT pool allocations'
    })
    def filescan(self, args, file, opts):
        return {'filescan': self.run_command(file, args, 'filescan')}

    def filescan_plaintext(self, json):
        return json['filescan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'a plugin to search for the Directory Table Base for windows system'
    })
    def find_dtb(self, args, file, opts):
        return {'find_dtb': self.run_command(file, args, 'find_dtb')}

    def find_dtb_plaintext(self, json):
        return json['find_dtb']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'none'
    })
    def fls(self, args, file, opts):
        return {'fls': self.run_command(file, args, 'fls')}

    def fls_plaintext(self, json):
        return json['fls']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump the USER handle type information'
    })
    def gahti(self, args, file, opts):
        return {'gahti': self.run_command(file, args, 'gahti')}

    def gahti_plaintext(self, json):
        return json['gahti']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'get the names of services in the Registry and return Calculated SID'
    })
    def getservicesids(self, args, file, opts):
        return {
            'getservicesid': self.run_command(file, args, 'getservicesids')
        }

    def getservicesids_plaintext(self, json):
        return json['getservicesids']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of open handles for each process'
    })
    def handles(self, args, file, opts):
        return {'handles': self.run_command(file, args, 'handles')}

    def handles_plaintext(self, json):
        return json['handles']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of registry hives on the system'
    })
    def hives(self, args, file, opts):
        return {'hives': self.run_command(file, args, 'hives')}

    def hives_plaintext(self, json):
        return json['hives']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'detect EAT hooks in process and kernel memory'
    })
    def hooks_eat(self, args, file, opts):
        return {'hooks_eat': self.run_command(file, args, 'hooks_eat')}

    def hooks_eat_plaintext(self, json):
        return json['hooks_eat']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'detect IAT/EAT hooks in process and kernel memory'
    })
    def hooks_iat(self, args, file, opts):
        return {'hooks_iat': self.run_command(file, args, 'hooks_iat')}

    def hooks_iat_plaintext(self, json):
        return json['hooks_iat']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'detect API hooks in process and kernel memory'
    })
    def hooks_inline(self, args, file, opts):
        return self.run_command(file, args, 'hooks_inline')

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan for calls to imported functions'
    })
    def impscan(self, args, file, opts):
        return {'impscan': self.run_command(file, args, 'impscan')}

    def impscan_plaintext(self, json):
        return json['impscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'a plugin to print all KPCR blocks'
    })
    def kpcr(self, args, file, opts):
        return {'kpcr': self.run_command(file, args, 'kpcr')}

    def kpcr_plaintext(self, json):
        return json['kpcr']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'detect unlinked DLLs'
    })
    def ldrmodules(self, args, file, opts):
        return {'ldrmodule': self.run_command(file, args, 'ldrmodules')}

    def ldrmodules_plaintext(self, json):
        return json['ldrmodules']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'find hidden and injected code'
    })
    def malfind(self, args, file, opts):
        return {'malfind': self.run_command(file, args, 'malfind')}

    def malfind_plaintext(self, json):
        return json['malfind']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'calculates the memory regions mapped by a process'
    })
    def memmap(self, args, file, opts):
        return {'memmap': self.run_command(file, args, 'memmap')}

    def memmap_plaintext(self, json):
        return json['memmap']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'list desktop and thread window message hooks'
    })
    def messagehooks(self, args, file, opts):
        return {'messagehook': self.run_command(file, args, 'messagehooks')}

    def messagehooks_plaintext(self, json):
        return json['messagehooks']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'extract and decrypt passwords from the LSA Security Service'
    })
    def mimikatz(self, args, file, opts):
        return {'mimikatz': self.run_command(file, args, 'mimikatz')}

    def mimikatz_plaintext(self, json):
        return json['mimikatz']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'scan Physical memory for _LDR_DATA_TABLE_ENTRY objects'
    })
    def modscan(self, args, file, opts):
        return {'modscan': self.run_command(file, args, 'modscan')}

    def modscan_plaintext(self, json):
        return json['modscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of loaded modules'
    })
    def modules(self, args, file, opts):
        return {'modules': self.run_command(file, args, 'modules')}

    def modules_plaintext(self, json):
        return json['modules']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan for mutant objects _KMUTANT'
    })
    def mutantscan(self, args, file, opts):
        return {'mutantscan': self.run_command(file, args, 'mutantscan')}

    def mutantscan_plaintext(self, json):
        return json['mutantscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'scan a Vista, 2008 or Windows 7 image for connections and sockets'
    })
    def netscan(self, args, file, opts):
        return {'netscan': self.run_command(file, args, 'netscan')}

    def netscan_plaintext(self, json):
        return json['netscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print the active network connections'
    })
    def netstat(self, args, file, opts):
        return {'netstat': self.run_command(file, args, 'netstat')}

    def netstat_plaintext(self, json):
        return json['netstat']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'visualize the kernel object tree'
    })
    def object_tree(self, args, file, opts):
        return {'object_tree': self.run_command(file, args, 'object_tree')}

    def object_tree_plaintext(self, json):
        return json['object_tree']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'displays all object Types on the system'
    })
    def object_types(self, args, file, opts):
        return {'object_types': self.run_command(file, args, 'object_types')}

    def object_types_plaintext(self, json):
        return json['object_types']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'report all the active pagefiles'
    })
    def pagefiles(self, args, file, opts):
        return {'pagefiles': self.run_command(file, args, 'pagefiles')}

    def pagefiles_plaintext(self, json):
        return json['pagefiles']

    @scale.command({
        'args': {
            'offset': fields.Str(required=True),
            'profile': fields.Str(required=False)
        },
        'info':
        'resolves a physical address to a virtual addrress in a process'
    })
    def pas2vas(self, args, file, opts):
        return {'pas2vas': self.run_command(file, args, 'pas2vas')}

    def pas2vas_plaintext(self, json):
        return json['pas2vas']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print information about a PE binary'
    })
    def peinfo(self, args, file, opts):
        return {'peinfo': self.run_command(file, args, 'peinfo')}

    def peinfo_plaintext(self, json):
        return json['peinfo']

    @scale.command({
        'args': {
            'pfn': fields.Str(required=True),
            'profile': fields.Str(required=False)
        },
        'info':
        'prints information about an address from the PFN database'
    })
    def pfn(self, args, file, opts):
        return {'pfn': self.run_command(file, args, 'pfn')}

    def pfn_plaintext(self, json):
        return json['pfn']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'prints the boot physical memory map'
    })
    def phys_map(self, args, file, opts):
        return {'phys_map': self.run_command(file, args, 'phys_map')}

    def phys_map_plaintext(self, json):
        return json['phys_map']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'enumerate pool tag usage statistics'
    })
    def pool_tracker(self, args, file, opts):
        return {'pool_tracker': self.run_command(file, args, 'pool_tracker')}

    def pool_tracker_plaintext(self, json):
        return json['pool_tracker']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'prints information about system pools'
    })
    def pools(self, args, file, opts):
        return {'pools': self.run_command(file, args, 'pools')}

    def pools_plaintext(self, json):
        return json['pools']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print a registry key, and its subkeys and values'
    })
    def printkey(self, args, file, opts):
        return {'printkey': self.run_command(file, args, 'printkey')}

    def printkey_plaintext(self, json):
        return json['printkey']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'prints process privileges'
    })
    def privileges(self, args, file, opts):
        return {'privileges': self.run_command(file, args, 'privileges')}

    def privileges_plaintext(self, json):
        return json['privileges']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump detailed information about a running process'
    })
    def procinfo(self, args, file, opts):
        return {'procinfo': self.run_command(file, args, 'procinfo')}

    def procinfo_plaintext(self, json):
        return json['procinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'list processes for windows'
    })
    def pslist(self, args, file, opts):
        return {'pslist': self.run_command(file, args, 'pslist')}

    def pslist_plaintext(self, json):
        return json['pslist']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'scan Physical memory for _EPROCESS pool allocations'
    })
    def psscan(self, args, file, opts):
        return {'psscan': self.run_command(file, args, 'psscan')}

    def psscan_plaintext(self, json):
        return json['psscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print process list as a tree'
    })
    def pstree(self, args, file, opts):
        return {'pstree': self.run_command(file, args, 'pstree')}

    def pstree_plaintext(self, json):
        return json['pstree']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'find hidden processes with various process listings'
    })
    def psxview(self, args, file, opts):
        return {'psxview': self.run_command(file, args, 'psxview')}

    def psxview_plaintext(self, json):
        return json['psxview']

    @scale.command({
        'args': {
            'offset': fields.Str(required=True),
            'profile': fields.Str(required=False)
        },
        'info': 'converts a physical address to a virtual address'
    })
    def ptov(self, args, file, opts):
        return {'ptov': self.run_command(file, args, 'psxview')}

    def ptov_plaintext(self, json):
        return json['ptov']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan all physical memory and report page owners'
    })
    def rammap(self, args, file, opts):
        return {'rammap': self.run_command(file, args, 'rammap')}

    def rammap_plaintext(self, json):
        return json['rammap']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'enumerate all services'
    })
    def services(self, args, file, opts):
        return {'services': self.run_command(file, args, 'services')}

    def services_plaintext(self, json):
        return json['services']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'list details on _MM_SESSION_SPACE (user logon sessions)'
    })
    def sessions(self, args, file, opts):
        return {'sessions': self.run_command(file, args, 'sessions')}

    def sessions_plaintext(self, json):
        return json['sessions']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'dump RSA private and public SSL keys from the physical address space'
    })
    def simple_certscan(self, args, file, opts):
        return {
            'simple_certscan': self.run_command(file, args, 'simple_certscan')
        }

    def simple_certscan_plaintext(self, json):
        return json['simple_certscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of open sockets [Windows XP only]'
    })
    def sockets(self, args, file, opts):
        return {'sockets': self.run_command(file, args, 'sockets')}

    def sockets_plaintext(self, json):
        return json['sockets']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'enumerate the SSDT'
    })
    def ssdt(self, args, file, opts):
        return {'ssdt': self.run_command(file, args, 'ssdt')}

    def ssdt_plaintext(self, json):
        return json['ssdt']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan for Windows services'
    })
    def svcscan(self, args, file, opts):
        return {'svcscan': self.run_command(file, args, 'svcscan')}

    def svcscan_plaintext(self, json):
        return json['svcscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan for symbolic link objects'
    })
    def symlinkscan(self, args, file, opts):
        return {'symlinkscan': self.run_command(file, args, 'symlinkscan')}

    def symlinkscan_plaintext(self, json):
        return json['symlinkscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan physical memory for _ETHREAD objects'
    })
    def thrdscan(self, args, file, opts):
        return {'thrdscan': self.run_command(file, args, 'thrdscan')}

    def thrdscan_plaintext(self, json):
        return json['thrdscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'enumerate threads'
    })
    def threads(self, args, file, opts):
        return {'threads': self.run_command(file, args, 'threads')}

    def threads_plaintext(self, json):
        return json['threads']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print kernel timers and associated module DPCs'
    })
    def timers(self, args, file, opts):
        return {'timers': self.run_command(file, args, 'timers')}

    def timers_plaintext(self, json):
        return json['timers']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'return current time, as known to the kernel'
    })
    def times(self, args, file, opts):
        return {'times': self.run_command(file, args, 'times')}

    def times_plaintext(self, json):
        return json['times']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print the SIDs owning each process token'
    })
    def tokens(self, args, file, opts):
        return {'tokens': self.run_command(file, args, 'tokens')}

    def tokens_plaintext(self, json):
        return json['tokens']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of recently unloaded modules'
    })
    def unloaded_modules(self, args, file, opts):
        return {
            'unloaded_modules': self.run_command(file, args,
                                                 'unloaded_modules')
        }

    def unloaded_modules_plaintext(self, json):
        return json['unloaded_modules']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print userassist registry keys and information'
    })
    def userassist(self, args, file, opts):
        return {'userassist': self.run_command(file, args, 'userassist')}

    def userassist_plaintext(self, json):
        return json['userassist']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump the USER handle tables'
    })
    def userhandles(self, args, file, opts):
        return {'userhandles': self.run_command(file, args, 'userhandles')}

    def userhandles_plaintext(self, json):
        return json['userhandles']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'enumerate all users of this system'
    })
    def users(self, args, file, opts):
        return {'users': self.run_command(file, args, 'users')}

    def users_plaintext(self, json):
        return json['users']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'enumerate all blocks cached in the cache manager'
    })
    def vacbs(self, args, file, opts):
        return {'vacbs': self.run_command(file, args, 'vacbs')}

    def vacbs_plaintext(self, json):
        return json['vacbs']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'concise dump of the VAD'
    })
    def vad(self, args, file, opts):
        return {'vad': self.run_command(file, args, 'vad')}

    def vad_plaintext(self, json):
        return json['vad']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'inspect each page in the VAD and report its status'
    })
    def vadmap(self, args, file, opts):
        return {'vadmap': self.run_command(file, args, 'vadmap')}

    def vadmap_plaintext(self, json):
        return json['vadmap']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'try to determine the versions for all kernel drivers'
    })
    def version_modules(self, args, file, opts):
        return {
            'version_modules': self.run_command(file, args, 'version_modules')
        }

    def version_modules_plaintext(self, json):
        return json['version_modules']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'prints the Windows Kernel Virtual Address Map'
    })
    def virt_map(self, args, file, opts):
        return {'virt_map': self.run_command(file, args, 'virt_map')}

    def virt_map_plaintext(self, json):
        return json['virt_map']

    @scale.command({
        'args': {
            'name': fields.Str(required=True),
            'profile': fields.Str(required=False)
        },
        'info':
        'prints information about the virtual to physical translation'
    })
    def vtop(self, args, file, opts):
        return {'vtop': self.run_command(file, args, 'vtop')}

    def vtop_plaintext(self, json):
        return json['vtop']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'automatically detect win32k struct layout'
    })
    def win32k_autodetect(self, args, file, opts):
        return {
            'win32k_autodetect': self.run_command(file, args,
                                                  'win32k_autodetect')
        }

    def win32k_autodetect_plaintext(self, json):
        return json['win32k_autodetect']
Beispiel #12
0
class UploadFileSchema(schema.FileSchema):
    """Extends `FileSchema`."""

    name = fields.Str(required=False)  # Override
    extract = fields.Bool(missing=False)
    password = fields.Str(missing=None)
Beispiel #13
0
class Commands(scale.Commands):  # pylint: disable=too-many-lines, too-many-public-methods
    def check(self):
        self.vol = None
        if config.scale_configs['volatility']['vol_path']:
            if path.exists(config.scale_configs['volatility']['vol_path']):
                self.vol = config.scale_configs['volatility']['vol_path']
        else:
            raise error.CommandError(
                "binary 'vol.py' not found - 'vol_path' not set")
        if not self.vol:
            raise error.CommandError("binary 'vol.py' not found")

    def get_profile(self, file):
        document = db.file_collection.select(file.sha256_digest)
        if 'profile' not in document:
            self.imageinfo(None, file.sha256_digest)  # pylint: disable=no-value-for-parameter
            document = db.file_collection.select(file.sha256_digest)
            if 'profile' not in document:
                raise error.CommandError(
                    'Unable to automatically determine profile!')
        return document['profile']

    # Generic run a command, useful for most commands
    def run_command(self, file, args, vol_cmd):
        cmd = [self.vol, '-f', file.file_path, '%s' % (vol_cmd)]
        if 'profile' in args and args['profile'] != '':
            cmd += ['--profile', args['profile']]
        else:
            profile = self.get_profile(file)
            cmd += ['--profile', profile]
        proc = subprocess.run(cmd,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        if proc.returncode != 0:
            raise error.CommandError(proc.stderr)
        return str(proc.stdout, encoding="utf-8")

    @scale.command({
        'args': {
            'hive_offset': fields.Str(required=True),
            'profile': fields.Str(required=False)
        },
        'info': 'prints out a hive'
    })
    def hivedump(self, args, file, opts):
        cmd = [
            self.vol, '-f', file.file_path, 'hivedump', '--hive-offset',
            '%s' % (args['hive_offset'])
        ]
        if 'profile' in args and args['profile'] != '':
            cmd += ['--profile', args['profile']]
        else:
            profile = self.get_profile(file)
            cmd += ['--profile', profile]
        proc = subprocess.run(cmd,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        if proc.returncode != 0:
            raise error.CommandError(proc.stderr)
        return {'hivedump': str(proc.stdout, encoding="utf-8")}

    def hivedump_plaintext(self, json):
        return json['hivedump']

    @scale.command({'info': 'search for and dump potential KDBG values'})
    def kdbgscan(self, args, file, opts):
        proc = subprocess.run([self.vol, '-f', file.file_path, 'kdbgscan'],
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        if proc.returncode != 0:
            raise error.CommandError(proc.stderr)
        return {'kdbgscan': str(proc.stdout, encoding="utf-8")}

    def kdbgscan_plaintext(self, json):
        return json['kdbgscan']

    @scale.autorun
    @scale.command({'info': 'identify information for the image'})
    def imageinfo(self, args, file, opts):
        proc = subprocess.run([self.vol, '-f', file.file_path, 'imageinfo'],
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        if proc.returncode != 0:
            raise error.CommandError(proc.stderr)
        output = str(proc.stdout, encoding="utf-8")

        # Try and extract profile
        try:
            prof = output.split('\n')[0].split(':')[1]
            if 'suggestion' not in prof:
                if ',' in prof:
                    prof = prof.split(',')[0]
                data = {'profile': prof.strip()}
                if not db.file_collection.update(file.sha256_digest, data):
                    raise error.MongoError(
                        'Error adding profile into file document %s' %
                        file.sha256_digest)
        except Exception:  # noqa pylint: disable=broad-except
            pass

        return {'imageinfo': output}

    def imageinfo_plaintext(self, json):
        return json['imageinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print AmCache information'
    })
    def amcache(self, args, file, opts):
        return {'amcache': self.run_command(file, args, 'amcache')}

    def amcache_plaintext(self, json):
        return json['amcache']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'detect API hooks in process and kernel memory'
    })
    def apihooks(self, args, file, opts):
        return {'apihooks': self.run_command(file, args, 'apihooks')}

    def apihooks_plaintext(self, json):
        return json['apihooks']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print session and window station atom tables'
    })
    def atoms(self, args, file, opts):
        return {'atoms': self.run_command(file, args, 'atoms')}

    def atoms_plaintext(self, json):
        return json['atoms']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for atom tables'
    })
    def atomscan(self, args, file, opts):
        return {'atomscan': self.run_command(file, args, 'atomscan')}

    def atomscan_plaintext(self, json):
        return json['atomscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        r'prints out the Audit Policies from HKLM\SECURITY\Policy\PolAdtEv'
    })
    def auditpol(self, args, file, opts):
        return {'auditpol': self.run_command(file, args, 'auditpol')}

    def auditpol_plaintext(self, json):
        return json['auditpol']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump the big page pools using BigPagePoolScanner'
    })
    def bigpools(self, args, file, opts):
        return {'bigpools': self.run_command(file, args, 'bigpools')}

    def bigpools_plaintext(self, json):
        return json['bigpools']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'reads the keyboard buffer from Real Mode memory'
    })
    def bioskbd(self, args, file, opts):
        return {'bioskbd': self.run_command(file, args, 'bioskbd')}

    def bioskbd_plaintext(self, json):
        return json['bioskbd']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dumps cached domain hashes from memory'
    })
    def cachedump(self, args, file, opts):
        return {'cachedump': self.run_command(file, args, 'cachedump')}

    def cachedump_plaintext(self, json):
        return json['cachedump']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print system-wide notification routines'
    })
    def callbacks(self, args, file, opts):
        return {'callbacks': self.run_command(file, args, 'callbacks')}

    def callbacks_plaintext(self, json):
        return json['callbacks']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'extract the contents of the windows clipboard'
    })
    def clipboard(self, args, file, opts):
        return {'clipboard': self.run_command(file, args, 'clipboard')}

    def clipboard_plaintext(self, json):
        return json['clipboard']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'display process command-line arguments'
    })
    def cmdline(self, args, file, opts):
        return {'cmdline': self.run_command(file, args, 'cmdline')}

    def cmdline_plaintext(self, json):
        return json['cmdline']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'extract command history by scanning for _COMMAND_HISTORY'
    })
    def cmdscan(self, args, file, opts):
        return {'cmdscan': self.run_command(file, args, 'cmdscan')}

    def cmdscan_plaintext(self, json):
        return json['cmdscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'print list of open connections [Windows XP and 2003 Only]'
    })
    def connections(self, args, file, opts):
        return {'connections': self.run_command(file, args, 'connections')}

    def connections_plaintext(self, json):
        return json['connections']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for tcp connections'
    })
    def connscan(self, args, file, opts):
        return {'connscan': self.run_command(file, args, 'connscan')}

    def connscan_plaintext(self, json):
        return json['connscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'extract command history by scanning for _CONSOLE_INFORMATION'
    })
    def consoles(self, args, file, opts):
        return {'consoles': self.run_command(file, args, 'consoles')}

    def consoles_plaintext(self, json):
        return json['consoles']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump crash-dump information'
    })
    def crashinfo(self, args, file, opts):
        return {'crashinfo': self.run_command(file, args, 'crashinfo')}

    def crashinfo_plaintext(self, json):
        return json['crashinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'poolscaner for tagDESKTOP (desktops)'
    })
    def deskscan(self, args, file, opts):
        return {'deskscan': self.run_command(file, args, 'deskscan')}

    def deskscan_plaintext(self, json):
        return json['deskscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'show device tree'
    })
    def devicetree(self, args, file, opts):
        return {'devicetree': self.run_command(file, args, 'devicetree')}

    def devicetree_plaintext(self, json):
        return json['devicetree']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of loaded dlls for each process'
    })
    def dlllist(self, args, file, opts):
        return {'dlllist': self.run_command(file, args, 'dlllist')}

    def dlllist_plaintext(self, json):
        return json['dlllist']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'driver IRP hook detection'
    })
    def driverirp(self, args, file, opts):
        return {'driverirp': self.run_command(file, args, 'driverirp')}

    def driverirp_plaintext(self, json):
        return json['driverirp']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'associate driver objects to kernel modules'
    })
    def drivermodule(self, args, file, opts):
        return {'drivermodule': self.run_command(file, args, 'drivermodule')}

    def drivermodule_plaintext(self, json):
        return json['drivermodule']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for driver objects'
    })
    def driverscan(self, args, file, opts):
        return {'driverscan': self.run_command(file, args, 'driverscan')}

    def driverscan_plaintext(self, json):
        return json['driverscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump RSA private and public SSL keys'
    })
    def dumpcerts(self, args, file, opts):
        return {'dumpcerts': self.run_command(file, args, 'dumpcerts')}

    def dumpcerts_plaintext(self, json):
        return json['dumpcerts']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'displays information about Edit controls. (Listbox experimental.)'
    })
    def editbox(self, args, file, opts):
        return {'editbox': self.run_command(file, args, 'editbox')}

    def editbox_plaintext(self, json):
        return json['editbox']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'display process environment variables'
    })
    def envars(self, args, file, opts):
        return {'envars': self.run_command(file, args, 'envars')}

    def envars_plaintext(self, json):
        return json['envars']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print details on windows event hooks'
    })
    def eventhooks(self, args, file, opts):
        return {'eventhooks': self.run_command(file, args, 'eventhooks')}

    def eventhooks_plaintext(self, json):
        return json['eventhooks']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'extract Windows Event Logs (XP/2003 only)'
    })
    def evtlogs(self, args, file, opts):
        return {'evtlogs': self.run_command(file, args, 'evtlogs')}

    def evtlogs_plaintext(self, json):
        return json['evtlogs']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for file objects'
    })
    def filescan(self, args, file, opts):
        return {'filescan': self.run_command(file, args, 'filescan')}

    def filescan_plaintext(self, json):
        return json['filescan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump the USER handle type information'
    })
    def gahti(self, args, file, opts):
        return {'gahti': self.run_command(file, args, 'gahti')}

    def gahti_plaintext(self, json):
        return json['gahti']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print installed GDI timers and callbacks'
    })
    def gditimers(self, args, file, opts):
        return {'gditimers': self.run_command(file, args, 'gditimers')}

    def gditimers_plaintext(self, json):
        return json['gditimers']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'display Global Descriptor Table'
    })
    def gdt(self, args, file, opts):
        return {'gdt': self.run_command(file, args, 'gdt')}

    def gdt_plaintext(self, json):
        return json['gdt']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'get the names of services in the Registry and return Calculated SID'
    })
    def getservicesids(self, args, file, opts):
        return {
            'getservicesids': self.run_command(file, args, 'getservicesids')
        }

    def getservicesids_plaintext(self, json):
        return json['getservicesids']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print the SIDs owning each process'
    })
    def getsids(self, args, file, opts):
        return {'getsids': self.run_command(file, args, 'getsids')}

    def getsids_plaintext(self, json):
        return json['getsids']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of open handles for each process'
    })
    def handles(self, args, file, opts):
        return {'handles': self.run_command(file, args, 'handles')}

    def handles_plaintext(self, json):
        return json['handles']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dumps passwords hashes (LM/NTLM) from memory'
    })
    def hashdump(self, args, file, opts):
        return {'hashdump': self.run_command(file, args, 'hashdump')}

    def hashdump_plaintext(self, json):
        return json['hashdump']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump hibernation file information'
    })
    def hibinfo(self, args, file, opts):
        return {'hibinfo': self.run_command(file, args, 'hibinfo')}

    def hibinfo_plaintext(self, json):
        return json['hibinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of registry hives'
    })
    def hivelist(self, args, file, opts):
        return {'hivelist': self.run_command(file, args, 'hivelist')}

    def hivelist_plaintext(self, json):
        return json['hivelist']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for registry hives'
    })
    def hivescan(self, args, file, opts):
        return {'hivescan': self.run_command(file, args, 'hivescan')}

    def hivescan_plaintext(self, json):
        return json['hivescan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'display Interrupt Descriptor Table'
    })
    def idt(self, args, file, opts):
        return {'idt': self.run_command(file, args, 'idt')}

    def idt_plaintext(self, json):
        return json['idt']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'reconstruct Internet Explorer cache / history'
    })
    def iehistory(self, args, file, opts):
        return {'iehistory': self.run_command(file, args, 'iehistory')}

    def iehistory_plaintext(self, json):
        return json['iehistory']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan for calls to imported functions'
    })
    def impscan(self, args, file, opts):
        return {'impscan': self.run_command(file, args, 'impscan')}

    def impscan_plaintext(self, json):
        return json['impscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print process job link information'
    })
    def joblinks(self, args, file, opts):
        return {'joblinks': self.run_command(file, args, 'joblinks')}

    def joblinks_plaintext(self, json):
        return json['joblinks']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'search for and dump potential KPCR values'
    })
    def kpcrscan(self, args, file, opts):
        return {'kpcrscan': self.run_command(file, args, 'kpcrscan')}

    def kpcrscan_plaintext(self, json):
        return json['kpcrscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'detect unlinked DLLs'
    })
    def ldrmodules(self, args, file, opts):
        return {'ldrmodules': self.run_command(file, args, 'ldrmodules')}

    def ldrmodules_plaintext(self, json):
        return json['ldrmodules']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump (decrypted) LSA secrets from the registry'
    })
    def lsadump(self, args, file, opts):
        return {'lsadump': self.run_command(file, args, 'lsadump')}

    def lsadump_plaintext(self, json):
        return json['lsadump']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump Mach-O file format information'
    })
    def machoinfo(self, args, file, opts):
        return {'machoinfo': self.run_command(file, args, 'machoinfo')}

    def machoinfo_plaintext(self, json):
        return json['machoinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'find hidden and injected code'
    })
    def malfind(self, args, file, opts):
        return {'malfind': self.run_command(file, args, 'malfind')}

    def malfind_plaintext(self, json):
        return json['malfind']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'scans for and parses potential Master Boot Records (MBRs)'
    })
    def mbrparser(self, args, file, opts):
        return {'mbrparser': self.run_command(file, args, 'mbrparser')}

    def mbrparser_plaintext(self, json):
        return json['mbrparser']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print the memory map'
    })
    def memmap(self, args, file, opts):
        return {'memmap': self.run_command(file, args, 'memmap')}

    def memmap_plaintext(self, json):
        return json['memmap']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'list desktop and thread window message hooks'
    })
    def messagehooks(self, args, file, opts):
        return {'messagehooks': self.run_command(file, args, 'messagehooks')}

    def messagehooks_plaintext(self, json):
        return json['messagehooks']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scans for and parses potential MFT entries'
    })
    def mftparser(self, args, file, opts):
        return {'mftparser': self.run_command(file, args, 'mftparser')}

    def mftparser_plaintext(self, json):
        return json['mftparser']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for kernel modules'
    })
    def modscan(self, args, file, opts):
        return {'modscan': self.run_command(file, args, 'modscan')}

    def modscan_plaintext(self, json):
        return json['modscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of loaded modules'
    })
    def modules(self, args, file, opts):
        return {'modules': self.run_command(file, args, 'modules')}

    def modules_plaintext(self, json):
        return json['modules']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for mutex objects'
    })
    def mutantscan(self, args, file, opts):
        return {'mutantscan': self.run_command(file, args, 'mutantscan')}

    def mutantscan_plaintext(self, json):
        return json['mutantscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'scan a vista (or later) image for connections and sockets'
    })
    def netscan(self, args, file, opts):
        return {'netscan': self.run_command(file, args, 'netscan')}

    def netscan_plaintext(self, json):
        return json['netscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'list currently displayed notepad text'
    })
    def notepad(self, args, file, opts):
        return {'notepad': self.run_command(file, args, 'notepad')}

    def notepad_plaintext(self, json):
        return json['notepad']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan for Windows object type objects'
    })
    def objtypescan(self, args, file, opts):
        return {'objtypescan': self.run_command(file, args, 'objtypescan')}

    def objtypescan_plaintext(self, json):
        return json['objtypescan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'display process privileges'
    })
    def privs(self, args, file, opts):
        return {'privs': self.run_command(file, args, 'privs')}

    def privs_plaintext(self, json):
        return json['privs']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'print all running processes by following the EPROCESS lists'
    })
    def pslist(self, args, file, opts):
        return {'pslist': self.run_command(file, args, 'pslist')}

    def pslist_plaintext(self, json):
        return json['pslist']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for process objects'
    })
    def psscan(self, args, file, opts):
        return {'psscan': self.run_command(file, args, 'psscan')}

    def psscan_plaintext(self, json):
        return json['psscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print process list as a tree'
    })
    def pstree(self, args, file, opts):
        return {'pstree': self.run_command(file, args, 'pstree')}

    def pstree_plaintext(self, json):
        return json['pstree']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'find hidden processes with various process listings'
    })
    def psxview(self, args, file, opts):
        return {'psxview': self.run_command(file, args, 'psxview')}

    def psxview_plaintext(self, json):
        return json['psxview']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump Qemu information'
    })
    def qemuinfo(self, args, file, opts):
        return {'qemuinfo': self.run_command(file, args, 'qemuinfo')}

    def qemuinfo_plaintext(self, json):
        return json['qemuinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'list Windows services (ala Plugx)'
    })
    def servicediff(self, args, file, opts):
        return {'servicediff': self.run_command(file, args, 'servicediff')}

    def servicediff_plaintext(self, json):
        return json['servicediff']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'list details on _MM_SESSION_SPACE (user logon sessions)'
    })
    def sessions(self, args, file, opts):
        return {'sessions': self.run_command(file, args, 'sessions')}

    def sessions_plaintext(self, json):
        return json['sessions']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'prints ShellBags info'
    })
    def shellbags(self, args, file, opts):
        return {'shellbags': self.run_command(file, args, 'shellbags')}

    def shellbags_plaintext(self, json):
        return json['shellbags']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info':
        'parses the Application Compatibility Shim Cache registry key'
    })
    def shimcache(self, args, file, opts):
        return {'shimcache': self.run_command(file, args, 'shimcache')}

    def shimcache_plaintext(self, json):
        return json['shimcache']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print ShutdownTime of machine from registry'
    })
    def shutdowntime(self, args, file, opts):
        return {'shutdowntime': self.run_command(file, args, 'shutdowntime')}

    def shutdowntime_plaintext(self, json):
        return json['shutdowntime']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of open sockets'
    })
    def sockets(self, args, file, opts):
        return {'sockets': self.run_command(file, args, 'sockets')}

    def sockets_plaintext(self, json):
        return json['sockets']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for tcp socket objects'
    })
    def sockscan(self, args, file, opts):
        return {'sockscan': self.run_command(file, args, 'sockscan')}

    def sockscan_plaintext(self, json):
        return json['sockscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'display SSDT entries'
    })
    def ssdt(self, args, file, opts):
        return {'ssdt': self.run_command(file, args, 'ssdt')}

    def ssdt_plaintext(self, json):
        return json['ssdt']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'scan for Windows services'
    })
    def svcscan(self, args, file, opts):
        return {'svcscan': self.run_command(file, args, 'svcscan')}

    def svcscan_plaintext(self, json):
        return json['svcscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for symlink objects'
    })
    def symlinkscan(self, args, file, opts):
        return {'symlinkscan': self.run_command(file, args, 'symlinkscan')}

    def symlinkscan_plaintext(self, json):
        return json['symlinkscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for thread objects'
    })
    def thrdscan(self, args, file, opts):
        return {'thrdscan': self.run_command(file, args, 'thrdscan')}

    def thrdscan_plaintext(self, json):
        return json['thrdscan']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'investigate _ETHREAD and _KTHREADs'
    })
    def threads(self, args, file, opts):
        return {'threads': self.run_command(file, args, 'threads')}

    def threads_plaintext(self, json):
        return json['threads']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print kernel timers and associated module DPCs'
    })
    def timers(self, args, file, opts):
        return {'timers': self.run_command(file, args, 'timers')}

    def timers_plaintext(self, json):
        return json['timers']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'recover TrueCrypt 7.1a Master Keys'
    })
    def truecryptmaster(self, args, file, opts):
        return {
            'truecryptmaster': self.run_command(file, args, 'truecryptmaster')
        }

    def truecryptmaster_plaintext(self, json):
        return json['truecryptmaster']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'TrueCrypt Cached Passphrase Finder'
    })
    def truecryptpassphrase(self, args, file, opts):
        return {
            'truecryptpassphrase':
            self.run_command(file, args, 'truecryptpassphrase')
        }

    def truecryptpassphrase_plaintext(self, json):
        return json['truecryptpassphrase']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'TrueCrypt Summary'
    })
    def truecryptsummary(self, args, file, opts):
        return {
            'truecryptsummary': self.run_command(file, args,
                                                 'truecryptsummary')
        }

    def truecryptsummary_plaintext(self, json):
        return json['truecryptsummary']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print list of unloaded modules'
    })
    def unloadedmodules(self, args, file, opts):
        return {
            'unloadedmodules': self.run_command(file, args, 'unloadedmodules')
        }

    def unloadedmodules_plaintext(self, json):
        return json['unloadedmodules']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print userassist registry keys and information'
    })
    def userassist(self, args, file, opts):
        return {'userassist': self.run_command(file, args, 'userassist')}

    def userassist_plaintext(self, json):
        return json['userassist']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump the USER handle tables'
    })
    def userhandles(self, args, file, opts):
        return {'userhandles': self.run_command(file, args, 'userhandles')}

    def userhandles_plaintext(self, json):
        return json['userhandles']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump the VAD info'
    })
    def vadinfo(self, args, file, opts):
        return {'vadinfo': self.run_command(file, args, 'vadinfo')}

    def vadinfo_plaintext(self, json):
        return json['vadinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'walk the VAD tree and display in tree format'
    })
    def vadtree(self, args, file, opts):
        return {'vadtree': self.run_command(file, args, 'vadtree')}

    def vadtree_plaintext(self, json):
        return json['vadtree']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'walk the VAD tree'
    })
    def vadwalk(self, args, file, opts):
        return {'vadwalk': self.run_command(file, args, 'vadwalk')}

    def vadwalk_plaintext(self, json):
        return json['vadwalk']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump virtualbox information'
    })
    def vboxinfo(self, args, file, opts):
        return {'vboxinfo': self.run_command(file, args, 'vboxinfo')}

    def vboxinfo_plaintext(self, json):
        return json['vboxinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'prints out the version information from PE images'
    })
    def verinfo(self, args, file, opts):
        return {'verinfo': self.run_command(file, args, 'verinfo')}

    def verinfo_plaintext(self, json):
        return json['verinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'dump VMware VMSS/VMSN information'
    })
    def vmwareinfo(self, args, file, opts):
        return {'vmwareinfo': self.run_command(file, args, 'vmwareinfo')}

    def vmwareinfo_plaintext(self, json):
        return json['vmwareinfo']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print Desktop Windows (verbose details)'
    })
    def windows(self, args, file, opts):
        return {'windows': self.run_command(file, args, 'windows')}

    def windows_plaintext(self, json):
        return json['windows']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'print Z-Order Desktop Windows Tree'
    })
    def wintree(self, args, file, opts):
        return {'wintree': self.run_command(file, args, 'wintree')}

    def wintree_plaintext(self, json):
        return json['wintree']

    @scale.command({
        'args': {
            'profile': fields.Str(required=False)
        },
        'info': 'pool scanner for window stations'
    })
    def wndscan(self, args, file, opts):
        return {'wndscan': self.run_command(file, args, 'wndscan')}

    def wndscan_plaintext(self, json):
        return json['wndscan']
Beispiel #14
0
class Commands(scale.Commands):
    def check(self):

        rule_files = []

        # Check rules_path
        if not RULES_PATH or RULES_PATH == '':
            raise error.CommandError("config variable 'rules_path' not set")
        if not os.path.exists(RULES_PATH):
            raise error.CommandError(
                "'rules_path': '{}' does not exist".format(RULES_PATH))
        if not os.listdir(RULES_PATH):
            raise error.CommandError(
                "'rules_path': '{}' is empty".format(RULES_PATH))
        # Loop through the rules folder and append all of the yar[a] files
        for dir_path, _dirs, files in os.walk(RULES_PATH):
            for f in files:
                if f.endswith('.yar') or f.endswith('.yara'):
                    rule_files.append(os.path.join(dir_path, f))

        # Compile each of the new yara files
        for rule_file in rule_files:
            compiled_rule = os.path.join(
                RULES_PATH,
                os.path.splitext(os.path.basename(rule_file))[0] + '.yarac')
            if not os.path.exists(compiled_rule):
                try:
                    rule = yara.compile(rule_file)
                    rule.save(compiled_rule)
                except Exception as err:  # pylint: disable=broad-except
                    # TODO: Raising a CommandWarning breaks the module load, hence hacking in app_log direct warning temporarily
                    app_log.warning(
                        'error with yara module when compiling rule: %s', err)
                    # raise CommandWarning('error with yara module when compiling rule: %s' % err)

    @scale.command({'info': 'show a list of the yara rule'})
    def rules(self, args, file, opts):
        output = []
        # Loop through the compiled rules
        for _root, _dirs, files in os.walk(RULES_PATH):
            for f in files:
                if f.endswith('.yara') or f.endswith('.yar'):
                    output += [os.path.join(RULES_PATH, f)]
        return output

    def rules_plaintext(self, json):
        return '\n'.join(json)

    @scale.command({
        'args': {
            'rule': fields.Str(required=False)
        },
        'info':
        'scan a file with the available yara rules. Allows for only a single rule to be passed'
    })
    def scan(self, args, file, opts):
        # pylint: disable=too-many-locals, too-many-branches
        compiled_rule_files = []
        output = []

        if 'rule' in args and args['rule'] != '':
            rule = args['rule']
            rule = rule.strip('.yar').strip('.yara')
            rule += '.yarac'
            path = os.path.join(RULES_PATH, rule)
            if os.path.exists(path):
                compiled_rule_files.append(path)
            else:
                raise error.CommandError('rule file does not exist')
        else:
            for _root, _dirs, files in os.walk(RULES_PATH):
                for f in files:
                    if f.endswith('.yarac'):
                        compiled_rule_files.append(os.path.join(RULES_PATH, f))

        # Load each of the compiled yara files
        for compiled_rule_file in compiled_rule_files:
            try:
                rules = yara.load(compiled_rule_file)
                matches = rules.match(file.file_path)
            except Exception:  # noqa pylint: disable=broad-except
                continue

            # Skip if no rule matches
            if not matches:
                continue

            # If the rule index doesn't exist we are likely using the yara plugin and not yara-python
            if matches[0].rule is None:
                raise error.CommandWarning(
                    'incorrect yara python plugin installed')

            # Loop through each match and append to output
            for match in matches:
                try:
                    if match.rule in config.scale_configs['yara'][
                            'blacklisted_rules']:
                        continue
                except Exception:  # noqa pylint: disable=broad-except
                    continue

                # Strings matches are stored as byte arrays, and whilst they can be converted to utf-8 strings,
                # in the case of hex values these are converted to ASCII which is not the desired output.
                # e.g:
                # b'This program cannot be run in DOS mo' = 'This program cannot be run in DOS mo'
                # b'\x40\x410x42' = @A0x42

                output += [{
                    'file':
                    str(os.path.basename(compiled_rule_file)),
                    'rule':
                    str(match.rule),
                    'hits': [{
                        'hit': str(x[2])[2:-1],
                        'offset': str(x[0])
                    } for x in match.strings],
                    'description':
                    str(match.meta['description'])
                    if 'description' in match.meta else '',
                    'author':
                    str(match.meta['author'])
                    if 'author' in match.meta else '',
                }]

        return output

    def scan_markdown(self, json):
        output = md.table_header(
            ['File', 'Rule', 'String', 'Offset', 'Description', 'Author'])
        for r in json:  # pylint: disable=invalid-name
            output += md.table_row([
                md.sanitize(r['file']),
                md.bold(md.sanitize(r['rule'])),
                md.code(md.sanitize(r['hits'][0]['hit']), inline=True)
                if r['hits'] else '',
                md.code(md.sanitize(r['hits'][0]['offset']), inline=True)
                if r['hits'] else '',
                md.sanitize(r['description']),
                md.sanitize(r['author'])
            ])
            for hit in r['hits'][1:]:
                output += md.table_row(
                    ('', '', md.code(md.sanitize(hit['hit']), inline=True),
                     md.code(md.sanitize(hit['offset']), inline=True), '', ''))
        if not json:
            output += md.table_row(('-', '-', '-', '-', '-'))
        return output
Beispiel #15
0
class FileSchema(Schema):
    """The file schema.

    This is the schema for the file document stored within the mongo database.
    """

    not_blank = marshmallow.validate.Length(min=1, error='Field cannot be blank')

    _id = fields.ObjectId(load_only=True)
    file_type = fields.Enum(required=True, type=enums.FileType, missing=enums.FileType.FILE)

    name = fields.Str(required=True, validate=not_blank)

    sha256_digest = fields.Str()

    description = fields.Str()
    tags = fields.Str()

    magic = fields.Str()
    mime = fields.Str()
    size = fields.Int()

    timestamp = fields.DateTime("%Y-%m-%dT%H:%M:%S.%f")

    submission_type = fields.Str(validate=not_blank, default="unknown")

    parents = fields.Dict(values=fields.List(fields.Str(validate=not_blank)), keys=fields.Str(validate=not_blank), default={})
    children = fields.Dict(values=fields.List(fields.Str(validate=not_blank)), keys=fields.Str(validate=not_blank), default={})
Beispiel #16
0
class Commands(scale.Commands):  # pylint: disable=too-many-public-methods
    def check(self):
        strings = shutil.which('radare2')
        if not strings:
            raise error.CommandWarning("binary 'radare2' not found")
        return

    @scale.command({
        'args': {
            'offset': fields.Str(required=True),
            'magic_bytes': fields.Str(default=None, missing=None),
            'patch': fields.Bool(default=True, missing=True),
            'size': fields.Str(required=True),
        },
        'info':
        'this function will carve binaries out of MDMP files'
    })
    def binary_carver(self, args, file, opts):
        sample = {}
        with tempfile.TemporaryDirectory(dir=path.abspath(
                path.expanduser(
                    config.snake_config['cache_dir']))) as temp_dir:
            # Try and carve
            file_path = r2_bin_carver.carve(file.file_path, temp_dir,
                                            args['offset'], args['size'],
                                            args['magic_bytes'])
            if not file_path:
                raise error.CommandError('failed to carve binary')
            if args['patch']:
                if not r2_bin_carver.patch(file_path):
                    raise error.CommandError(
                        'failed to patch binary, not a valid pe file')

            # Get file name
            document = db.file_collection.select(file.sha256_digest)
            if not document:
                raise error.SnakeError("failed to get sample's metadata")

            # Create schema and save
            name = '{}.{}'.format(document['name'], args['offset'])
            file_schema = schema.FileSchema().load({
                'name':
                name,
                'description':
                'extracted with radare2 script r2_bin_carver.py'
            })
            new_file = fs.FileStorage()
            new_file.create(file_path)
            sample = submitter.submit(file_schema, enums.FileType.FILE,
                                      new_file, file, NAME)
            sample = schema.FileSchema().dump(schema.FileSchema().load(
                sample))  # Required to clean the above

        return sample

    def binary_carver_markdown(self, json):
        output = md.table_header(('Name', 'SHA256 Digest', 'File Type'))
        output += md.table_row(
            (json['name'],
             md.url(
                 json['sha256_digest'],
                 '/#/{}/{}'.format(json['file_type'],
                                   json['sha256_digest'])), json['file_type']))
        if not json.keys():
            output += md.table_row(('-', '-', '-'))
        return output

    @scale.command({
        'args': {
            'bits': fields.Str(default='32', missing='32'),
            'technique': fields.Str(required=True)
        },
        'info': 'scan shellcode for hashed functions'
    })
    def hash_function_decoder(self, args, file, opts):
        # Validate
        if args['bits'] not in ['32', '64']:
            raise error.CommandError(
                'invalid bits provided, currently supported: 32, 64')
        if args['technique'] not in r2_hash_func_decoder.TECHNIQUES:
            raise error.CommandError(
                'invalid technique provided, currently supported: {}'.format(
                    r2_hash_func_decoder.TECHNIQUES))

        scale_dir = path.dirname(__file__)
        func_decoder = path.join(scale_dir, 'scripts/r2_hash_func_decoder.py')
        hash_db = path.join(scale_dir, 'scripts/r2_hash_func_decoder.db')

        # Get the output
        proc = subprocess.run([
            'python3', '{}'.format(func_decoder), 'analyse', '-f', '{}'.format(
                file.file_path), '-d', '{}'.format(hash_db), '{}'.format(
                    args['technique'])
        ],
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        if proc.returncode:
            raise error.CommandError('failed to execute script')

        return {'analysis': str(proc.stdout, encoding='utf-8')}

    def hash_function_decoder_plaintext(self, json):
        return json['analysis']
Beispiel #17
0
class CommandHandler(snake_handler.SnakeHandler):
    """Extends `SnakeHandler`."""
    @tornadoparser.use_args({
        # 'args': fields.Dict(required=False, default={}, missing={}),
        'command':
        fields.Str(required=True),
        'format':
        fields.Str(type=enums.Format, missing=enums.Format.JSON),
        'output':
        fields.Bool(required=False, default=True, missing=True),
        'scale':
        fields.Str(required=True),
        'sha256_digest':
        fields.Str(required=True)
    })
    async def get(self, data):
        # NOTE: Tornado/Marshmallow does not like Dict in args, will have to parse manually
        # TODO: Use marshmallow validation
        if 'args' in self.request.arguments and self.request.arguments['args']:
            data['args'] = json.loads(self.request.arguments['args'][0])
        else:
            data['args'] = {}
        document = await db.async_command_collection.select(
            data['sha256_digest'], data['scale'], data['command'],
            data['args'])
        if not document:
            self.write_warning("no output for given data", 404, data)
            self.finish()
            return

        if document['status'] == enums.Status.ERROR:
            self.write_warning("%s" % document['output'], 404, data)
            self.finish()
            return

        document = schema.CommandSchema().load(document)
        output = None
        if document['_output_id']:
            output = await db.async_command_output_collection.get(
                document['_output_id'])
        try:
            scale = scale_manager.get_scale(data['scale'])
            commands = scale_manager.get_component(
                scale, enums.ScaleComponent.COMMANDS)
            if data['output']:
                document['output'] = commands.snake.format(
                    data['format'], document['command'], output)
            document['format'] = data['format']
        except (SnakeError, TypeError) as err:
            self.write_warning("%s" % err, 404, data)
            self.finish()
            return

        document = schema.CommandSchema().dump(document)
        self.jsonify({'command': document})
        self.finish()

    @tornadoparser.use_args({
        'args':
        fields.Dict(required=False, default={}, missing={}),
        'asynchronous':
        fields.Bool(required=False),
        'command':
        fields.Str(required=True),
        'format':
        fields.Str(type=enums.Format, missing=enums.Format.JSON),
        'scale':
        fields.Str(required=True),
        'sha256_digest':
        fields.Str(required=True),
        'timeout':
        fields.Int(required=False)
    })
    async def post(self, data):
        # Check that there is a file for this hash
        document = await db.async_file_collection.select(data['sha256_digest'])
        if not document:
            self.write_warning("no sample for given data", 404, data)
            self.finish()
            return

        # Check scale support
        try:
            scale = scale_manager.get_scale(data['scale'],
                                            document['file_type'])
            commands = scale_manager.get_component(
                scale, enums.ScaleComponent.COMMANDS)
            cmd = commands.snake.command(data['command'])
        except SnakeError as err:
            self.write_warning("%s" % err, 404, data)
            self.finish()
            return

        # Validate arguments as to not waste users time, yes this is also done on execution
        result, args = validate_args(cmd, data['args'])
        if not result:
            self.write_warning(args, 422, data)
            self.finish()
            return
        data['args'] = args

        # Queue command
        try:
            document = await route_support.queue_command(data)
        except SnakeError as err:
            self.write_warning("%s" % err, 500, data)
            self.finish()
            return

        document = schema.CommandSchema().load(document)
        output = None
        if document['_output_id']:
            output = await db.async_command_output_collection.get(
                document['_output_id'])
        try:
            document['output'] = commands.snake.format(data['format'],
                                                       document['command'],
                                                       output)
            document['format'] = data['format']
        except SnakeError as err:
            self.write_warning("%s" % err, 404, data)
            self.finish()
            return

        # Dump and finish
        document = schema.CommandSchema().dump(document)
        self.jsonify({"command": document})
        self.finish()
Beispiel #18
0
class NotesHandler(snake_handler.SnakeHandler):
    """Extends `SnakeHandler`."""
    @tornadoparser.use_args({
        'sha256_digest': fields.Str(required=False),
    })
    async def get(self, data):
        documents = []
        if 'sha256_digest' in data.keys():
            cursor = db.async_note_collection.select_many(
                data['sha256_digest'])
            while await cursor.fetch_next:
                documents += [cursor.next_object()]
        else:
            cursor = db.async_note_collection.select_all()
            while await cursor.fetch_next:
                documents += [cursor.next_object()]
        documents = schema.NoteSchema(many=True).dump(
            schema.NoteSchema(many=True).load(documents))
        self.jsonify({'notes': documents})
        self.finish()

    @tornadoparser.use_args(schema.NoteSchema(many=True))
    async def post(self, data):
        if data == []:
            self.write_warning("note - no request body found", 422)
            self.finish()
            return

        # Check that there is a file for each hash
        missing = []
        for i in data:
            document = await db.async_file_collection.select(i['sha256_digest']
                                                             )
            if not document:
                missing += [i]
        if missing:
            self.write_warning("note - no sample for given data", 404, missing)
            self.finish()
            return

        # Check that there is a note for each hash
        exists = []
        for i in data:
            document = await db.async_note_collection.select(i['sha256_digest']
                                                             )
            if document:
                exists += [
                    schema.NoteSchema().dump(
                        schema.NoteSchema().load(document))
                ]
        if exists:
            self.write_warning("note - note already exists for given data",
                               409, exists)
            self.finish()
            return

        documents = []
        timestamp = datetime.utcnow()
        for i in data:
            i['timestamp'] = timestamp
            i = schema.NoteSchema().dump(i)
            await db.async_note_collection.insert(i)
            documents += [
                await db.async_note_collection.select(i['sha256_digest'])
            ]
        documents = schema.NoteSchema(many=True).dump(
            schema.NoteSchema(many=True).load(documents))
        self.jsonify({'notes': documents})
        self.finish()