def scan(filelist, conf=DEFAULTCONF):
    results = []

    mmb = MaliciousMacroBot()
    mmb.mmb_init_model()

    for fname in filelist:
        # Ensure libmagic returns results
        if REQUIRES[0] is not None:
            # only run the analytic if it is an Office document
            if 'Microsoft' in _get_libmagicresults(REQUIRES[0][0], fname):
                result = mmb.mmb_predict(fname, datatype='filepath')
                prediction = result.iloc[0].get('prediction', None)
                confidence = result.iloc[0].get('result_dictionary',
                                                {}).get('confidence')
                result_dict = {
                    'Prediction': prediction,
                    'Confidence': confidence
                }
                results.append((fname, result_dict))

    metadata = {}
    metadata["Name"] = NAME
    metadata["Type"] = TYPE
    return (results, metadata)
示例#2
0
    def run(self):
        self.key = "mmbot"
        results = dict()
        ftype = File(self.file_path).get_type()

        if self.task["category"] == "file":
            if not HAVE_MMBOT:
                log.error(
                    "MaliciousMacroBot not installed, 'pip3 install mmbot', aborting mmbot analysis."
                )
                return results

            package = ""
            if "info" in self.results and "package" in self.results["info"]:
                package = self.results["info"]["package"]

            if (package not in ("doc", "ppt", "xls", "pub")
                    and ("Zip archive data, at least v2.0" not in ftype
                         or "Composite Document File V2 Document" not in ftype
                         or "Microsoft OOXML" not in ftype)):
                return results

            opts = dict()
            opts['benign_path'] = self.options.get(
                "benign_path",
                os.path.join(CUCKOO_ROOT, "data", "mmbot", "benign"))
            opts['malicious_path'] = self.options.get(
                "malicious_path",
                os.path.join(CUCKOO_ROOT, "data", "mmbot", "malicious"))
            opts['model_path'] = self.options.get(
                "model_path",
                os.path.join(CUCKOO_ROOT, "data", "mmbot", "model"))

            try:
                mmb = MaliciousMacroBot(opts["benign_path"],
                                        opts["malicious_path"],
                                        opts["model_path"],
                                        retain_sample_contents=False)

                mmb.mmb_init_model(modelRebuild=False)
                predresult = mmb.mmb_predict(self.file_path)
                results = mmb.mmb_prediction_to_json(predresult)[0]

                if "malicious" in results["prediction"]:
                    link_path = os.path.join(opts["malicious_path"],
                                             os.path.basename(self.file_path))
                    if not os.path.isfile(link_path):
                        os.symlink(self.file_path, link_path)
                elif "benign" in results["prediction"]:
                    link_path = os.path.join(opts["benign_path"],
                                             os.path.basename(self.file_path))
                    if not os.path.isfile(link_path):
                        os.symlink(self.file_path, link_path)

            except Exception as xcpt:
                log.error("Failed to run mmbot processing: %s", xcpt)

        return results
示例#3
0
 def run(self, obj, config):
     mmb = MaliciousMacroBot()
     mmb.mmb_init_model()
     mmb.set_model_paths(benign_path=None, malicious_path=None, model_path=self.model)
     fc =(obj.filedata.read())
     result = mmb.mmb_predict(fc, datatype='filecontents')
     json = mmb.mmb_prediction_to_json(result)[0]
     for k,v in json.iteritems():
         if k == 'prediction':
             self._add_result("Prediction", v, {"name": k})
     for k,v in json.iteritems():
         if k != 'prediction': 
             self._add_result("Features", v, {"name": k})
示例#4
0
 def run(self, obj, config):
     mmb = MaliciousMacroBot()
     mmb.mmb_init_model()
     mmb.set_model_paths(benign_path=None,
                         malicious_path=None,
                         model_path=self.model)
     f = tempfile.NamedTemporaryFile()
     f.write(obj.filedata.read())
     result = mmb.mmb_predict(f.name, datatype='filepath')
     f.close()
     json = mmb.mmb_prediction_to_json(result)[0]
     for k, v in json.iteritems():
         self._add_result("Prediction", k, {"value": v})
示例#5
0
def test_init_files_in_directories():
    """
    Test ensures the mmb_init function can build a model based on the samples provided.
    """
    resetTest()
    mmb = MaliciousMacroBot(benign_path,
                            malicious_path,
                            model_path,
                            retain_sample_contents=False)
    result = mmb.mmb_init_model(modelRebuild=True)
    os.remove(os.path.join(model_path, 'modeldata.pickle'))
    assert result
示例#6
0
def test_init_files_in_directories_retain_contents():
    """
    Test ensures the mmb_init function can rebuild a model leveraging saved results
    without reprocessing all samples every time
    """
    # Create model with a few samples
    resetTest()
    mmb = MaliciousMacroBot(benign_path,
                            malicious_path,
                            model_path,
                            retain_sample_contents=True)
    result = mmb.mmb_init_model(modelRebuild=True)

    shutil.copy(origsample_path, os.path.join(malicious_path, sample))

    # Add a file and rebuild
    mmb = MaliciousMacroBot(benign_path,
                            malicious_path,
                            model_path,
                            retain_sample_contents=True)
    result = mmb.mmb_init_model(modelRebuild=True)
    assert result
def scan(filelist, conf=DEFAULTCONF):
    results = []

    mmb = MaliciousMacroBot()
    mmb.mmb_init_model()

    for fname in filelist:
        # Ensure libmagic returns results
        if REQUIRES[0] is not None:
            # only run the analytic if it is an Office document
            if 'Microsoft' in _get_libmagicresults(REQUIRES[0][0], fname):
                result = mmb.mmb_predict(fname, datatype='filepath')
                prediction = result.iloc[0].get('prediction', None)
                confidence = result.iloc[0].get('result_dictionary', {}).get('confidence')
                result_dict = {
                    'Prediction': prediction,
                    'Confidence': confidence
                }
                results.append((fname, result_dict))

    metadata = {}
    metadata["Name"] = NAME
    metadata["Type"] = TYPE
    return (results, metadata)
示例#8
0
def test_mmb_predict_sample_from_extracted_vba_df():
    """
    Test ensures the mmb_predict function can make a prediction from a single vba_sample.
    """
    resetTest()
    mmb = MaliciousMacroBot(benign_path,
                            malicious_path,
                            model_path,
                            retain_sample_contents=False)
    result = mmb.mmb_init_model(modelRebuild=True)
    samplevba = 'MsgBox "this is vba"'
    predresult = mmb.mmb_predict(samplevba, datatype='vba')

    predicted_label = predresult.iloc[0]['prediction']
    logging.info('predicted label: {}'.format(predicted_label))

    assert (predicted_label == 'benign' or predicted_label == 'malicious')
示例#9
0
def test_mmb_predict_sample_on_disk():
    """
    Test ensures the mmb_predict function can make a prediction from a single sample on disk.
    """
    resetTest()
    mmb = MaliciousMacroBot(benign_path,
                            malicious_path,
                            model_path,
                            retain_sample_contents=False)
    result = mmb.mmb_init_model(modelRebuild=True)
    predresult = mmb.mmb_predict(origsample_path, datatype='filepath')
    predicted_label = predresult.iloc[0]['prediction']
    logging.info('predicted label: {}'.format(predicted_label))
    logging.info(mmb.mmb_prediction_to_json(predresult))
    logging.info('predicted label: {}'.format(predicted_label))

    assert (predicted_label == 'benign' or predicted_label == 'malicious')
示例#10
0
def main():
    mmb = MaliciousMacroBot()
    if not mmb.mmb_init_model():
        return EXIT_FAILURE

    mime = os.environ['BROAPT_MIME']
    path = os.environ['BROAPT_PATH']
    name = os.path.split(path)[1]

    # run prediction
    prediction = mmb.mmb_predict(path, datatype='filepath')
    records = prediction.to_dict(orient='records')

    log_name = f'{os.path.splitext(name)[0]}.json'
    with open(os.path.join(MMB_LOG, log_name), 'w') as log:
        json.dump(records, log, indent=2)

    result = {'time': time.time(),
              'path': path,
              'mime': mime,
              'rate': MMB_MAP[prediction.loc[0].prediction]}
    with open(os.path.join(LOGS_PATH, 'rate.log'), 'at', 1) as file:
        print(json.dumps(result), file=file)
    return EXIT_SUCCESS
示例#11
0
#!/usr/bin/python

import sys
from mmbot import MaliciousMacroBot

mmb = MaliciousMacroBot()
mmb.mmb_init_model()

result = mmb.mmb_predict(sys.argv[1], datatype='filepath')

print result.iloc[0]
class MacroSampleTester(object):
    """
    This class is aimed to test multiple documents from a given folder with
     MaliciousMacroBot.

    :param folder:      path to the samples folder
    :param dump:        dump the extracted VBA macros
    :param load:        load previous results before starting
    :param save:        save results after processing
    :param display:     display report in terminal after processing
    :param filter_func: function for filtering files
    :param api_key:     VirusTotal API key
    :param update:      force updating VirusTotal result
    :param retry:       retry VirusTotal request if previous result was None
    """
    def __init__(self,
                 folder,
                 dump=True,
                 load=False,
                 save=False,
                 display=False,
                 filter_func=None,
                 api_key=None,
                 update=False,
                 retry=False):
        assert hasattr(filter_func, '__call__') or filter_func is None
        self.__display = display
        self.__dump = dump
        self.__filter_func = filter_func
        self.__retry = retry
        self.__save = save
        self.__update = update
        self.folder = folder
        self.report = None
        self.results = None
        self.vt = VirusTotalClient(api_key)
        if load:
            self._load()
            if self.results is None:
                return
        else:
            if not load and not isdir(folder):
                logger.error(
                    "'{}' isn't a valid samples folder".format(folder))
                return
            logger.info("Initializing MaliciousMacroBot...")
            self.bot = MaliciousMacroBot()
            self.bot.mmb_init_model()
        self.process()

    def _load(self):
        """
        Load results from a Pickle.
        """
        fn = self.folder + ".pickle"
        try:
            with open(fn, 'rb') as f:
                logger.info("Loading previous results from pickle...")
                self.results = pickle.load(f)
        except IOError:
            logger.error("'{}' does not exist".format(fn))
            self.results = None

    def _save(self):
        """
        Save results as a Pickle.
        """
        with open(self.folder + '.pickle', 'wb') as f:
            logger.info("Saving results to pickle...")
            pickle.dump(self.results, f)

    def process(self):
        """
        Test all files with mmbot in a given folder and produce a report.
        """
        assert isinstance(self.results, dict) or self.results is None
        logger.info("Processing samples...")
        # first, get the results of mmbot
        if self.results is None:
            self.results = {}
            for fn in os.listdir(self.folder):
                fp = os.path.abspath(os.path.join(self.folder, fn))
                if os.path.isfile(fp):
                    logger.debug("MMBot: classifying '{}'...".format(fn))
                    try:
                        r = self.bot.mmb_predict(fp, datatype='filepath') \
                            .iloc[0]
                        r = {k: v for k, v in r.iteritems() \
                             if k != 'result_dictionary'}
                        r['sha256'] = hash_file(fp, "sha256")
                        self.results[fn] = r
                    except (TypeError, ValueError):
                        logger.error("Failed to classify '{}'".format(fn))
                        self.results[fn] = None
        # second, if enabled, get the result from VirusTotal
        if self.vt.is_enabled:
            for k, v in self.results.items():
                check = False
                f = "vt_detection_rate"
                if f not in v:
                    check = not logger.debug(
                        "> Getting VT information ({})...".format(k))
                elif self.__update:
                    check = not logger.debug(
                        "> Updating VT information ({})...".format(k))
                elif v.get(f) is None and self.__retry:
                    check = not logger.debug(
                        "> Retrying VT information ({})...".format(k))
                if check:
                    v["vt_detection_rate"] = self.vt.check(v['sha256'])
        # if flag '__save' was set, pickle results to a file
        if self.__save:
            self._save()
        # prepare folders for extracting the macros
        if self.__dump:
            vba = join(self.folder, 'vba')
            logger.warn("Macros will be saved to: {}".format(vba))
            vba = abspath(vba)
            bf, mf = join(vba, 'benign'), join(vba, 'malicious')
            if not os.path.isdir(vba):
                os.makedirs(vba)
            if not os.path.isdir(bf):
                os.makedirs(bf)
            if not os.path.isdir(mf):
                os.makedirs(mf)
        # parse the results
        logger.info("Parsing results...")
        benign, c_all, c_vba = [], [0] * 4, [0] * 4
        if self.vt.is_enabled:
            r = "{: <16}  {: <16}  {}\n".format("FILE", "PREDICTION",
                                                "VT DETECTION")
        else:
            r = "{: <16}  {}\n".format("FILE", "PREDICTION")
        j = OrderedDict([
            ('title', "Malicious Macro Detection Report"),
            ('statistics', None),
            ('results', []),
        ])
        for k, v in sorted(self.results.items()):
            # filter according to the input lambda function 'filter_func'
            if self.__filter_func is not None and not self.__filter_func(k):
                continue
            # define shortnames
            drate = v.get('vt_detection_rate')
            macro = v['extracted_vba']
            failed = macro.startswith("Error:'utf8'") \
                  or macro.startswith("Error:Failed") \
                  or macro == "No VBA Macros found"
            pred = v['prediction']
            malicious = pred == "malicious"
            i = {'file': k, 'prediction': pred, 'sha256': v['sha256']}
            # save the VBA code to the samples folder in subfolder 'vba'
            if not failed:
                if self.__dump:
                    dest = [bf, mf][malicious]
                    vba_fn = join(dest, "{}.vba".format(k))
                    with open(vba_fn, 'w') as f:
                        f.write(macro)
            # add stats line to report if it has a valid macro
            if self.vt.is_enabled:
                i['vt_detection'] = drate
                r += "{: <16}  {: <16}  {}\n".format(k, pred, drate)
            else:
                r += "{: <16}  {}\n".format(k, pred)
            j['results'].append(i)
            # perform counts
            if malicious:
                c_all[0] += 1
            else:
                benign.append(k)
            if drate is None:
                c_all[1] += 1
            if malicious and drate is not None:
                c_all[2] += 1
            c_all[-1] += 1
            if not failed:
                if malicious:
                    c_vba[0] += 1
                if drate is None:
                    c_vba[1] += 1
                if malicious and drate is not None:
                    c_vba[2] += 1
                c_vba[-1] += 1
        # make the report
        # - handle the whole list of files first
        j['statistics'] = {'all': {'malicious': c_all[0], 'total': c_all[-1]}}
        r += "\nAll files:" \
             "\n  Marked as malicious:                  {: >3}/{} ({}%)" \
             .format(c_all[0], c_all[-1], 100 * c_all[0] / c_all[-1])
        if self.vt.is_enabled:
            j['statistics']['all'].update({
                'vt_unknown': c_all[1],
                'malicious_and_vt_known': c_all[2]
            })
            r += "\n  Unknown from VT:                      {: >3}/{} ({}%)" \
                 .format(c_all[1], c_all[-1], 100 * c_all[1] / c_all[-1]) + \
                 "\n  Marked as malicious and known from VT:{: >3}/{} ({}%)" \
                 .format(c_all[2], c_all[-1], 100 * c_all[2] / c_all[-1])
        # - only handle files with a successfully extracted VBA macro
        j['statistics']['vba'] = {'malicious': c_vba[0], 'total': c_vba[-1]}
        r += "\n\nOnly files for which the VBA macro could be extracted:" \
             "\n  Marked as malicious:                  {: >3}/{} ({}%)" \
             .format(c_vba[0], c_vba[-1], 100 * c_vba[0] / c_vba[-1])
        if self.vt.is_enabled:
            j['statistics']['vba'].update({
                'vt_unknown': c_vba[1],
                'malicious_and_vt_known': c_vba[2]
            })
            r += "\n  Unknown from VT:                      {: >3}/{} ({}%)" \
                 .format(c_vba[1], c_vba[-1], 100 * c_vba[1] / c_vba[-1]) + \
                 "\n  Marked as malicious and known from VT:{: >3}/{} ({}%)" \
                 .format(c_vba[2], c_vba[-1], 100 * c_vba[2] / c_vba[-1])
        r += "\n\nBenign files:\n{}".format(", ".join(benign))
        if self.__display:
            print(r)
        self.report = r
        self.json = j