attack

MITRE ATT&CK Enterprise at your fingertips: look up a technique by id (attack.technique("T1110")), search by words, list a tactic's techniques, and map detect alerts to techniques through their Sigma tags (attack.t1110.001). TB bundles the official Enterprise dataset from MITRE, made compact: ids, names, tactics, platforms, the first sentence of each description, mitigations and groups. attack.info() tells which ATT&CK version it is; attack.load(path) switches to another enterprise-attack.json. ATT&CK is (c) The MITRE Corporation, used under its terms of use; attack.info().copyright has the notice.

import attack

Example

import attack

let t = attack.technique("T1110.003")
say(f"{t.id} {t.full_name} ({t.tactics.join(', ')})")
say(t.url)

for found in attack.search("kerberos", 3) {
  say(f"{found.id}  {found.full_name}")
}

# Alerts carry Sigma tags like attack.t1110.001; map() groups them by tactic.
let alerts = [{"rule": "SSH brute force", "level": "high", "tags": ["attack.t1110.001"]}]
for tactic in attack.map(alerts).tactics {
  say(f"{tactic.name}: {tactic.techniques}")
}
say(attack.info().snapshot)

Functions

technique(id)

returns map

One technique or sub-technique: {"id", "name", "full_name", "tactics", "platforms", "description", "url", "sub_techniques" (or "parent" and "parent_name"), "mitigations" and "groups" (lists of {"id", "name"})}. id can be "T1110", "t1110.001" or a Sigma tag like "attack.t1110.001". Gives nil when the id isn't in the table.

Visualizehow attack.technique works

attack.technique("T1110.001") gives {"id": "T1110.001", "name": "Password Guessing", "tactics": ["credential-access"], "platf…

attack.technique: inputs flowing into the function and the resultidT1110.001the ATT&CK table201 techniques, 423 sub-techniquesattack.techniqueresult · mapid"T1110.001"full_name"Brute Force: Password Guessing"tactics["credential-access"]parent"T1110"url"https://attack.mitre.org/techniq…idattack.t1059.001the ATT&CK table201 techniques, 423 sub-techniquesattack.techniqueresult · mapid"T1059.001"full_name"Command and Scripting Interprete…tactics["execution"]parent"T1059"url"https://attack.mitre.org/techniq…idT9999the ATT&CK table201 techniques, 423 sub-techniquesattack.techniqueresult · mapnil

Real result: worked out by running this example with TB while the site was built.

tactic(name, platform?)

returns list

The techniques (without sub-techniques) under a tactic.

name can be:

  • the short name, like "credential-access".
  • the Sigma tag spelling, like "credential_access".
  • the display name, like "Credential Access".
  • the id, like "TA0006".

ATT&CK v19 split Defense Evasion into stealth (TA0005) and defense-impairment (TA0112). The old name defense-evasion (and Sigma's attack.defense_evasion tag) means both.

platform ("Windows", "Linux", "macOS", "IaaS"...) keeps only the techniques for it.

Example

let found = attack.tactic("credential-access", "Linux")
say(found[0].name)
Visualizehow attack.tactic works

attack.tactic("credential-access", "Linux").map(t => t.id + " " + t.name) gives ["T1003 OS Credential Dumping", "T1040 Network Sniffing", "T1056 Input Capture", "T1110 B…

Drawing…

Real result: worked out by running this example with TB while the site was built.

tactics()

returns list

The Enterprise tactics in kill-chain order (reconnaissance first, impact last): [{"id": "TA0043", "shortname": "reconnaissance", "name", "description"}, ...].

Visualizehow attack.tactics works

attack.tactics().map(t => t.shortname) gives ["reconnaissance", "resource-development", "initial-access", "execution", "persistence", …

attack.tactics: inputs flowing into the function and the resultattack.tacticsresult · the 14 tactics in kill-chain order (short names shown)"reconnaissance""resource-development""initial-access""execution""persistence""privilege-escalation""stealth""defense-impairment""credential-access""discovery""lateral-movement""collection""command-and-control""exfiltration"+1 more

No inputs: call it as it is.

Real result: worked out by running this example with TB while the site was built.

techniques(all?)

returns list

Every top-level technique in the table, by id. attack.techniques(true) includes sub-techniques too.

Visualizehow attack.techniques works

attack.techniques(false).len() gives 227

attack.techniques: inputs flowing into the function and the resultall?falseattack.techniquesresult · how many techniques the list holds227all?trueattack.techniquesresult · how many techniques the list holds706

Real result: worked out by running this example with TB while the site was built.

map(alerts)

returns map

Which ATT&CK techniques and tactics a list of alerts (from detect.run()) or rules points at. It reads their tags, like attack.t1110.001 and attack.credential_access.

Returns a map

  • "techniques" a list of {"id", "name", "tactics", "url", "count", "rules"}, most alerts first.
  • "tactics" a list of {"tactic", "name", "id", "count", "techniques"}, in kill-chain order.
  • "unmapped" alerts without ATT&CK tags.
  • "unknown" technique ids the table doesn't have.
Visualizehow attack.map works

attack.map(alerts) gives {"techniques": [{"id": "T1110.001", "name": "Brute Force: Password Guessing", "tactics": …

attack.map: inputs flowing into the function and the resultalertsSSH Brute Force (Sigma) alerttags: attack.t1110.001attack.mapresult · techniques and tactics hittechniques[list of 1]0{map}id"T1110.001"name"Brute Force: Password Guessing"tactics["credential-access"]url"https://attack.mitre.org/technique…count1rules["SSH Brute Force From One Addres…tactics[list of 1]0{map}tactic"credential-access"

Real result: worked out by running this example with TB while the site was built.

tags(alert)

returns list

The technique ids an alert, rule or list of tags points at: ["T1110.001"]. Tactic tags are left out.

Visualizehow attack.tags works

attack.tags({"rule": "SSH brute force", "tags": ["attack.credential_access", "attack.t1110.001"]}) gives ["T1110.001"]

attack.tags: inputs flowing into the function and the resultalertrule"SSH brute force"tags["attack.credential_access", "attack.t…attack.tagsresult · technique ids (tactic tags left out)"T1110.001"

Real result: worked out by running this example with TB while the site was built.

tag(id)

returns text

The Sigma tag for a technique id: attack.tag("T1110.001") is "attack.t1110.001".

Visualizehow attack.tag works

attack.tag("T1110.001") gives "attack.t1110.001"

attack.tag: inputs flowing into the function and the resultidT1110.001attack.tagresult · text"attack.t1110.001"idT1059attack.tagresult · text"attack.t1059"

Real result: worked out by running this example with TB while the site was built.

url(id)

returns text

The technique's page on attack.mitre.org: "https://attack.mitre.org/techniques/T1110/001/".

Visualizehow attack.url works

attack.url("T1110.001") gives "https://attack.mitre.org/techniques/T1110/001/"

attack.url: inputs flowing into the function and the resultidT1110.001attack.urlresult · texthttps://attack.mitre.org/techniques/T1110/001/

Real result: worked out by running this example with TB while the site was built.

load(path)

returns number

Use a different ATT&CK table for the rest of the program: the official enterprise-attack.json (a STIX bundle from MITRE's attack-stix-data repository) or a file written by attack.save(). Revoked and deprecated techniques are skipped. Gives back how many techniques were loaded.

Visualizehow attack.load works

attack.load("attack-table.json") gives 706

attack.load: inputs flowing into the function and the resultpathenterprise-attack.json from MITRE,or a file from attack.save()attack.loadresult · how many techniques were loaded706

Real result: worked out by running this example with TB while the site was built.

save(path)

returns nil

Write the table in use as TB's compact JSON format (handy after attack.load() of the big official file).

Visualizehow attack.save works

attack.save("attack-table.json") gives nil

attack.save: inputs flowing into the function and the resultthe table in usebundled, or from attack.load()attack.savepathattack-table.jsonresult · nil: the file is writtennil

Real result: worked out by running this example with TB while the site was built.

info()

returns map

About the table in use.

Fields

  • version the ATT&CK release, like "18.0" (nil if the file doesn't say).
  • modified when MITRE last changed that release.
  • snapshot a label, like "official ATT&CK v18.0".
  • source "bundled" or the path given to attack.load().
  • techniques, sub_techniques, tactics, mitigations, groups how many.
  • copyright MITRE's notice for the data.
Visualizehow attack.info works

attack.info() gives {"version": "20.0", "modified": "2026-10-13T17:53:10.145Z", "snapshot": "official ATT&CK …

attack.info: inputs flowing into the function and the resultattack.inforesult · about the table in useversion"20.0"modified"2026-10-13T17:53:10.145Z"snapshot"official ATT&CK v20.0"source"bundled"techniques227sub_techniques479tactics15… 3 more keys

No inputs: call it as it is.

Real result: worked out by running this example with TB while the site was built.