def test_popen(): """Ensures that Popen is working properly.""" with mock.patch("subprocess.Popen") as p: p.return_value = None Popen(["foo", "bar"]) p.assert_called_once_with(["foo", "bar"]) with mock.patch("subprocess.Popen") as p: p.return_value = None Popen( ["foo", "bar"], close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) if is_windows(): p.assert_called_once_with( ["foo", "bar"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) else: p.assert_called_once_with( ["foo", "bar"], close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) # Test that the method actually works. p = Popen("echo 123", stdout=subprocess.PIPE, shell=True) out, err = p.communicate() assert out.strip() == "123" and not err # The following would normally throw an exception on Windows. p = Popen("echo 1234", close_fds=True, stdout=subprocess.PIPE, shell=True) out, err = p.communicate() assert out.strip() == "1234" and not err
def import_(ctx, mode, path): """Imports an older Cuckoo setup into a new CWD. The old setup should be identified by PATH and the new CWD may be specified with the --cwd parameter, e.g., "cuckoo --cwd /tmp/cwd import old-cuckoo".""" if mode == "symlink" and is_windows(): sys.exit(red( "You can only use the 'symlink' mode on non-Windows platforms." )) print yellow("You are importing an existing Cuckoo setup. Please") print yellow("understand that, depending on the mode taken, if ") print yellow("you remove the old Cuckoo setup after this import ") print yellow("you may still"), red("loose ALL of your data!") print print yellow("Additionally, database migrations will be performed ") print yellow("in-place. You won't be able to use your old Cuckoo ") print yellow("setup anymore afterwards! However, we'll provide ") print yellow("you with the option to create a SQL backup beforehand.") print print red("TL;DR Cleaning the old setup after the import may") print red("corrupt your new setup: its SQL, MongoDB, and ") print red("ElasticSearch database may be dropped and, in 'symlink'") print red("mode, the analyses removed.") print value = click.confirm( "... I've read the above and understand the consequences", False ) if not value: sys.exit(red("Aborting operation.. please try again!")) try: import_cuckoo(ctx.parent.user, mode, path) except KeyboardInterrupt: print(red("Aborting import of Cuckoo instance.."))
def import_legacy_analyses(mode, dirpath): """Imports the raw results of a legacy analysis. Using either the 'copy', 'move', or 'symlink' mode.""" if mode == "copy": import_analysis = import_analysis_copy elif mode == "move": import_analysis = shutil.move elif mode == "symlink": if is_windows(): raise RuntimeError("Can't use 'symlink' mode under Windows!") import_analysis = os.symlink analyses = os.path.join(dirpath, "storage", "analyses") if not os.path.isdir(analyses): log.warning("Didn't find any analyses, so not much to import!") return tasks = [] for task_id in os.listdir(analyses): if task_id == "latest": continue import_analysis( os.path.join(analyses, task_id), cwd(analysis=task_id) ) tasks.append(int(task_id)) return tasks
def import_legacy_analyses(mode, dirpath): """Imports the raw results of a legacy analysis. Using either the 'copy', 'move', or 'symlink' mode.""" if mode == "copy": import_analysis = shutil.copytree elif mode == "move": import_analysis = shutil.move elif mode == "symlink": if is_windows(): raise RuntimeError("Can't use 'symlink' mode under Windows!") import_analysis = os.symlink analyses = os.path.join(dirpath, "storage", "analyses") if not os.path.isdir(analyses): log.warning("Didn't find any analyses, so not much to import!") return tasks = [] for task_id in os.listdir(analyses): if task_id == "latest": continue import_analysis(os.path.join(analyses, task_id), cwd(analysis=task_id)) tasks.append(int(task_id)) return tasks
def init_legacy_analyses(): dirpath = tempfile.mkdtemp() mkdir(dirpath, "storage") mkdir(dirpath, "storage", "analyses") mkdir(dirpath, "storage", "analyses", "1") mkdir(dirpath, "storage", "analyses", "1", "logs") Files.create( (dirpath, "storage", "analyses", "1", "logs"), "a.txt", "a" ) mkdir(dirpath, "storage", "analyses", "1", "reports") Files.create( (dirpath, "storage", "analyses", "1", "reports"), "b.txt", "b" ) mkdir(dirpath, "storage", "analyses", "2") Files.create((dirpath, "storage", "analyses", "2"), "cuckoo.log", "log") if not is_windows(): os.symlink( "thisisnotanexistingfile", os.path.join(dirpath, "storage", "analyses", "2", "binary") ) Files.create((dirpath, "storage", "analyses"), "latest", "last!!1") return dirpath
def test_empty_symlink(self): oldfilepath = Files.temp_put("hello") try: movesql("sqlite:///%s" % oldfilepath, "symlink", temppath()) # Following is non-windows. assert os.path.exists(oldfilepath) assert os.path.exists(cwd("cuckoo.db")) assert os.path.islink(cwd("cuckoo.db")) assert open(cwd("cuckoo.db"), "rb").read() == "hello" except RuntimeError as e: assert is_windows() assert "'symlink'" in e.message
def import_(ctx, mode, path): """Imports an older Cuckoo setup into a new CWD. The old setup should be identified by PATH and the new CWD may be specified with the --cwd parameter, e.g., "cuckoo --cwd /tmp/cwd import old-cuckoo".""" if os.path.exists(os.path.join(path, ".cwd")): print(yellow( "The 'cuckoo import' feature is meant to import a legacy Cuckoo, " "i.e., Cuckoo 1.2, 2.0-dev, 2.0-rc1, or 2.0-rc2 into a new Cuckoo " "CWD." )) print(red( "You're attempting to import an existing Cuckoo CWD. To upgrade " "Cuckoo / your CWD, simply run 'pip install -U cuckoo' and re-run " "the cuckoo commands!" )) sys.exit(1) if mode == "symlink" and is_windows(): sys.exit(red( "You can only use the 'symlink' mode on non-Windows platforms." )) print yellow("You are importing an existing Cuckoo setup. Please") print yellow("understand that, depending on the mode taken, if ") print yellow("you remove the old Cuckoo setup after this import ") print yellow("you may still"), red("lose ALL of your data!") print print yellow("Additionally, database migrations will be performed ") print yellow("in-place*. You won't be able to use your old Cuckoo ") print yellow("setup anymore afterwards! However, we'll provide ") print yellow("you with the option to create a SQL backup beforehand.") print print red("TL;DR Cleaning the old setup after the import may") print red("corrupt your new setup: its SQL, MongoDB, and ") print red("ElasticSearch database may be dropped and, in 'symlink'") print red("mode, the analyses removed.") print print yellow("*: Except for sqlite3 databases in combination with") print yellow(" the import 'copy' approach.") print value = click.confirm( "... I've read the above and understand the consequences", False ) if not value: sys.exit(red("Aborting operation.. please try again!")) try: import_cuckoo(ctx.parent.user, mode, path) except KeyboardInterrupt: print(red("Aborting import of Cuckoo instance.."))
def import_(ctx, mode, path): """Import an older Cuckoo setup into a new CWD. The old setup should be identified by PATH and the new CWD may be specified with the --cwd parameter, e.g., "cuckoo --cwd /tmp/cwd import old-cuckoo".""" if os.path.exists(os.path.join(path, ".cwd")): print(yellow( "The 'cuckoo import' feature is meant to import a legacy Cuckoo, " "i.e., Cuckoo 1.2, 2.0-dev, 2.0-rc1, or 2.0-rc2 into a new Cuckoo " "CWD." )) print(red( "You're attempting to import an existing Cuckoo CWD. To upgrade " "Cuckoo / your CWD, simply run 'pip install -U cuckoo' and re-run " "the cuckoo commands!" )) sys.exit(1) if mode == "symlink" and is_windows(): sys.exit(red( "You can only use the 'symlink' mode on non-Windows platforms." )) print yellow("You are importing an existing Cuckoo setup. Please") print yellow("understand that, depending on the mode taken, if ") print yellow("you remove the old Cuckoo setup after this import ") print yellow("you may still"), red("lose ALL of your data!") print print yellow("Additionally, database migrations will be performed ") print yellow("in-place*. You won't be able to use your old Cuckoo ") print yellow("setup anymore afterwards! However, we'll provide ") print yellow("you with the option to create a SQL backup beforehand.") print print red("TL;DR Cleaning the old setup after the import may") print red("corrupt your new setup: its SQL, MongoDB, and ") print red("ElasticSearch database may be dropped and, in 'symlink'") print red("mode, the analyses removed.") print print yellow("*: Except for sqlite3 databases in combination with") print yellow(" the import 'copy' approach.") print value = click.confirm( "... I've read the above and understand the consequences", False ) if not value: sys.exit(red("Aborting operation.. please try again!")) try: import_cuckoo(ctx.parent.user, mode, path) except KeyboardInterrupt: print(red("Aborting import of Cuckoo instance.."))
def movesql(dburi, mode, dirpath): engine = _dburi_engine(dburi) if engine.name != "sqlite": return if mode == "copy": import_file = shutil.copy elif mode == "move": import_file = shutil.move elif mode == "symlink": if is_windows(): raise RuntimeError("Can't use 'symlink' mode under Windows!") import_file = os.symlink # For more information on the os.path.join() usage see also dumpcmd(). import_file(os.path.abspath(os.path.join(dirpath, engine.url.database)), cwd("cuckoo.db"))
def movesql(dburi, mode, dirpath): engine = _dburi_engine(dburi) if engine.name != "sqlite": return if mode == "copy": import_file = shutil.copy elif mode == "move": import_file = shutil.move elif mode == "symlink": if is_windows(): raise RuntimeError("Can't use 'symlink' mode under Windows!") import_file = os.symlink # For more information on the os.path.join() usage see also dumpcmd(). import_file( os.path.abspath(os.path.join(dirpath, engine.url.database)), cwd("cuckoo.db") )
def init_legacy_analyses(): dirpath = tempfile.mkdtemp() mkdir(dirpath, "storage") mkdir(dirpath, "storage", "analyses") mkdir(dirpath, "storage", "analyses", "1") mkdir(dirpath, "storage", "analyses", "1", "logs") Files.create((dirpath, "storage", "analyses", "1", "logs"), "a.txt", "a") mkdir(dirpath, "storage", "analyses", "1", "reports") Files.create((dirpath, "storage", "analyses", "1", "reports"), "b.txt", "b") mkdir(dirpath, "storage", "analyses", "2") Files.create((dirpath, "storage", "analyses", "2"), "cuckoo.log", "log") if not is_windows(): os.symlink("thisisnotanexistingfile", os.path.join(dirpath, "storage", "analyses", "2", "binary")) Files.create((dirpath, "storage", "analyses"), "latest", "last!!1") return dirpath
# Copyright (C) 2017 Cuckoo Foundation. # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. import sys from cuckoo.misc import is_windows, is_linux, is_macosx # 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") 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")
def test_is_macosx(): assert is_windows() is False assert is_linux() is False assert is_macosx() is True
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
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
# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. import os import shutil import sys import tempfile 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")
assert os.path.isdir(cwd(analysis=1)) assert os.path.isdir(cwd(analysis=2)) def test_import_legacy_analyses_move(): dirpath = init_import_legacy("move") dirpath1 = os.path.join(dirpath, "storage", "analyses", "1") assert not os.path.isdir(dirpath1) dirpath2 = os.path.join(dirpath, "storage", "analyses", "2") assert not os.path.isdir(dirpath2) assert os.path.isdir(cwd(analysis=1)) assert os.path.isdir(cwd(analysis=2)) if not is_windows(): def test_import_legacy_analyses_symlink(): dirpath = init_import_legacy("symlink") assert os.path.islink(cwd(analysis=1)) assert os.path.islink(cwd(analysis=2)) dirpath1 = os.path.join(dirpath, "storage", "analyses", "1") assert os.path.isdir(dirpath1) filepath = os.path.join(dirpath1, "logs", "a.txt") assert open(filepath, "rb").read() == "a" assert os.readlink(cwd(analysis=1)) == dirpath1 dirpath2 = os.path.join(dirpath, "storage", "analyses", "2") assert os.path.isdir(dirpath2)
def test_import_legacy_analyses_move(): dirpath = init_import_legacy("move") dirpath1 = os.path.join(dirpath, "storage", "analyses", "1") assert not os.path.isdir(dirpath1) dirpath2 = os.path.join(dirpath, "storage", "analyses", "2") assert not os.path.isdir(dirpath2) assert os.path.isdir(cwd(analysis=1)) assert os.path.isdir(cwd(analysis=2)) if not is_windows(): def test_import_legacy_analyses_symlink(): dirpath = init_import_legacy("symlink") assert os.path.islink(cwd(analysis=1)) assert os.path.islink(cwd(analysis=2)) dirpath1 = os.path.join(dirpath, "storage", "analyses", "1") assert os.path.isdir(dirpath1) filepath = os.path.join(dirpath1, "logs", "a.txt") assert open(filepath, "rb").read() == "a" assert os.readlink(cwd(analysis=1)) == dirpath1 dirpath2 = os.path.join(dirpath, "storage", "analyses", "2")