UNPKG

@mitre-attack/attack-data-model

Version:

A TypeScript API for the MITRE ATT&CK data model

345 lines (339 loc) 14 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/schemas/common/common-properties.ts var common_properties_exports = {}; __export(common_properties_exports, { aliasesSchema: () => aliasesSchema, attackDomainSchema: () => attackDomainSchema, createOldMitreAttackIdSchema: () => createOldMitreAttackIdSchema, descriptionSchema: () => descriptionSchema, killChainNameSchema: () => killChainNameSchema, killChainPhaseSchema: () => killChainPhaseSchema, nameSchema: () => nameSchema, objectMarkingRefsSchema: () => objectMarkingRefsSchema, versionSchema: () => versionSchema, xMitreAttackSpecVersionSchema: () => xMitreAttackSpecVersionSchema, xMitreContributorsSchema: () => xMitreContributorsSchema, xMitreDeprecatedSchema: () => xMitreDeprecatedSchema, xMitreDomainsSchema: () => xMitreDomainsSchema, xMitreIdentity: () => xMitreIdentity, xMitreModifiedByRefSchema: () => xMitreModifiedByRefSchema, xMitreOldAttackIdSchema: () => xMitreOldAttackIdSchema, xMitrePlatformsSchema: () => xMitrePlatformsSchema, xMitreVersionSchema: () => xMitreVersionSchema }); module.exports = __toCommonJS(common_properties_exports); var import_zod3 = require("zod"); // src/schemas/common/stix-identifier.ts var import_zod2 = require("zod"); // src/schemas/common/stix-type.ts var import_zod = require("zod"); var stixTypeToTypeName = { "attack-pattern": "Technique", bundle: "StixBundle", campaign: "Campaign", "course-of-action": "Mitigation", identity: "Identity", "intrusion-set": "Group", malware: "Malware", tool: "Tool", "marking-definition": "MarkingDefinition", "x-mitre-data-component": "DataComponent", "x-mitre-data-source": "DataSource", "x-mitre-tactic": "Tactic", "x-mitre-asset": "Asset", "x-mitre-matrix": "Matrix", "x-mitre-collection": "Collection", relationship: "Relationship", file: "", // not used in ATT&CK but used in sample_refs for Malware artifact: "" // not used in ATT&CK but used in sample_refs for Malware // 'observed-data': 'ObservedData', // not used in ATT&CK // 'report': 'Report', // not used in ATT&CK // 'threat-actor': 'ThreatActor', // not used in ATT&CK // 'vulnerability': 'Vulnerability', // not used in ATT&CK }; var supportedStixTypes = [ "attack-pattern", "bundle", "campaign", "course-of-action", "identity", "intrusion-set", "malware", "tool", "marking-definition", "x-mitre-data-component", "x-mitre-data-source", "x-mitre-tactic", "x-mitre-asset", "x-mitre-matrix", "x-mitre-collection", "relationship", "file", // not used in ATT&CK but used in sample_refs for Malware "artifact" // not used in ATT&CK but used in sample_refs for Malware // "indicator", // not used in ATT&CK // "observed-data", // not used in ATT&CK // "report", // not used in ATT&CK // "threat-actor", // not used in ATT&CK // "vulnerability", // not used in ATT&CK ]; var stixTypeSchema = import_zod.z.enum(supportedStixTypes, { errorMap: (issue, ctx) => { if (issue.code === "invalid_enum_value") { const received = typeof ctx.data === "string" ? ctx.data : String(ctx.data); return { message: `Invalid STIX type '${received}'. Expected one of the supported STIX types.` }; } return { message: ctx.defaultError }; } }).describe( "The type property identifies the type of STIX Object (SDO, Relationship Object, etc). The value of the type field MUST be one of the types defined by a STIX Object (e.g., indicator)." ); // src/schemas/common/stix-identifier.ts var isValidUuid = (uuid) => { return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid); }; var createStixIdError = (id, errorType) => { const parts = id.split("--"); const stixType = parts.length > 0 ? parts[0] : ""; const typeName = stixType in stixTypeToTypeName ? stixTypeToTypeName[stixType] : "STIX"; let message; switch (errorType) { case "format": message = `Invalid STIX Identifier for ${typeName} object: must comply with format 'type--UUIDv4'`; break; case "type": message = `Invalid STIX Identifier for ${typeName} object: contains invalid STIX type '${stixType}'`; break; case "uuid": message = `Invalid STIX Identifier for ${typeName} object: contains invalid UUIDv4 format`; break; } return { code: import_zod2.z.ZodIssueCode.custom, message, path: ["id"] }; }; var stixIdentifierSchema = import_zod2.z.string().refine( (val) => { if (typeof val !== "string") return false; if (!val.includes("--")) return false; const [type, uuid] = val.split("--"); const isValidType = stixTypeSchema.safeParse(type).success; const isValidUuidValue = isValidUuid(uuid); return isValidType && isValidUuidValue; }, (val) => { if (typeof val !== "string") { return createStixIdError(String(val), "format"); } if (!val.includes("--")) { return createStixIdError(val, "format"); } const [type, uuid] = val.split("--"); if (!stixTypeSchema.safeParse(type).success) { return createStixIdError(val, "type"); } if (!isValidUuid(uuid)) { return createStixIdError(val, "uuid"); } return createStixIdError(val, "format"); } ).describe( "Represents identifiers across the CTI specifications. The format consists of the name of the top-level object being identified, followed by two dashes (--), followed by a UUIDv4." ); // src/schemas/common/common-properties.ts var versionSchema = import_zod3.z.string().regex(/^\d+\.\d+$/, "Version must be in the format 'major.minor'").default("2.1").describe( "Represents the version of the object in a 'major.minor' format, where both 'major' and 'minor' are integers. This versioning follows semantic versioning principles but excludes the patch number. The version number is incremented by ATT&CK when the content of the object is updated. This property does not apply to relationship objects." ); var nameSchema = import_zod3.z.string().min(1, "Name must not be empty").describe("The name of the object."); var descriptionSchema = import_zod3.z.string().describe("A description of the object."); var aliasesSchema = import_zod3.z.array(import_zod3.z.string(), { invalid_type_error: "Aliases must be an array of strings." }).describe( "Alternative names used to identify this object. The first alias must match the object's name." ); var majorMinorVersionRegex = /^(\d{1,3})\.(\d{1,3})$/; var xMitreVersionSchema = import_zod3.z.custom().refine( (value) => { if (!majorMinorVersionRegex.test(value)) return false; const [major, minor] = value.split(".").map(Number); return Number.isInteger(major) && Number.isInteger(minor) && major >= 0 && major <= 99 && minor >= 0 && minor <= 99; }, { message: "The version must be in the format 'M.N' where M and N are integers between 0 and 99" } ).describe( "Represents the version of the object in a 'major.minor' format, where both 'major' and 'minor' are integers between 0 and 99. This versioning follows semantic versioning principles but excludes the patch number. The version number is incremented by ATT&CK when the content of the object is updated. This property does not apply to relationship objects." ); var majorMinorPatchVersionRegex = /^[0-9]\.[0-9]\.[0-9]$/; var xMitreAttackSpecVersionSchema = import_zod3.z.string().refine( (value) => { if (!majorMinorPatchVersionRegex.test(value)) return false; const [major, minor, patch] = value.split(".").map(Number); return major >= 0 && major <= 9 && minor >= 0 && minor <= 9 && patch >= 0 && patch <= 9; }, { message: "Must be in the format 'M.N.P' where M, N, and P are single-digit integers (0-9)" } ).describe( "The version of the ATT&CK spec used by the object. This field helps consuming software determine if the data format is supported. If the field is not present on an object, the spec version will be assumed to be 2.0.0. Refer to the ATT&CK CHANGELOG for all supported versions." ); var oldAttackIdRegex = /^MOB-(M|S)\d{4}$/; function createOldMitreAttackIdSchema(stixType) { const baseSchema = import_zod3.z.string().describe("Old ATT&CK IDs that may have been associated with this object"); switch (stixType) { case "malware": case "tool": return baseSchema.refine( (value) => { return /^MOB-S\d{4}$/.test(value); }, { message: `x_mitre_old_attack_id for ${stixType} need to be in the format MOB-S####` } ); case "course-of-action": return baseSchema.refine( (value) => { return /^MOB-M\d{4}$/.test(value); }, { message: `x_mitre_old_attack_id for ${stixType} need to be in the format MOB-M####` } ); default: throw new Error(`Unsupported STIX type: ${stixType}`); } } var xMitreOldAttackIdSchema = import_zod3.z.string().refine( (value) => { return oldAttackIdRegex.test(value); }, { message: "Must be in the format 'MOB-X0000' where X is either 'M' or 'S', followed by exactly four digits" } ).describe("Old ATT&CK IDs that may have been associated with this object"); var attackDomainSchema = import_zod3.z.enum(["enterprise-attack", "mobile-attack", "ics-attack"]); var xMitreDomainsSchema = import_zod3.z.array(attackDomainSchema).min(1, { message: "At least one MITRE ATT&CK domain must be specified." }).describe("The technology domains to which the ATT&CK object belongs."); var xMitreDeprecatedSchema = import_zod3.z.boolean({ invalid_type_error: "x_mitre_deprecated must be a boolean." }).describe("Indicates whether the object has been deprecated."); var supportedMitrePlatforms = [ "Field Controller/RTU/PLC/IED", "Network Devices", "Data Historian", "Google Workspace", "Office Suite", "ESXi", "Identity Provider", "Containers", "Azure AD", "Engineering Workstation", "Control Server", "Human-Machine Interface", "Windows", "Linux", "IaaS", "None", "iOS", "PRE", "SaaS", "Input/Output Server", "macOS", "Android", "Safety Instrumented System/Protection Relay", "Embedded" ]; var xMitrePlatformsSchema = import_zod3.z.array(import_zod3.z.enum(supportedMitrePlatforms), { invalid_type_error: "x_mitre_platforms must be an array of strings.", message: "x_mitre_platforms may only contain values from the following list: " + supportedMitrePlatforms.join(", ") }).min(1).refine((items) => new Set(items).size === items.length, { message: "Platforms must be unique (no duplicates allowed)." }).describe("List of platforms that apply to the object."); var objectMarkingRefsSchema = import_zod3.z.array(stixIdentifierSchema).superRefine((val, ctx) => { val.forEach((identifier, index) => { if (!identifier.startsWith("marking-definition--")) { ctx.addIssue({ code: import_zod3.z.ZodIssueCode.custom, message: `All identifiers must start with 'marking-definition--'. Invalid identifier at index ${index}.`, path: [index] }); } }); }).describe("The list of marking-definition objects to be applied to this object."); var xMitreContributorsSchema = import_zod3.z.array(import_zod3.z.string()).describe( "People and organizations who have contributed to the object. Not found on relationship objects." ); var xMitreIdentity = "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5"; var xMitreModifiedByRefSchema = stixIdentifierSchema.refine((val) => val == xMitreIdentity).describe( "The STIX ID of the MITRE identity object. Used to track the identity of the MITRE organization, which created the current version of the object. Previous versions of the object may have been created by other individuals or organizations." ); var killChainNameSchema = import_zod3.z.enum([ "mitre-attack", "mitre-mobile-attack", "mitre-ics-attack" ]); var killChainPhaseSchema = import_zod3.z.object({ phase_name: import_zod3.z.string({ required_error: "Phase name is required.", invalid_type_error: "Phase name must be a string." }).describe( "The name of the phase in the kill chain. The value of this property SHOULD be all lowercase and SHOULD use hyphens instead of spaces or underscores as word separators." ).refine( (value) => { const isLowercase = value === value.toLowerCase(); const usesHyphens = !value.includes(" ") && !value.includes("_"); return isLowercase && usesHyphens; }, { message: "Phase name should be all lowercase and use hyphens instead of spaces or underscores." } ), kill_chain_name: killChainNameSchema }).strict(); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { aliasesSchema, attackDomainSchema, createOldMitreAttackIdSchema, descriptionSchema, killChainNameSchema, killChainPhaseSchema, nameSchema, objectMarkingRefsSchema, versionSchema, xMitreAttackSpecVersionSchema, xMitreContributorsSchema, xMitreDeprecatedSchema, xMitreDomainsSchema, xMitreIdentity, xMitreModifiedByRefSchema, xMitreOldAttackIdSchema, xMitrePlatformsSchema, xMitreVersionSchema });