Skip to content

Commit

Permalink
Merge pull request #248 from ryanohoro/scan_png_eof_upload
Browse files Browse the repository at this point in the history
Scan png eof upload to coordinator
  • Loading branch information
phutelmyer authored Dec 20, 2022
2 parents 4b8362f + de0b9a3 commit 9d8dbde
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/python/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ rarfile==4.0
redis==3.5.3
requests==2.25.1
rpmfile==1.0.8
signify==0.3.0
signify==0.4.0
speakeasy-emulator==1.5.2
ssdeep==3.4
tldextract==3.1.0
Expand Down
43 changes: 28 additions & 15 deletions src/python/strelka/scanners/scan_png_eof.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
from strelka import strelka

class ScanPngEof(strelka.Scanner):
""" Extract data embended in PNG files.

class ScanPngEof(strelka.Scanner):
"""Extract data embeded in PNG files.
This scanner extracts data that is inserted past the PNG file end
"""

def scan(self, data, file, options, expire_at):
datalen = len(data)
if (data[datalen - 1] == b'\x82') and (data[datalen - 2] == b'\x60') and (data[len(data) - 3] == b'\x42'):
if (
(data[datalen - 1] == b"\x82")
and (data[datalen - 2] == b"\x60")
and (data[len(data) - 3] == b"\x42")
):
# file DOES NOT have data after EOF, found end of file
self.flags.append('no_trailer')
else: # the file DOES have data after EOF, did not find end of file
trailer_index = data.rfind(b'\x42\x60\x82')
if trailer_index == -1 :
self.event['end_index'] = -1 # didn't find the offical ending of the file
self.flags.append("no_trailer")
else: # the file DOES have data after EOF, did not find end of file
trailer_index = data.rfind(b"\x42\x60\x82")
if trailer_index == -1:
self.event[
"end_index"
] = -1 # didn't find the offical ending of the file
else:
trailer_index = trailer_index + 3
self.event['trailer_index'] = trailer_index
self.event["trailer_index"] = trailer_index

extract_file = strelka.File(source=self.name)
self.event["PNG_EOF"] = data[trailer_index:]

extract_file = strelka.File (
source = self.name
)
self.event['PNG_EOF'] = data[trailer_index:]
for c in strelka.chunk_string(data[trailer_index:]):
self.upload_to_coordinator(
extract_file.pointer,
c,
expire_at,
)

self.files.append(extract_file)
self.files.append(extract_file)
Binary file added src/python/strelka/tests/fixtures/test.exe
Binary file not shown.
Binary file added src/python/strelka/tests/fixtures/test.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions src/python/strelka/tests/test_scan_jpeg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import datetime
from pathlib import Path
from unittest import TestCase, mock

from strelka.scanners.scan_jpeg import ScanJpeg


def test_scan_jpeg(mocker):
"""
This tests the ScanJpeg scanner.
It attempts to validate several given JPEG metadata values.
Pass: Sample event matches output of ScanJpeg.
Failure: Unable to load file or sample event fails to match.
"""

test_scan_jpeg_event = {"elapsed": mock.ANY, "flags": []}

scanner = ScanJpeg(
{"name": "ScanJpeg", "key": "scan_jpeg", "limits": {"scanner": 10}},
"test_coordinate",
)

mocker.patch.object(ScanJpeg, "upload_to_coordinator", return_value=None)
scanner.scan_wrapper(
Path(Path(__file__).parent / "fixtures/test.jpg").read_bytes(),
{"uid": "12345", "name": "somename"},
{"scanner_timeout": 5},
datetime.date.today(),
)

TestCase.maxDiff = None
TestCase().assertDictEqual(test_scan_jpeg_event, scanner.event)


def test_scan_jpeg_pe_overlay(mocker):
"""
This tests the ScanJpeg scanner.
It attempts to validate several given JPEG metadata values.
Pass: Sample event matches output of ScanJpeg.
Failure: Unable to load file or sample event fails to match.
"""

test_scan_jpeg_event = {"elapsed": mock.ANY, "flags": [], "trailer_index": 308564}

scanner = ScanJpeg(
{"name": "ScanJpeg", "key": "scan_jpeg", "limits": {"scanner": 10}},
"test_coordinate",
)

mocker.patch.object(ScanJpeg, "upload_to_coordinator", return_value=None)
scanner.scan_wrapper(
Path(Path(__file__).parent / "fixtures/test_pe_overlay.jpg").read_bytes(),
{"uid": "12345", "name": "somename"},
{"scanner_timeout": 5},
datetime.date.today(),
)

TestCase.maxDiff = None
TestCase().assertDictEqual(test_scan_jpeg_event, scanner.event)
152 changes: 152 additions & 0 deletions src/python/strelka/tests/test_scan_pe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import datetime
from pathlib import Path
from unittest import TestCase, mock

from strelka.scanners.scan_pe import ScanPe


def test_scan_pe(mocker):
"""
This tests the ScanPe scanner.
It attempts to validate several given PE metadata values.
Pass: Sample event matches output of ScanPe.
Failure: Unable to load file or sample event fails to match.
"""

test_scan_pe_event = {
"elapsed": mock.ANY,
"flags": ["no_certs_found"],
"total": {"libraries": 0, "resources": 2, "sections": 2, "symbols": 0},
"summary": {
"resource_md5": mock.ANY,
"resource_sha1": mock.ANY,
"resource_sha256": mock.ANY,
"section_md5": mock.ANY,
"section_sha1": mock.ANY,
"section_sha256": mock.ANY,
},
"debug": {
"type": "rsds",
"guid": b"a66307d0-9b84-b944-bf030bff2d7d1e4a",
"age": 1,
"pdb": b"C:\\Users\\tmcguff\\source\\repos\\HelloWorld\\HelloWorld\\obj\\x64\\Release\\HelloWorld.pdb",
},
"file_info": {
"fixed": {
"flags": [],
"operating_systems": ["WINDOWS32"],
"type": {"primary": "APP", "sub": ""},
},
"string": [],
"var": {"language": None, "character_set": "Unicode"},
"comments": "",
"company_name": ".",
"file_description": "HelloWorld",
"file_version": "1.0.0.0",
"internal_name": "HelloWorld.exe",
"legal_copyright": "Copyright © . 2020",
"legal_trademarks": "",
"original_filename": "HelloWorld.exe",
"product_name": "HelloWorld",
"product_version": "1.0.0.0",
"assembly_version": "1.0.0.0",
},
"header": {
"machine": {"id": 34404, "type": "AMD64"},
"magic": {"dos": "DOS", "image": "64_BIT"},
"subsystem": "WINDOWS_CUI",
},
"base_of_code": 8192,
"address_of_entry_point": 0,
"image_base": 5368709120,
"size_of_code": 2048,
"size_of_initialized_data": 1536,
"size_of_headers": 512,
"size_of_heap_reserve": 1048576,
"size_of_image": 24576,
"size_of_stack_commit": 16384,
"size_of_stack_reserve": 4194304,
"size_of_heap_commit": 8192,
"size_of_uninitialized_data": 0,
"file_alignment": 512,
"section_alignment": 8192,
"checksum": 0,
"major_image_version": 0,
"minor_image_version": 0,
"major_linker_version": 48,
"minor_linker_version": 0,
"major_operating_system_version": 4,
"minor_operating_system_version": 0,
"major_subsystem_version": 4,
"minor_subsystem_version": 0,
"image_version": 0.0,
"linker_version": 48.0,
"operating_system_version": 4.0,
"subsystem_version": 4.0,
"compile_time": "2104-07-18T17:22:04",
"dll_characteristics": [
"DYNAMIC_BASE",
"NX_COMPAT",
"NO_SEH",
"TERMINAL_SERVER_AWARE",
],
"image_characteristics": ["EXECUTABLE_IMAGE", "LARGE_ADDRESS_AWARE"],
"resources": [
{
"id": 1,
"language": {"sub": "NEUTRAL", "primary": "NEUTRAL"},
"type": "VERSION",
"md5": "f4741884351459aa7733725b88e693af",
"sha1": "5371904ee7671fb0b066d9323eda553269f344f9",
"sha256": "d8df3d0358a91b3ef97c4d472b34a60f7cf9ee7f1a6f37058fc3d1af3a156a36",
},
{
"id": 1,
"language": {"sub": "NEUTRAL", "primary": "NEUTRAL"},
"type": "MANIFEST",
"md5": "b7db84991f23a680df8e95af8946f9c9",
"sha1": "cac699787884fb993ced8d7dc47b7c522c7bc734",
"sha256": "539dc26a14b6277e87348594ab7d6e932d16aabb18612d77f29fe421a9f1d46a",
},
],
"sections": [
{
"address": {"physical": 1743, "virtual": 8192},
"characteristics": ["CNT_CODE", "MEM_EXECUTE", "MEM_READ"],
"entropy": 4.621214196319175,
"name": ".text",
"size": 2048,
"md5": "cc14da7fb94ef9b27a926fe95b86b44f",
"sha1": "3d584b265a558dc22fa6dfa9991ae7eafee5c1a4",
"sha256": "bb31a5224e9f78905909655d9c80ba7d63f03910e4f22b296d6b7865e2a477c3",
},
{
"address": {"physical": 1472, "virtual": 16384},
"characteristics": ["CNT_INITIALIZED_DATA", "MEM_READ"],
"entropy": 4.09070377434219,
"name": ".rsrc",
"size": 1536,
"md5": "c3eafa2cd34f98a226e31b8ea3fea400",
"sha1": "00104b432a8e7246695843e4f2d7cf2582efa3e6",
"sha256": "86d9755b2ba9d8ffd765621f09844dd62d0b082fdc4aafa63b3b3f3ae25d9c77",
},
],
"symbols": {"exported": [], "imported": [], "libraries": [], "table": []},
}

scanner = ScanPe(
{"name": "ScanPe", "key": "scan_pe", "limits": {"scanner": 10}},
"test_coordinate",
)

mocker.patch.object(ScanPe, "upload_to_coordinator", return_value=None)
scanner.scan_wrapper(
Path(Path(__file__).parent / "fixtures/test.exe").read_bytes(),
{"uid": "12345", "name": "somename"},
{"scanner_timeout": 5},
datetime.date.today(),
)

TestCase.maxDiff = None
TestCase().assertDictEqual(test_scan_pe_event, scanner.event)
61 changes: 61 additions & 0 deletions src/python/strelka/tests/test_scan_png_eof.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import datetime
from pathlib import Path
from unittest import TestCase, mock

from strelka.scanners.scan_jpeg import ScanJpeg


def test_scan_jpeg(mocker):
"""
This tests the ScanJpeg scanner.
It attempts to validate several given JPEG metadata values.
Pass: Sample event matches output of ScanJpeg.
Failure: Unable to load file or sample event fails to match.
"""

test_scan_jpeg_event = {"elapsed": mock.ANY, "flags": []}

scanner = ScanJpeg(
{"name": "ScanJpeg", "key": "scan_jpeg", "limits": {"scanner": 10}},
"test_coordinate",
)

mocker.patch.object(ScanJpeg, "upload_to_coordinator", return_value=None)
scanner.scan_wrapper(
Path(Path(__file__).parent / "fixtures/test.jpg").read_bytes(),
{"uid": "12345", "name": "somename"},
{"scanner_timeout": 5},
datetime.date.today(),
)

TestCase.maxDiff = None
TestCase().assertDictEqual(test_scan_jpeg_event, scanner.event)


def test_scan_jpeg_pe_overlay(mocker):
"""
This tests the ScanJpeg scanner.
It attempts to validate several given JPEG metadata values.
Pass: Sample event matches output of ScanJpeg.
Failure: Unable to load file or sample event fails to match.
"""

test_scan_jpeg_event = {"elapsed": mock.ANY, "flags": [], "trailer_index": 308564}

scanner = ScanJpeg(
{"name": "ScanJpeg", "key": "scan_jpeg", "limits": {"scanner": 10}},
"test_coordinate",
)

mocker.patch.object(ScanJpeg, "upload_to_coordinator", return_value=None)
scanner.scan_wrapper(
Path(Path(__file__).parent / "fixtures/test_pe_overlay.jpg").read_bytes(),
{"uid": "12345", "name": "somename"},
{"scanner_timeout": 5},
datetime.date.today(),
)

TestCase.maxDiff = None
TestCase().assertDictEqual(test_scan_jpeg_event, scanner.event)

0 comments on commit 9d8dbde

Please sign in to comment.