Skip to content

Commit

Permalink
Merge pull request #96 from center-for-threat-informed-defense/af176-…
Browse files Browse the repository at this point in the history
…hashes

AF-176: Hashes
  • Loading branch information
mikecarenzo committed Aug 23, 2023
2 parents 9dbc195 + 79808b4 commit f7debc3
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 3 deletions.
33 changes: 33 additions & 0 deletions src/attack_flow_builder/src/assets/builder.config.publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -296,6 +300,35 @@ 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) {
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 //////////////////////////////////////////
Expand Down
81 changes: 78 additions & 3 deletions src/attack_flow_builder/src/assets/builder.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,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 },
},
Expand Down Expand Up @@ -638,7 +663,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 },
Expand Down Expand Up @@ -804,7 +854,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 },
Expand Down
55 changes: 55 additions & 0 deletions src/attack_flow_builder/src/assets/builder.config.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ListProperty,
Property,
PropertyType,
RawEntries,
SemanticAnalyzer
} from "./scripts/BlockDiagram";

Expand Down Expand Up @@ -153,6 +154,13 @@ 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.")
Expand All @@ -164,6 +172,9 @@ class AttackFlowValidator extends DiagramValidator {
if(!hash?.isDefined() && !name?.isDefined()) {
this.addError(id, "File requires one of the following properties: Hashes, Name");
}
if(hashes?.isDefined()) {
this.validateHash(id, hashes as ListProperty);
}
break;
case "grouping":
if(node.next.length === 0) {
Expand Down Expand Up @@ -229,6 +240,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;
}
}
}

Expand Down Expand Up @@ -304,6 +322,43 @@ 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}$/;
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 = hashDictionary.toRawValue()! as RawEntries;
if(!Object.fromEntries(entries).hash_type) {
this.addError(id, "Hash Type cannot be left empty.");
}

let key = hashDictionary.toString();
if (!validKey.test(key)) {
this.addError(id, "Invalid hash key.");
}
}
}

/**
* Validates the links to/from a network-traffic node.
*
Expand Down

0 comments on commit f7debc3

Please sign in to comment.