Amass
OWASP Amass performs passive-by-default subdomain enumeration and attack-surface mapping, combining certificate transparency logs, passive DNS sources, search engines, and (optionally) active techniques like zone-transfer attempts and DNS brute-forcing. It’s typically the first name-gathering pass alongside subfinder/assetfinder in Stage 00 — Passive External Recon.
[!warning] Version note — v5 changed the CLI shape Amass v5 rewrote storage around a local graph database (the “OAM” — Open Asset Model) served by a background engine process. Older tutorials referencing
amass intel -asn,amass intel -whois, oramass enum -o results.txtare describing v3/v4 and do not apply to v5 — there is nointelsubcommand anymore; ASN/CIDR discovery moved directly intoenum, and results live in the graph DB, read back out withamass subsrather than a plain output file. Confirmed against v5.1.1 (amass -version).
Subcommands (v5)
amass enum interface with the engine that performs enumerations
amass subs analyze and present discovered subdomains and associated data
amass track diff OAM data to identify newly discovered assets since a timestamp
amass viz generate graph visualizations (DOT / GEXF) from OAM data
amass assoc query the OAM along an association "triple" walk
amass engine run/manage the collection engine that backs the OAM database
amass enum auto-starts the background engine the first time it’s needed (ps aux | grep amass will show amass engine running afterward); it stays up across invocations so repeated enum/subs calls against the same domain reuse the same graph DB. Stop it with pkill -f "amass engine" if you want a clean slate.
amass enum — the main pass
# passive is the DEFAULT in v5 — this alone is the safe, non-contact baseline
amass enum -d $DOMAIN
# multiple domains in one run
amass enum -d $DOMAIN,$DOMAIN2
# active mode: adds zone-transfer attempts + cert-name grabs against the target's own infra
amass enum -d $DOMAIN -active
# brute force on top of the passive/active sources, with a custom wordlist
amass enum -d $DOMAIN -brute -w /path/to/subdomains.txt
# ASN/CIDR-driven discovery — folded directly into `enum` in v5 (no more `intel` subcommand)
amass enum -asn 12345
amass enum -cidr 203.0.113.0/24 -d $DOMAIN
# seed the engine with names you already have (other tools' output) so they're in scope from the start
amass enum -d $DOMAIN -nf known_subs.txt
# write files out under a directory instead of just the graph DB
amass enum -d $DOMAIN -oA ./recon/amass_$DOMAIN
| Flag | Description | Default |
|---|---|---|
-d value | Domain(s), comma-separated | — |
-df file | File of domains | — |
-active | Attempt zone transfers + cert-name grabs (this is what makes a run “active”, not a -passive flag — that flag still exists but is a no-op since passive is now default) | off |
-brute | Run DNS brute forcing after the search/API sources | off |
-w file / -aw file | Wordlist for brute forcing / name alterations | — |
-alts | Generate altered/permuted names from what’s found | off |
-asn value | ASN(s), comma-separated — org-wide discovery | — |
-cidr value | CIDR(s), comma-separated | — |
-addr value | IPs/ranges (192.168.1.1-254) | — |
-p value | Ports to check when resolving | 80, 443 |
-r / -tr value | Untrusted / trusted DNS resolver IPs | system default |
-nf file | Seed the engine with already-known names (from other tools) | — |
-bl value / -blf file | Blacklist subdomains (inline / from file) | — |
-timeout N | Minutes with no progress before terminating | 30 |
-oA prefix | Path prefix for all output files | — |
-dir path | Directory holding the graph database | default state dir |
-list | (dead in v5.1.1 — does not print sources; read datasources.yaml instead) | — |
-include / -exclude value | Restrict to / drop specific data sources | all |
-v | Verbose/debug output | off |
-silent | No output during the run | off |
[!tools] Related in the same recon stage subfinder, assetfinder, and puredns (wildcard-aware resolving) — see Stage 00 for unioning all of them together. No single passive source is complete; run at least two and merge.
Config files (v5) — wiring API keys
v5 reads two YAML files from the state dir — config.yaml (scope, engine/DB, brute/alt toggles, per-asset transform TTLs) and datasources.yaml (per-source credentials). Point any subcommand at them with -config.
Linux: ~/.config/amass/{config.yaml,datasources.yaml}
macOS: ~/Library/Application Support/amass/{config.yaml,datasources.yaml}
# config.yaml (trimmed to the parts you actually touch)
scope:
domains:
- example.com # root/registered domains in scope
# ips: [ 192.0.2.1, 192.168.0.3-8 ]
# cidrs: [ 192.0.2.0/24 ]
ports: [ 80, 443, 8080, 8443 ] # ports used when probing services
# blacklist:
# - dev.example.com
options:
datasources: "./datasources.yaml" # path is relative to THIS file, not your cwd
# engine: "http://127.0.0.1:4000" # reuse/point at a specific engine
# database: "postgres://amass:amass4OWASP@assetdb:5432/assetdb" # or bolt://... (neo4j)
bruteforce:
enabled: false
wordlists: [ "./wordlists/short-wordlist.txt" ]
alterations:
enabled: false
default_transform_values:
ttl: 1440 # minutes a result is cached before re-querying
confidence: 50
priority: 5
transformations: # which asset->source expansions run, and their TTLs
FQDN->ALL:
FQDN->DomainRecord:
ttl: 43200
TLSCertificate->ALL:
ttl: 10800
# datasources.yaml — uncomment a source and drop your key in
global_options:
minimum_ttl: 1440 # floor applied when a source omits its own ttl
datasources:
- name: VirusTotal
ttl: 10080
creds:
account:
apikey: VT_API_KEY_HERE
- name: SecurityTrails
ttl: 1440
creds:
account:
apikey: ST_API_KEY_HERE
- name: Shodan
ttl: 10080
creds:
account:
apikey: SHODAN_API_KEY_HERE
- name: Chaos # ProjectDiscovery — same key subfinder uses
ttl: 4320
creds:
account:
apikey: CHAOS_API_KEY_HERE
Some sources key differently — a named account, multiple accounts, or username+secret:
- name: GitHub # keyed by a custom account name, not "account"
ttl: 4320
creds:
accountname:
apikey: ghp_xxx
- name: PassiveTotal # username + apikey (CIRCL/FOFA/Yandex/ZoomEye are similar)
creds:
account:
username: you@example.com
apikey: PT_KEY
- name: C99 # multiple keys under account1/account2
ttl: 4320
creds:
account1: { apikey: KEY1 }
account2: { apikey: KEY2 }
amass enum -config ./config.yaml -d example.com # enum uses the configured keys
amass enum -d example.com # uses the default-path config if present
amass subs -config ./config.yaml -d example.com -names # subs/track/assoc/viz also accept -config
[!tip] The
datasourcespath is resolved relative toconfig.yaml, not your shell’s cwd. Keepconfig.yaml,datasources.yaml, andwordlists/in the same directory, or use absolute paths.
[!info] The default OAM store is a local SQLite graph —
asset.db(plusasset.db-wal/asset.db-shm) in the state dir. For a shared/team graph, setoptions.databaseto a Postgres (postgres://...) or Neo4j (bolt://...) URL instead.
[!warning] Only VirusTotal, SecurityTrails, Shodan (and Chaos) are wired above because those are what v5.1.1 actually ships in
datasources.yaml. Censys is not a v5.1.1 data source — there is no stanza for it; don’t invent one. The shipped roster (VirusTotal, SecurityTrails, Shodan, Chaos, BinaryEdge, FullHunt, Netlas, LeakIX, IntelX, ZoomEye, AlienVault, HackerTarget, URLScan, WhoisXMLAPI, GitHub/GitLab, PassiveTotal, and more) is exactly the set of- name:entries in that file.
Trusted vs untrusted resolvers
# untrusted resolvers (bulk, for volume) from a file; trusted (reliable) inline
amass enum -d example.com -rf untrusted-resolvers.txt -tr 1.1.1.1,8.8.8.8,9.9.9.9
# a few untrusted resolvers inline instead of a file
amass enum -d example.com -r 1.0.0.1,8.8.4.4
| Flag | Class | Input | Use for |
|---|---|---|---|
-r value | untrusted | inline IPs, comma-sep, repeatable | bulk resolvers, throughput |
-rf file | untrusted | file of resolver IPs | a large scraped public-resolver list |
-tr value | trusted | inline IPs, comma-sep, repeatable | reliable resolvers used to validate findings |
[!note] v5.1.1 has no trusted-resolver file flag — trusted resolvers are inline-only via
-tr. Only the untrusted pool takes a file (-rf). Keep-tra short list you actually trust (1.1.1.1 / 8.8.8.8 / 9.9.9.9); dump the big list into-rf. Amass validates candidate names against the trusted set to cut false positives from unreliable untrusted resolvers.
Reading results back out
Amass v5 doesn’t dump to stdout the way older versions did — query the graph DB with subs after enum finishes:
amass subs -d $DOMAIN -names # just the discovered names, one per line
amass subs -d $DOMAIN -ip # names + IPs
amass subs -d $DOMAIN -ipv4 # IPv4 only
amass subs -d $DOMAIN -summary # ASN table summary instead of names
amass subs -d $DOMAIN -names > subs_amass.txt # pipe into the union step alongside subfinder/assetfinder
More subs reads
amass subs -d example.com -ipv6 # IPv6 addresses only
amass subs -d example.com -show # full result set for the enumeration index + domains
amass subs -df roots.txt -names # read many root domains from a file
amass subs -dir ./engagement-db -d example.com -names # read a NON-default graph dir
amass subs -d example.com -names -o subs.txt # also tee terminal output to a file
| Flag | Output |
|---|---|
-names | discovered FQDNs, one per line |
-ip / -ipv4 / -ipv6 | names with resolved addresses (all / v4 / v6) |
-summary | ASN + netblock rollup instead of names |
-show | full results for the enumeration index + provided domains |
-df file | read root domains from a file |
-dir path | query a specific graph-DB directory (not the default state dir) |
-o file | tee stdout/stderr to a text file |
-config file | apply a YAML config while reading |
amass assoc — association walks
[!info]
amass assocwalks associations in the OAM graph — pivoting from a seed asset (domain, org, netblock, ASN, TLS cert…) to other assets the graph has linked to it. It is how v5 replaces the oldintel“find related orgs/domains” idea: enumerate first withenum, then walk the graph you built.
# association walk over the default graph DB (one hop per -tN)
amass assoc -t1 '<subject> <predicate> <object>'
# chain up to ten hops (-t1 .. -t10), or load the triples from a file
amass assoc -tf triples.txt
# walk a specific (non-default) graph DB, or apply a config
amass assoc -dir ./engagement-db -t1 '<triple>'
amass assoc -config ./config.yaml -tf triples.txt
| Flag | Meaning |
|---|---|
-t1 … -t10 | up to 10 triples defining the walk (one hop each) |
-tf file | file containing the triples list |
-dir path | graph-DB directory to query |
-config file | YAML config to use |
[!warning] The exact triple grammar (asset-type / predicate / asset-type ordering and quoting) is version-specific and easy to get wrong — confirm the fields against
amass assoc -hand the Open Asset Model docs before scripting a walk. Don’t guess predicate names. OAM asset types you’ll pivot between includeFQDN,IPAddress,Netblock,AutonomousSystem,TLSCertificate,DomainRecord, andOrganization.
Diffing over time & visualizing
# only assets discovered since a given time — good for re-scanning a target periodically
amass track -d $DOMAIN -since '09/01 00:00:00 2026 UTC'
# export the asset graph — viz REQUIRES -d (it exits "No root domain names were
# provided" before it even reads the DB if you give only -dir)
amass viz -d $DOMAIN -dir <graph-db-dir> -dot -oA ./recon/amass_graph
amass viz -d $DOMAIN -dir <graph-db-dir> -gexf -oA ./recon/amass_graph # open the .gexf in Gephi
[!warning] Watch out
-activesends zone-transfer attempts and TLS connections straight at the target’s own nameservers/hosts — that’s active recon, not passive; keep engagements scoped accordingly (same rule as Stage 00’samass enum -passivenote, now spelled-active’s absence rather than a-passiveflag’s presence).- API keys for VirusTotal/SecurityTrails/Shodan/Netlas/FullHunt etc. meaningfully increase yield — configure them in
datasources.yamland pass it with-configrather than relying on the free/keyless sources alone. There is no working “list sources” flag in v5.1.1 (-listis dead code — it neither lists nor errors usefully); the authoritative roster is the set of- name:entries in the shippeddatasources.yaml(see above). Censys is not a v5.1.1 source — don’t add a stanza for it.- The background engine persists between runs; if a
subs/trackquery looks stale, confirm you’re pointed at the same-dirtheenumrun used, or that the engine process is even still the one you expect (ps aux | grep amass).
amass track — periodic re-scan diffing
track reads the same OAM graph enum writes and prints assets newer than a timestamp — good for scheduled re-scans where you only want the delta.
# names added since a timestamp (Go reference layout: 01/02 15:04:05 2006 MST)
amass track -d example.com -since '09/01 00:00:00 2026 UTC'
# many roots from a file, against a specific graph DB
amass track -df roots.txt -dir ./engagement-db -since '09/01 00:00:00 2026 UTC'
Weekly re-scan capturing only what’s new since last run:
amass enum -d example.com # refresh the graph first (same -dir)
# macOS date:
amass track -d example.com -since "$(date -u -v-7d '+%m/%d %H:%M:%S %Y UTC')"
# Linux date:
# amass track -d example.com -since "$(date -u -d '7 days ago' '+%m/%d %H:%M:%S %Y UTC')"
[!tip]
trackonly reports — it never enumerates. Run a freshenumagainst the same-dirfirst, thentrack -since <last run>for the delta. If the graph isn’t persisted between runs, the diff is meaningless. The-sincestring must match Go’s reference layout01/02 15:04:05 2006 MST(month/day, then year, then zone).
End-to-end recon pipeline (union + resolve)
No single passive source is complete. Union amass with subfinder + assetfinder, then resolve the merged list wildcard-aware with puredns.
DOMAIN=example.com
UNTRUSTED=untrusted-resolvers.txt # big scraped public-resolver list
# 1) three passive engines (union beats any one source)
amass enum -d "$DOMAIN" -tr 1.1.1.1,8.8.8.8,9.9.9.9 -rf "$UNTRUSTED"
subfinder -d "$DOMAIN" -all -silent -o subfinder.txt
assetfinder --subs-only "$DOMAIN" > assetfinder.txt
# 2) pull amass names back out of the OAM graph
amass subs -d "$DOMAIN" -names > amass.txt
# 3) union + dedupe
cat amass.txt subfinder.txt assetfinder.txt | sort -u > all_subs.txt
# 4) wildcard-aware resolve — keep only names that actually resolve
puredns resolve all_subs.txt \
--resolvers "$UNTRUSTED" \
--resolvers-trusted trusted-resolvers.txt \
-w resolved.txt
# 5) (optional) feed the union back to amass as seeds and re-run for depth
amass enum -d "$DOMAIN" -nf all_subs.txt
amass subs -d "$DOMAIN" -names > amass_round2.txt
[!tools] Pipeline pieces subfinder
-all(every source), assetfinder--subs-only, puredns (wildcard-aware mass resolver). The full unioning workflow lives in Stage 00 — Passive External Recon. Feeding the merged list back via-nflets amass mine the graph around names the other tools found.
Common v5 errors
| Symptom | Cause | Fix |
|---|---|---|
The Amass engine is already running. | a background amass engine still holds :4000 from a prior run | reuse it (usually fine), or pkill -f "amass engine" for a clean slate, or target another with -engine http://127.0.0.1:PORT |
Configuration error: No root domain names were provided | enum/subs/track have no scope | pass -d example.com (or -df roots.txt), or set scope.domains in config.yaml |
subs/track return stale or empty data | querying a different -dir than enum wrote to | point -dir at the same directory enum used; defaults are ~/.config/amass/ (Linux) / ~/Library/Application Support/amass/ (macOS) |
| enum finishes with almost no names | only keyless sources are active | wire API keys in datasources.yaml (-config); add -brute -w <wordlist> and/or -active if scope allows |
| need a genuinely clean run | the OAM SQLite graph persists between runs | delete asset.db asset.db-shm asset.db-wal from the state dir, or use a fresh -dir ./new-db |
[!warning] The graph DB is a real on-disk SQLite file —
asset.dbplusasset.db-wal/asset.db-shm— in the state dir, alongside per-runsession-<uuid>/dirs andamass_engine_<timestamp>.log. When results look wrong, read the newest engine log and confirm which-diryou’re actually hitting before blaming the sources.
See Also
- Passive External Recon — where subdomain enumeration sits in the wider OSINT / attack-surface stage.
- Recon & Host Discovery — turning resolved names into a live-host list to scan.
- Nmap — port-scan the hosts
amassresolves; feed its output with-iL. - Web Enumeration & Exploitation — vhost and content discovery once you have the resolved web surface.
Sources
- https://github.com/owasp-amass/amass
amass -h,amass enum -h,amass subs -h,amass track -h,amass viz -h(v5.1.1, confirmed locally)