ioc

Indicators of compromise (IOCs): pull IPs, domains, URLs, emails, file hashes and CVE IDs out of any text, check what something is, and defang them (1.2.3[.]4, hxxp://) so nobody clicks a bad link by accident.

import ioc

Example

import fs
import ioc

let email = fs.read("apps/data/phishing_email.txt")
let found = ioc.extract(email)
say("Domains:", found.domains)
say("IPs:", found.ips)
say("URLs:", found.urls.map(fn(u) { return ioc.defang(u) }))
say(ioc.kind("44d88612fea8a8f36de82e1278abb02f"), ioc.is_ip("10.0.0.300"))

Functions

extract(text, options?)

returns map

Find every IOC in text: {"ips", "domains", "urls", "emails", "md5", "sha1", "sha256", "cves"}, each a list without repeats, in the order they first appear. Defanged IOCs (hxxp://, [.], (.), [@]) are found too and given back refanged; pass {"refang": false} to skip that. File names like report.pdf are not counted as domains. Domains and IPs inside URLs and emails are listed as well. Email addresses keep the case of the part before @. Message-ID / References header values are not counted as emails.

rows(found)

returns list

Turn the map from extract() (or the text itself) into a list of {"type", "value"} maps, one per IOC, ready for report.table().

defang(text)

returns text

Make the IOCs in text safe to share: http becomes hxxp, dots in hosts become [.], colons in IPv6 addresses become [:] and @ in emails becomes [@]. Everything else in the text stays the same. refang() undoes it.

refang(text)

returns text

Undo defanging: hxxp:// and hxxps:// become http(s)://, [.] (.) {.} [dot] become dots, [@] [at] become @, and [:] becomes a colon.

is_ip(text)

returns bool

True for a valid IPv4 (each part 0-255) or IPv6 address. Defanged ones count.

is_domain(text)

returns bool

True for a domain name with a real-looking ending, like evil.example.com. "report.pdf" is a file, so it is false.

is_hash(text)

returns bool

True for an MD5, SHA-1, SHA-256 or SHA-512 hash (hex of the right length).

kind(text)

returns text or nil

What an IOC is: "ip", "url", "email", "md5", "sha1", "sha256", "sha512", "cve" or "domain". nil if it's none of them.