Files
cuckoo/tests/test_objects.py
Jurriaan Bremer df0c6da1ca allow submission of files pointed to by symbolic links
In the future this will be improved by copying over the file upon
submission, however, for now this will do just fine.
2018-02-07 16:51:42 +01:00

327 lines
9.6 KiB
Python

# Copyright (C) 2012-2013 Claudio Guarnieri.
# Copyright (C) 2014-2018 Cuckoo Foundation.
# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
# See the file 'docs/LICENSE' for copying permission.
import os
import pytest
import re
import tempfile
from cuckoo.common.files import Files
from cuckoo.common.objects import (
Dictionary, File, Archive, Buffer, YaraMatch, URL_REGEX
)
from cuckoo.core.startup import init_yara
from cuckoo.main import cuckoo_create
from cuckoo.misc import set_cwd, cwd
from cuckoo.processing.static import PortableExecutable
class TestDictionary(object):
def setup_method(self, method):
self.d = Dictionary()
def test_usage(self):
self.d.a = "foo"
assert "foo" == self.d.a
self.d.a = "bar"
assert "bar" == self.d.a
def test_exception(self):
with pytest.raises(AttributeError):
self.d.b.a
class TestFile(object):
def setup(self):
# File() will invoke cwd(), so any CWD is required.
set_cwd(tempfile.mkdtemp())
self.path = tempfile.mkstemp()[1]
self.file = File(self.path)
def test_get_name(self):
assert self.path.split(os.sep)[-1] == self.file.get_name()
def test_get_data(self):
assert "" == self.file.get_data()
def test_get_size(self):
assert 0 == self.file.get_size()
def test_get_crc32(self):
assert "00000000" == self.file.get_crc32()
def test_get_md5(self):
assert "d41d8cd98f00b204e9800998ecf8427e" == self.file.get_md5()
def test_get_sha1(self):
assert "da39a3ee5e6b4b0d3255bfef95601890afd80709" == self.file.get_sha1()
def test_get_sha256(self):
assert "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" == self.file.get_sha256()
def test_get_sha512(self):
assert "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" == self.file.get_sha512()
def test_get_ssdeep(self):
try:
import pydeep
assert self.file.get_ssdeep() is not None
pydeep # Fake usage.
except ImportError:
assert self.file.get_ssdeep() is None
def test_get_type(self):
assert "empty" in self.file.get_type()
def test_get_content_type(self):
assert self.file.get_content_type() in ["inode/x-empty", "application/x-empty"]
def test_get_all_type(self):
assert isinstance(self.file.get_all(), dict)
def test_get_all_keys(self):
for key in ["name", "size", "crc32", "md5", "sha1", "sha256", "sha512", "ssdeep", "type"]:
assert key in self.file.get_all()
class TestMagic(object):
def test_magic1(self):
f = File("tests/files/foo.txt")
assert "ASCII text" in f.get_type()
assert f.get_content_type() == "text/plain"
def test_magic2(self):
pe = PortableExecutable(None)
assert "ASCII text" in pe._get_filetype("hello world")
def test_magic3(self):
assert File(__file__).get_type().startswith((
"Python script", "ASCII ",
))
assert File(__file__).get_content_type() in (
"text/x-python", "text/plain",
)
@pytest.mark.skipif("sys.platform != 'linux2'")
def test_symlink_magic(self):
filepath = tempfile.mktemp()
os.symlink(__file__, filepath)
assert File(filepath).get_type().startswith("Python script")
assert File(filepath).get_content_type() == "text/x-python"
def test_regex():
r = re.findall(URL_REGEX, "foo http://google.com/search bar")
assert len(r) == 1
assert "".join(r[0]) == "http://google.com/search"
@pytest.mark.skipif("sys.platform != 'linux2'")
def test_m2crypto():
pe = PortableExecutable("tests/files/icardres.dll")
sig0 = pe.run()["signature"][0]
assert sig0["organization"] == "Microsoft Corporation"
assert sig0["sha1"] == "9e95c625d81b2ba9c72fd70275c3699613af61e3"
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_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_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_get_urls():
filepath = Files.temp_put("""
http://google.com
google.com/foobar
thisisnotadomain
https://1.2.3.4:9001/hello
""")
assert sorted(File(filepath).get_urls()) == [
# TODO Why does this not work properly at my own machine?
"http://google.com",
"https://1.2.3.4:9001/hello",
]
class TestArchive(object):
def test_get_file(self):
a = Archive("tests/files/pdf0.zip")
assert a.get_file("files/pdf0.pdf").get_size() == 680
def test_not_temporary_file(self):
f = File("tests/files/pdf0.pdf")
assert os.path.exists("tests/files/pdf0.pdf")
del f
assert os.path.exists("tests/files/pdf0.pdf")
def test_temporary_file(self):
a = Archive("tests/files/pdf0.zip")
f = a.get_file("files/pdf0.pdf")
filepath = f.file_path
assert f.get_size() == 680
assert os.path.exists(filepath)
del f
assert not os.path.exists(filepath)
class TestBuffer(object):
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"]
class TestPubPrivKeys(object):
def test_no_keys(self):
assert File("tests/files/pdf0.pdf").get_keys() == []
def test_pub_key(self):
buf = open("tests/files/pdf0.pdf", "rb").read()
filepath = Files.temp_put((
buf +
"-----BEGIN PUBLIC KEY-----\n"
"HELLOWORLD\n"
"-----END PUBLIC KEY-----" +
buf
))
assert File(filepath).get_keys() == [
"-----BEGIN PUBLIC KEY-----\n"
"HELLOWORLD\n"
"-----END PUBLIC KEY-----"
]
def test_private_key(self):
buf = open("tests/files/pdf0.pdf", "rb").read()
filepath = Files.temp_put((
buf +
"-----BEGIN RSA PRIVATE KEY-----\n"
"HELLOWORLD\n"
"-----END RSA PRIVATE KEY-----" +
buf
))
assert File(filepath).get_keys() == [
"-----BEGIN RSA PRIVATE KEY-----\n"
"HELLOWORLD\n"
"-----END RSA PRIVATE KEY-----"
]
class TestYaraMatch(object):
def test_basics(self):
ym = YaraMatch({
"name": "foo",
"meta": {},
"offsets": {
"a": [
(1, 0),
],
},
"strings": [
"bar".encode("base64"),
],
})
assert ym.string("a", 0) == "bar"
assert ym.string("a") == "bar"
def test_multiple(self):
ym = YaraMatch({
"name": "foo",
"meta": {},
"offsets": {
"a": [
(1, 0),
(2, 2),
],
"b": [
(3, 1),
],
},
"strings": [
"bar".encode("base64"),
"baz".encode("base64"),
"foo".encode("base64"),
],
})
assert ym.string("a", 0) == "bar"
assert ym.string("a", 1) == "foo"
assert ym.string("b", 0) == "baz"
assert ym.strings("a") == ["bar", "foo"]
assert ym.strings("b") == ["baz"]