Exemplo n.º 1
0
    def main(self) -> list:
        # Perform Operations on self.data to unpack the sample
        pe = pefile.PE(data=self.data)

        extractedPayload, extractedDecryptionSection, extractedValue = self.selectingSections(
            pe)
        decrementationCounter = extractedValue // 512  # that's how it is calculated
        obfuscatedPayload = self.payloadDecrypt(
            self.payloadDecode(extractedPayload), decrementationCounter)
        deobfuscatedPayload = self.runObfuscationCode(obfuscatedPayload)
        unpackedExecutable = self.decryptSecondStage(
            deobfuscatedPayload, extractedDecryptionSection)
        task = Task(
            headers={
                'type': 'sample',
                'kind': 'runnable',
                'stage': 'recognized'
            },
            payload={
                'parent':
                Resource(name='sample',
                         content=self.data),  # Set Parent Data (Packed Sample)
                'sample': Resource(name='unpacked', content=unpackedExecutable
                                   )  # Set Child Data (Unpacked Sample)
            })
        # A list of tasks must be returned, as there can be more than one unpacked child
        return [task]
Exemplo n.º 2
0
    def build_profile_payload(self) -> Dict[str, LocalResource]:
        with tempfile.TemporaryDirectory() as tmp_path:
            tmp_dir = Path(tmp_path)

            for profile in dll_file_list:
                fpath = Path(PROFILE_DIR) / f"{profile.dest}.json"
                if fpath.is_file():
                    shutil.copy(fpath, tmp_dir / fpath.name)

            return Resource.from_directory(name="profiles", directory_path=tmp_dir)
Exemplo n.º 3
0
 def test_pass(self) -> None:
     res = Resource("sample", b"z")
     task = Task(
         {
             "type": "sample",
             "stage": "recognized",
             "kind": "runnable"
         },
         payload={"sample": res},
     )
     res_tasks = self.run_task(task)
     self.assertTasksEqual(res_tasks, [])
Exemplo n.º 4
0
 def get_tasks(self):
     global memory_dumps
     self.memory_dump_cleanup()
     tasks = []
     if len(memory_dumps) <= 0:
         return tasks
     log.info(
         "Successfully Extracted {memory_dumps_count} Suspicious Memory Dump(s)"
         .format(memory_dumps_count=len(memory_dumps)))
     for memory_dump in memory_dumps:
         if self.config['debug'] is True:
             log.debug('EXTRACTED_PAYLOAD:')
             hexdump.hexdump(memory_dump)
         tasks.append(
             Task(headers=self.get_headers(memory_dump),
                  payload={
                      'parent': Resource(name='sample', content=self.data),
                      'sample': Resource(name='unpacked',
                                         content=memory_dump)
                  }))
     return tasks
Exemplo n.º 5
0
def upload():
    producer = Producer(conf)

    with NamedTemporaryFile() as f:
        request.files["file"].save(f.name)

        with open(f.name, "rb") as fr:
            sample = Resource("sample", fr.read())

    task = Task({"type": "sample", "stage": "recognized", "platform": "win32"})
    task.add_payload("override_uid", task.uid)

    # Add analysis timeout to task
    timeout = request.form.get("timeout")
    if timeout:
        task.add_payload("timeout", int(timeout))

    # Add filename override to task
    if request.form.get("file_name"):
        filename = request.form.get("file_name")
    else:
        filename = request.files["file"].filename
    if not re.fullmatch(
            r"^((?![\\/><|:&])[\x20-\xfe])+\.(?:dll|exe|ps1|bat|doc|docm|docx|dotm|xls|xlsx|xlsm|xltx|xltm|ppt|pptx|vbs|js|jse|hta|html|htm)$",
            filename,
            flags=re.IGNORECASE,
    ):
        return jsonify({"error": "invalid file_name"}), 400
    task.add_payload("file_name", os.path.splitext(filename)[0])

    # Extract and add extension
    extension = os.path.splitext(filename)[1][1:]
    if extension:
        task.headers["extension"] = extension

    # Add startup command to task
    start_command = request.form.get("start_command")
    if start_command:
        task.add_payload("start_command", start_command)

    # Add plugins to task
    plugins = request.form.get("plugins")
    if plugins:
        plugins = json.loads(plugins)
        task.add_payload("plugins", plugins)

    task.add_resource("sample", sample)

    producer.send_task(task)

    return jsonify({"task_uid": task.uid})
Exemplo n.º 6
0
 def main(self) -> list:
     log.info(f"upx unpacking {self.name}")
     upx = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'upx')
     sample_unpacked = tempfile.mktemp()
     sample_packed = tempfile.mktemp()
     f = open(sample_packed, 'wb')
     f.write(self.data)
     f.close()
     command = [upx, '-d', sample_packed, '-o', sample_unpacked]
     command = subprocess.list2cmdline(command)
     out = ''
     with timeout(self.config['timeout']):
         try:
             out = subprocess.getoutput(command)
         except Exception as error:
             log.error(error)
             return []
     if os.path.exists(sample_packed):
         os.remove(sample_packed)
     if "Unpacked 1 file".lower() in out.lower():
         log.info(f"saved unpacked upx executable to {sample_unpacked}")
         f = open(sample_unpacked, 'rb')
         child_resource = Resource(name='unpacked', content=f.read())
         f.close()
         if os.path.exists(sample_unpacked):
             os.remove(sample_unpacked)
         task = Task(headers={
             "type": "sample",
             "kind": "raw"
         },
                     payload={
                         "parent": Resource(name='sample',
                                            content=self.data),
                         "sample": child_resource
                     })
         return [task]
     log.error(f"failed to unpack: {self.name}")
     return []
 def main(self):
     config_encrypted = self.extract_encrypted_config()
     config_encrypted = re.sub(br'\x00+', b'\x00', config_encrypted)
     config_encrypted = config_encrypted.split(b'\x00')
     self.setup_emulator()
     log.debug('emulation started')
     self.mu.emu_start(self.BASE_ADDRESS,
                       self.BASE_ADDRESS + len(self.CODE))
     log.debug('emulation completed')
     unpacked = self.mu.mem_read(self.DATA_ADDRESS, len(self.PACKED_CODE))
     if unpacked is not None:
         log.debug('succesfully unpacked binary')
         task = Task(headers={
             "type": "sample",
             "kind": "raw"
         },
                     payload={
                         "parent":
                         Resource(name='sample', content=self.data),
                         "sample":
                         Resource(name='unpacked', content=bytes(unpacked))
                     })
         return [task]
     return []
    def test_process_unknown_file(self):
        resource = Resource("file.txt", b"\x00", sha256="sha256")
        res = self.run_task(mock_task(resource))

        expected = Task(
            headers={
                "type": "sample",
                "stage": "unrecognized",
                "origin": "karton.classifier",
                "kind": "unknown",
                "quality": "high",
            },
            payload={
                "sample": resource,
            },
        )
        self.assertTasksEqual(res, [expected])
Exemplo n.º 9
0
    def submit_main(cls):
        parser = cls.args_parser()
        args = parser.parse_args()

        conf_path = os.path.join(ETC_DIR, "config.ini")
        config = patch_config(Config(conf_path))

        with open(args.tests) as tests:
            testcases = [TestCase(**case) for case in json.load(tests)]

        root_uids = []

        for test in testcases:
            sample = test.get_sample()
            sys.stderr.write(f"Submitting {test.sha256}\n")

            t = Task(headers=dict(type="sample-test", platform="win64"))
            t.add_payload("sample", Resource("malwar", sample))
            t.add_payload("testcase", test.to_json())

            if args.timeout:
                t.add_payload("timeout", args.timeout)

            p = Producer(config)
            p.send_task(t)
            root_uids.append(t.root_uid)

        consumer = RegressionTester(config)
        results = {}

        with tqdm(total=len(root_uids)) as pbar:
            while len(results) != len(root_uids):
                for root_uid in cls.get_finished_tasks(consumer.backend,
                                                       root_uids):
                    if root_uid not in results:
                        res = json.load(
                            consumer.backend.minio.get_object(
                                "draktestd", root_uid))
                        results[root_uid] = res
                        print(json.dumps(results[root_uid]))
                        pbar.update(1)

                time.sleep(1)

        print(json.dumps(list(results.values())))
Exemplo n.º 10
0
def send_file_to_karton(file) -> str:
    from mwdb.model.file import File

    tmpfile = None

    try:
        # TODO: Use file.open() directly when Resource(fd=...)
        # is implemented in Karton
        try:
            # If file contents are available via path: just use the path
            path = file.get_path()
        except (ValueError, IOError):
            # If get_path doesn't work: download content to NamedTemporaryFile
            tmpfile = tempfile.NamedTemporaryFile()
            file_stream = file.open()
            shutil.copyfileobj(file_stream, tmpfile)
            File.close(file_stream)
            path = tmpfile.name

        producer = get_karton_producer()
        feed_quality = g.auth_user.feed_quality
        task_priority = (TaskPriority.NORMAL
                         if feed_quality == "high" else TaskPriority.LOW)
        task = Task(
            headers={
                "type": "sample",
                "kind": "raw",
                "quality": feed_quality
            },
            payload={
                "sample":
                Resource(file.file_name, path=path, sha256=file.sha256),
                "attributes":
                file.get_attributes(as_dict=True, check_permissions=False),
            },
            priority=task_priority,
        )
        producer.send_task(task)
    finally:
        if tmpfile is not None:
            tmpfile.close()

    logger.info("File sent to Karton with %s", task.root_uid)
    return task.root_uid
Exemplo n.º 11
0
def main():
    parser = argparse.ArgumentParser(description="Push sample to the karton")
    parser.add_argument("sample", help="Path to the sample")
    parser.add_argument(
        "--start_command",
        help="e.g. start %f, %f will be replaced by file name",
        required=False,
    )
    parser.add_argument(
        "--timeout",
        default=600,
        type=int,
        help="analysis timeout in seconds",
        required=False,
    )
    args = parser.parse_args()

    conf = patch_config(Config(os.path.join(ETC_DIR, "config.ini")))
    producer = Producer(conf)

    task = Task({"type": "sample", "stage": "recognized", "platform": "win32"})

    with open(args.sample, "rb") as f:
        sample = Resource("sample", f.read())
    task.add_resource("sample", sample)

    # Add filename
    filename = os.path.basename(args.sample)
    task.add_payload("file_name", os.path.splitext(filename)[0])

    # Extract and add extension
    extension = os.path.splitext(filename)[1][1:]
    if extension:
        task.headers["extension"] = extension

    if args.start_command is not None:
        task.add_payload("start_command", args.start_command)

    if args.timeout is not None:
        task.add_payload("timeout", args.timeout)

    producer.send_task(task)
Exemplo n.º 12
0
    def test_process(self):
        resource = Resource("file.txt",
                            b"ffafafffa\nfafafafa",
                            sha256="sha256")
        res = self.run_task(mock_task(resource))

        expected = Task(
            headers={
                "type": "sample",
                "stage": "recognized",
                "origin": "karton.classifier",
                "quality": "high",
                "kind": "ascii",
                "mime": "text/plain",
            },
            payload={
                "sample": resource,
                "tags": ["misc:ascii"],
                "magic": "ASCII text",
            },
        )
        self.assertTasksEqual(res, [expected])
Exemplo n.º 13
0
def send_file_to_karton(file: File) -> str:
    try:
        path = file.get_path()
        tmpfile = None
    except Exception:
        # If get_path doesn't work: download content to NamedTemporaryFile
        # It won't work if we use S3 storage and try to reanalyze
        # existing file (not uploaded within the same request).
        tmpfile = tempfile.NamedTemporaryFile()
        file_stream = file.open()
        shutil.copyfileobj(file_stream, tmpfile)
        File.close(file_stream)
        path = tmpfile.name

    producer = Producer(identity="karton.mwdb",
                        config=KartonConfig(config.karton.config_path))

    feed_quality = g.auth_user.feed_quality
    task_priority = TaskPriority.NORMAL if feed_quality == "high" else TaskPriority.LOW
    task = Task(headers={
        "type": "sample",
        "kind": "raw",
        "quality": feed_quality
    },
                payload={
                    "sample":
                    Resource(file.file_name, path=path, sha256=file.sha256),
                    "attributes":
                    file.get_metakeys(as_dict=True, check_permissions=False)
                },
                priority=task_priority)
    producer.send_task(task)

    if tmpfile is not None:
        tmpfile.close()

    file.add_metakey("karton", task.root_uid, check_permissions=False)
    logger.info("File sent to karton with %s", task.root_uid)
    return task.root_uid
Exemplo n.º 14
0
    def test_process_error(self):
        m = MagicMock()
        m.side_effect = Exception("unknown error")
        self.karton = Classifier(magic=m,
                                 config=self.config,
                                 backend=self.backend)

        resource = Resource("file.txt", b"ffafafffa", sha256="sha256")
        res = self.run_task(mock_task(resource))

        expected = Task(
            headers={
                "type": "sample",
                "stage": "unrecognized",
                "origin": "karton.classifier",
                "kind": "unknown",
                "quality": "high",
            },
            payload={
                "sample": resource,
            },
        )
        self.assertTasksEqual(res, [expected])
Exemplo n.º 15
0
 def test_match_2(self) -> None:
     res = Resource("sample", b"ab")
     input_task = Task(
         {
             "type": "sample",
             "stage": "recognized",
             "kind": "runnable"
         },
         payload={"sample": res},
     )
     expected_task = Task(
         {
             "type": "sample",
             "origin": "karton.yaramatcher",
             "stage": "analyzed"
         },
         payload={
             "sample": res,
             "tags": ["yara:a", "yara:b"]
         },
     )
     res_tasks = self.run_task(input_task)
     self.assertTasksEqual(res_tasks, [expected_task])
Exemplo n.º 16
0
    def process(self, task: Task) -> None:
        # Get the incoming sample
        sample_resource = task.get_resource("sample")

        # Log with self.log
        self.log.info(f"Hi {sample_resource.name}, let me analyse you!")

        # Download the resource to a temporary file
        with sample_resource.download_temporary_file() as sample_file:
            # And run `strings` on it
            strings = subprocess.check_output(["strings", sample_file.name])

        # Send our results for further processing or reporting
        task = Task(
            {
                "type": "sample",
                "stage": "analyzed"
            },
            payload={
                "parent": sample_resource,
                "sample": Resource("string", strings)
            },
        )
        self.send_task(task)
Exemplo n.º 17
0
    def process(self, task: Task) -> None:  # type: ignore
        sample = task.get_resource("sample")
        ascii_content = sample.content

        classifier = AsciiClassifier(ascii_content)
        classifier.classify()
        decoder = Decoder(ascii_content, classifier.verdict)
        try:
            decoder.decode()
        except binascii.Error:
            logging.warning("Error why trying to decode base64.")
            return

        if decoder.decoded:
            self.log.info("Decoded possible executable")
            if decoder.decoded[:2] == b"MZ":
                task_params = {
                    "type": "sample",
                    "kind": "runnable",
                    "stage": "recognized",
                    "platform": "win32",
                    "extension": "exe",
                }
            else:
                task_params = {"type": "sample", "kind": "raw"}
            new_sample = Resource(
                sample.name,
                decoder.decoded,
            )

            task = Task(task_params,
                        payload={
                            "sample": new_sample,
                            "parent": sample
                        })
            self.send_task(task)
            return [task]
        return []


if __name__ in '__main__':
    parser = argparse.ArgumentParser(
        prog='fatalrat.py',
        description=
        f'Karton Unpacker Service Example Module v{__version__} (CLI Test Utility)',
        epilog=f'Author: {__author__}')
    parser.add_argument('-i',
                        '--input',
                        help='Input File',
                        type=str,
                        required=True)
    parser.add_argument('--debug',
                        help='Debug',
                        action="store_true",
                        default=False,
                        required=False)
    args = parser.parse_args()
    f = open(args.input, 'rb')
    sample = Resource(name=args.input, content=f.read())
    f.close()
    module = KartonUnpackerModule(sample, {'debug': args.debug})
    if module.enabled is True:
        log.debug('unpacking started')
        task = module.main()
        data = json.loads(str(task))
        print(json.dumps(data, indent=4))
Exemplo n.º 19
0
def mock_resource(filename: str, with_name=False) -> Resource:
    filepath = tests_dir / "testdata" / filename
    return Resource(
        filename if with_name else "file", filepath.read_bytes(), sha256="sha256"
    )
Exemplo n.º 20
0
    def process(self, task: Task) -> None:
        sample = task.get_resource("sample")
        task_password = task.get_payload("password", default=None)

        attributes = task.get_payload("attributes", default={})
        if not task_password and attributes.get("password"):
            self.log.info("Accepting password from attributes")
            task_password = attributes.get("password")[0]

        try:
            if sample.name:
                fname = sample.name.encode("utf8")

                classifier_extension = "." + task.headers.get("extension")
                if classifier_extension and not fname.endswith(
                        classifier_extension.encode("utf-8")):
                    fname += classifier_extension.encode("utf-8")

        except Exception as e:
            self.log.warning("Exception during extraction: %r", e)
            fname = None

        extraction_level = task.get_payload("extraction_level", 0)

        if extraction_level > self.max_depth:
            self.log.warning(
                "Maximum extraction depth exceeded. Can't extract this archive."
            )
            return

        with tempfile.TemporaryDirectory() as dir_name:
            filepath = f"{dir_name}/{fname}"
            with open(filepath, "wb") as f:
                f.write(sample.content)

            archive_password = None
            if task_password is not None:
                archive_password = task_password.encode()

            unpacked = unpack(
                filename=fname,
                filepath=filepath.encode("utf-8"),
                password=archive_password,
            )

        try:
            fname = (unpacked.filename
                     and unpacked.filename.decode("utf8")) or unpacked.sha256
        except Exception as e:
            self.log.warning("Exception during extraction: %r", e)
            fname = "(unknown)"

        self.log.info("Got archive {}".format(fname))

        if not unpacked.children:
            self.log.warning("Don't know how to unpack this archive")
            return

        for child in unpacked.children:
            fname = (child.filename
                     and child.filename.decode("utf8")) or child.sha256

            self.log.info("Unpacked child {}".format(fname))

            if not child.contents:
                self.log.warning(
                    "Child has no contents or protected by unknown password")
                continue

            if len(child.contents) > self.max_size:
                self.log.warning("Child is too big for further processing")
                continue

            task = Task(
                headers={
                    "type": "sample",
                    "kind": "raw",
                    "quality": task.headers.get("quality", "high"),
                },
                payload={
                    "sample": Resource(fname, child.contents),
                    "parent": sample,
                    "extraction_level": extraction_level + 1,
                },
            )
            self.send_task(task)
Exemplo n.º 21
0
    def analyze_dumps(self, sample, dump_infos):
        """
        Analyse multiple dumps from given sample. There can be more than one
        dump from which we managed to extract config from – try to find the best
        candidate for each family.
        """
        extractor = create_extractor(self)
        dump_candidates = {}

        results = {
            "analysed": 0,
            "crashed": 0,
        }

        for i, dump_info in enumerate(dump_infos):
            dump_basename = os.path.basename(dump_info.path)
            results["analysed"] += 1
            self.log.debug("Analyzing dump %d/%d %s", i, len(dump_infos),
                           str(dump_basename))

            with open(dump_info.path, "rb") as f:
                dump_data = f.read()

            if not dump_data:
                self.log.warning("Dump {} is empty".format(dump_basename))
                continue

            try:
                family = extractor.push_file(dump_info.path,
                                             base=dump_info.base)
                if family:
                    self.log.info("Found better %s config in %s", family,
                                  dump_basename)
                    dump_candidates[family] = (dump_basename, dump_data)
            except Exception:
                self.log.exception(
                    "Error while extracting from {}".format(dump_basename))
                results["crashed"] += 1

            self.log.debug("Finished analysing dump no. %d", i)

        self.log.info("Merging and reporting extracted configs")
        for family, config in extractor.configs.items():
            dump_basename, dump_data = dump_candidates[family]
            self.log.info("* (%s) %s => %s", family, dump_basename,
                          json.dumps(config))
            parent = Resource(name=dump_basename, content=dump_data)
            task = Task(
                {
                    "type": "sample",
                    "stage": "analyzed",
                    "kind": "dump",
                    "platform": "win32",
                    "extension": "exe",
                },
                payload={
                    "sample": parent,
                    "parent": sample,
                    "tags": ["dump:win32:exe"],
                },
            )
            self.send_task(task)
            self.report_config(config, sample, parent=parent)

        self.log.info("done analysing, results: {}".format(
            json.dumps(results)))
Exemplo n.º 22
0
    def process(self, task: Task) -> None:
        sample = task.get_resource("sample")
        resources = None

        m = self.yara.match(data=sample.content)
        if "autoit_v3_00" in m:
            self.log.info("Found a possible autoit v3.00 binary")
            resources = extract(data=sample.content,
                                version=AutoItVersion.EA05)
        elif "autoit_v3_26" in m:
            self.log.info("Found a possible autoit v3.26+ binary")
            resources = extract(data=sample.content,
                                version=AutoItVersion.EA06)

        if resources:
            self.log.info("Found embedded data, reporting!")

            for res_name, res_data in resources:
                if res_name.endswith(".dll") or res_name.endswith(".exe"):
                    task_params = {
                        "type": "sample",
                        "kind": "raw",
                    }
                elif res_name == "script.au3":
                    task_params = {
                        "type": "sample",
                        "kind": "script",
                        "stage": "analyzed",
                        "extension": "au3",
                    }
                else:
                    continue

                self.log.info("Sending a task with %s", res_name)
                script = Resource(res_name, res_data)
                self.send_task(
                    Task(task_params,
                         payload={
                             "sample": script,
                             "parent": sample
                         }))
                if res_name == "script.au3":
                    self.log.info(
                        "Looking for a binary embedded in the script")
                    drop = extract_binary(res_data.decode())
                    if drop:
                        self.log.info("Found an embedded binary")
                        self.send_task(
                            Task(
                                {
                                    "type": "sample",
                                    "kind": "raw"
                                },
                                payload={
                                    "sample":
                                    Resource(name="autoit_drop.exe",
                                             content=drop),
                                    "parent":
                                    script,
                                },
                            ))
Exemplo n.º 23
0
def mock_resource(filename: str) -> Resource:
    return Resource(filename, b"feeddecaf\n", sha256="sha256")