From 5c6a298ab8bf1ea2e56c2dd339822359ca1c95fd Mon Sep 17 00:00:00 2001 From: Josh Feather <142008135+josh-feather@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:23:45 +0000 Subject: [PATCH 1/6] Fix order of precedence in Config enumeration --- lib/cuckoo/common/config.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/cuckoo/common/config.py b/lib/cuckoo/common/config.py index 0984ead4e94..af3b840b90b 100644 --- a/lib/cuckoo/common/config.py +++ b/lib/cuckoo/common/config.py @@ -107,12 +107,13 @@ def __init__(self, fname_base: str = "cuckoo"): self._read_files(files) def _get_files_to_read(self, fname_base): - files = [ - os.path.join(CUCKOO_ROOT, "conf", f"{fname_base}.conf.default"), - os.path.join(CUCKOO_ROOT, "conf", f"{fname_base}.conf"), - os.path.join(CUSTOM_CONF_DIR, f"{fname_base}.conf"), - ] - files.extend(sorted(glob.glob(os.path.join(CUCKOO_ROOT, "conf", f"{fname_base}.conf.d", "*.conf")))) + # Allows test workflows to ignore custom root configs + include_root_configs = "CAPE_DISABLE_ROOT_CONFIGS" not in os.environ + files = [os.path.join(CUCKOO_ROOT, "conf", f"{fname_base}.conf.default")] + if include_root_configs: + files.append(os.path.join(CUCKOO_ROOT, "conf", f"{fname_base}.conf")) + files.extend(sorted(glob.glob(os.path.join(CUCKOO_ROOT, "conf", f"{fname_base}.conf.d", "*.conf")))) + files.append(os.path.join(CUSTOM_CONF_DIR, f"{fname_base}.conf")) files.extend(sorted(glob.glob(os.path.join(CUSTOM_CONF_DIR, f"{fname_base}.conf.d", "*.conf")))) return files From ccdc8fa15d9f34dc709861c4f154478621e72b32 Mon Sep 17 00:00:00 2001 From: Josh Feather <142008135+josh-feather@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:26:55 +0000 Subject: [PATCH 2/6] Flush Error table between database tests --- tests/test_database.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_database.py b/tests/test_database.py index a14d0c47f65..d44b67eb7b9 100644 --- a/tests/test_database.py +++ b/tests/test_database.py @@ -14,7 +14,7 @@ from lib.cuckoo.common.exceptions import CuckooOperationalError from lib.cuckoo.common.path_utils import path_mkdir from lib.cuckoo.common.utils import store_temp_file -from lib.cuckoo.core.database import Database, Machine, Tag, Task, machines_tags, tasks_tags +from lib.cuckoo.core.database import Database, Error, Machine, Tag, Task, machines_tags, tasks_tags @pytest.fixture(autouse=True) @@ -57,11 +57,13 @@ def setup_method(self, method): stmt3 = delete(machines_tags) stmt4 = delete(tasks_tags) stmt5 = delete(Tag) + stmt6 = delete(Error) self.session.execute(stmt) self.session.execute(stmt2) self.session.execute(stmt3) self.session.execute(stmt4) self.session.execute(stmt5) + self.session.execute(stmt6) self.session.commit() def teardown_method(self): From 2425f053a3e2f372174ac7613ec6c06feeeb666b Mon Sep 17 00:00:00 2001 From: Josh Feather <142008135+josh-feather@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:29:31 +0000 Subject: [PATCH 3/6] Make tests only use the '*.conf.default' files unless necessary --- tests/conftest.py | 14 ++++++ tests/test_config.py | 103 +++++++++++++------------------------------ 2 files changed, 44 insertions(+), 73 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index ff0c06f3d42..bcccc2f9be9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,22 @@ +import pathlib import pytest +from lib.cuckoo.common.config import ConfigMeta +import lib.cuckoo.common.config import lib.cuckoo.core.database @pytest.fixture def tmp_cuckoo_root(monkeypatch, tmp_path): monkeypatch.setattr(lib.cuckoo.core.database, "CUCKOO_ROOT", str(tmp_path)) + yield tmp_path + + +@pytest.fixture(autouse=True) +def custom_conf_path(request, monkeypatch, tmp_cuckoo_root): + ConfigMeta.reset() + monkeypatch.setenv("CAPE_DISABLE_ROOT_CONFIGS", "1") + path: pathlib.Path = tmp_cuckoo_root / "custom" / "conf" + path.mkdir(mode=0o755, parents=True) + monkeypatch.setattr(lib.cuckoo.common.config, "CUSTOM_CONF_DIR", str(path)) + yield path \ No newline at end of file diff --git a/tests/test_config.py b/tests/test_config.py index 19fd06b1081..d4a9a48aafc 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -7,8 +7,7 @@ import pytest -import lib.cuckoo.common.config -from lib.cuckoo.common.config import AnalysisConfig, Config, ConfigMeta +from lib.cuckoo.common.config import AnalysisConfig, Config from lib.cuckoo.common.exceptions import CuckooOperationalError from lib.cuckoo.common.path_utils import path_write_file @@ -31,11 +30,6 @@ def analysis_config(tmp_path): yield AnalysisConfig(path) -@pytest.fixture(autouse=True) -def reset(): - ConfigMeta.reset() - - class TestAnalysisConfig: def test_get_option_exist(self, analysis_config): """Fetch an option of each type from default config file.""" @@ -67,60 +61,34 @@ def write_config(path, content): path_write_file(path, textwrap.dedent(content), mode="text") -@pytest.fixture -def custom_conf_dir(monkeypatch, tmp_path): - custom_dir = tmp_path / "custom" - custom_dir.mkdir() - monkeypatch.setattr(lib.cuckoo.common.config, "CUSTOM_CONF_DIR", str(custom_dir)) - yield custom_dir - - -@pytest.fixture -def default_config(monkeypatch, tmp_path): - default_dir = tmp_path / "default" - default_dir.mkdir() - default_conf = default_dir / "conf" / "cuckoo.conf" - default_conf.parent.mkdir() - write_config( - default_conf, - """ - [cuckoo] - debug = false - analysis_timeout = 120 - """, - ) - monkeypatch.setattr(lib.cuckoo.common.config, "CUCKOO_ROOT", str(default_dir)) - yield default_conf - - class TestConfig: - def test_option_override(self, custom_conf_dir, default_config): + def test_option_override(self, custom_conf_path): """Fetch an option of each type from default config file.""" - custom_conf = custom_conf_dir / "cuckoo.conf" + custom_conf = custom_conf_path / "cuckoo.conf" write_config( custom_conf, """ [cuckoo] - debug = true + machinery_screenshots = true """, ) config = Config("cuckoo") # This was overridden in the custom config. - assert config.get("cuckoo")["debug"] is True + assert config.get("cuckoo")["machinery_screenshots"] is True # This was inherited from the default config. - assert config.get("cuckoo")["analysis_timeout"] == 120 + assert config.get("cuckoo")["max_analysis_count"] == 0 - def test_nonexistent_custom_file(self, custom_conf_dir, default_config): + def test_nonexistent_custom_file(self): """Verify that there are no problems when the file to be processed does not exist in the custom config dir. """ config = Config("cuckoo") - assert config.get("cuckoo")["debug"] is False - assert config.get("cuckoo")["analysis_timeout"] == 120 + assert config.get("cuckoo")["machinery_screenshots"] is False + assert config.get("cuckoo")["max_analysis_count"] == 0 - def test_subdirs(self, custom_conf_dir): - api_conf = custom_conf_dir / "api.conf" + def test_subdirs(self, custom_conf_path): + api_conf = custom_conf_path / "api.conf" write_config( api_conf, """ @@ -128,7 +96,7 @@ def test_subdirs(self, custom_conf_dir): ratelimit = no """, ) - api_conf_d_dir = custom_conf_dir / "api.conf.d" + api_conf_d_dir = custom_conf_path / "api.conf.d" api_conf_d_dir.mkdir() host_specific_conf = api_conf_d_dir / "01_host_specific.conf" url = "https://somehost.example.com" @@ -149,7 +117,7 @@ def test_subdirs(self, custom_conf_dir): # api.conf.d/01_host_specific.conf. assert config.get("api")["url"] == url - def test_singleton_configs(self, default_config): + def test_singleton_configs(self): """Verify that Config objects that were passed the same "file_name" argument are reused. """ @@ -157,54 +125,43 @@ def test_singleton_configs(self, default_config): config2 = Config("cuckoo") assert config1 is config2 - def test_environment_interpolation(self, default_config, custom_conf_dir, monkeypatch): + def test_environment_interpolation(self, custom_conf_path, monkeypatch): """Verify that environment variables are able to be referenced in config files. """ - default_dir = default_config.parent - aux_conf = default_dir / "auxiliary.conf" - write_config( - aux_conf, - """ - [virustotaldl] - enabled = no - #dlintelkey = SomeKeyWithDLAccess - dlpath = /tmp/ - """, - ) - custom_conf = custom_conf_dir / "auxiliary.conf" + custom_conf = custom_conf_path / "processing.conf" write_config( custom_conf, """ - [virustotaldl] - enabled = yes - dlintelkey = %(ENV:DLINTELKEY)s + [virustotal] + on_demand = yes + key = %(ENV:DLINTELKEY)s """, ) custom_secret = "MyReallySecretKeyWithAPercent(%)InIt" monkeypatch.setenv("DLINTELKEY", custom_secret) - config = Config("auxiliary") - section = config.get("virustotaldl") + config = Config("processing") + section = config.get("virustotal") # Inherited from default config - assert section.dlpath == "/tmp/" - # Overridden from custom config assert section.enabled is True + # Overridden from custom config + assert section.on_demand is True # Overridden from custom config and uses environment variable - assert section.dlintelkey == custom_secret + assert section.key == custom_secret - def test_missing_environment_interpolation(self, default_config, custom_conf_dir, monkeypatch): + def test_missing_environment_interpolation(self, custom_conf_path, monkeypatch): """Verify that an exception is raised if an ENV variable is to be used in a config file, but that variable is not present in the environment. """ - default_dir = default_config.parent - aux_conf = default_dir / "auxiliary.conf" + custom_conf = custom_conf_path / "processing.conf" write_config( - aux_conf, + custom_conf, """ - [foo] - bar = %(ENV:IDONTEXIST)s + [virustotal] + key = %(ENV:IDONTEXIST)s """, ) + with pytest.raises(configparser.InterpolationMissingOptionError): - _ = Config("auxiliary") + _ = Config("processing") From 35829829a1336a4b8b1427beb842cf756d938027 Mon Sep 17 00:00:00 2001 From: Josh Feather <142008135+josh-feather@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:29:59 +0000 Subject: [PATCH 4/6] Additional test_file_extra_info skip criteria, move Config load into extractor_ctx --- .../file_extra_info_modules/__init__.py | 2 +- tests/test_file_extra_info.py | 59 ++++++++++++++----- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/lib/cuckoo/common/integrations/file_extra_info_modules/__init__.py b/lib/cuckoo/common/integrations/file_extra_info_modules/__init__.py index d28218c39d7..4fb477ae3d9 100644 --- a/lib/cuckoo/common/integrations/file_extra_info_modules/__init__.py +++ b/lib/cuckoo/common/integrations/file_extra_info_modules/__init__.py @@ -11,7 +11,6 @@ from lib.cuckoo.common.config import Config from lib.cuckoo.common.path_utils import path_mkdir, path_object -cfg = Config() log = logging.getLogger(__name__) @@ -50,6 +49,7 @@ def wrapped(*args, **kwargs): @contextlib.contextmanager def extractor_ctx(filepath, tool_name, prefix=None): + cfg = Config() folder = os.path.join(cfg.cuckoo.get("tmppath", "/tmp"), "cape-external") path_mkdir(folder, exist_ok=True) diff --git a/tests/test_file_extra_info.py b/tests/test_file_extra_info.py index 20b24dfa485..8068687380b 100644 --- a/tests/test_file_extra_info.py +++ b/tests/test_file_extra_info.py @@ -8,11 +8,15 @@ from lib.cuckoo.common.integrations import file_extra_info +self_extraction_dir = (pathlib.Path(__file__).parent / "data" / "selfextraction") @pytest.mark.skipif( - not (pathlib.Path(__file__).parent / "data" / "selfextraction").exists(), reason="Required data file is not present" + not (self_extraction_dir).exists(), reason="Required data file is not present" ) class TestFileExtraInfo: + @pytest.mark.skipif( + not (self_extraction_dir / "0ea5e25b12ab314bc9a0569c3ca756f205f40b792119f8e0fc62c874628dfea0.msi").exists(), reason="Required data file is not present" + ) def test_generic_file_extractors(self): results = {} data_dictionary = {"type": "MSI Installer"} @@ -20,7 +24,7 @@ def test_generic_file_extractors(self): tmpdir = tempfile.mkdtemp() duplicated = {"sha256": set()} file_extra_info.generic_file_extractors( - "tests/data/selfextraction/0ea5e25b12ab314bc9a0569c3ca756f205f40b792119f8e0fc62c874628dfea0.msi", + f"{self_extraction_dir}/0ea5e25b12ab314bc9a0569c3ca756f205f40b792119f8e0fc62c874628dfea0.msi", tmpdir, data_dictionary, options_dict, @@ -31,6 +35,9 @@ def test_generic_file_extractors(self): assert data_dictionary["extracted_files_tool"] == "MsiExtract" assert len(data_dictionary["extracted_files"]) == 2 + @pytest.mark.skipif( + not (self_extraction_dir / "5b354397f6393ed777639b7d40dec3f37215dcb5078c63993e8a9703e819e2bc.inno").exists(), reason="Required data file is not present" + ) def test_generic_file_extractors_no_tests(self): results = {} data_dictionary = {"die": ["Inno Setup"], "type": ""} @@ -38,7 +45,7 @@ def test_generic_file_extractors_no_tests(self): tmpdir = tempfile.mkdtemp() duplicated = {"sha256": set()} file_extra_info.generic_file_extractors( - "tests/data/selfextraction/5b354397f6393ed777639b7d40dec3f37215dcb5078c63993e8a9703e819e2bc.inno", + f"{self_extraction_dir}/5b354397f6393ed777639b7d40dec3f37215dcb5078c63993e8a9703e819e2bc.inno", tmpdir, data_dictionary, options_dict, @@ -51,20 +58,23 @@ def test_generic_file_extractors_no_tests(self): @pytest.mark.skip(reason="Not implemented yet") def test_batch_extract(self): extracted_files = file_extra_info.batch_extract( - file="tests/data/selfextraction/", + file=f"{self_extraction_dir}/", ) assert len(extracted_files["result"]["extracted_files"]) == 4 + @pytest.mark.skipif( + not (self_extraction_dir / "c738cdd8ec0d65769e17eed1d6fe371893a2972b7a432c6532446d225e166733.vbe").exists(), reason="Required data file is not present" + ) def test_vbe_extract(self): extracted_files = file_extra_info.vbe_extract( - file="tests/data/selfextraction/c738cdd8ec0d65769e17eed1d6fe371893a2972b7a432c6532446d225e166733.vbe", + file=f"{self_extraction_dir}/c738cdd8ec0d65769e17eed1d6fe371893a2972b7a432c6532446d225e166733.vbe", ) assert len(extracted_files["result"]["extracted_files"]) == 1 @pytest.mark.skip(reason="Not implemented yet") def test_eziriz_deobfuscate(self): extracted_files = file_extra_info.eziriz_deobfuscate( - file="tests/data/selfextraction/", + file=f"{self_extraction_dir}/", data_dictionary={"die": ["Eziriz .NET Reactor"]} ** {"test": True, "options": {}}, ) self.assertEqual(len(extracted_files["result"]["extracted_files"]), 4, "Failed to extract.") @@ -72,21 +82,27 @@ def test_eziriz_deobfuscate(self): @pytest.mark.skip(reason="Not implemented yet") def test_de4dot_deobfuscate(self): extracted_files = file_extra_info.de4dot_deobfuscate( - file="tests/data/selfextraction/", filetype="Mono", **{"test": True, "options": {}} + file=f"{self_extraction_dir}/", filetype="Mono", **{"test": True, "options": {}} ) self.assertEqual(len(extracted_files["result"]["extracted_files"]), 4, "Failed to extract.") + @pytest.mark.skipif( + not (self_extraction_dir / "0ea5e25b12ab314bc9a0569c3ca756f205f40b792119f8e0fc62c874628dfea0.msi").exists(), reason="Required data file is not present" + ) def test_msi_extract(self): extracted_files = file_extra_info.msi_extract( - file="tests/data/selfextraction/0ea5e25b12ab314bc9a0569c3ca756f205f40b792119f8e0fc62c874628dfea0.msi", + file=f"{self_extraction_dir}/0ea5e25b12ab314bc9a0569c3ca756f205f40b792119f8e0fc62c874628dfea0.msi", filetype="MSI Installer", **{"tests": True, "options": {}}, ) assert len(extracted_files["result"]["extracted_files"]) == 2 + @pytest.mark.skipif( + not (self_extraction_dir / "5b354397f6393ed777639b7d40dec3f37215dcb5078c63993e8a9703e819e2bc.inno").exists(), reason="Required data file is not present" + ) def test_Inno_extract(self): extracted_files = file_extra_info.Inno_extract( - file="tests/data/selfextraction/5b354397f6393ed777639b7d40dec3f37215dcb5078c63993e8a9703e819e2bc.inno", + file=f"{self_extraction_dir}/5b354397f6393ed777639b7d40dec3f37215dcb5078c63993e8a9703e819e2bc.inno", data_dictionary={"die": ["Inno Setup"]}, ) assert len(extracted_files["result"]["extracted_files"]) == 1 @@ -95,22 +111,25 @@ def test_Inno_extract(self): @pytest.mark.skip(reason="Not implemented yet - need to include community repo") def test_kixtart_extract(self): extracted_files = file_extra_info.kixtart_extract( - file="tests/data/selfextraction/d0d415dbe02e893fb1b2d6112c0f38d8ce65ab3268c896bfc64ba06096d4d09a.kix", + file=f"{self_extraction_dir}/d0d415dbe02e893fb1b2d6112c0f38d8ce65ab3268c896bfc64ba06096d4d09a.kix", ) assert len(extracted_files["result"]["extracted_files"]) == 4 @pytest.mark.skip(reason="Not implemented yet") def test_UnAutoIt_extract(self): extracted_files = file_extra_info.kixtart_extract( - file="tests/data/selfextraction/5b354397f6393ed777639b7d40dec3f37215dcb5078c63993e8a9703e819e2bc.inno", + file=f"{self_extraction_dir}/5b354397f6393ed777639b7d40dec3f37215dcb5078c63993e8a9703e819e2bc.inno", data_dictionary={"yara": [{"name": "AutoIT_Compiled"}]}, **{"test": True, "options": {}}, ) assert len(extracted_files["result"]["extracted_files"]) == 4 + @pytest.mark.skipif( + not (self_extraction_dir / "1b0c4149df7892b2497c955dc393ed49e458062324a81288589b15492ce8b50b.upx").exists(), reason="Required data file is not present" + ) def test_UPX_unpack(self): extracted_files = file_extra_info.UPX_unpack( - file="tests/data/selfextraction/1b0c4149df7892b2497c955dc393ed49e458062324a81288589b15492ce8b50b.upx", + file=f"{self_extraction_dir}/1b0c4149df7892b2497c955dc393ed49e458062324a81288589b15492ce8b50b.upx", filetype="UPX compressed", data_dictionary={}, **{"test": True, "options": {}}, @@ -120,9 +139,12 @@ def test_UPX_unpack(self): "1b0c4149df7892b2497c955dc393ed49e458062324a81288589b15492ce8b50b.upx_unpacked" ] + @pytest.mark.skipif( + not (self_extraction_dir / "ab77ea6ad4b6766e0db88d4f49c2c0075ba18b3573d7c6d07ee878bd6e71c388.7z").exists(), reason="Required data file is not present" + ) def test_SevenZip_unpack(self): extracted_files = file_extra_info.SevenZip_unpack( - file="tests/data/selfextraction/ab77ea6ad4b6766e0db88d4f49c2c0075ba18b3573d7c6d07ee878bd6e71c388.7z", + file=f"{self_extraction_dir}/ab77ea6ad4b6766e0db88d4f49c2c0075ba18b3573d7c6d07ee878bd6e71c388.7z", data_dictionary={"die": ["7-zip Installer data"]}, filetype="", **{"test": True, "options": {}}, @@ -137,18 +159,25 @@ def test_SevenZip_unpack(self): "自述.txt", ] + @pytest.mark.skipif( + not (self_extraction_dir / "9e69c36d967afbb1a948a022fcfb1a6384b35b233a47e7d859145db19018d21e.sfx").exists(), reason="Required data file is not present" + ) def test_RarSFX_extract(self): extracted_files = file_extra_info.RarSFX_extract( - file="tests/data/selfextraction/9e69c36d967afbb1a948a022fcfb1a6384b35b233a47e7d859145db19018d21e.sfx", + file=f"{self_extraction_dir}/9e69c36d967afbb1a948a022fcfb1a6384b35b233a47e7d859145db19018d21e.sfx", data_dictionary={"type": "RAR self-extracting archive"}, options={}, ) assert len(extracted_files["result"]["extracted_files"]) == 3 assert sorted(extracted_files["result"]["extracted_files"]) == ["Manag.exe", "mLib.cs", "x64.xr"] + + @pytest.mark.skipif( + not (self_extraction_dir / "12c4d9eddce807d10e3578fcf2918366def586ec374a35957880a65dbd467efc.one").exists(), reason="Required data file is not present" + ) def test_office_one_extract(self): extracted_files = file_extra_info.office_one( - file="tests/data/selfextraction/12c4d9eddce807d10e3578fcf2918366def586ec374a35957880a65dbd467efc.one", + file=f"{self_extraction_dir}/12c4d9eddce807d10e3578fcf2918366def586ec374a35957880a65dbd467efc.one", ) assert len(extracted_files["result"]["extracted_files"]) == 6 assert sorted(extracted_files["result"]["extracted_files"]) == [ From 96602f7cc8d02cf5c22a4cf00452151fd35052b9 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Thu, 15 Feb 2024 14:26:58 +0100 Subject: [PATCH 5/6] fix conf load on each file processing --- .../common/integrations/file_extra_info.py | 28 +++++++++---------- .../file_extra_info_modules/__init__.py | 5 +--- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/cuckoo/common/integrations/file_extra_info.py b/lib/cuckoo/common/integrations/file_extra_info.py index 3b10b0f7e6c..105fb11ea08 100644 --- a/lib/cuckoo/common/integrations/file_extra_info.py +++ b/lib/cuckoo/common/integrations/file_extra_info.py @@ -59,7 +59,7 @@ DuplicatesType = DefaultDict[str, Set[str]] - +cfg = Config() processing_conf = Config("processing") selfextract_conf = Config("selfextract") @@ -133,7 +133,7 @@ exclude_startswith = ("parti_",) excluded_extensions = (".parti",) - +tools_folder = os.path.join(cfg.cuckoo.get("tmppath", "/tmp"), "cape-external") def static_file_info( data_dictionary: dict, @@ -515,7 +515,7 @@ def generic_file_extractors( def _generic_post_extraction_process(file: str, tool_name: str, decoded: str) -> SuccessfulExtractionReturnType: - with extractor_ctx(file, tool_name) as ctx: + with extractor_ctx(file, tool_name, folder=tools_folder) as ctx: basename = f"{os.path.basename(file)}_decoded" decoded_file_path = os.path.join(ctx["tempdir"], basename) _ = path_write_file(decoded_file_path, decoded, mode="text") @@ -595,7 +595,7 @@ def eziriz_deobfuscate(file: str, *, data_dictionary: dict, **_) -> ExtractorRet log.error("You need to add execution permissions: chmod a+x data/NETReactorSlayer.CLI") return - with extractor_ctx(file, "eziriz", prefix="eziriz_") as ctx: + with extractor_ctx(file, "eziriz", prefix="eziriz_", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] dest_path = os.path.join(tempdir, os.path.basename(file)) _ = run_tool( @@ -628,7 +628,7 @@ def de4dot_deobfuscate(file: str, *, filetype: str, **_) -> ExtractorReturnType: log.error("Missed dependency: sudo apt install de4dot") return - with extractor_ctx(file, "de4dot", prefix="de4dot_") as ctx: + with extractor_ctx(file, "de4dot", prefix="de4dot_", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] dest_path = os.path.join(tempdir, os.path.basename(file)) _ = run_tool( @@ -657,7 +657,7 @@ def msi_extract(file: str, *, filetype: str, **kwargs) -> ExtractorReturnType: extracted_files = [] # sudo apt install msitools or 7z - with extractor_ctx(file, "MsiExtract", prefix="msidump_") as ctx: + with extractor_ctx(file, "MsiExtract", prefix="msidump_", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] output = False if not kwargs.get("tests"): @@ -705,7 +705,7 @@ def Inno_extract(file: str, *, data_dictionary: dict, **_) -> ExtractorReturnTyp log.error("Missed dependency: sudo apt install innoextract") return - with extractor_ctx(file, "InnoExtract", prefix="innoextract_") as ctx: + with extractor_ctx(file, "InnoExtract", prefix="innoextract_", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] run_tool( [selfextract_conf.Inno_extract.binary, file, "--output-dir", tempdir], @@ -731,7 +731,7 @@ def kixtart_extract(file: str, **_) -> ExtractorReturnType: if not data.startswith(b"\x1a\xaf\x06\x00\x00\x10"): return - with extractor_ctx(file, "Kixtart", prefix="kixtart_") as ctx: + with extractor_ctx(file, "Kixtart", prefix="kixtart_", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] kix = Kixtart(file, dump_dir=tempdir) kix.decrypt() @@ -756,7 +756,7 @@ def UnAutoIt_extract(file: str, *, data_dictionary: dict, **_) -> ExtractorRetur UN_AUTOIT_NOTIF = True return - with extractor_ctx(file, "UnAutoIt", prefix="unautoit_") as ctx: + with extractor_ctx(file, "UnAutoIt", prefix="unautoit_", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] output = run_tool( [unautoit_binary, "extract-all", "--output-dir", tempdir, file], @@ -778,7 +778,7 @@ def UPX_unpack(file: str, *, filetype: str, data_dictionary: dict, **_) -> Extra ): return - with extractor_ctx(file, "UnUPX", prefix="unupx_") as ctx: + with extractor_ctx(file, "UnUPX", prefix="unupx_", folder=tools_folder) as ctx: basename = f"{os.path.basename(file)}_unpacked" dest_path = os.path.join(ctx["tempdir"], basename) output = run_tool( @@ -852,7 +852,7 @@ def SevenZip_unpack(file: str, *, filetype: str, data_dictionary: dict, options: else: return - with extractor_ctx(file, tool, prefix=prefix) as ctx: + with extractor_ctx(file, tool, prefix=prefix, folder=tools_folder) as ctx: tempdir = ctx["tempdir"] HAVE_SFLOCK = False if HAVE_SFLOCK: @@ -892,7 +892,7 @@ def RarSFX_extract(file, *, data_dictionary, options: dict, **_) -> ExtractorRet log.warning("Missed UnRar binary: /usr/bin/unrar. sudo apt install unrar") return - with extractor_ctx(file, "UnRarSFX", prefix="unrar_") as ctx: + with extractor_ctx(file, "UnRarSFX", prefix="unrar_", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] password = options.get("password", "infected") output = run_tool( @@ -914,7 +914,7 @@ def office_one(file, **_) -> ExtractorReturnType: ): return - with extractor_ctx(file, "OfficeOne", prefix="office_one") as ctx: + with extractor_ctx(file, "OfficeOne", prefix="office_one", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] try: document = OneNoteExtractor(path_read_file(file)) @@ -937,7 +937,7 @@ def msix_extract(file: str, *, data_dictionary: dict, **_) -> ExtractorReturnTyp ): return - with extractor_ctx(file, "MSIX", prefix="msixdump_") as ctx: + with extractor_ctx(file, "MSIX", prefix="msixdump_", folder=tools_folder) as ctx: tempdir = ctx["tempdir"] _ = run_tool( ["unzip", file, "-d", tempdir], diff --git a/lib/cuckoo/common/integrations/file_extra_info_modules/__init__.py b/lib/cuckoo/common/integrations/file_extra_info_modules/__init__.py index 4fb477ae3d9..fc22fcdf8f4 100644 --- a/lib/cuckoo/common/integrations/file_extra_info_modules/__init__.py +++ b/lib/cuckoo/common/integrations/file_extra_info_modules/__init__.py @@ -8,7 +8,6 @@ import timeit from typing import List, Optional, TypedDict -from lib.cuckoo.common.config import Config from lib.cuckoo.common.path_utils import path_mkdir, path_object log = logging.getLogger(__name__) @@ -48,9 +47,7 @@ def wrapped(*args, **kwargs): @contextlib.contextmanager -def extractor_ctx(filepath, tool_name, prefix=None): - cfg = Config() - folder = os.path.join(cfg.cuckoo.get("tmppath", "/tmp"), "cape-external") +def extractor_ctx(filepath, tool_name, prefix=None, folder="/tmp/cape-external"): path_mkdir(folder, exist_ok=True) tempdir = tempfile.mkdtemp(prefix=prefix, dir=folder) From 3048bf21d71ec59fe62c4ba936670c439ff86802 Mon Sep 17 00:00:00 2001 From: Josh Feather <142008135+josh-feather@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:59:16 +0000 Subject: [PATCH 6/6] Set tools_folder to tmp in test_file_extra_info --- tests/test_file_extra_info.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_file_extra_info.py b/tests/test_file_extra_info.py index 8068687380b..affe09eba15 100644 --- a/tests/test_file_extra_info.py +++ b/tests/test_file_extra_info.py @@ -8,6 +8,11 @@ from lib.cuckoo.common.integrations import file_extra_info +@pytest.fixture(autouse=True) +def set_tools_folder(): + file_extra_info.tools_folder = "/tmp" + yield + self_extraction_dir = (pathlib.Path(__file__).parent / "data" / "selfextraction") @pytest.mark.skipif(