mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2026-05-06 06:35:29 -04:00
Using a fuzzy hash test for the clamav daemon JPEG attached to the XLS document. Not yet testing PNG, because the fuzzy hash implementation isn't properly hashing that file, yet. This test is for a regression where malware detection wasn't properly being tracked for OLE2 (XLS) image extraction / scanning.
503 lines
21 KiB
Python
503 lines
21 KiB
Python
# Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
|
|
|
"""
|
|
Run clamscan tests.
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import unittest
|
|
|
|
import testcase
|
|
|
|
|
|
os_platform = platform.platform()
|
|
operating_system = os_platform.split('-')[0].lower()
|
|
|
|
|
|
class TC(testcase.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super(TC, cls).setUpClass()
|
|
|
|
TC.testpaths = list(TC.path_build.glob('unit_tests/input/clamav_hdb_scanfiles/clam*')) # A list of Path()'s of each of our generated test files
|
|
|
|
# Prepare a directory to store our test databases
|
|
TC.path_db = TC.path_tmp / 'database'
|
|
TC.path_db.mkdir(parents=True)
|
|
|
|
shutil.copy(
|
|
str(TC.path_build / 'unit_tests' / 'input' / 'clamav.hdb'),
|
|
str(TC.path_db),
|
|
)
|
|
|
|
(TC.path_db / 'clamav.ign2').write_text('ClamAV-Test-File\n')
|
|
|
|
(TC.path_db / 'phish.pdb').write_text('H:example.com\n')
|
|
|
|
(TC.path_db / 'icon.idb').write_text(
|
|
"EA0X-32x32x8:ea0x-grp1:ea0x-grp2:2046f030a42a07153f4120a0031600007000005e1617ef0000d21100cb090674150f880313970b0e7716116d01136216022500002f0a173700081a004a0e\n"
|
|
"IScab-16x16x8:iscab-grp1:iscab-grp2:107b3000168306015c20a0105b07060be0a0b11c050bea0706cb0a0bbb060b6f00017c06018301068109086b03046705081b000a270a002a000039002b17\n"
|
|
)
|
|
(TC.path_db / 'icon.ldb').write_text(
|
|
"ClamAV-Test-Icon-EA0X;Engine:52-1000,Target:1,IconGroup1:ea0x-grp1,IconGroup2:*;(0);0:4d5a\n"
|
|
"ClamAV-Test-Icon-IScab;Engine:52-1000,Target:1,IconGroup2:iscab-grp2;(0);0:4d5a\n"
|
|
)
|
|
(TC.path_db / 'Clam-VI.ldb').write_text(
|
|
"Clam-VI-Test:Target;Engine:52-255,Target:1;(0&1);VI:43006f006d00700061006e0079004e0061006d0065000000000063006f006d00700061006e007900;VI:500072006f0064007500630074004e0061006d0065000000000063006c0061006d00\n"
|
|
)
|
|
(TC.path_db / 'yara-at-offset.yara').write_text(
|
|
"rule yara_at_offset {strings: $tar_magic = { 75 73 74 61 72 } condition: $tar_magic at 257}\n"
|
|
)
|
|
(TC.path_db / 'yara-in-range.yara').write_text(
|
|
"rule yara_in_range {strings: $tar_magic = { 75 73 74 61 72 } condition: $tar_magic in (200..300)}\n"
|
|
)
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
super(TC, cls).tearDownClass()
|
|
|
|
def setUp(self):
|
|
super(TC, self).setUp()
|
|
|
|
def tearDown(self):
|
|
super(TC, self).tearDown()
|
|
self.verify_valgrind_log()
|
|
|
|
def test_clamscan_00_version(self):
|
|
self.step_name('clamscan version test')
|
|
|
|
command = '{valgrind} {valgrind_args} {clamscan} -V'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 0 # success
|
|
|
|
expected_results = [
|
|
'ClamAV {}'.format(TC.version),
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_01_all_testfiles(self):
|
|
self.step_name('Test that clamscan alerts on all test files')
|
|
|
|
testfiles = ' '.join([str(testpath) for testpath in TC.testpaths])
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_db=TC.path_db / "clamav.hdb", testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus found
|
|
|
|
expected_results = ['{}: ClamAV-Test-File.UNOFFICIAL FOUND'.format(testpath.name) for testpath in TC.testpaths]
|
|
expected_results.append('Scanned files: {}'.format(len(TC.testpaths)))
|
|
expected_results.append('Infected files: {}'.format(len(TC.testpaths)))
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_02_all_testfiles_ign2(self):
|
|
self.step_name('Test that clamscan ignores ClamAV-Test-File alerts')
|
|
|
|
testfiles = ' '.join([str(testpath) for testpath in TC.testpaths])
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} -d {path_ign_db} {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_db=TC.path_db / "clamav.hdb", path_ign_db=TC.path_db / "clamav.ign2", testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus found
|
|
|
|
expected_results = ['{}: ClamAV-Test-File.UNOFFICIAL FOUND'.format(testpath.name) for testpath in TC.testpaths]
|
|
expected_results.append('Scanned files: {}'.format(len(TC.testpaths)))
|
|
expected_results.append('Infected files: {}'.format(len(TC.testpaths)))
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_03_phish_test_not_enabled(self):
|
|
self.step_name('Test that clamscan will load the phishing sigs w/out issue')
|
|
|
|
testpaths = list(TC.path_source.glob('unit_tests/input/other_scanfiles/phish-test-*'))
|
|
|
|
testfiles = ' '.join([str(testpath) for testpath in testpaths])
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_db=TC.path_db / "phish.pdb", path_ign_db=TC.path_db / "clamav.ign2", testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 0 # virus NOT found
|
|
|
|
expected_results = [
|
|
'Scanned files: 3',
|
|
'Infected files: 0',
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_04_phish_test_alert_phishing_ssl_alert_phishing_cloak(self):
|
|
self.step_name('Test clamscan --alert-phishing-ssl --alert-phishing-cloak')
|
|
|
|
testpaths = list(TC.path_source.glob('unit_tests/input/other_scanfiles/phish-test-*'))
|
|
|
|
testfiles = ' '.join([str(testpath) for testpath in testpaths])
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} --alert-phishing-ssl --alert-phishing-cloak {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_db=TC.path_db / "phish.pdb", testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus found
|
|
|
|
expected_results = [
|
|
'phish-test-ssl: Heuristics.Phishing.Email.SSL-Spoof FOUND',
|
|
'phish-test-cloak: Heuristics.Phishing.Email.Cloaked.Null FOUND',
|
|
'Scanned files: 3',
|
|
'Infected files: 2', # there's a clean one
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_05_icon(self):
|
|
self.step_name('Test icon (.ldb + .idb) signatures')
|
|
|
|
testfiles = ' '.join([str(testpath) for testpath in TC.testpaths])
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_ldb} -d {path_idb} {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_ldb=TC.path_db / "icon.ldb", path_idb=TC.path_db / "icon.idb", testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus found
|
|
|
|
# Use check_fpu_endian to determine expected results
|
|
command = '{}'.format(TC.check_fpu_endian)
|
|
fpu_endian_output = self.execute_command(command)
|
|
|
|
expected_results = [
|
|
'clam_IScab_ext.exe: ClamAV-Test-Icon-IScab.UNOFFICIAL FOUND',
|
|
'clam_IScab_int.exe: ClamAV-Test-Icon-IScab.UNOFFICIAL FOUND',
|
|
]
|
|
if fpu_endian_output.ec == 3:
|
|
expected_num_infected = 3
|
|
else:
|
|
expected_results.append('clam.ea06.exe: ClamAV-Test-Icon-EA0X.UNOFFICIAL FOUND')
|
|
expected_num_infected = 4
|
|
expected_results.append('Infected files: {}'.format(expected_num_infected))
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_06_LDB_VI(self):
|
|
self.step_name('Test LDB VI feature')
|
|
|
|
testfiles = ' '.join([str(testpath) for testpath in TC.testpaths])
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_db=TC.path_db / "Clam-VI.ldb", testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus found
|
|
|
|
expected_results = [
|
|
'clam_ISmsi_ext.exe: Clam-VI-Test:Target.UNOFFICIAL FOUND',
|
|
'clam_ISmsi_int.exe: Clam-VI-Test:Target.UNOFFICIAL FOUND',
|
|
'Infected files: 2',
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_07_yara_at_offset(self):
|
|
self.step_name('Test yara signature - detect TAR file magic at an offset')
|
|
|
|
testfiles = ' '.join([str(testpath) for testpath in TC.testpaths])
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_db=TC.path_db / "yara-at-offset.yara", testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus found
|
|
|
|
expected_results = [
|
|
'clam.tar.gz: YARA.yara_at_offset.UNOFFICIAL FOUND',
|
|
'clam_cache_emax.tgz: YARA.yara_at_offset.UNOFFICIAL FOUND',
|
|
'Infected files: 3',
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_08_yara_in_range(self):
|
|
self.step_name('Test yara signature - detect TAR file magic in a range')
|
|
|
|
testfiles = ' '.join([str(testpath) for testpath in TC.testpaths])
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_db=TC.path_db / "yara-in-range.yara", testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus found
|
|
|
|
expected_results = [
|
|
'clam.tar.gz: YARA.yara_in_range.UNOFFICIAL FOUND',
|
|
'clam_cache_emax.tgz: YARA.yara_in_range.UNOFFICIAL FOUND',
|
|
'Infected files: 3',
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_09_xls_jpeg_png_extraction(self):
|
|
self.step_name('Test that clamav can successfully extract jpeg and png images from XLS documents')
|
|
# Note: we aren't testing BMP, TIFF, or GIF because excel converts them to PNG when you try to insert them.
|
|
|
|
testfiles = TC.path_source / 'unit_tests' / 'input' / 'other_scanfiles' / 'has_png_and_jpeg.xls'
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --gen-json --debug'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
|
|
path_db=TC.path_build / 'unit_tests' / 'input' / 'clamav.hdb',
|
|
testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 0 # no virus, no failures
|
|
|
|
expected_results = [
|
|
'Recognized PNG file',
|
|
'Recognized JPEG file',
|
|
'"FileMD5":"41e64a9ddb49690f0b6fbbd71362b1b3"',
|
|
'"FileMD5":"5341e0efde53a50c416b2352263e7693"',
|
|
]
|
|
self.verify_output(output.err, expected=expected_results)
|
|
|
|
def test_clamscan_10_bytecode_pdf_hook(self):
|
|
self.step_name('Test that pdf bytecode hooks trigger')
|
|
|
|
testfiles = TC.path_build / 'unit_tests' / 'input' / 'clamav_hdb_scanfiles' / 'clam.pdf'
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --bytecode-unsigned'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
|
|
path_db=TC.path_source / 'unit_tests' / 'input' / 'bytecode_sigs' / 'pdf-hook.cbc',
|
|
testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus
|
|
|
|
expected_results = [
|
|
'Test.Case.BC.PDF.hook FOUND',
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_11_allmatch_hash_sigs(self):
|
|
self.step_name('Test that each type of hash sig is detected in all-match mode')
|
|
|
|
os.mkdir(str(TC.path_db / 'allmatch-test-sigs'))
|
|
|
|
(TC.path_db / 'allmatch-test-sigs' / 'clam.hdb').write_text(
|
|
"aa15bcf478d165efd2065190eb473bcb:544:Test.MD5.Hash:73\n"
|
|
"aa15bcf478d165efd2065190eb473bcb:*:Test.MD5.Hash.NoSize:73\n"
|
|
)
|
|
(TC.path_db / 'allmatch-test-sigs' / 'clam.hsb').write_text(
|
|
"71e7b604d18aefd839e51a39c88df8383bb4c071dc31f87f00a2b5df580d4495:544:Test.Sha256.Hash:73\n"
|
|
"71e7b604d18aefd839e51a39c88df8383bb4c071dc31f87f00a2b5df580d4495:*:Test.Sha256.Hash.NoSize:73\n"
|
|
"62dd70f5e7530e0239901ac186f1f9ae39292561:544:Test.Sha1.Hash:73\n"
|
|
"62dd70f5e7530e0239901ac186f1f9ae39292561:*:Test.Sha1.NoSize:73\n"
|
|
)
|
|
(TC.path_db / 'allmatch-test-sigs' / 'clam.imp').write_text(
|
|
"98c88d882f01a3f6ac1e5f7dfd761624:39:Test.Import.Hash\n"
|
|
"98c88d882f01a3f6ac1e5f7dfd761624:*:Test.Import.Hash.NoSize\n"
|
|
)
|
|
(TC.path_db / 'allmatch-test-sigs' / 'clam.mdb').write_text(
|
|
"512:23db1dd3f77fae25610b6a32701313ae:Test.PESection.Hash:73\n"
|
|
"*:23db1dd3f77fae25610b6a32701313ae:Test.PESection.Hash.NoSize:73\n"
|
|
)
|
|
|
|
testfiles = TC.path_build / 'unit_tests' / 'input' / 'clamav_hdb_scanfiles' / 'clam.exe'
|
|
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --allmatch'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
|
|
path_db=TC.path_db / 'allmatch-test-sigs',
|
|
testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus
|
|
|
|
expected_results = [
|
|
'Test.MD5.Hash.UNOFFICIAL FOUND',
|
|
'Test.MD5.Hash.NoSize.UNOFFICIAL FOUND',
|
|
'Test.Sha1.Hash.UNOFFICIAL FOUND',
|
|
'Test.Sha1.NoSize.UNOFFICIAL FOUND',
|
|
'Test.Sha256.Hash.UNOFFICIAL FOUND',
|
|
'Test.Sha256.Hash.NoSize.UNOFFICIAL FOUND',
|
|
'Test.PESection.Hash.UNOFFICIAL FOUND',
|
|
'Test.PESection.Hash.NoSize.UNOFFICIAL FOUND',
|
|
'Test.Import.Hash.UNOFFICIAL FOUND',
|
|
'Test.Import.Hash.NoSize.UNOFFICIAL FOUND',
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_12_image_fuzzy_hash_sigs(self):
|
|
self.step_name('Test that each type of hash sig is detected in all-match mode')
|
|
|
|
os.mkdir(str(TC.path_db / 'image-fuzzy-hash-test-sigs'))
|
|
|
|
(TC.path_db / 'image-fuzzy-hash-test-sigs' / 'good.ldb').write_text(
|
|
"logo.png.good;Engine:150-255,Target:0;0;fuzzy_img#af2ad01ed42993c7#0\n"
|
|
"logo.png.bad.with.second.subsig;Engine:150-255,Target:0;0&1;deadbeef;fuzzy_img#af2ad01ed42993c7#0\n"
|
|
"logo.png.good.with.second.subsig;Engine:150-255,Target:0;0&1;49484452;fuzzy_img#af2ad01ed42993c7#0\n"
|
|
)
|
|
|
|
testfiles = TC.path_source / 'logo.png'
|
|
|
|
#
|
|
# First check with the good database in all-match mode.
|
|
#
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --allmatch'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
|
|
path_db=TC.path_db / 'image-fuzzy-hash-test-sigs' / 'good.ldb',
|
|
testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus
|
|
|
|
expected_stdout = [
|
|
'logo.png.good.UNOFFICIAL FOUND',
|
|
'logo.png.good.with.second.subsig.UNOFFICIAL FOUND',
|
|
]
|
|
unexpected_stdout = [
|
|
'logo.png.bad.with.second.subsig.UNOFFICIAL FOUND',
|
|
]
|
|
self.verify_output(output.out, expected=expected_stdout)
|
|
|
|
#
|
|
# Next check with the bad signatures
|
|
#
|
|
|
|
# Invalid hash
|
|
(TC.path_db / 'image-fuzzy-hash-test-sigs' / 'invalid-hash.ldb').write_text(
|
|
"logo.png.bad;Engine:150-255,Target:0;0;fuzzy_img#abcdef#0\n"
|
|
)
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --allmatch'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
|
|
path_db=TC.path_db / 'image-fuzzy-hash-test-sigs' / 'invalid-hash.ldb',
|
|
testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 2 # error
|
|
|
|
expected_stderr = [
|
|
'LibClamAV Error: Failed to load',
|
|
'Invalid hash: Image fuzzy hash must be 16 characters in length: abcdef',
|
|
]
|
|
unexpected_stdout = [
|
|
'logo.png.bad.UNOFFICIAL FOUND',
|
|
]
|
|
self.verify_output(output.err, expected=expected_stderr)
|
|
self.verify_output(output.out, unexpected=unexpected_stdout)
|
|
|
|
# Unsupported hamming distance
|
|
(TC.path_db / 'image-fuzzy-hash-test-sigs' / 'invalid-ham.ldb').write_text(
|
|
"logo.png.bad;Engine:150-255,Target:0;0;fuzzy_img#af2ad01ed42993c7#1\n"
|
|
)
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --allmatch'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
|
|
path_db=TC.path_db / 'image-fuzzy-hash-test-sigs' / 'invalid-ham.ldb',
|
|
testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 2 # error
|
|
|
|
expected_stderr = [
|
|
'LibClamAV Error: Failed to load',
|
|
'Invalid hamming distance: 1',
|
|
]
|
|
unexpected_stdout = [
|
|
'logo.png.bad.UNOFFICIAL FOUND',
|
|
]
|
|
self.verify_output(output.err, expected=expected_stderr)
|
|
self.verify_output(output.out, unexpected=unexpected_stdout)
|
|
|
|
# invalid algorithm
|
|
(TC.path_db / 'image-fuzzy-hash-test-sigs' / 'invalid-alg.ldb').write_text(
|
|
"logo.png.bad;Engine:150-255,Target:0;0;fuzzy_imgy#af2ad01ed42993c7#0\n"
|
|
)
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --allmatch'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
|
|
path_db=TC.path_db / 'image-fuzzy-hash-test-sigs' / 'invalid-alg.ldb',
|
|
testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 2 # error
|
|
|
|
expected_stderr = [
|
|
'cli_loadldb: failed to parse subsignature 0 in logo.png',
|
|
]
|
|
unexpected_stdout = [
|
|
'logo.png.bad.UNOFFICIAL FOUND',
|
|
]
|
|
self.verify_output(output.err, expected=expected_stderr)
|
|
self.verify_output(output.out, unexpected=unexpected_stdout)
|
|
|
|
def test_clamscan_13_yara_regex(self):
|
|
self.step_name('Test yara signature - detect TAR file magic in a range')
|
|
|
|
db = TC.path_tmp / 'regex.yara'
|
|
db.write_text(
|
|
r'''
|
|
rule regex
|
|
{
|
|
meta:
|
|
author = "Micah"
|
|
date = "2022/03/12"
|
|
description = "Just a test"
|
|
strings:
|
|
$a = "/+eat/" /* <-- not a regex */
|
|
$b = /\$protein+=\([a-z]+\)/ /* <-- is a regex */
|
|
condition:
|
|
all of them
|
|
}
|
|
'''
|
|
)
|
|
testfile = TC.path_tmp / 'regex.sample'
|
|
testfile.write_text('var $protein=(slugs); /+eat/ $protein')
|
|
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles}'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan, path_db=db, testfiles=testfile,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # virus found
|
|
|
|
expected_results = [
|
|
'regex.sample: YARA.regex.UNOFFICIAL FOUND',
|
|
'Infected files: 1',
|
|
]
|
|
self.verify_output(output.out, expected=expected_results)
|
|
|
|
def test_clamscan_14_xls_jpeg_detection(self):
|
|
self.step_name('Test that clamav can successfully alert on jpeg image extracted from XLS documents')
|
|
# Note: we aren't testing PNG because the attached PNG is not properly fuzzy-hashed by clamav, yet.
|
|
|
|
os.mkdir(str(TC.path_db / 'xls-jpeg-detection-sigs'))
|
|
|
|
(TC.path_db / 'image-fuzzy-hash-test-sigs' / 'good.ldb').write_text(
|
|
"logo.png.good;Engine:150-255,Target:0;0;fuzzy_img#ea0f85d0de719887#0\n"
|
|
)
|
|
|
|
testfiles = TC.path_source / 'unit_tests' / 'input' / 'other_scanfiles' / 'has_png_and_jpeg.xls'
|
|
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --gen-json --debug --allmatch'.format(
|
|
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
|
|
path_db=TC.path_db / 'image-fuzzy-hash-test-sigs' / 'good.ldb',
|
|
testfiles=testfiles,
|
|
)
|
|
output = self.execute_command(command)
|
|
|
|
assert output.ec == 1 # no virus, no failures
|
|
|
|
expected_stderr = [
|
|
'Recognized PNG file',
|
|
'Recognized JPEG file',
|
|
'"FileMD5":"41e64a9ddb49690f0b6fbbd71362b1b3"',
|
|
'"FileMD5":"5341e0efde53a50c416b2352263e7693"',
|
|
]
|
|
self.verify_output(output.err, expected=expected_stderr)
|
|
|
|
expected_stdout = [
|
|
'has_png_and_jpeg.xls: logo.png.good.UNOFFICIAL FOUND',
|
|
]
|
|
self.verify_output(output.out, expected=expected_stdout)
|