def test_invalid_rule(self): # TODO Cuckoo could help figuring out which Yara rule is the culprit, # but on the other hand, where's the fun in that? with pytest.raises(CuckooStartupError) as e: open(cwd("yara", "binaries", "invld.yar"), "wb").write("rule") init_yara(True) e.match("(unexpected _RULE_|unexpected \\$end)")
def test_basics(): set_cwd(tempfile.mkdtemp()) cuckoo_create() mkdir(cwd(analysis=1)) init_yara() em = ExtractManager(1) em.write_extracted("foo", "bar") filepath = cwd("extracted", "0.foo", analysis=1) assert open(filepath, "rb").read() == "bar" scr = Scripting() cmd = scr.parse_command("powershell -e %s" % "foobar".encode("utf-16le").encode("base64")) em.push_script({ "pid": 1, "first_seen": 2, }, cmd) filepath = cwd("extracted", "0.ps1", analysis=1) assert open(filepath, "rb").read() == "foobar" em.push_command_line("powershell -e %s" % "world!".encode("utf-16le").encode("base64")) filepath = cwd("extracted", "1.ps1", analysis=1) assert open(filepath, "rb").read() == "world!"
def test_invalid_rule(self): # TODO Cuckoo could help figuring out which Yara rule is the culprit, # but on the other hand, where's the fun in that? with pytest.raises(CuckooStartupError) as e: open(cwd("yara", "binaries", "invld.yar"), "wb").write("rule") init_yara() e.match("(unexpected _RULE_|unexpected \\$end)")
def test_yara_no_description(): set_cwd(tempfile.mkdtemp()) cuckoo_create() open(cwd("yara", "binaries", "empty.yara"), "wb").write(""" rule EmptyRule { condition: 1 } rule DescrRule { meta: description = "this is description" condition: 1 } """) init_yara() a, b = File(Files.temp_put("hello")).get_yara() assert a["name"] == "EmptyRule" assert a["meta"] == { "description": "(no description)", } assert b["name"] == "DescrRule" assert b["meta"] == { "description": "this is description", }
def test_basics(): set_cwd(tempfile.mkdtemp()) cuckoo_create() mkdir(cwd(analysis=1)) init_yara() em = ExtractManager(1) em.write_extracted("foo", "bar") filepath = cwd("extracted", "0.foo", analysis=1) assert open(filepath, "rb").read() == "bar" scr = Scripting() cmd = scr.parse_command( "powershell -e %s" % "foobar".encode("utf-16le").encode("base64") ) em.push_script({ "pid": 1, "first_seen": 2, }, cmd) filepath = cwd("extracted", "0.ps1", analysis=1) assert open(filepath, "rb").read() == "foobar" em.push_command_line( "powershell -e %s" % "world!".encode("utf-16le").encode("base64") ) filepath = cwd("extracted", "1.ps1", analysis=1) assert open(filepath, "rb").read() == "world!"
def test_process_json_logging(): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() init_logfile("process-p0.json") def process_tasks(instance, maxcount): logger("foo bar", action="hello.world", status="success") with mock.patch("cuckoo.main.Database"): with mock.patch("cuckoo.main.process_tasks") as p1: with mock.patch("time.time") as p2: p1.side_effect = process_tasks p2.return_value = 1484232003 main.main( ("--cwd", cwd(), "process", "p0"), standalone_mode=False ) assert json.load(open(cwd("log", "process-p0.json"), "rb")) == { "asctime": mock.ANY, "action": "hello.world", "level": "info", "message": "foo bar", "status": "success", "task_id": None, "time": 1484232003, }
def test_process_json_logging(): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() init_logfile("process-p0.json") def process_tasks(instance, maxcount): logger("foo bar", action="hello.world", status="success") with mock.patch("cuckoo.main.Database"): with mock.patch("cuckoo.main.process_tasks") as p1: with mock.patch("time.time") as p2: p1.side_effect = process_tasks p2.return_value = 1484232003 main.main(("--cwd", cwd(), "process", "p0"), standalone_mode=False) assert json.load(open(cwd("log", "process-p0.json"), "rb")) == { "asctime": mock.ANY, "action": "hello.world", "level": "info", "message": "foo bar", "status": "success", "task_id": None, "time": 1484232003, }
def test_yara_offsets(): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() buf = ( # The SSEXY payload as per vmdetect.yar "66 0F 70 ?? ?? 66 0F DB ?? ?? ?? ?? " "?? 66 0F DB ?? ?? ?? ?? ?? 66 0F EF " # A VirtualBox MAC address. "30 38 2d 30 30 2d 32 37") filepath = Files.temp_put( "A" * 64 + buf.replace("??", "00").replace(" ", "").decode("hex")) assert File(filepath).get_yara() == [{ "meta": { "description": "Possibly employs anti-virtualization techniques", "author": "nex" }, "name": "vmdetect", "offsets": { "ssexy": [ (64, 1), ], "virtualbox_mac_1a": [ (88, 0), ], }, "strings": [ "MDgtMDAtMjc=", "Zg9wAABmD9sAAAAAAGYP2wAAAAAAZg/v", ], }]
def test_yara_offsets(): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() buf = ( # The SSEXY payload as per vmdetect.yar "66 0F 70 ?? ?? 66 0F DB ?? ?? ?? ?? " "?? 66 0F DB ?? ?? ?? ?? ?? 66 0F EF " # A VirtualBox MAC address. "30 38 2d 30 30 2d 32 37" ) filepath = Files.temp_put( "A"*64 + buf.replace("??", "00").replace(" ", "").decode("hex") ) assert File(filepath).get_yara() == [{ "meta": { "description": "Possibly employs anti-virtualization techniques", "author": "nex" }, "name": "vmdetect", "offsets": { "ssexy": [ (64, 1), ], "virtualbox_mac_1a": [ (88, 0), ], }, "strings": [ "MDgtMDAtMjc=", "Zg9wAABmD9sAAAAAAGYP2wAAAAAAZg/v", ], }]
def process(ctx, instance, report, maxcount): """Process raw task data into reports.""" init_console_logging(level=ctx.parent.level) if instance: init_logfile("process-%s.json" % instance) Database().connect() # Load additional Signatures. load_signatures() # Initialize all modules & Yara rules. init_modules() init_yara(False) try: # Regenerate one or more reports. if report: process_task_range(report) elif not instance: print ctx.get_help(), "\n" sys.exit("In automated mode an instance name is required!") else: log.info( "Initialized instance=%s, ready to process some tasks", instance ) process_tasks(instance, maxcount) except KeyboardInterrupt: print(red("Aborting (re-)processing of your analyses.."))
def test_symlink(self): if not is_linux(): return # Include all Yara rules from binaries/ into memory/ as well. os.symlink(cwd("yara", "binaries"), cwd("yara", "memory", "bins")) init_yara() assert len(list(File.yara_rules["memory"])) == 5
def test_yara_quick(self): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() buf = ( # The SSEXY payload as per vmdetect.yar "66 0F 70 ?? ?? 66 0F DB ?? ?? ?? ?? " "?? 66 0F DB ?? ?? ?? ?? ?? 66 0F EF ") contents = "A" * 64 + buf.replace("??", "00").replace(" ", "").decode("hex") assert Buffer(contents).get_yara_quick("binaries") == ["vmdetect"]
def test_default(self): # Will change when we start shipping more Yara rules by default. assert self.count(cwd("yara", "binaries")) == 3 assert not self.count(cwd("yara", "urls")) assert not self.count(cwd("yara", "memory")) init_yara() # This counts the amount of rules loaded, not files. assert len(list(File.yara_rules["binaries"])) == 5 assert not list(File.yara_rules["urls"]) assert not list(File.yara_rules["memory"])
def test_yara_quick(self): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() buf = ( # The SSEXY payload as per vmdetect.yar "66 0F 70 ?? ?? 66 0F DB ?? ?? ?? ?? " "?? 66 0F DB ?? ?? ?? ?? ?? 66 0F EF " ) contents = "A"*64 + buf.replace("??", "00").replace(" ", "").decode("hex") assert Buffer(contents).get_yara_quick("binaries") == ["vmdetect"]
def test_extract_scripts(self): set_cwd(self.mkdtemp()) cuckoo_create() init_yara() mkdir(cwd(analysis=1)) ba = BehaviorAnalysis() ba.set_path(cwd(analysis=1)) ba.set_task({ "id": 1, }) es = ExtractScripts(ba) es.handle_event({ "command_line": "cmd.exe /c ping 1.2.3.4", "first_seen": 1, "pid": 1234, }) es.handle_event({ "command_line": ( "powershell.exe -e " "ZQBjAGgAbwAgACIAUgBlAGMAdQByAHMAaQB2AGUAIgA=" ), "first_seen": 2, "pid": 1235, }) assert es.run() is None e = Extracted() e.set_task(Dictionary({ "id": 1, })) out = e.run() assert out == [{ "category": "script", "first_seen": 1, "pid": 1234, "program": "cmd", "raw": cwd("extracted", "0.bat", analysis=1), "yara": [], "info": {}, }, { "category": "script", "first_seen": 2, "pid": 1235, "program": "powershell", "raw": cwd("extracted", "1.ps1", analysis=1), "yara": [], "info": {}, }] assert open(out[0]["raw"], "rb").read() == "ping 1.2.3.4" assert open(out[1]["raw"], "rb").read() == 'echo "Recursive"'
def test_extract_scripts(self): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() mkdir(cwd(analysis=1)) ba = BehaviorAnalysis() ba.set_path(cwd(analysis=1)) ba.set_task({ "id": 1, }) es = ExtractScripts(ba) es.handle_event({ "command_line": "cmd.exe /c ping 1.2.3.4", "first_seen": 1, "pid": 1234, }) es.handle_event({ "command_line": ( "powershell.exe -e " "ZQBjAGgAbwAgACIAUgBlAGMAdQByAHMAaQB2AGUAIgA=" ), "first_seen": 2, "pid": 1235, }) assert es.run() is None e = Extracted() e.set_task(Dictionary({ "id": 1, })) out = e.run() assert out == [{ "category": "script", "first_seen": 1, "pid": 1234, "program": "cmd", "raw": cwd("extracted", "0.bat", analysis=1), "yara": [], "info": {}, }, { "category": "script", "first_seen": 2, "pid": 1235, "program": "powershell", "raw": cwd("extracted", "1.ps1", analysis=1), "yara": [], "info": {}, }] assert open(out[0]["raw"], "rb").read() == "ping 1.2.3.4" assert open(out[1]["raw"], "rb").read() == 'echo "Recursive"'
def process(ctx, instance, report, maxcount): """Process raw task data into reports.""" init_console_logging(level=ctx.parent.level) if instance: pidfile = Pidfile(instance) if pidfile.exists(): log.error(red( "Cuckoo process instance '%s' already exists. PID: %s\n" ), instance, pidfile.pid) sys.exit(1) pidfile.create() init_logfile("process-%s.json" % instance) Database().connect() # Load additional Signatures. load_signatures() try: # Initialize all modules & Yara rules. init_modules() init_yara() 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) try: # Regenerate one or more reports. if report: process_task_range(report) elif not instance: print ctx.get_help(), "\n" sys.exit("In automated mode an instance name is required!") else: log.info( "Initialized instance=%s, ready to process some tasks", instance ) process_tasks(instance, maxcount) except KeyboardInterrupt: print(red("Aborting (re-)processing of your analyses..")) if instance: Pidfile(instance).remove()
def test_ident_shellcode(): set_cwd(tempfile.mkdtemp()) cuckoo_create() mkdir(cwd("yara", "scripts")) open(cwd("yara", "scripts", "1.yar"), "wb").write(""" rule Shellcode1 { strings: $Shellcode = /=\s*((0x)?[0-9A-F]{2}\s*[,;]\s*)+/ nocase condition: all of them } """) init_yara() class Shellcode1(Extractor): yara_rules = "Shellcode1" def handle_yara(self, filepath, match): sc = match.string("Shellcode", 0) self.push_shellcode( "".join(chr(int(x, 16)) for x in sc[2:-1].split(",")) ) ExtractManager.init_once() sc = shikata(open("tests/files/shellcode/shikata/1.bin", "rb").read()) sc = ",".join("0x%02x" % ord(ch) for ch in sc) scr = Scripting() ps1 = ("[Byte[]]$s = %s;" % sc).encode("utf-16le") cmd = scr.parse_command( "powershell -e %s" % ps1.encode("base64").replace("\n", "") ) mkdir(cwd(analysis=1)) em = ExtractManager(1) em.push_script({ "pid": 1, "first_seen": 2, }, cmd) assert len(em.items) == 2 filepath = cwd("extracted", "0.ps1", analysis=1) assert open(filepath, "rb").read().startswith("[Byte[]]$s = 0xfc") buf = open(cwd("extracted", "1.bin.txt", analysis=1), "rb").read() assert "call 0x88" in buf assert "0x00c1: push 0xc69f8957" in buf assert ".db 'www.service.chrome-up.date',0" in buf
def test_default(self): # Will change when we start shipping more Yara rules by default. assert self.count(cwd("yara", "binaries")) == 3 assert not self.count(cwd("yara", "urls")) assert not self.count(cwd("yara", "memory")) init_yara(True) assert os.path.exists(cwd("yara", "index_binaries.yar")) assert os.path.exists(cwd("yara", "index_urls.yar")) assert os.path.exists(cwd("yara", "index_memory.yar")) buf = open(cwd("yara", "index_binaries.yar"), "rb").read().split("\n") assert 'include "%s"' % cwd("yara", "binaries", "embedded.yar") in buf
def init(package, *filename): id_ = task_id() init_analysis(id_, package, *filename) init_yara() s = Static() s.set_task({ "id": id_, "category": "file", "package": package, "target": filename[-1], }) s.file_path = cwd("binary", analysis=id_) e = ExtractManager.for_task(id_) return s.run(), e.results()
def test_ident_shellcode(): set_cwd(tempfile.mkdtemp()) cuckoo_create() mkdir(cwd("yara", "scripts")) open(cwd("yara", "scripts", "1.yar"), "wb").write(""" rule Shellcode1 { strings: $Shellcode = /=\s*((0x)?[0-9A-F]{2}\s*[,;]\s*)+/ nocase condition: all of them } """) init_yara() class Shellcode1(Extractor): yara_rules = "Shellcode1" def handle_yara(self, filepath, match): sc = match.string("Shellcode", 0) self.push_shellcode("".join( chr(int(x, 16)) for x in sc[2:-1].split(","))) ExtractManager.init_once() sc = shikata(open("tests/files/shellcode/shikata/1.bin", "rb").read()) sc = ",".join("0x%02x" % ord(ch) for ch in sc) scr = Scripting() ps1 = ("[Byte[]]$s = %s;" % sc).encode("utf-16le") cmd = scr.parse_command("powershell -e %s" % ps1.encode("base64").replace("\n", "")) mkdir(cwd(analysis=1)) em = ExtractManager(1) em.push_script({ "pid": 1, "first_seen": 2, }, cmd) assert len(em.items) == 2 filepath = cwd("extracted", "0.ps1", analysis=1) assert open(filepath, "rb").read().startswith("[Byte[]]$s = 0xfc") buf = open(cwd("extracted", "1.bin.txt", analysis=1), "rb").read() assert "call 0x88" in buf assert "0x00c1: push 0xc69f8957" in buf assert ".db 'www.service.chrome-up.date',0" in buf
def test_static_extracted(self): set_cwd(self.mkdtemp()) cuckoo_create(cfg={ "processing": { "analysisinfo": { "enabled": False, }, "debug": { "enabled": False, } }, }) mkdir(cwd(analysis=1)) shutil.copy("tests/files/createproc1.docm", cwd("binary", analysis=1)) open(cwd("yara", "office", "ole.yar"), "wb").write(""" rule OleInside { strings: $s1 = "Win32_Process" condition: filename matches /word\/vbaProject.bin/ and $s1 } """) init_yara() class OleInsideExtractor(Extractor): def handle_yara(self, filepath, match): return ( match.category == "office" and match.yara[0].name == "OleInside" ) class X(object): @staticmethod def p(): return [Extracted, Static] with mock.patch("cuckoo.processing.plugins", new_callable=X.p) as p: ExtractManager._instances = {} ExtractManager.extractors = OleInsideExtractor, results = RunProcessing(Dictionary({ "id": 1, "category": "file", "target": "tests/files/createproc1.docm", })).run() assert len(results["extracted"]) == 1
def test_office(self): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() s = Static() s.set_task({ "id": 1, "category": "file", "package": "doc", "target": "createproc1.docm", }) s.file_path = "tests/files/createproc1.docm" r = s.run()["office"] assert "ThisDocument" in r["macros"][0]["orig_code"] assert "Sub AutoOpen" in r["macros"][1]["orig_code"] assert 'process.Create("notepad.exe"' in r["macros"][1]["orig_code"]
def test_unreferenced_variable(self): # TODO This is probably a bit too harsh. Is it possible to suppress # such errors? Would the "error_on_warning" flag help here (we used # this flag in the past, btw)? Answer to the last question: probably # not provided it raises a SyntaxError rather than a WarningError (?). with pytest.raises(CuckooStartupError) as e: open(cwd("yara", "binaries", "invld.yar"), "wb").write(""" rule a { strings: $s1 = "foo" $s2 = "bar" condition: $s1 } """) init_yara(True) e.match("unreferenced string")
def test_stuff(self): open(cwd("yara", "memory", "hello.yara"), "wb").write(""" rule A { condition: 1 } """) init_yara() # $CWD/stuff/index_memory.yar assert os.path.exists(cwd("stuff", "index_memory.yar")) buf = open(cwd("stuff", "index_memory.yar"), "rb").read() assert 'include "%s"' % cwd("yara", "memory", "hello.yara") in buf # $CWD/stuff/dumpmem.yarac assert os.path.exists(cwd("stuff", "dumpmem.yarac")) assert os.path.getsize(cwd("stuff", "dumpmem.yarac")) > 2048
def test_office(self): set_cwd(self.mkdtemp()) cuckoo_create() init_yara() s = Static() s.set_task({ "id": 1, "category": "file", "package": "doc", "target": "createproc1.docm", }) s.file_path = "tests/files/createproc1.docm" r = s.run()["office"] assert "ThisDocument" in r["macros"][0]["orig_code"] assert "Sub AutoOpen" in r["macros"][1]["orig_code"] assert 'process.Create("notepad.exe"' in r["macros"][1]["orig_code"]
def test_unreferenced_variable(self): # TODO This is probably a bit too harsh. Is it possible to suppress # such errors? Would the "error_on_warning" flag help here (we used # this flag in the past, btw)? Answer to the last question: probably # not provided it raises a SyntaxError rather than a WarningError (?). with pytest.raises(CuckooStartupError) as e: open(cwd("yara", "binaries", "invld.yar"), "wb").write(""" rule a { strings: $s1 = "foo" $s2 = "bar" condition: $s1 } """) init_yara() e.match("unreferenced string")
def cuckoo_init(level, ctx, cfg=None): """Initialize Cuckoo configuration. @param quiet: enable quiet mode. """ logo() # It would appear this is the first time Cuckoo is being run (on this # Cuckoo Working Directory anyway). if not os.path.isdir(cwd()) or not os.listdir(cwd()): cuckoo_create(ctx.user, cfg) sys.exit(0) # Determine if this is a proper CWD. if not os.path.exists(cwd(".cwd")): sys.exit( "No proper Cuckoo Working Directory was identified, did you pass " "along the correct directory?" ) init_console_logging(level) check_configs() check_version() ctx.log and init_logging(level) # Determine if any CWD updates are required and if so, do them. current = open(cwd(".cwd"), "rb").read().strip() latest = open(cwd(".cwd", private=True), "rb").read().strip() if current != latest: migrate_cwd() open(cwd(".cwd"), "wb").write(latest) Database().connect() # Load additional Signatures. load_signatures() init_modules() init_tasks() init_yara(True) init_binaries() init_rooter() init_routing()
def cuckoo_init(level, ctx, cfg=None): """Initialize Cuckoo configuration. @param quiet: enable quiet mode. """ logo() # It would appear this is the first time Cuckoo is being run (on this # Cuckoo Working Directory anyway). if not os.path.isdir(cwd()) or not os.listdir(cwd()): cuckoo_create(ctx.user, cfg) sys.exit(0) # Determine if this is a proper CWD. if not os.path.exists(cwd(".cwd")): sys.exit( "No proper Cuckoo Working Directory was identified, did you pass " "along the correct directory?" ) # Determine if any CWD updates are required. current = open(cwd(".cwd"), "rb").read() latest = open(cwd(".cwd", private=True), "rb").read() if current != latest: pass check_configs() check_version() if ctx.log: init_logging(level) else: init_console_logging(level) Database().connect() # Load additional Signatures. load_signatures() init_modules() init_tasks() init_yara(True) init_binaries() init_rooter() init_routing()
def test_yara_externals(): set_cwd(tempfile.mkdtemp()) cuckoo_create() open(cwd("yara", "office", "external.yara"), "wb").write(""" rule ExternalRule { condition: filename matches /document.xml/ } """) init_yara() assert not File(Files.temp_put("")).get_yara("office") assert not File(Files.temp_put("hello")).get_yara("office", { "filename": "hello.jpg", }) a, = File(Files.temp_put("hello")).get_yara("office", { "filename": "document.xml", }) assert a["name"] == "ExternalRule"
def test_targetinfo(self): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() ti = TargetInfo() ti.file_path = __file__ ti.set_task({ "category": "file", "target": __file__, }) obj = ti.run() assert obj["category"] == "file" assert os.path.basename(obj["file"]["name"]) == "test_processing.py" ti = TargetInfo() ti.file_path = "tests/files/pdf0.zip" ti.set_task({ "category": "archive", "target": "tests/files/pdf0.zip", "options": { "filename": "files/pdf0.pdf", }, }) obj = ti.run() assert obj["category"] == "archive" assert os.path.basename(obj["archive"]["name"]) == "pdf0.zip" assert obj["filename"] == "files/pdf0.pdf" assert obj["human"] == "files/pdf0.pdf @ pdf0.zip" assert obj["file"]["name"] == "pdf0.pdf" assert obj["file"]["size"] == 680 ti = TargetInfo() ti.file_path = __file__ ti.set_task({ "category": "url", "target": "http://google.com", }) assert ti.run() == { "category": "url", "url": "http://google.com", }
def test_static_extracted(): set_cwd(tempfile.mkdtemp()) cuckoo_create(cfg={ "processing": { "analysisinfo": { "enabled": False, }, "debug": { "enabled": False, } }, }) mkdir(cwd(analysis=1)) shutil.copy("tests/files/createproc1.docm", cwd("binary", analysis=1)) open(cwd("yara", "office", "ole.yar"), "wb").write(""" rule OleInside { strings: $s1 = "Win32_Process" condition: filename matches /word\/vbaProject.bin/ and $s1 } """) init_yara() class OleInsideExtractor(Extractor): def handle_yara(self, filepath, match): return ( match.category == "office" and match.yara[0].name == "OleInside" ) ExtractManager._instances = {} ExtractManager.extractors = OleInsideExtractor, results = RunProcessing(Dictionary({ "id": 1, "category": "file", "target": "tests/files/createproc1.docm", })).run() assert len(results["extracted"]) == 1
def test_push_script_recursive(): set_cwd(tempfile.mkdtemp()) cuckoo_create() mkdir(cwd(analysis=1)) open(cwd("yara", "office", "ole.yar"), "wb").write(""" rule OleInside { strings: $s1 = "Win32_Process" condition: filename matches /word\/vbaProject.bin/ and $s1 } """) init_yara() s = Static() s.file_path = "tests/files/createproc1.docm" s.set_task({ "id": 1, "category": "file", "target": s.file_path, "package": "doc", }) s.run() assert ExtractManager.for_task(1).results()[0]["yara"] == [{ "name": "OleInside", "meta": { "description": "(no description)", }, "offsets": { "s1": [ (3933, 0), ], }, "strings": [ "Win32_Process".encode("base64").strip(), ], }]
def test_no_init_yara(p): init_yara(None) p.warning.assert_called_once()
def test_noinit(self): # This happens in case "cuckoo process" is invoked without having run # the Cuckoo daemon (i.e., without having generated the index rules). with pytest.raises(CuckooStartupError) as e: init_yara(False) e.match("before being able to run")
def cuckoo_init(level, ctx, cfg=None): """Initialize Cuckoo configuration. @param quiet: enable quiet mode. """ logo() # It would appear this is the first time Cuckoo is being run (on this # Cuckoo Working Directory anyway). if not os.path.isdir(cwd()) or not os.listdir(cwd()): cuckoo_create(ctx.user, cfg) sys.exit(0) # Determine if this is a proper CWD. if not os.path.exists(cwd(".cwd")): sys.exit( "No proper Cuckoo Working Directory was identified, did you pass " "along the correct directory? For new installations please use a " "non-existant directory to build up the CWD! You can craft a CWD " "manually, but keep in mind that the CWD layout may change along " "with Cuckoo releases (and don't forget to fill out '$CWD/.cwd')!" ) init_console_logging(level) # Only one Cuckoo process should exist per CWD. Run this check before any # files are possibly modified. Note that we mkdir $CWD/pidfiles/ here as # its CWD migration rules only kick in after the pidfile check. mkdir(cwd("pidfiles")) pidfile = Pidfile("cuckoo") if pidfile.exists(): log.error(red("Cuckoo is already running. PID: %s"), pidfile.pid) sys.exit(1) pidfile.create() check_configs() check_version() ctx.log and init_logging(level) # Determine if any CWD updates are required and if so, do them. current = open(cwd(".cwd"), "rb").read().strip() latest = open(cwd(".cwd", private=True), "rb").read().strip() if current != latest: migrate_cwd() open(cwd(".cwd"), "wb").write(latest) Database().connect() # Load additional Signatures. load_signatures() init_modules() init_tasks() init_yara() init_binaries() init_rooter() init_routing() signatures = 0 for sig in cuckoo.signatures: if not sig.enabled: continue signatures += 1 if not signatures: log.warning( "It appears that you haven't loaded any Cuckoo Signatures. " "Signatures are highly recommended and improve & enrich the " "information extracted during an analysis. They also make up " "for the analysis score that you see in the Web Interface - so, " "pretty important!" ) log.warning( "You'll be able to fetch all the latest Cuckoo Signaturs, Yara " "rules, and more goodies by running the following command:" ) raw = cwd(raw=True) if raw == "." or raw == "~/.cuckoo": command = "cuckoo community" elif " " in raw or "'" in raw: command = 'cuckoo --cwd "%s" community' % raw else: command = "cuckoo --cwd %s community" % raw log.info("$ %s", green(command))
def setup(self): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara()
def test_missing_category(self): File.yara_rules = {} shutil.rmtree(cwd("yara", "binaries")) init_yara() assert len(File.yara_rules) == 7 assert not list(File.yara_rules["binaries"])
def test_stap_log(self): set_cwd(tempfile.mkdtemp()) cuckoo_create() init_yara() mkdir(cwd(analysis=1)) mkdir(cwd("logs", analysis=1)) shutil.copy( "tests/files/log_full.stap", cwd("logs", "all.stap", analysis=1) ) ba = BehaviorAnalysis() ba.set_path(cwd(analysis=1)) ba.set_task({ "id": 1, }) assert ba.run() == { "generic": [{ "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 618541), "pid": 820, "ppid": 819, "process_name": "sh", "process_path": None, "summary": {}, }, { "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 619135), "pid": 821, "ppid": 820, "process_name": "bash", "process_path": None, "summary": {}, }, { "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 646318), "pid": 822, "ppid": 821, "process_name": "ls", "process_path": None, "summary": {}, }], "processes": [{ "calls": [], "command_line": "/bin/sh /tmp/execve.sh", "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 618541), "pid": 820, "ppid": 819, "process_name": "sh", "type": "process" }, { "calls": [], "command_line": ( "/bin/bash -c python -c 'import subprocess; " "subprocess.call([\"/bin/ls\", \"/hax\"])'" ), "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 619135), "pid": 821, "ppid": 820, "process_name": "bash", "type": "process" }, { "calls": [], "command_line": "/bin/ls /hax", "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 646318), "pid": 822, "ppid": 821, "process_name": "ls", "type": "process" }], "processtree": [{ "children": [{ "children": [{ "children": [], "command_line": "/bin/ls /hax", "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 646318), "pid": 822, "ppid": 821, "process_name": "ls", "track": True }], "command_line": ( "/bin/bash -c python -c 'import subprocess; " "subprocess.call([\"/bin/ls\", \"/hax\"])'" ), "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 619135), "pid": 821, "ppid": 820, "process_name": "bash", "track": True }], "command_line": "/bin/sh /tmp/execve.sh", "first_seen": datetime.datetime(2017, 8, 28, 14, 29, 32, 618541), "pid": 820, "ppid": 819, "process_name": "sh", "track": True }], }
def test_on_yara(): set_cwd(os.path.realpath(tempfile.mkdtemp())) cuckoo_create() init_modules() shutil.copy( cwd("yara", "binaries", "vmdetect.yar"), cwd("yara", "memory", "vmdetect.yar") ) init_yara() mkdir(cwd(analysis=1)) open(cwd("binary", analysis=1), "wb").write("\x0f\x3f\x07\x0b") mkdir(cwd("files", analysis=1)) open(cwd("files", "1.txt", analysis=1), "wb").write("\x56\x4d\x58\x68") mkdir(cwd("memory", analysis=1)) open(cwd("memory", "1-0.dmp", analysis=1), "wb").write( struct.pack("QIIII", 0x400000, 0x1000, 0, 0, 0) + "\x45\xc7\x00\x01" ) Database().connect() results = RunProcessing(task=Dictionary({ "id": 1, "category": "file", "target": __file__, })).run() assert results["target"]["file"]["yara"][0]["offsets"] == { "virtualpc": [(0, 0)], } assert results["procmemory"][0]["yara"][0]["offsets"] == { "vmcheckdll": [(24, 0)], } assert results["dropped"][0]["yara"][0]["offsets"] == { "vmware": [(0, 0)], "vmware1": [(0, 0)], } class sig1(object): name = "sig1" @property def matched(self): return False @matched.setter def matched(self, value): pass def init(self): pass def on_signature(self): pass def on_complete(self): pass def on_extract(self): pass on_yara = mock.MagicMock() rs = RunSignatures(results) rs.signatures = sig1(), rs.run() assert sig1.on_yara.call_count == 3 sig1.on_yara.assert_any_call( "sample", cwd("binary", analysis=1), mock.ANY ) sig1.on_yara.assert_any_call( "dropped", cwd("files", "1.txt", analysis=1), mock.ANY ) sig1.on_yara.assert_any_call( "procmem", cwd("memory", "1-0.dmp", analysis=1), mock.ANY ) ym = sig1.on_yara.call_args_list[0][0][2] assert ym.offsets == { "virtualpc": [(0, 0)], } assert ym.string("virtualpc", 0) == "\x0f\x3f\x07\x0b"
def cuckoo_init(level, ctx, cfg=None): """Initialize Cuckoo configuration. @param quiet: enable quiet mode. """ logo() # It would appear this is the first time Cuckoo is being run (on this # Cuckoo Working Directory anyway). if not os.path.isdir(cwd()) or not os.listdir(cwd()): cuckoo_create(ctx.user, cfg) sys.exit(0) # Determine if this is a proper CWD. if not os.path.exists(cwd(".cwd")): sys.exit( "No proper Cuckoo Working Directory was identified, did you pass " "along the correct directory? For new installations please use a " "non-existant directory to build up the CWD! You can craft a CWD " "manually, but keep in mind that the CWD layout may change along " "with Cuckoo releases (and don't forget to fill out '$CWD/.cwd')!" ) init_console_logging(level) check_configs() check_version() ctx.log and init_logging(level) # Determine if any CWD updates are required and if so, do them. current = open(cwd(".cwd"), "rb").read().strip() latest = open(cwd(".cwd", private=True), "rb").read().strip() if current != latest: migrate_cwd() open(cwd(".cwd"), "wb").write(latest) Database().connect() # Load additional Signatures. load_signatures() init_modules() init_tasks() init_yara() init_binaries() init_rooter() init_routing() signatures = 0 for sig in cuckoo.signatures: if not sig.enabled: continue signatures += 1 if not signatures: log.warning( "It appears that you haven't loaded any Cuckoo Signatures. " "Signatures are highly recommended and improve & enrich the " "information extracted during an analysis. They also make up " "for the analysis score that you see in the Web Interface - so, " "pretty important!" ) log.warning( "You'll be able to fetch all the latest Cuckoo Signaturs, Yara " "rules, and more goodies by running the following command:" ) raw = cwd(raw=True) if raw == "." or raw == "~/.cuckoo": command = "cuckoo community" elif " " in raw or "'" in raw: command = 'cuckoo --cwd "%s" community' % raw else: command = "cuckoo --cwd %s community" % raw log.info("$ %s", green(command))
def test_missing_category(self): File.yara_rules = {} shutil.rmtree(cwd("yara", "binaries")) init_yara() assert len(File.yara_rules) == 6 assert not list(File.yara_rules["binaries"])
def cuckoo_init(level, ctx, cfg=None): """Initialize Cuckoo configuration. @param quiet: enable quiet mode. """ logo() # It would appear this is the first time Cuckoo is being run (on this # Cuckoo Working Directory anyway). if not os.path.isdir(cwd()) or not os.listdir(cwd()): cuckoo_create(ctx.user, cfg) sys.exit(0) # Determine if this is a proper CWD. if not os.path.exists(cwd(".cwd")): sys.exit( "No proper Cuckoo Working Directory was identified, did you pass " "along the correct directory? For new installations please use a " "non-existant directory to build up the CWD! You can craft a CWD " "manually, but keep in mind that the CWD layout may change along " "with Cuckoo releases (and don't forget to fill out '$CWD/.cwd')!") init_console_logging(level) # Only one Cuckoo process should exist per CWD. Run this check before any # files are possibly modified. Note that we mkdir $CWD/pidfiles/ here as # its CWD migration rules only kick in after the pidfile check. mkdir(cwd("pidfiles")) pidfile = Pidfile("cuckoo") if pidfile.exists(): log.error(red("Cuckoo is already running. PID: %s"), pidfile.pid) sys.exit(1) pidfile.create() check_configs() check_version() ctx.log and init_logging(level) # Determine if any CWD updates are required and if so, do them. current = open(cwd(".cwd"), "rb").read().strip() latest = open(cwd(".cwd", private=True), "rb").read().strip() if current != latest: migrate_cwd() open(cwd(".cwd"), "wb").write(latest) # Ensure the user is able to create and read temporary files. if not ensure_tmpdir(): sys.exit(1) Database().connect() # Load additional Signatures. load_signatures() init_modules() init_tasks() init_yara() init_binaries() init_rooter() init_routing() signatures = 0 for sig in cuckoo.signatures: if not sig.enabled: continue signatures += 1 if not signatures: log.warning( "It appears that you haven't loaded any Cuckoo Signatures. " "Signatures are highly recommended and improve & enrich the " "information extracted during an analysis. They also make up " "for the analysis score that you see in the Web Interface - so, " "pretty important!") log.warning( "You'll be able to fetch all the latest Cuckoo Signaturs, Yara " "rules, and more goodies by running the following command:") log.info("$ %s", green(format_command("community")))
def test_unicode(self): set_cwd(tempfile.mkdtemp(u"\u202e")) cuckoo_create() init_yara() assert len(list(File.yara_rules["binaries"])) == 5