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 mapOne 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("attack.t1059.001") gives {"id": "T1059.001", "name": "PowerShell", "tactics": ["execution"], "platforms": ["Window…attack.technique("T9999") gives nil
Real result: worked out by running this example with TB while the site was built.
search(words, limit?)
returns listTechniques whose id, name or description contain every word (case doesn't matter), best matches first: name matches before description matches. attack.search("brute") finds Brute Force and its sub-techniques.
Visualizehow attack.search works
attack.search("brute", 3) gives [{"id": "T1110", "name": "Brute Force", "tactics": ["credential-access"], "platforms": ["…attack.search("powershell", 3) gives [{"id": "T1059.001", "name": "PowerShell", "tactics": ["execution"], "platforms": ["Windo…attack.search("credential dump", 3) gives [{"id": "T1003", "name": "OS Credential Dumping", "tactics": ["credential-access"], "plat…
Real result: worked out by running this example with TB while the site was built.
tactic(name, platform?)
returns listThe 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…attack.tactic("credential-access", "Windows").map(t => t.id + " " + t.name) gives ["T1003 OS Credential Dumping", "T1040 Network Sniffing", "T1056 Input Capture", "T1110 B…attack.tactic("credential-access", "IaaS").map(t => t.id + " " + t.name) gives ["T1040 Network Sniffing", "T1110 Brute Force", "T1528 Steal Application Access Token", "…
Drawing…
Real result: worked out by running this example with TB while the site was built.
tactics()
returns listThe 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", …
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 listEvery top-level technique in the table, by id. attack.techniques(true) includes sub-techniques too.
Visualizehow attack.techniques works
attack.techniques(false).len() gives 227attack.techniques(true).len() gives 706
Real result: worked out by running this example with TB while the site was built.
map(alerts)
returns mapWhich 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": …
Real result: worked out by running this example with TB while the site was built.
tags(alert)
returns listThe 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"]
Real result: worked out by running this example with TB while the site was built.
tag(id)
returns textThe 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("T1059") gives "attack.t1059"
Real result: worked out by running this example with TB while the site was built.
url(id)
returns textThe 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/"
Real result: worked out by running this example with TB while the site was built.
load(path)
returns numberUse 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
Real result: worked out by running this example with TB while the site was built.
save(path)
returns nilWrite 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
Real result: worked out by running this example with TB while the site was built.
info()
returns mapAbout the table in use.
Fields
versionthe ATT&CK release, like "18.0" (nil if the file doesn't say).modifiedwhen MITRE last changed that release.snapshota label, like "official ATT&CK v18.0".source"bundled" or the path given to attack.load().techniques, sub_techniques, tactics, mitigations, groupshow many.copyrightMITRE'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 …
No inputs: call it as it is.
Real result: worked out by running this example with TB while the site was built.