Пример #1
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)
Пример #2
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_resource("override_uid", task.uid)

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

    # Add filename override to task
    filename = request.form.get("file_name")
    if filename:
        task.add_resource("file_name", filename)

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

    task.add_resource("sample", sample)
    producer.send_task(task)

    return jsonify({"task_uid": task.uid})
Пример #3
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.payload["override_uid"] = task.uid
    task.add_resource("sample", sample)

    producer.send_task(task)
    return jsonify({"task_uid": task.uid})
Пример #4
0
def main():
    parser = argparse.ArgumentParser(description='Push sample to the karton')
    parser.add_argument('sample', help='Path to the sample')
    args = parser.parse_args()

    conf = Config('/etc/drakrun/config.ini')
    producer = Producer(conf)

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

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

    producer.send_task(task)
Пример #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|doc|docm|docx|dotm|xls|xlsx|xlsm|xltx|xltm)$',
            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)

    task.add_resource("sample", sample)

    producer.send_task(task)

    return jsonify({"task_uid": task.uid})
Пример #6
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
    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)

    task.add_resource("sample", sample)

    producer.send_task(task)

    return jsonify({"task_uid": task.uid})
Пример #7
0
    def process(self):
        sample = self.current_task.get_resource("sample")
        local_sample = self.download_resource(sample)
        self.log.info("hostname: {}".format(socket.gethostname()))
        sha256sum = hashlib.sha256(local_sample.content).hexdigest()
        magic_output = magic.from_buffer(local_sample.content)
        self.log.info("running sample sha256: {}".format(sha256sum))

        analysis_uid = self.current_task.uid
        override_uid = self.current_task.payload.get('override_uid')

        self.log.info(f"analysis UID: {analysis_uid}")

        if override_uid:
            analysis_uid = override_uid
            self.log.info(f"override UID: {override_uid}")
            self.log.info("note that artifacts will be stored under this overriden identifier")

        workdir = '/tmp/drakrun/vm-{}'.format(int(INSTANCE_ID))
        extension = self.current_task.headers.get("extension", "exe").lower()
        start_command = 'start malwar.{}'.format(extension)

        if extension == 'dll':
            run_command = self._get_dll_run_command(local_sample.content)

            if not run_command:
                self.log.info('Unable to run malware sample, could not generate any suitable command to run it.')
                return

            self.log.info('Using command: {}'.format(run_command))
            start_command = 'start {}'.format(run_command)

        try:
            shutil.rmtree(workdir)
        except Exception as e:
            print(e)

        outdir = os.path.join(workdir, 'output')
        os.makedirs(workdir, exist_ok=True)
        os.mkdir(outdir)
        os.mkdir(os.path.join(outdir, 'dumps'))

        metadata = {
            "sample_sha256": sha256sum,
            "magic_output": magic_output,
            "time_started": int(time.time()),
            "start_command": start_command
        }

        with open(os.path.join(outdir, 'sample_sha256.txt'), 'w') as f:
            f.write(hashlib.sha256(local_sample.content).hexdigest())

        with open(os.path.join(workdir, 'run.bat'), 'wb') as f:
            f.write(b'ipconfig /renew\r\nxcopy D:\\malwar.' + extension.encode('ascii') + b' %USERPROFILE%\\Desktop\\\r\nC:\r\ncd %USERPROFILE%\\Desktop\r\n' + start_command.encode('ascii'))

        with open(os.path.join(workdir, 'malwar.{}'.format(extension)), 'wb') as f:
            f.write(local_sample.content)

        try:
            subprocess.run(["genisoimage", "-o", os.path.join(workdir, 'malwar.iso'), os.path.join(workdir, 'malwar.{}'.format(extension)), os.path.join(workdir, 'run.bat')], cwd=workdir, check=True)
        except subprocess.CalledProcessError as e:
            logging.exception("Failed to generate CD ISO image. Please install genisoimage")
            raise e

        watcher_tcpdump = None
        watcher_dnsmasq = None

        for _ in range(3):
            try:
                self.log.info("running vm {}".format(INSTANCE_ID))
                watcher_dnsmasq = start_dnsmasq(INSTANCE_ID, self.config.config['drakrun'].get('dns_server', '8.8.8.8'))

                d_run.ETC_DIR = ETC_DIR
                d_run.LIB_DIR = LIB_DIR
                d_run.logging = self.log
                d_run.run_vm(INSTANCE_ID)

                watcher_tcpdump = start_tcpdump_collector(INSTANCE_ID, outdir)

                self.log.info("running monitor {}".format(INSTANCE_ID))

                kernel_profile = os.path.join(LIB_DIR, "profiles/kernel.json")
                runtime_profile = os.path.join(LIB_DIR, "profiles/runtime.json")
                with open(runtime_profile, 'r') as runtime_f:
                    rp = json.loads(runtime_f.read())
                    inject_pid = rp['inject_pid']
                    kpgd = rp['vmi_offsets']['kpgd']

                hooks_list = os.path.join(ETC_DIR, "hooks.txt")
                dump_dir = os.path.join(outdir, "dumps")
                drakmon_log_fp = os.path.join(outdir, "drakmon.log")

                drakvuf_cmd = ["drakvuf",
                               "-o", "json",
                               "-x", "poolmon",
                               "-x", "objmon",
                               "-j", "5",
                               "-t", "600",
                               "-i", inject_pid,
                               "-k", kpgd,
                               "-d", "vm-{vm_id}".format(vm_id=INSTANCE_ID),
                               "--dll-hooks-list", hooks_list,
                               "--memdump-dir", dump_dir,
                               "-r", kernel_profile,
                               "-e", "D:\\run.bat"]

                with open(drakmon_log_fp, "wb") as drakmon_log:
                    drakvuf = subprocess.Popen(drakvuf_cmd, stdout=drakmon_log)

                    try:
                        exit_code = drakvuf.wait(660)
                    except subprocess.TimeoutExpired as e:
                        logging.error("BUG: Monitor command doesn\'t terminate automatically after timeout expires.")
                        logging.error("Trying to terminate DRAKVUF...")
                        drakvuf.terminate()
                        drakvuf.wait(10)
                        logging.error("BUG: Monitor command also doesn\'t terminate after sending SIGTERM.")
                        drakvuf.kill()
                        drakvuf.wait()
                        logging.error("Monitor command was forcefully killed.")
                        raise e

                    if exit_code != 0:
                        raise subprocess.CalledProcessError(exit_code, drakvuf_cmd)
                break
            except subprocess.CalledProcessError:
                self.log.info("Something went wrong with the VM {}".format(INSTANCE_ID), exc_info=True)
            finally:
                try:
                    subprocess.run(["xl", "destroy", "vm-{}".format(INSTANCE_ID)], cwd=workdir, check=True)
                except subprocess.CalledProcessError:
                    self.log.info("Failed to destroy VM {}".format(INSTANCE_ID), exc_info=True)

                if watcher_dnsmasq:
                    watcher_dnsmasq.terminate()
        else:
            self.log.info("Failed to analyze sample after 3 retries, giving up.")
            return

        self.log.info("waiting for tcpdump to exit")

        if watcher_tcpdump:
            try:
                watcher_tcpdump.wait(timeout=60)
            except subprocess.TimeoutExpired:
                self.log.exception("tcpdump doesn't exit cleanly after 60s")

        self.crop_dumps(os.path.join(outdir, 'dumps'), os.path.join(outdir, 'dumps.zip'))
        if os.path.exists("/opt/procdot/procmon2dot"):
            self.generate_graphs(outdir)
        self.slice_logs(outdir)
        self.log.info("uploading artifacts")

        metadata['time_finished'] = int(time.time())

        with open(os.path.join(outdir, 'metadata.json'), 'w') as f:
            f.write(json.dumps(metadata))

        payload = {"analysis_uid": analysis_uid}
        payload.update(metadata)

        t = Task(
            {
                "type": "analysis",
                "kind": "drakrun",
                "quality": self.current_task.headers.get("quality", "high")
            },
            payload=payload
        )

        for resource in self.upload_artifacts(analysis_uid, workdir):
            t.add_resource(resource.name, resource)

        t.add_resource('sample', sample)
        self.send_task(t)