Beispiel #1
0
def server(ctx, host, port, uwsgi, nginx):
    username = ctx.parent.parent.user or getuser()
    if uwsgi:
        print "[uwsgi]"
        print "plugins = python"
        if os.environ.get("VIRTUAL_ENV"):
            print "virtualenv =", os.environ["VIRTUAL_ENV"]
        print "module = cuckoo.apps.distributed"
        print "callable = app"
        print "uid =", username
        print "gid =", username
        print "env = CUCKOO_APP=dist"
        print "env = CUCKOO_CWD=%s" % cwd()
        return

    if nginx:
        print "upstream _uwsgi_cuckoo_distributed {"
        print "    server unix:/run/uwsgi/app/cuckoo-distributed/socket;"
        print "}"
        print
        print "server {"
        print "    listen %s:%d;" % (host, port)
        print
        print "    # REST Distributed app"
        print "    location / {"
        print "        client_max_body_size 1G;"
        print "        uwsgi_pass  _uwsgi_cuckoo_distributed;"
        print "        include     uwsgi_params;"
        print "    }"
        print "}"
        return

    cuckoo_distributed(host, port, ctx.parent.parent.level == logging.DEBUG)
Beispiel #2
0
def server(ctx, host, port, uwsgi, nginx):
    username = ctx.parent.parent.user or getuser()
    if uwsgi:
        print "[uwsgi]"
        print "plugins = python"
        if os.environ.get("VIRTUAL_ENV"):
            print "virtualenv =", os.environ["VIRTUAL_ENV"]
        print "module = cuckoo.apps.distributed"
        print "callable = app"
        print "uid =", username
        print "gid =", username
        print "env = CUCKOO_APP=dist"
        print "env = CUCKOO_CWD=%s" % cwd()
        return

    if nginx:
        print "upstream _uwsgi_cuckoo_distributed {"
        print "    server unix:/run/uwsgi/app/cuckoo-distributed/socket;"
        print "}"
        print
        print "server {"
        print "    listen %s:%d;" % (host, port)
        print
        print "    # REST Distributed app"
        print "    location / {"
        print "        client_max_body_size 1G;"
        print "        uwsgi_pass  _uwsgi_cuckoo_distributed;"
        print "        include     uwsgi_params;"
        print "    }"
        print "}"
        return

    cuckoo_distributed(host, port, ctx.parent.parent.level == logging.DEBUG)
Beispiel #3
0
def temppath():
    """Return the true temporary directory."""
    tmppath = config("cuckoo:cuckoo:tmppath")

    # Backwards compatibility with older configuration.
    if not tmppath or tmppath == "/tmp":
        return os.path.join(tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser())

    return tmppath
Beispiel #4
0
def temppath():
    """Returns the true temporary directory."""
    tmppath = config("cuckoo:cuckoo:tmppath")

    # Backwards compatibility with older configuration.
    if not tmppath or tmppath == "/tmp":
        return os.path.join(
            tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser()
        )

    return tmppath
Beispiel #5
0
def test_temppath():
    set_cwd(tempfile.mkdtemp())
    cuckoo_create()

    assert temppath() == os.path.join(
        tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser()
    )

    set_cwd(tempfile.mkdtemp())
    cuckoo_create(cfg={
        "cuckoo": {
            "cuckoo": {
                "tmppath": "",
            },
        },
    })
    assert temppath() == os.path.join(
        tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser()
    )

    set_cwd(tempfile.mkdtemp())
    cuckoo_create(cfg={
        "cuckoo": {
            "cuckoo": {
                "tmppath": "/tmp",
            },
        },
    })
    assert temppath() == os.path.join(
        tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser()
    )

    set_cwd(tempfile.mkdtemp())
    cuckoo_create(cfg={
        "cuckoo": {
            "cuckoo": {
                "tmppath": "/custom/directory",
            },
        },
    })
    assert temppath() == "/custom/directory"
Beispiel #6
0
def test_temppath():
    set_cwd(tempfile.mkdtemp())
    cuckoo_create()

    assert temppath() == os.path.join(
        tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser()
    )

    set_cwd(tempfile.mkdtemp())
    cuckoo_create(cfg={
        "cuckoo": {
            "cuckoo": {
                "tmppath": "",
            },
        },
    })
    assert temppath() == os.path.join(
        tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser()
    )

    set_cwd(tempfile.mkdtemp())
    cuckoo_create(cfg={
        "cuckoo": {
            "cuckoo": {
                "tmppath": "/tmp",
            },
        },
    })
    assert temppath() == os.path.join(
        tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser()
    )

    set_cwd(tempfile.mkdtemp())
    cuckoo_create(cfg={
        "cuckoo": {
            "cuckoo": {
                "tmppath": "/custom/directory",
            },
        },
    })
    assert temppath() == "/custom/directory"
Beispiel #7
0
def init(ctx, conf):
    """Initializes Cuckoo and its configuration."""
    if conf and os.path.exists(conf):
        cfg = read_kv_conf(conf)
    else:
        cfg = None

    # If this is a new install, also apply the provided configuration.
    cuckoo_init(logging.INFO, ctx.parent, cfg)

    # If this is an existing install, overwrite the supervisord.conf
    # configuration file (if needed) as well as the Cuckoo configuration.
    write_supervisor_conf(ctx.parent.user or getuser())
    write_cuckoo_conf(cfg)
Beispiel #8
0
def init(ctx, conf):
    """Initializes Cuckoo and its configuration."""
    if conf and os.path.exists(conf):
        cfg = read_kv_conf(conf)
    else:
        cfg = None

    # If this is a new install, also apply the provided configuration.
    cuckoo_init(logging.INFO, ctx.parent, cfg)

    # If this is an existing install, overwrite the supervisord.conf
    # configuration file (if needed) as well as the Cuckoo configuration.
    write_supervisor_conf(ctx.parent.user or getuser())
    write_cuckoo_conf(cfg)
Beispiel #9
0
def cuckoo_create(username=None, cfg=None, quiet=False):
    """Create a new Cuckoo Working Directory."""
    if not quiet:
        print jinja2.Environment().from_string(
            open(cwd("cwd", "init-pre.jinja2", private=True), "rb").read()
        ).render(cwd=cwd, yellow=yellow, red=red)

    if not os.path.exists(cwd(".cwd", private=True)):
        print red(
            "The cuckoo/private/.cwd file is missing. Please run "
            "'python setup.py sdist' before 'pip install ...'!"
        )
        return

    if not os.path.isdir(cwd()):
        os.mkdir(cwd())

    def _ignore_pyc(src, names):
        """Don't copy .pyc files."""
        return [name for name in names if name.endswith(".pyc")]

    # The following effectively nops the first os.makedirs() call that
    # shutil.copytree() does as we've already created the destination
    # directory ourselves (assuming it didn't exist already).
    orig_makedirs = shutil.os.makedirs

    def _ignore_first_makedirs(dst):
        shutil.os.makedirs = orig_makedirs

    shutil.os.makedirs = _ignore_first_makedirs

    shutil.copytree(
        os.path.join(cuckoo.__path__[0], "data"),
        cwd(), symlinks=True, ignore=_ignore_pyc
    )

    # Drop our version of the CWD.
    our_version = open(cwd(".cwd", private=True), "rb").read()
    open(cwd(".cwd"), "wb").write(our_version)

    # Write the supervisord.conf configuration file.
    write_supervisor_conf(username or getuser())
    write_cuckoo_conf(cfg=cfg)

    if not quiet:
        print
        print jinja2.Environment().from_string(
            open(cwd("cwd", "init-post.jinja2", private=True), "rb").read()
        ).render()
Beispiel #10
0
def cuckoo_create(username=None, cfg=None, quiet=False):
    """Create a new Cuckoo Working Directory."""
    if not quiet:
        print jinja2.Environment().from_string(
            open(cwd("cwd", "init-pre.jinja2", private=True), "rb").read()
        ).render(cwd=cwd, yellow=yellow, red=red)

    if not os.path.exists(cwd(".cwd", private=True)):
        print red(
            "The cuckoo/private/.cwd file is missing. Please run "
            "'python setup.py sdist' before 'pip install ...'!"
        )
        return

    if not os.path.isdir(cwd()):
        os.mkdir(cwd())

    def _ignore_pyc(src, names):
        """Don't copy .pyc files."""
        return [name for name in names if name.endswith(".pyc")]

    # The following effectively nops the first os.makedirs() call that
    # shutil.copytree() does as we've already created the destination
    # directory ourselves (assuming it didn't exist already).
    orig_makedirs = shutil.os.makedirs

    def _ignore_first_makedirs(dst):
        shutil.os.makedirs = orig_makedirs

    shutil.os.makedirs = _ignore_first_makedirs

    shutil.copytree(
        os.path.join(cuckoo.__path__[0], "data"),
        cwd(), symlinks=True, ignore=_ignore_pyc
    )

    # Drop our version of the CWD.
    our_version = open(cwd(".cwd", private=True), "rb").read()
    open(cwd(".cwd"), "wb").write(our_version)

    # Write the supervisord.conf configuration file.
    write_supervisor_conf(username or getuser())
    write_cuckoo_conf(cfg=cfg)

    if not quiet:
        print
        print jinja2.Environment().from_string(
            open(cwd("cwd", "init-post.jinja2", private=True), "rb").read()
        ).render()
Beispiel #11
0
def api(ctx, host, port, uwsgi, nginx):
    """Operate the Cuckoo REST API."""
    username = ctx.parent.user or getuser()
    if uwsgi:
        print "[uwsgi]"
        print "plugins = python"
        if os.environ.get("VIRTUAL_ENV"):
            print "virtualenv =", os.environ["VIRTUAL_ENV"]
        print "module = cuckoo.apps.api"
        print "callable = app"
        print "uid =", username
        print "gid =", username
        print "env = CUCKOO_APP=api"
        print "env = CUCKOO_CWD=%s" % cwd()
        return

    if nginx:
        print "upstream _uwsgi_cuckoo_api {"
        print "    server unix:/run/uwsgi/app/cuckoo-api/socket;"
        print "}"
        print
        print "server {"
        print "    listen %s:%d;" % (host, port)
        print
        print "    # REST API app"
        print "    location / {"
        print "        client_max_body_size 1G;"
        print "        uwsgi_pass  _uwsgi_cuckoo_api;"
        print "        include     uwsgi_params;"
        print "    }"
        print "}"
        return

    init_console_logging(level=ctx.parent.level)
    Database().connect()

    if not ensure_tmpdir():
        sys.exit(1)

    cuckoo_api(host, port, ctx.parent.level == logging.DEBUG)
Beispiel #12
0
def api(ctx, host, port, uwsgi, nginx):
    """Operate the Cuckoo REST API."""
    username = ctx.parent.user or getuser()
    if uwsgi:
        print "[uwsgi]"
        print "plugins = python"
        if os.environ.get("VIRTUAL_ENV"):
            print "virtualenv =", os.environ["VIRTUAL_ENV"]
        print "module = cuckoo.apps.api"
        print "callable = app"
        print "uid =", username
        print "gid =", username
        print "env = CUCKOO_APP=api"
        print "env = CUCKOO_CWD=%s" % cwd()
        return

    if nginx:
        print "upstream _uwsgi_cuckoo_api {"
        print "    server unix:/run/uwsgi/app/cuckoo-api/socket;"
        print "}"
        print
        print "server {"
        print "    listen %s:%d;" % (host, port)
        print
        print "    # REST API app"
        print "    location / {"
        print "        client_max_body_size 1G;"
        print "        uwsgi_pass  _uwsgi_cuckoo_api;"
        print "        include     uwsgi_params;"
        print "    }"
        print "}"
        return

    init_console_logging(level=ctx.parent.level)
    Database().connect()
    cuckoo_api(host, port, ctx.parent.level == logging.DEBUG)
Beispiel #13
0
    def start(self):
        if not self.machine.interface:
            log.error("Network interface not defined, network capture aborted")
            return False

        # Handle special pcap dumping options.
        if "nictrace" in self.machine.options:
            return True

        tcpdump = self.options["tcpdump"]
        bpf = self.options["bpf"] or ""
        file_path = cwd("storage", "analyses", "%s" % self.task.id,
                        "dump.pcap")

        if not os.path.exists(tcpdump):
            log.error(
                "Tcpdump does not exist at path \"%s\", network "
                "capture aborted", tcpdump)
            return False

        # TODO: this isn't working. need to fix.
        # mode = os.stat(tcpdump)[stat.ST_MODE]
        # if (mode & stat.S_ISUID) == 0:
        #    log.error("Tcpdump is not accessible from this user, "
        #              "network capture aborted")
        #    return

        pargs = [
            tcpdump,
            "-U",
            "-q",
            "-s",
            "0",
            "-n",
            "-i",
            self.machine.interface,
        ]

        # Trying to save pcap with the same user which cuckoo is running.
        user = getuser()
        if user:
            pargs.extend(["-Z", user])

        pargs.extend(["-w", file_path])
        pargs.extend(["host", self.machine.ip])

        if self.task.options.get("sniffer.debug") != "1":
            # Do not capture Agent traffic.
            pargs.extend([
                "and",
                "not",
                "(",
                "dst",
                "host",
                self.machine.ip,
                "and",
                "dst",
                "port",
                "%s" % CUCKOO_GUEST_PORT,
                ")",
                "and",
                "not",
                "(",
                "src",
                "host",
                self.machine.ip,
                "and",
                "src",
                "port",
                "%s" % CUCKOO_GUEST_PORT,
                ")",
            ])

            # Do not capture ResultServer traffic.
            pargs.extend([
                "and",
                "not",
                "(",
                "dst",
                "host",
                self.machine.resultserver_ip,
                "and",
                "dst",
                "port",
                "%s" % self.machine.resultserver_port,
                ")",
                "and",
                "not",
                "(",
                "src",
                "host",
                self.machine.resultserver_ip,
                "and",
                "src",
                "port",
                "%s" % self.machine.resultserver_port,
                ")",
            ])

            if bpf:
                pargs.extend(["and", "(", bpf, ")"])

        try:
            self.proc = Popen(pargs,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              close_fds=True)
        except (OSError, ValueError):
            log.exception(
                "Failed to start sniffer (interface=%s, host=%s, pcap=%s)",
                self.machine.interface,
                self.machine.ip,
                file_path,
            )
            return False

        log.info(
            "Started sniffer with PID %d (interface=%s, host=%s, pcap=%s)",
            self.proc.pid,
            self.machine.interface,
            self.machine.ip,
            file_path,
        )
        return True
Beispiel #14
0
def test_sniffer():
    set_cwd(tempfile.mkdtemp())

    s = Sniffer()
    s.set_task(task)
    s.set_machine(machine)
    s.set_options({
        "tcpdump": __file__,
        "bpf": None,
    })

    with mock.patch("subprocess.Popen") as p:
        p.return_value = BasePopen()
        assert s.start() is True

    user = getuser()
    if user:
        user = "******" % user

    # Test regular setup.
    command = (
        "%s -U -q -s 0 -n -i interface %s-w %s "
        "host 1.2.3.4 and "
        "not ( dst host 1.2.3.4 and dst port 8000 ) and "
        "not ( src host 1.2.3.4 and src port 8000 ) and "
        "not ( dst host 1.1.1.1 and dst port 1234 ) and "
        "not ( src host 1.1.1.1 and src port 1234 )" % (
            __file__, user or "",
            cwd("storage", "analyses", "42", "dump.pcap")
        )
    )

    if is_windows():
        p.assert_called_once_with(
            command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )
    else:
        p.assert_called_once_with(
            command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            close_fds=True
        )

    assert s.stop() is None

    # Test a bpf rule.
    s.options["bpf"] = "not arp"
    with mock.patch("subprocess.Popen") as p:
        p.return_value = BasePopen()
        assert s.start() is True

    if is_windows():
        p.assert_called_once_with(
            command.split() + ["and", "(", "not arp", ")"],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )
    else:
        p.assert_called_once_with(
            command.split() + ["and", "(", "not arp", ")"],
            close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )

    assert s.stop() is None

    # Test an invalid executable path.
    with mock.patch("os.path.exists") as p:
        p.return_value = False
        assert s.start() is False

    # Test stdout output from tcpdump.
    with mock.patch("subprocess.Popen") as p:
        p.return_value = PopenStdout()
        assert s.start() is True

    with pytest.raises(CuckooOperationalError) as e:
        assert s.stop()
    e.match("did not expect standard output")

    # Test unknown stderr output from tcpdump.
    with mock.patch("subprocess.Popen") as p:
        p.return_value = PopenStderr()
        assert s.start() is True

    with pytest.raises(CuckooOperationalError) as e:
        assert s.stop()
    e.match("following standard error output")

    # Test OSError and/or ValueError exceptions.
    with mock.patch("subprocess.Popen") as p:
        p.side_effect = OSError("this is awkward")
        assert s.start() is False

    with mock.patch("subprocess.Popen") as p:
        p.side_effect = ValueError("this is awkward")
        assert s.start() is False
Beispiel #15
0
def web(ctx, args, host, port, uwsgi, nginx):
    """Operate the Cuckoo Web Interface.

    Use "--help" to get this help message and "help" to find Django's
    manage.py potential subcommands.
    """
    username = ctx.parent.user or getuser()
    if uwsgi:
        print "[uwsgi]"
        print "plugins = python"
        if os.environ.get("VIRTUAL_ENV"):
            print "virtualenv =", os.environ["VIRTUAL_ENV"]
        print "module = cuckoo.web.web.wsgi"
        print "uid =", username
        print "gid =", username
        dirpath = os.path.join(cuckoo.__path__[0], "web", "static")
        print "static-map = /static=%s" % dirpath
        print "# If you're getting errors about the PYTHON_EGG_CACHE, then"
        print "# uncomment the following line and add some path that is"
        print "# writable from the defined user."
        print "# env = PYTHON_EGG_CACHE="
        print "env = CUCKOO_APP=web"
        print "env = CUCKOO_CWD=%s" % cwd()
        return

    if nginx:
        print "upstream _uwsgi_cuckoo_web {"
        print "    server unix:/run/uwsgi/app/cuckoo-web/socket;"
        print "}"
        print
        print "server {"
        print "    listen %s:%d;" % (host, port)
        print
        print "    # Cuckoo Web Interface"
        print "    location / {"
        print "        client_max_body_size 1G;"
        print "        proxy_redirect off;"
        print "        proxy_set_header X-Forwarded-Proto $scheme;"
        print "        uwsgi_pass  _uwsgi_cuckoo_web;"
        print "        include     uwsgi_params;"
        print "    }"
        print "}"
        return

    # Switch to cuckoo/web and add the current path to sys.path as the Web
    # Interface is using local imports here and there.
    # TODO Rename local imports to either cuckoo.web.* or relative imports.
    sys.argv[0] = os.path.abspath(sys.argv[0])
    os.chdir(os.path.join(cuckoo.__path__[0], "web"))
    sys.path.insert(0, ".")

    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cuckoo.web.web.settings")

    # The Django HTTP server also imports the WSGI module for some reason, so
    # ensure that WSGI is able to load.
    os.environ["CUCKOO_APP"] = "web"
    os.environ["CUCKOO_CWD"] = cwd()

    from django.core.management import execute_from_command_line

    init_console_logging(level=ctx.parent.level)
    Database().connect()

    try:
        execute_from_command_line(
            ("cuckoo", "runserver", "%s:%d" % (host, port), "--noreload")
            if not args else
            ("cuckoo",) + args
        )
    except CuckooCriticalError as e:
        message = red("{0}: {1}".format(e.__class__.__name__, e))
        if len(log.handlers):
            log.critical(message)
        else:
            sys.stderr.write("{0}\n".format(message))
        sys.exit(1)
Beispiel #16
0
from cuckoo.misc import is_windows, is_linux, is_macosx, getuser, mkdir

# Note that collect_ignore is a parameter for pytest so that it knows which
# unit tests to skip etc. In other words, perform platform-specific unit tests
# (in terms of the Cuckoo Analyzer) depending on the current host machine.
collect_ignore = []

if is_windows():
    sys.path.insert(0, "cuckoo/data/analyzer/windows")
    collect_ignore.append("tests/linux")
    collect_ignore.append("tests/darwin")

    # Copy over the monitoring binaries as if we were in a real analysis.
    monitor = open("cuckoo/data/monitor/latest", "rb").read().strip()
    for filename in os.listdir("cuckoo/data/monitor/%s" % monitor):
        shutil.copy("cuckoo/data/monitor/%s/%s" % (monitor, filename),
                    "cuckoo/data/analyzer/windows/bin/%s" % filename)

if is_linux():
    sys.path.insert(0, "cuckoo/data/analyzer/linux")
    collect_ignore.append("tests/windows")
    collect_ignore.append("tests/darwin")

if is_macosx():
    sys.path.insert(0, "cuckoo/data/analyzer/darwin")
    collect_ignore.append("tests/windows")
    collect_ignore.append("tests/linux")

# Ensure the Cuckoo TMP dir exists, as some tests rely on it.
mkdir(os.path.join(tempfile.gettempdir(), "cuckoo-tmp-%s" % getuser()))
def test_getuser():
    # TODO This probably doesn't work on all platforms.
    assert getuser() == subprocess.check_output(["id", "-un"]).strip()
Beispiel #18
0
def web(ctx, args, host, port, uwsgi, nginx):
    """Operate the Cuckoo Web Interface.

    Use "--help" to get this help message and "help" to find Django's
    manage.py potential subcommands.
    """
    username = ctx.parent.user or getuser()
    if uwsgi:
        print "[uwsgi]"
        print "plugins = python"
        if os.environ.get("VIRTUAL_ENV"):
            print "virtualenv =", os.environ["VIRTUAL_ENV"]
        print "module = cuckoo.web.web.wsgi"
        print "uid =", username
        print "gid =", username
        dirpath = os.path.join(cuckoo.__path__[0], "web", "static")
        print "static-map = /static=%s" % dirpath
        print "# If you're getting errors about the PYTHON_EGG_CACHE, then"
        print "# uncomment the following line and add some path that is"
        print "# writable from the defined user."
        print "# env = PYTHON_EGG_CACHE="
        print "env = CUCKOO_APP=web"
        print "env = CUCKOO_CWD=%s" % cwd()
        return

    if nginx:
        print "upstream _uwsgi_cuckoo_web {"
        print "    server unix:/run/uwsgi/app/cuckoo-web/socket;"
        print "}"
        print
        print "server {"
        print "    listen %s:%d;" % (host, port)
        print
        print "    # Cuckoo Web Interface"
        print "    location / {"
        print "        client_max_body_size 1G;"
        print "        proxy_redirect off;"
        print "        proxy_set_header X-Forwarded-Proto $scheme;"
        print "        uwsgi_pass  _uwsgi_cuckoo_web;"
        print "        include     uwsgi_params;"
        print "    }"
        print "}"
        return

    # Switch to cuckoo/web and add the current path to sys.path as the Web
    # Interface is using local imports here and there.
    # TODO Rename local imports to either cuckoo.web.* or relative imports.
    os.chdir(os.path.join(cuckoo.__path__[0], "web"))
    sys.path.insert(0, ".")

    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cuckoo.web.web.settings")

    # The Django HTTP server also imports the WSGI module for some reason, so
    # ensure that WSGI is able to load.
    os.environ["CUCKOO_APP"] = "web"
    os.environ["CUCKOO_CWD"] = cwd()

    from django.core.management import execute_from_command_line

    init_console_logging(level=ctx.parent.level)
    Database().connect()

    if not args:
        execute_from_command_line(
            ("cuckoo", "runserver", "%s:%d" % (host, port))
        )
    else:
        execute_from_command_line(("cuckoo",) + args)
Beispiel #19
0
    def start(self):
        if not self.machine.interface:
            log.error("Network interface not defined, network capture aborted")
            return False

        # Handle special pcap dumping options.
        if "nictrace" in self.machine.options:
            return True

        tcpdump = self.options["tcpdump"]
        bpf = self.options["bpf"] or ""
        file_path = cwd("storage", "analyses", "%s" % self.task.id, "dump.pcap")

        if not os.path.exists(tcpdump):
            log.error("Tcpdump does not exist at path \"%s\", network "
                      "capture aborted", tcpdump)
            return False

        # TODO: this isn't working. need to fix.
        # mode = os.stat(tcpdump)[stat.ST_MODE]
        # if (mode & stat.S_ISUID) == 0:
        #    log.error("Tcpdump is not accessible from this user, "
        #              "network capture aborted")
        #    return

        pargs = [
            tcpdump, "-U", "-q", "-s", "0", "-n",
            "-i", self.machine.interface,
        ]

        # Trying to save pcap with the same user which cuckoo is running.
        user = getuser()
        if user:
            pargs.extend(["-Z", user])

        pargs.extend(["-w", file_path])
        pargs.extend(["host", self.machine.ip])

        if self.task.options.get("sniffer.debug") != "1":
            # Do not capture Agent traffic.
            pargs.extend([
                "and", "not", "(",
                "dst", "host", self.machine.ip, "and",
                "dst", "port", "%s" % CUCKOO_GUEST_PORT,
                ")", "and", "not", "(",
                "src", "host", self.machine.ip, "and",
                "src", "port", "%s" % CUCKOO_GUEST_PORT,
                ")",
            ])

            # Do not capture ResultServer traffic.
            pargs.extend([
                "and", "not", "(",
                "dst", "host", self.machine.resultserver_ip, "and",
                "dst", "port", "%s" % self.machine.resultserver_port,
                ")", "and", "not", "(",
                "src", "host", self.machine.resultserver_ip, "and",
                "src", "port", "%s" % self.machine.resultserver_port,
                ")",
            ])

            if bpf:
                pargs.extend(["and", "(", bpf, ")"])

        try:
            self.proc = Popen(
                pargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True
            )
        except (OSError, ValueError):
            log.exception(
                "Failed to start sniffer (interface=%s, host=%s, pcap=%s)",
                self.machine.interface, self.machine.ip, file_path,
            )
            return False

        log.info(
            "Started sniffer with PID %d (interface=%s, host=%s, pcap=%s)",
            self.proc.pid, self.machine.interface, self.machine.ip, file_path,
        )
        return True
Beispiel #20
0
def test_sniffer():
    set_cwd(tempfile.mkdtemp())

    s = Sniffer()
    s.set_task(task)
    s.set_machine(machine)
    s.set_options({
        "tcpdump": __file__,
        "bpf": None,
    })

    with mock.patch("subprocess.Popen") as p:
        p.return_value = BasePopen()
        assert s.start() is True

    user = getuser()
    if user:
        user = "******" % user

    # Test regular setup.
    command = (
        "%s -U -q -s 0 -n -i interface %s-w %s "
        "host 1.2.3.4 and "
        "not ( dst host 1.2.3.4 and dst port 8000 ) and "
        "not ( src host 1.2.3.4 and src port 8000 ) and "
        "not ( dst host 1.1.1.1 and dst port 1234 ) and "
        "not ( src host 1.1.1.1 and src port 1234 )" %
        (__file__, user or "", cwd("storage", "analyses", "42", "dump.pcap")))

    if is_windows():
        p.assert_called_once_with(command.split(),
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE)
    else:
        p.assert_called_once_with(command.split(),
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE,
                                  close_fds=True)

    assert s.stop() is None

    # Test a bpf rule.
    s.options["bpf"] = "not arp"
    with mock.patch("subprocess.Popen") as p:
        p.return_value = BasePopen()
        assert s.start() is True

    if is_windows():
        p.assert_called_once_with(command.split() +
                                  ["and", "(", "not arp", ")"],
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE)
    else:
        p.assert_called_once_with(command.split() +
                                  ["and", "(", "not arp", ")"],
                                  close_fds=True,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE)

    assert s.stop() is None

    # Test an invalid executable path.
    with mock.patch("os.path.exists") as p:
        p.return_value = False
        assert s.start() is False

    # Test permission denied on tcpdump.
    with mock.patch("subprocess.Popen") as p:
        p.return_value = PopenPermissionDenied()
        assert s.start() is True

    with pytest.raises(CuckooOperationalError) as e:
        assert s.stop()
    e.match("the network traffic during the")
    e.match("denied-for-tcpdump")

    # Test stdout output from tcpdump.
    with mock.patch("subprocess.Popen") as p:
        p.return_value = PopenStdout()
        assert s.start() is True

    with pytest.raises(CuckooOperationalError) as e:
        assert s.stop()
    e.match("did not expect standard output")

    # Test unknown stderr output from tcpdump.
    with mock.patch("subprocess.Popen") as p:
        p.return_value = PopenStderr()
        assert s.start() is True

    with pytest.raises(CuckooOperationalError) as e:
        assert s.stop()
    e.match("following standard error output")

    # Test OSError and/or ValueError exceptions.
    with mock.patch("subprocess.Popen") as p:
        p.side_effect = OSError("this is awkward")
        assert s.start() is False

    with mock.patch("subprocess.Popen") as p:
        p.side_effect = ValueError("this is awkward")
        assert s.start() is False
Beispiel #21
0
def test_getuser():
    # TODO This probably doesn't work on all platforms.
    assert getuser() == subprocess.check_output(["id", "-un"]).strip()