From 3e79b91d544913d16f22d23feb28760e9bf00764 Mon Sep 17 00:00:00 2001 From: ditekshen Date: Wed, 30 Dec 2020 13:24:19 +0000 Subject: [PATCH] Add scripts, update README, minor addition to Yara/ClamAV rule --- README.md | 6 +- clamav/clamav.ldb | 4 +- scripts/mbcscbyar.py | 126 ++++++++++++++++++++++++++++++++++++++ scripts/mbfyar.py | 126 ++++++++++++++++++++++++++++++++++++++ yara/indicator_office.yar | 3 +- 5 files changed, 261 insertions(+), 4 deletions(-) create mode 100644 scripts/mbcscbyar.py create mode 100644 scripts/mbfyar.py diff --git a/README.md b/README.md index d5cb643..8f43b37 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,8 @@ A set of interrelated network and host detection rules with the aim of improving ## Supported Rules -Currently, Snort, Yara and ClamAV rules are supported. Additional singatures and formats are work in progress. \ No newline at end of file +Currently, Snort, Yara and ClamAV rules are supported. Additional singatures and formats are work in progress. + +## Scripts + +Currently, only scripts available are used to aid in auto-generation of hash-based and certificate-based Yara rules. diff --git a/clamav/clamav.ldb b/clamav/clamav.ldb index 43077ca..fe06f9e 100644 --- a/clamav/clamav.ldb +++ b/clamav/clamav.ldb @@ -2,7 +2,7 @@ ditekSHen.INDICATOR.RTF.AncalogExploitBuilderDocument;Engine:51-255,Target:0;0&1 ditekSHen.INDICATOR.RTF.EquationBITSAdminDownloader;Engine:81-255,Container:CL_TYPE_RTF,Target:2;0&1&(2|3);6269747361646d696e::i;6571756174696f6e::iaw;2f7472616e73666572;2f646f776e6c6f6164 ditekSHen.INDICATOR.RTF.EquationPowerShellDownloader;Engine:81-255,Container:CL_TYPE_RTF,Target:2;0&1;706f7765727368656c6c::i;6571756174696f6e::iaw ditekSHen.INDICATOR.RTF.EquationCertUtilDownloader;Engine:81-255,Container:CL_TYPE_RTF,Target:2;0&1;636572747574696c::i;6571756174696f6e::iaw -ditekSHen.INDICATOR.OOXML.Excel4MacrosEXEC;Engine:79-255,Container:CL_TYPE_OOXML_XL,Target:0;0&(1|2|3)>1;3c786d3a6d6163726f7368656574;3e464f524d554c412e46494c4c28;3e524547495354455228;3e4558454328 +ditekSHen.INDICATOR.OOXML.Excel4MacrosEXEC;Engine:79-255,Container:CL_TYPE_OOXML_XL,Target:0;0&(1|2|3|4)>1;3c786d3a6d6163726f7368656574;3e464f524d554c412e46494c4c28;3e524547495354455228;3e4558454328;3e52554e28 ditekSHen.INDICATOR.Packed.NyanXCAT-CSharpLoader;Engine:51-255,Target:1;0;0050726f6772616d004c6f61646572004e79616e00 ditekSHen.MALWARE.Win.Trojan.Firebird-HiveRAT;Engine:51-255,Target:1;(0|1|2|3)|(4&5&6&7&8&9&10&11&12)>5;46697265626972642052656d6f74652041646d696e697374726174696f6e20546f6f6c::w;57656c636f6d6520746f2046697265626972642120596f75722073797374656d2069732063757272656e746c79206265696e67206d6f6e69746f726564::w;486976652052656d6f74652041646d696e697374726174696f6e20546f6f6c::w;57656c636f6d6520746f20486976652120596f75722073797374656d2069732063757272656e746c79206265696e67206d6f6e69746f726564::w;5245504c41434554484553454b45595354524f4b4553::w;5f454e41424c455f50524f46494c494e47::w;4b65796c6f675375626a656374::w;77656263616d656e61626c6564;73637265656e6c6f6773;6d6f6e69746f726f6e;5443505f5441424c455f4f574e45525f5049445f414c4c;73637265656e47726162;656e63727970746564636f6e6e656374696f6e ditekSHen.MALWARE.Win.Trojan.AcridRain;Engine:51-255,Target:1;0&1&2&3&4&5&6&7&8&9;2f4c6962732e7a6970;2f55706c6f61642f;74656d706c6f67696d;74656d706c6f67696b;74656d70505368;74656d70505768;436f6f6b696573;53454c454354202a2046524f4d20;54656c656772616d2e657865;633a5c75736572735c69676f72315c::w @@ -114,4 +114,4 @@ ditekSHen.MALWARE.Linux.Trojan.HiddenWasp-ELF;Engine:51-255,Target:6;(0&1&2&3&4) ditekSHen.MALWARE.Linux.Trojan.WellMess_Golang;Engine:51-255,Target:6;0&1&2&3&4&5;3c3b686561643b3e3c3b7469746c653b3e;3c3b7469746c653b3e3c3b736572766963653b3e;5f2f686f6d652f7562756e74752f476f50726f6a6563742f7372632f626f742f626f746c6962;6e65742f687474702e282a70657273697374436f6e6e292e72656164526573706f6e7365;6e65742f687474702f636f6f6b69656a61722e282a4a6172292e536574436f6f6b696573;687474703a2f2f696e76616c69646c6f6f6b7570 ditekSHen.MALWARE.Linux.Trojan.PLEAD;Engine:51-255,Target:6;0&1&2&3&4&5;4346696c655472616e73666572;4346696c654d616e61676572;43506f7274466f7277617264;43506f7274466f72776172644d616e61676572;4352656d6f74655368656c6c;43536f636b436c69656e74 ditekSHen.MALWARE.Aix.Trojan.FastcachInjector;Engine:51-255,Target:0;0&1&2&3&4&5&6&7&8;0:01f7;73746f72655f636f6e666967;6c6f61645f636f6e666967;66696c655f64756d70;2f746d702f2e4943452d756e69782f636f6e6669675f2564;2f746d702f2e4943452d756e69782f44554d5025582e646174;496e6a6563742053746172740a;2e6f75745f6c6f67;2e6f75745f72656773 -ditekSHen.MALWARE.Aix.Trojan.FastcachDLL;Engine:51-255,Target:0;0&1&2&3&4&5&6&7&8;0:01f7;2f746d702f2e4943452d756e69782f746d7025645f25642e6c6f67;2f746d702f2e4943452d756e69782f746d70777425645f25642e6c6f67;2f746d702f2e4943452d756e69782f746d70726425645f25642e6c6f;6f75745f64756d705f6c6f67;4d53472044554d50;686f6f6b5f66756e635f6164647228257829;6f72675f66756e6328257029;636f70795f66756e6328257829 \ No newline at end of file +ditekSHen.MALWARE.Aix.Trojan.FastcachDLL;Engine:51-255,Target:0;0&1&2&3&4&5&6&7&8;0:01f7;2f746d702f2e4943452d756e69782f746d7025645f25642e6c6f67;2f746d702f2e4943452d756e69782f746d70777425645f25642e6c6f67;2f746d702f2e4943452d756e69782f746d70726425645f25642e6c6f;6f75745f64756d705f6c6f67;4d53472044554d50;686f6f6b5f66756e635f6164647228257829;6f72675f66756e6328257029;636f70795f66756e6328257829 diff --git a/scripts/mbcscbyar.py b/scripts/mbcscbyar.py new file mode 100644 index 0000000..5e06a42 --- /dev/null +++ b/scripts/mbcscbyar.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 + +import os +import csv +import codecs +import requests +import argparse + +from contextlib import closing + +__author__ = "ditekSHen" +__copyright__ = "Copyright 2020, ditekShen" +__version__ = "1.0" +__reference__ = "https://github.com/ditekshen" + +FILE_URL = "https://bazaar.abuse.ch/export/csv/cscb/" + +def parse_csv(infile=None): + cert_data = list() + if infile: + infile = os.path.join(os.path.dirname(__file__), infile) + try: + with open(infile, 'r', encoding='utf-8') as csvfile: + reader = csv.reader(csvfile, delimiter=',', quotechar='"', skipinitialspace=True) + try: + for row in reader: + if not row[0].startswith('#'): + cert = dict() + cert["serial_number"] = row[1] + cert["thumbprint"] = row[2] + cert["subject_cn"] = row[4] + cert["reason"] = row[8] + cert_data.append(cert) + except IndexError as err: + print("Input file is potentially not a CSV file") + raise SystemExit(err) + except IOError as err: + raise SystemExit(err) + + return cert_data + else: + try: + with closing(requests.get(FILE_URL, stream=True)) as response: + if response.status_code == 200: + reader = csv.reader(codecs.iterdecode(response.iter_lines(),'utf-8'), delimiter=',', quotechar='"', skipinitialspace=True) + try: + for row in reader: + if not row[0].startswith('#'): + cert = dict() + cert["serial_number"] = row[1] + cert["thumbprint"] = row[2] + cert["subject_cn"] = row[4] + cert["reason"] = row[8] + cert_data.append(cert) + except IndexError as err: + print("Response data is potentially not CSV formatted") + raise SystemExit(err) + except requests.exceptions.RequestException as err: + raise SystemExit(err) + + return cert_data + +def write_yara(iocs, outfile): + rules = str() + + try: + fw = open(outfile, 'w') + except IOError: + print("Could not open file for writting output Yara rules file") + + file_header = "/*\n" + file_header += " Auto-generated certificate-based Yara rules from Abuse.ch MalwareBazar Code Signing Certificate Blocklist\n" + file_header += " Author: Automatically generated by MBCSCBYar (ditekSHen)\n" + file_header += " Reference: https://bazaar.abuse.ch/faq/#cscb\n" + file_header += " Reference: https://github.com/ditekshen\n" + file_header += "*/\n\n" + fw.write(file_header) + + fw.write('import "pe"\n\n') + + for cert in iocs: + rule_name = "rule INDICATOR_KB_CERT_%s {\n" % cert["serial_number"].lower() + rule_meta = " meta:\n" + rule_meta += " author = \"ditekSHen\"\n" + rule_meta += " description = \"Detects executables signed with stolen, revoked or invalid certificates\"\n" + rule_meta += " thumbprint = \"%s\"\n" % cert["thumbprint"].lower() + rule_meta += " reason = \"%s\"\n" % cert["reason"] + rule_meta += " reference = \"https://bazaar.abuse.ch/faq/#cscb\"\n" + rule_condition = " condition:\n" + rule_condition += " uint16(0) == 0x5a4d and\n" + rule_condition += " for any i in (0..pe.number_of_signatures): (\n" + rule_condition += " pe.signatures[i].subject contains \"%s\" and\n" % cert["subject_cn"] + rule_condition += " pe.signatures[i].serial == \"%s\"\n" % ':'.join(cert["serial_number"][i:i + 2] for i in range(0, len(cert["serial_number"]), 2)).lower() + rule_condition += " )\n" + rule_end = "}\n\n" + + rules += rule_name + rule_meta + rule_condition + rule_end + + fw.write(rules) + + try: + fw.close() + except IOError: + print("Could not close output Yara rules file") + +def main(): + usage_text = '''Example Usage: + mbcscb_to_yara.py - Download CSCB CSV file from URL and write Yara rules file using default file name (defaults) + mbcscb_to_yara.py -o name.yar - Download CSCB CSV file from URL and save generated Yara rules file using custom name + mbcscb_to_yara.py -i cscb.csv - Read local CSCB CSV file and write Yara rules file using default file name + mbcscb_to_yara.py -i cscb.csv -o name.yar - Read local CSCB CSV file and and save generated Yara rules file using custom name''' + + parser = argparse.ArgumentParser(description='Generate Yara rules from Abuse.ch MalwareBazar Code Signing Certificate Blocklist (CSCB)', + epilog=usage_text, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('-i', '--input', type=str, metavar='INPUT', required=False, action='store', help='Input CSCB CSV local file',) + parser.add_argument('-o', '--output', type=str, metavar='OUTPUT', required=False, default='certificates.yar', help='Output Yara rules file name') + args = parser.parse_args() + + cert_data = parse_csv(args.input) + if len(cert_data) > 0: + write_yara(cert_data, args.output) + else: + print("No certificate IOCs found, or something went wrong!") + +if __name__ == "__main__": + main() diff --git a/scripts/mbfyar.py b/scripts/mbfyar.py new file mode 100644 index 0000000..4946433 --- /dev/null +++ b/scripts/mbfyar.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 + +import os +import csv +import argparse + +__author__ = "ditekSHen" +__copyright__ = "Copyright 2020, ditekShen" +__version__ = "1.0" +__reference__ = "https://github.com/ditekshen" + +def parse_csv(infile=None,hashtype='md5'): + samples = list() + if infile: + infile = os.path.join(os.path.dirname(__file__), infile) + try: + with open(infile, 'r', encoding='utf-8') as csvfile: + reader = csv.reader(csvfile, delimiter=',', quotechar='"', skipinitialspace=True) + try: + for row in reader: + if not row[0].startswith('#'): + sample = dict() + if ("dosexec" or "executable" or "exe") in row[7] and ("exe" or "dll" or "elf") in row[6]: + sample["first_seen"] = row[0] + sample["md5"] = row[2] + sample["sha1"] = row[3] + sample["sha2"] = row[1] + sample["filetype"] = row[6] + sample["mimetype"] = row[7] + sample["signature"] = row[8] + sample["imphash"] = row[11] + sample["ssdeep"] = row[12] + + samples.append(sample) + except IndexError as err: + print("Input file is potentially not a CSV file") + raise SystemExit(err) + except IOError as err: + raise SystemExit(err) + + return samples + else: + return None + +def write_yara(samples, hashtype, minsize, maxsize, outfile): + rules = str() + + try: + fw = open(outfile, 'w') + except IOError: + print("Could not open file for writting output Yara rules file") + + file_header = "/*\n" + file_header += " Auto-generated hash-based Yara rules for executables (exe, dll, elf) from Abuse.ch MalwareBazar\n" + file_header += " Author: Automatically generated by MBYar (ditekSHen)\n" + file_header += " Reference: https://bazaar.abuse.ch/faq/\n" + file_header += " Reference: https://github.com/ditekshen\n" + file_header += "*/\n\n" + fw.write(file_header) + + fw.write('import "hash"\n\n') + + rule_name_prefix = "rule INDICATOR_MB_Hash_" + for sample in samples: + if hashtype == "md5": + rule_name = "rule INDICATOR_MB_Hash_%s {\n" % sample["md5"].lower() + elif hashtype == "sha1": + rule_name = "rule INDICATOR_MB_Hash_%s {\n" % sample["sha1"].lower() + elif hashtype == "sha2": + rule_name = "rule INDICATOR_MB_Hash_%s {\n" % sample["sha2"].lower() + rule_meta = " meta:\n" + rule_meta += " author = \"ditekSHen\"\n" + rule_meta += " description = \"Detects malicious sample based on known hash from Abuse.ch MalwareBazar\"\n" + rule_meta += " first_seen = \"%s\"\n" % sample["first_seen"].lower() + rule_meta += " signature = \"%s\"\n" % sample["signature"] + rule_meta += " md5 = \"%s\"\n" % sample["md5"].lower() + rule_meta += " sha1 = \"%s\"\n" % sample["sha1"].lower() + rule_meta += " sha2 = \"%s\"\n" % sample["sha2"].lower() + if len(sample["imphash"]) == 32: + rule_meta += " imphash = \"%s\"\n" % sample["imphash"].lower() + rule_meta += " ssdeep = \"%s\"\n" % sample["ssdeep"] + rule_condition = " condition:\n" + if ("exe" or "dll") in sample["filetype"]: + rule_condition += " uint16(0) == 0x5a4d and\n" + elif ("elf") in sample["filetype"]: + rule_condition += " uint16(0) == 0x457f and\n" + rule_condition += " filesize > {0}KB and filesize < {1}KB and\n".format(minsize, maxsize) + if hashtype == "md5": + rule_condition += " hash.md5(0,filesize) == \"%s\"\n" % sample["md5"] + elif hashtype == "sha1": + rule_condition += " hash.sha1(0,filesize) == \"%s\"\n" % sample["sha1"] + elif hashtype == "sha2": + rule_condition += " hash.sha256(0,filesize) == \"%s\"\n" % sample["sha2"] + rule_end = "}\n\n" + + rules += rule_name + rule_meta + rule_condition + rule_end + + fw.write(rules) + + try: + fw.close() + except IOError: + print("Could not close output Yara rules file") + +def main(): + usage_text = '''Example Usage: + mbfyar.py -i full.csv - Generate Yara rules from MalwareBazar CSV file (defaults - hash: md5, minsize:100, maxsize:2000) + mbfyar.py -H sha1 -i full.csv - Generate SHA1-based Yara rules from MalwareBazar CSV file + mbyar.py -n 500 -x 5000 -i full.csv -o output.yar - Generate MD5-based Yara rules limiting matches to file size range to custom output file name''' + + parser = argparse.ArgumentParser(description='Generate Yara hash rules for executables (exe, dll, elf) from Absue.ch MalwareBazar', epilog=usage_text, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('-H', '--hash', help='Hash type to generate Yara rules against', type=str, metavar="HASH", required=False, default="md5", choices=['md5', 'sha1', 'sha2']) + parser.add_argument('-n', '--minsize', type=int, metavar='SIZE', required=False, action='store', default=100, help='Minimum file size in kilobytes (KB)') + parser.add_argument('-x', '--maxsize', type=int, metavar='SIZE', required=False, action='store', default=2000, help='Maximum file size in kilobytes (KB)') + parser.add_argument('-i', '--input', type=str, metavar='INPUT', required=True, action='store', help='Input full dump from Absue.ch MalwareBazar') + parser.add_argument('-o', '--output', type=str, metavar='OUTPUT', required=False, default='hashes.yar', help='Output Yara rules file name') + args = parser.parse_args() + + data = parse_csv(args.input) + if data and len(data) > 0: + write_yara(data, args.hash, args.minsize, args.maxsize, args.output) + else: + print("No hash IOCs found, or something went wrong!") + +if __name__ == "__main__": + main() diff --git a/yara/indicator_office.yar b/yara/indicator_office.yar index f72968b..08fcbc4 100644 --- a/yara/indicator_office.yar +++ b/yara/indicator_office.yar @@ -855,6 +855,7 @@ rule INDICATOR_OOXML_Excel4Macros_EXEC { $s1 = ">FORMULA.FILL(" ascii nocase $s2 = ">REGISTER(" ascii nocase $s3 = ">EXEC(" ascii nocase + $s4 = ">RUN(" ascii nocase condition: uint32(0) == 0x6d783f3c and $ms and 2 of ($s*) -} \ No newline at end of file +}