From 62a976e1718d1a3302c0121bf0bcfa2b3eab9614 Mon Sep 17 00:00:00 2001 From: tlee Date: Wed, 2 Aug 2023 17:20:35 -0400 Subject: [PATCH 1/4] Added hash field type --- .../src/assets/builder.config.ts | 84 ++++++++++++++++++- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/src/attack_flow_builder/src/assets/builder.config.ts b/src/attack_flow_builder/src/assets/builder.config.ts index d6360d29..c7cb9c6e 100644 --- a/src/attack_flow_builder/src/assets/builder.config.ts +++ b/src/attack_flow_builder/src/assets/builder.config.ts @@ -7,7 +7,8 @@ import { EnumPropertyDescriptor, PropertyType, SemanticRole, - TemplateType + TemplateType, + Property } from "./scripts/BlockDiagram"; const BoolEnum: EnumPropertyDescriptor = { @@ -555,7 +556,32 @@ const config: AppConfiguration = { mime_type : { type: PropertyType.String }, payload_bin : { type: PropertyType.String }, url : { type: PropertyType.String }, - hashes : { type: PropertyType.String }, + hashes : { + type: PropertyType.List, + form: { + type: PropertyType.Dictionary, + form: { + hash_type: { + type: PropertyType.Enum, + options: { + type: PropertyType.List, + form: { type: PropertyType.String }, + value: [ + ["custom", "Custom hash key"], + ["md5", "MD5"], + ["sha-1", "SHA-1"], + ["sha-256", "SHA-256"], + ["sha-512", "SHA-512"], + ["sha3-256", "SHA3-256"], + ["ssdeep", "SSDEEP"], + ["tlsh", "TLSH"] + ] + } + }, + hash_value: { type: PropertyType.String, is_primary: true } + } + } + }, encryption_algorithm : { type: PropertyType.String }, decryption_key : { type: PropertyType.String }, }, @@ -638,7 +664,32 @@ const config: AppConfiguration = { type: TemplateType.DictionaryBlock, role: SemanticRole.Node, properties: { - hashes : { type: PropertyType.String }, + hashes : { + type: PropertyType.List, + form: { + type: PropertyType.Dictionary, + form: { + hash_type: { + type: PropertyType.Enum, + options: { + type: PropertyType.List, + form: { type: PropertyType.String }, + value: [ + ["custom", "Custom hash key"], + ["md5", "MD5"], + ["sha-1", "SHA-1"], + ["sha-256", "SHA-256"], + ["sha-512", "SHA-512"], + ["sha3-256", "SHA3-256"], + ["ssdeep", "SSDEEP"], + ["tlsh", "TLSH"] + ] + } + }, + hash_value: { type: PropertyType.String, is_primary: true } + } + } + }, size : { type: PropertyType.String }, name : { type: PropertyType.String, is_primary: true }, name_enc : { type: PropertyType.String }, @@ -804,7 +855,32 @@ const config: AppConfiguration = { properties: { subject : { type: PropertyType.String, is_primary: true, is_required: true }, is_self_signed : BoolEnum, - hashes : { type: PropertyType.String }, + hashes : { + type: PropertyType.List, + form: { + type: PropertyType.Dictionary, + form: { + hash_type: { + type: PropertyType.Enum, + options: { + type: PropertyType.List, + form: { type: PropertyType.String }, + value: [ + ["custom", "Custom hash key"], + ["md5", "MD5"], + ["sha-1", "SHA-1"], + ["sha-256", "SHA-256"], + ["sha-512", "SHA-512"], + ["sha3-256", "SHA3-256"], + ["ssdeep", "SSDEEP"], + ["tlsh", "TLSH"] + ] + } + }, + hash_value: { type: PropertyType.String, is_primary: true } + } + } + }, version : { type: PropertyType.String }, serial_number : { type: PropertyType.String }, signature_algorithm : { type: PropertyType.String }, From 9cb247e557a409a868ac2ae702839aabe28beee1 Mon Sep 17 00:00:00 2001 From: tlee Date: Tue, 8 Aug 2023 16:32:29 -0400 Subject: [PATCH 2/4] fixed publishing of hash objects --- .../src/assets/builder.config.publisher.ts | 35 +++++++++++++++++++ .../src/assets/builder.config.ts | 9 +++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/attack_flow_builder/src/assets/builder.config.publisher.ts b/src/attack_flow_builder/src/assets/builder.config.publisher.ts index 4941b1a4..e0bfb335 100644 --- a/src/attack_flow_builder/src/assets/builder.config.publisher.ts +++ b/src/attack_flow_builder/src/assets/builder.config.publisher.ts @@ -242,6 +242,10 @@ class AttackFlowPublisher extends DiagramPublisher { break; case PropertyType.List: if (prop.isDefined()) { + if(key === "hashes") { + this.mergeComplexListProperty(node, key, prop as ListProperty); + break; + } this.mergeBasicListProperty(node, key, prop as ListProperty); } break; @@ -292,6 +296,37 @@ class AttackFlowPublisher extends DiagramPublisher { } } + /** + * Merges a more complicated list into a STIX node. + * @param node + * The STIX node. + * @param key + * The list property's key. + * @param property + * The list property. + */ + private mergeComplexListProperty(node: Sdo, key: string, property: ListProperty) { + // Check if node[key] has any values first + + switch(key) { + case "hashes": + let hashList = []; + for(let prop of property.value.values()) { + switch(prop.type) { + case PropertyType.Dictionary: + if(prop.isDefined()) { + let entries = prop.toRawValue() as RawEntries; + hashList.push(Object.fromEntries(entries)); + } + break; + } + } + if (hashList.length > 0) { + let hashes = hashList.map(hash => [hash.hash_type, hash.hash_value]); // Drop the property labels + node[key] = Object.fromEntries(hashes); + } + } + } /////////////////////////////////////////////////////////////////////////// // 2. Relationships Embeddings ////////////////////////////////////////// diff --git a/src/attack_flow_builder/src/assets/builder.config.ts b/src/attack_flow_builder/src/assets/builder.config.ts index c7cb9c6e..1c2e06a8 100644 --- a/src/attack_flow_builder/src/assets/builder.config.ts +++ b/src/attack_flow_builder/src/assets/builder.config.ts @@ -7,8 +7,7 @@ import { EnumPropertyDescriptor, PropertyType, SemanticRole, - TemplateType, - Property + TemplateType } from "./scripts/BlockDiagram"; const BoolEnum: EnumPropertyDescriptor = { @@ -567,7 +566,7 @@ const config: AppConfiguration = { type: PropertyType.List, form: { type: PropertyType.String }, value: [ - ["custom", "Custom hash key"], + ["custom", "Custom Hash Key"], ["md5", "MD5"], ["sha-1", "SHA-1"], ["sha-256", "SHA-256"], @@ -675,7 +674,7 @@ const config: AppConfiguration = { type: PropertyType.List, form: { type: PropertyType.String }, value: [ - ["custom", "Custom hash key"], + ["custom", "Custom Hash Key"], ["md5", "MD5"], ["sha-1", "SHA-1"], ["sha-256", "SHA-256"], @@ -866,7 +865,7 @@ const config: AppConfiguration = { type: PropertyType.List, form: { type: PropertyType.String }, value: [ - ["custom", "Custom hash key"], + ["custom", "Custom Hash Key"], ["md5", "MD5"], ["sha-1", "SHA-1"], ["sha-256", "SHA-256"], From 906355d035a56b62031cb6dcf00c006d91ed08d6 Mon Sep 17 00:00:00 2001 From: tlee Date: Wed, 9 Aug 2023 01:35:11 -0400 Subject: [PATCH 3/4] Added validation for hash to disallow erronous publishing --- .../src/assets/builder.config.publisher.ts | 2 - .../src/assets/builder.config.validator.ts | 51 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/attack_flow_builder/src/assets/builder.config.publisher.ts b/src/attack_flow_builder/src/assets/builder.config.publisher.ts index e0bfb335..07d43a77 100644 --- a/src/attack_flow_builder/src/assets/builder.config.publisher.ts +++ b/src/attack_flow_builder/src/assets/builder.config.publisher.ts @@ -306,8 +306,6 @@ class AttackFlowPublisher extends DiagramPublisher { * The list property. */ private mergeComplexListProperty(node: Sdo, key: string, property: ListProperty) { - // Check if node[key] has any values first - switch(key) { case "hashes": let hashList = []; diff --git a/src/attack_flow_builder/src/assets/builder.config.validator.ts b/src/attack_flow_builder/src/assets/builder.config.validator.ts index a521be21..d9c2d40a 100644 --- a/src/attack_flow_builder/src/assets/builder.config.validator.ts +++ b/src/attack_flow_builder/src/assets/builder.config.validator.ts @@ -7,6 +7,7 @@ import { ListProperty, Property, PropertyType, + RawEntries, SemanticAnalyzer } from "./scripts/BlockDiagram"; @@ -151,11 +152,25 @@ class AttackFlowValidator extends DiagramValidator { } // Validate links switch(node.template.id) { + case "artifact": { + const hashes = node.props.value.get("hashes"); + if(hashes?.isDefined()) { + this.validateHash(id, hashes as ListProperty); + } + break; + } case "email_address": // Additional validation for email addresses if (!AttackFlowValidator.Emailregex.test(String(node.props.value.get("value")))) { this.addError(id, "Invalid email address.") } break; + case "file": { + const hashes = node.props.value.get("hashes"); + if(hashes?.isDefined()) { + this.validateHash(id, hashes as ListProperty); + } + break; + } case "grouping": if(node.next.length === 0) { this.addError(id, "A Grouping must point to at least one object."); @@ -208,6 +223,13 @@ class AttackFlowValidator extends DiagramValidator { this.addError(id, "Invalid Windows registry key."); } break; + case "x509_certificate": { + const hashes = node.props.value.get("hashes"); + if(hashes?.isDefined()) { + this.validateHash(id, hashes as ListProperty); + } + break; + } } } @@ -283,6 +305,35 @@ class AttackFlowValidator extends DiagramValidator { } } + /** + * Validate a hash from any hash-containing node. + * + * Reference: https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html#_odoabbtwuxyd + * + * @param id + * The node's id. + * @param hashes + * The list of hashes to validate. + */ + protected validateHash(id: string, hashes: ListProperty) { + const validKey = /^[a-zA-Z0-9_-]{3,250}$/; + for(let hash of hashes.value.values()) { + if(!hash.isDefined()) { + this.addError(id, "Hash Value cannot be empty."); + } + // Make sure hash_type is not empty. + let entries = hash.toRawValue()! as RawEntries; + if(!Object.fromEntries(entries).hash_type) { + this.addError(id, "Hash Type cannot be left empty."); + } + + let key = hash.toString(); + if (!validKey.test(key)) { + this.addError(id, "Invalid hash key."); + } + } + } + /** * Validates the links to/from a network-traffic node. * From 611786520a6c905a9f5f6a4967c0d1e3e676b4e2 Mon Sep 17 00:00:00 2001 From: Tiffany Lee Date: Sat, 19 Aug 2023 16:11:44 -0400 Subject: [PATCH 4/4] Allowed compatibility with older AFB files, which is what caused the build to break. --- .../src/assets/builder.config.validator.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/attack_flow_builder/src/assets/builder.config.validator.ts b/src/attack_flow_builder/src/assets/builder.config.validator.ts index 561c3f0f..816d6aff 100644 --- a/src/attack_flow_builder/src/assets/builder.config.validator.ts +++ b/src/attack_flow_builder/src/assets/builder.config.validator.ts @@ -331,17 +331,25 @@ class AttackFlowValidator extends DiagramValidator { */ protected validateHash(id: string, hashes: ListProperty) { const validKey = /^[a-zA-Z0-9_-]{3,250}$/; - for(let hash of hashes.value.values()) { - if(!hash.isDefined()) { + const hashDictionaryProps = hashes.value; + + if(!hashDictionaryProps) { + // This is an older AFB file that does not have the Hash property updated to current version. + this.addWarning(id, "This AFB is outdated, please remake it in a new file."); + return; + } + + for(let hashDictionary of hashDictionaryProps.values()) { + if(!hashDictionary.isDefined()) { this.addError(id, "Hash Value cannot be empty."); } // Make sure hash_type is not empty. - let entries = hash.toRawValue()! as RawEntries; + let entries = hashDictionary.toRawValue()! as RawEntries; if(!Object.fromEntries(entries).hash_type) { this.addError(id, "Hash Type cannot be left empty."); } - let key = hash.toString(); + let key = hashDictionary.toString(); if (!validKey.test(key)) { this.addError(id, "Invalid hash key."); }