Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AF-176: Hashes #96

Merged
merged 6 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading