From e7a887b342488dc74d86c8dd01d5844668c38f21 Mon Sep 17 00:00:00 2001 From: Sami Mokaddem Date: Fri, 18 Sep 2026 09:03:02 +0200 Subject: [PATCH 1/2] new: [reputation, page-capture, breach] Add three generic object templates Three answers that free sources already produce had no shape to be returned in, so modules returning them fell back to free text: - reputation: a verdict (classification and/or score) from a source that does not warrant a template of its own - blocklists, DNSBLs, scam lists - and a place for vendors to state a verdict beside their own richer object. Generic counterpart to abuseipdb, greynoise-ip, crowdsec-ip-context and virustotal-report. - page-capture: a copy of a page as it was when fetched, with the date the capture was taken. Complements image (a screenshot, no date) and domain-crawled (the URLs a crawl found, not what they returned). - breach: the named incident itself, so an address or account found in a breach references it rather than restating it. credential holds what was exposed; ail-leak holds a leak as one analysis framework saw it. sane_default is set on the fields that have a real vocabulary, as suggestions rather than constraints: breach/data-classes (the HIBP vocabulary the description quotes, and the field an analyst filters on), breach/source and reputation/source (both correlate, so two emitters spelling one service differently would split the correlation), and the breach/verified and breach/sensitive booleans, as verified does in parler-account, twitter-account and github-user. reputation/list-name is left open, since seeding it with DNSBL zones would over-fit a generic field, and no page-capture field is enumerable. No existing template is touched and no schema change is required: every misp-attribute type used is already in the schema_objects.json enum. Co-Authored-By: Claude Opus 5 (1M context) --- objects/breach/definition.json | 119 +++++++++++++++++++++++++++ objects/page-capture/definition.json | 60 ++++++++++++++ objects/reputation/definition.json | 75 +++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 objects/breach/definition.json create mode 100644 objects/page-capture/definition.json create mode 100644 objects/reputation/definition.json diff --git a/objects/breach/definition.json b/objects/breach/definition.json new file mode 100644 index 00000000..3c59069f --- /dev/null +++ b/objects/breach/definition.json @@ -0,0 +1,119 @@ +{ + "attributes": { + "added-date": { + "description": "When the breach was added to the notification service - not when it happened", + "disable_correlation": true, + "misp-attribute": "datetime", + "ui-priority": 0 + }, + "breach-date": { + "description": "When the breach occurred, as far as the service knows", + "disable_correlation": true, + "misp-attribute": "datetime", + "ui-priority": 1 + }, + "data-classes": { + "description": "A class of data exposed by the breach (e.g. `Email addresses`, `Passwords`, `Phone numbers`). One attribute per class", + "misp-attribute": "text", + "multiple": true, + "sane_default": [ + "Email addresses", + "Passwords", + "Usernames", + "Names", + "IP addresses", + "Phone numbers", + "Physical addresses", + "Dates of birth", + "Genders", + "Geographic locations", + "Job titles", + "Employers", + "Social media profiles", + "Website activity", + "Password hints", + "Security questions and answers", + "Partial credit card data", + "Credit cards", + "Browser user agent details", + "Device information" + ], + "ui-priority": 1 + }, + "description": { + "description": "The service's own description of the breach", + "disable_correlation": true, + "misp-attribute": "text", + "ui-priority": 0 + }, + "domain": { + "description": "Domain of the breached service", + "misp-attribute": "domain", + "ui-priority": 1 + }, + "link": { + "description": "Link to the service's page for this breach", + "misp-attribute": "link", + "ui-priority": 0 + }, + "modification-date": { + "description": "When the service last changed its record of the breach", + "disable_correlation": true, + "misp-attribute": "datetime", + "ui-priority": 0 + }, + "name": { + "description": "The breach as the service names it, stable across its API", + "misp-attribute": "text", + "ui-priority": 1 + }, + "pwn-count": { + "description": "How many accounts the breach exposed", + "disable_correlation": true, + "misp-attribute": "counter", + "ui-priority": 1 + }, + "sensitive": { + "description": "Whether the service treats the breach as sensitive, meaning membership is not publicly searchable", + "misp-attribute": "boolean", + "sane_default": [ + "True", + "False" + ], + "ui-priority": 0 + }, + "source": { + "description": "The breach notification service the record came from", + "misp-attribute": "text", + "sane_default": [ + "Have I Been Pwned", + "XposedOrNot", + "LeakCheck", + "DeHashed" + ], + "ui-priority": 1 + }, + "title": { + "description": "Display name of the breach, where the service gives one distinct from `name`", + "misp-attribute": "text", + "ui-priority": 0 + }, + "verified": { + "description": "Whether the service considers the breach verified rather than claimed", + "misp-attribute": "boolean", + "sane_default": [ + "True", + "False" + ], + "ui-priority": 0 + } + }, + "description": "A data breach in which accounts or personal data were exposed, as published by a breach notification service. Describes the breach itself, so that an address or account found in one links to the breach rather than restating it; `credential` holds what was exposed and `ail-leak` holds a leak as an analysis framework saw it.", + "meta-category": "misc", + "name": "breach", + "required": [ + "name" + ], + "uuid": "9a73cc75-6e1a-41dc-8a71-6f24e4db1f2d", + "version": 1 +} \ No newline at end of file diff --git a/objects/page-capture/definition.json b/objects/page-capture/definition.json new file mode 100644 index 00000000..160041d6 --- /dev/null +++ b/objects/page-capture/definition.json @@ -0,0 +1,60 @@ +{ + "attributes": { + "archive": { + "description": "Link to an archived copy of the page held elsewhere", + "misp-attribute": "link", + "multiple": true, + "ui-priority": 1 + }, + "attachment": { + "description": "The captured page itself, stored as an attachment", + "misp-attribute": "attachment", + "ui-priority": 1 + }, + "capture-date": { + "description": "When the capture was taken. Distinct from the date the object was created: a capture fetched from an archive can be years older", + "disable_correlation": true, + "misp-attribute": "datetime", + "ui-priority": 1 + }, + "domain": { + "description": "Domain the page was served from", + "misp-attribute": "domain", + "ui-priority": 0 + }, + "filename": { + "description": "Filename of the stored capture", + "misp-attribute": "filename", + "ui-priority": 0 + }, + "link": { + "description": "Link to the capture as the capturing service publishes it", + "misp-attribute": "link", + "ui-priority": 1 + }, + "text": { + "description": "Text extracted from the captured page", + "disable_correlation": true, + "misp-attribute": "text", + "ui-priority": 0 + }, + "url": { + "description": "URL that was fetched", + "misp-attribute": "url", + "ui-priority": 1 + } + }, + "description": "A copy of a page as it was when somebody fetched it: the stored bytes, the text extracted from them, or a link to an archived copy, with the date the capture was taken. Complements `image`, which holds a screenshot and no date, and `domain-crawled`, which holds the URLs a crawl found and not what they returned.", + "meta-category": "network", + "name": "page-capture", + "required": [ + "url" + ], + "requiredOneOf": [ + "attachment", + "archive", + "text" + ], + "uuid": "555f0d10-5df6-4e04-bf8a-145156d37ab6", + "version": 1 +} \ No newline at end of file diff --git a/objects/reputation/definition.json b/objects/reputation/definition.json new file mode 100644 index 00000000..a3c42e18 --- /dev/null +++ b/objects/reputation/definition.json @@ -0,0 +1,75 @@ +{ + "attributes": { + "classification": { + "description": "The verdict the source gives, in its own word. `malicious`, `suspicious` and `benign` are the words MISP reads as a verdict; anything else, including `unknown`, is recorded as the source said it and read as no opinion.", + "misp-attribute": "text", + "sane_default": [ + "malicious", + "suspicious", + "benign", + "safe", + "known", + "legitimate", + "unknown" + ], + "ui-priority": 1 + }, + "first-seen": { + "description": "First time the source saw the value on this list, or first observation behind the verdict", + "disable_correlation": true, + "misp-attribute": "datetime", + "ui-priority": 0 + }, + "last-seen": { + "description": "Last time the source saw the value on this list, or most recent observation behind the verdict", + "disable_correlation": true, + "misp-attribute": "datetime", + "ui-priority": 0 + }, + "link": { + "description": "Link to the source's own report for this value", + "misp-attribute": "link", + "ui-priority": 1 + }, + "list-name": { + "description": "The specific list or zone the value was found on, where the source publishes more than one (e.g. a DNSBL zone)", + "misp-attribute": "text", + "ui-priority": 1 + }, + "score": { + "description": "How sure the source is, on its own scale. State the scale in `text` where it is not 0-100", + "disable_correlation": true, + "misp-attribute": "float", + "ui-priority": 1 + }, + "source": { + "description": "The service or list that gave the verdict", + "misp-attribute": "text", + "sane_default": [ + "AbuseIPDB", + "GreyNoise", + "CrowdSec", + "VirusTotal", + "Google Threat Intelligence", + "Spamhaus", + "SpamCop" + ], + "ui-priority": 1 + }, + "text": { + "description": "Anything the source said that the fields above do not hold, including the scale a non-standard score is on", + "disable_correlation": true, + "misp-attribute": "text", + "ui-priority": 0 + } + }, + "description": "What an outside source thinks of a value: a classification, a score, or both. The generic counterpart to the vendor verdict objects (abuseipdb, greynoise-ip, crowdsec-ip-context, virustotal-report), for the sources that do not warrant a template of their own - blocklists, DNSBLs, scam lists - and a place for vendors to state a verdict beside their own richer object.", + "meta-category": "misc", + "name": "reputation", + "requiredOneOf": [ + "classification", + "score" + ], + "uuid": "0a606d84-87ea-4a92-9bdb-528f899ff531", + "version": 1 +} \ No newline at end of file From 5bf7606dad78aba6d05afb0fa6ca475e908c0f67 Mon Sep 17 00:00:00 2001 From: Sami Mokaddem Date: Fri, 18 Sep 2026 09:59:04 +0200 Subject: [PATCH 2/2] chg: [btc-transaction, exploit] relations for what modules actually hold Two templates turned out not to fit answers an expansion module already has in hand, found while converting misp-modules to return objects. btc-transaction/btc-address becomes multiple, and stops disabling correlation. A transaction has counterparties as well as the wallet being described, and blockchain.info returns both; with a single address relation they had nowhere to go and were dropped. A counterparty you cannot pivot from is most of the reason to record one, so the field now correlates - note this changes how btc-transaction objects already in an instance behave. exploit gains title and reference in requiredOneOf. A source such as Vulners lists exploits it knows of by title and link without always carrying the source, so an object holding exactly what is known could not satisfy exploit / filename / exploit-as-attachment. Co-Authored-By: Claude Opus 5 (1M context) --- objects/btc-transaction/definition.json | 6 +++--- objects/exploit/definition.json | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/objects/btc-transaction/definition.json b/objects/btc-transaction/definition.json index 0b5dcd5b..4dc92a67 100644 --- a/objects/btc-transaction/definition.json +++ b/objects/btc-transaction/definition.json @@ -1,9 +1,9 @@ { "attributes": { "btc-address": { - "description": "A Bitcoin transactional address", - "disable_correlation": true, + "description": "A Bitcoin address taking part in the transaction: the wallet the object describes, and the counterparties it exchanged value with", "misp-attribute": "btc", + "multiple": true, "ui-priority": 0 }, "time": { @@ -47,5 +47,5 @@ "value_BTC" ], "uuid": "B7341729-5A8A-439F-A775-6D814DA3C7B5", - "version": 4 + "version": 5 } \ No newline at end of file diff --git a/objects/exploit/definition.json b/objects/exploit/definition.json index 5ad10281..fa0833f7 100644 --- a/objects/exploit/definition.json +++ b/objects/exploit/definition.json @@ -99,8 +99,10 @@ "requiredOneOf": [ "exploit", "filename", - "exploit-as-attachment" + "exploit-as-attachment", + "title", + "reference" ], "uuid": "611a25d5-d8aa-4dde-b9c8-c084e786ebf3", - "version": 1 + "version": 2 } \ No newline at end of file