daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

amass.md (19320B)


      1 ---
      2 title: "Amass"
      3 description: "OWASP Amass v5 subdomain enumeration and attack-surface mapping — enum, ASN/CIDR discovery, and reading results back out of its graph database."
      4 category: enumeration
      5 tags: [enumeration, osint, recon, dns, subdomains, attack-surface, api-keys]
      6 tools: [Amass, subfinder, assetfinder, puredns]
      7 difficulty: intermediate
      8 updated: "2026-09-25"
      9 ---
     10 
     11 # Amass
     12 
     13 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](/sheets/pentest-workflow/passive-external-recon).
     14 
     15 > [!warning] Version note — v5 changed the CLI shape
     16 > 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`, or `amass enum -o results.txt` are describing v3/v4 and **do not apply to v5** — there is no `intel` subcommand anymore; ASN/CIDR discovery moved directly into `enum`, and results live in the graph DB, read back out with `amass subs` rather than a plain output file. Confirmed against v5.1.1 (`amass -version`).
     17 
     18 ## Subcommands (v5)
     19 
     20 ```text
     21 amass enum    interface with the engine that performs enumerations
     22 amass subs    analyze and present discovered subdomains and associated data
     23 amass track   diff OAM data to identify newly discovered assets since a timestamp
     24 amass viz     generate graph visualizations (DOT / GEXF) from OAM data
     25 amass assoc   query the OAM along an association "triple" walk
     26 amass engine  run/manage the collection engine that backs the OAM database
     27 ```
     28 
     29 `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.
     30 
     31 ## `amass enum` — the main pass
     32 
     33 ```bash
     34 # passive is the DEFAULT in v5 — this alone is the safe, non-contact baseline
     35 amass enum -d $DOMAIN
     36 
     37 # multiple domains in one run
     38 amass enum -d $DOMAIN,$DOMAIN2
     39 
     40 # active mode: adds zone-transfer attempts + cert-name grabs against the target's own infra
     41 amass enum -d $DOMAIN -active
     42 
     43 # brute force on top of the passive/active sources, with a custom wordlist
     44 amass enum -d $DOMAIN -brute -w /path/to/subdomains.txt
     45 
     46 # ASN/CIDR-driven discovery — folded directly into `enum` in v5 (no more `intel` subcommand)
     47 amass enum -asn 12345
     48 amass enum -cidr 203.0.113.0/24 -d $DOMAIN
     49 
     50 # seed the engine with names you already have (other tools' output) so they're in scope from the start
     51 amass enum -d $DOMAIN -nf known_subs.txt
     52 
     53 # write files out under a directory instead of just the graph DB
     54 amass enum -d $DOMAIN -oA ./recon/amass_$DOMAIN
     55 ```
     56 
     57 | Flag | Description | Default |
     58 |---|---|---|
     59 | `-d value` | Domain(s), comma-separated | — |
     60 | `-df file` | File of domains | — |
     61 | `-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 |
     62 | `-brute` | Run DNS brute forcing after the search/API sources | off |
     63 | `-w file` / `-aw file` | Wordlist for brute forcing / name alterations | — |
     64 | `-alts` | Generate altered/permuted names from what's found | off |
     65 | `-asn value` | ASN(s), comma-separated — org-wide discovery | — |
     66 | `-cidr value` | CIDR(s), comma-separated | — |
     67 | `-addr value` | IPs/ranges (`192.168.1.1-254`) | — |
     68 | `-p value` | Ports to check when resolving | 80, 443 |
     69 | `-r` / `-tr value` | Untrusted / trusted DNS resolver IPs | system default |
     70 | `-nf file` | Seed the engine with already-known names (from other tools) | — |
     71 | `-bl value` / `-blf file` | Blacklist subdomains (inline / from file) | — |
     72 | `-timeout N` | Minutes with no progress before terminating | 30 |
     73 | `-oA prefix` | Path prefix for all output files | — |
     74 | `-dir path` | Directory holding the graph database | default state dir |
     75 | `-list` | *(dead in v5.1.1 — does not print sources; read `datasources.yaml` instead)* | — |
     76 | `-include` / `-exclude value` | Restrict to / drop specific data sources | all |
     77 | `-v` | Verbose/debug output | off |
     78 | `-silent` | No output during the run | off |
     79 
     80 > [!tools] Related in the same recon stage
     81 > [subfinder](https://github.com/projectdiscovery/subfinder), [assetfinder](https://github.com/tomnomnom/assetfinder), and [puredns](https://github.com/d3mondev/puredns) (wildcard-aware resolving) — see [Stage 00](/sheets/pentest-workflow/passive-external-recon) for unioning all of them together. No single passive source is complete; run at least two and merge.
     82 
     83 ## Config files (v5) — wiring API keys
     84 
     85 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`.
     86 
     87 ```text
     88 Linux:  ~/.config/amass/{config.yaml,datasources.yaml}
     89 macOS:  ~/Library/Application Support/amass/{config.yaml,datasources.yaml}
     90 ```
     91 
     92 ```yaml
     93 # config.yaml  (trimmed to the parts you actually touch)
     94 scope:
     95   domains:
     96     - example.com              # root/registered domains in scope
     97   # ips:   [ 192.0.2.1, 192.168.0.3-8 ]
     98   # cidrs: [ 192.0.2.0/24 ]
     99   ports: [ 80, 443, 8080, 8443 ]   # ports used when probing services
    100   # blacklist:
    101   #   - dev.example.com
    102 options:
    103   datasources: "./datasources.yaml"   # path is relative to THIS file, not your cwd
    104   # engine:   "http://127.0.0.1:4000"           # reuse/point at a specific engine
    105   # database: "postgres://amass:amass4OWASP@assetdb:5432/assetdb"  # or bolt://...  (neo4j)
    106   bruteforce:
    107     enabled: false
    108     wordlists: [ "./wordlists/short-wordlist.txt" ]
    109   alterations:
    110     enabled: false
    111   default_transform_values:
    112     ttl: 1440          # minutes a result is cached before re-querying
    113     confidence: 50
    114     priority: 5
    115 transformations:       # which asset->source expansions run, and their TTLs
    116   FQDN->ALL:
    117   FQDN->DomainRecord:
    118     ttl: 43200
    119   TLSCertificate->ALL:
    120     ttl: 10800
    121 ```
    122 
    123 ```yaml
    124 # datasources.yaml  — uncomment a source and drop your key in
    125 global_options:
    126   minimum_ttl: 1440                 # floor applied when a source omits its own ttl
    127 datasources:
    128   - name: VirusTotal
    129     ttl: 10080
    130     creds:
    131       account:
    132         apikey: VT_API_KEY_HERE
    133   - name: SecurityTrails
    134     ttl: 1440
    135     creds:
    136       account:
    137         apikey: ST_API_KEY_HERE
    138   - name: Shodan
    139     ttl: 10080
    140     creds:
    141       account:
    142         apikey: SHODAN_API_KEY_HERE
    143   - name: Chaos                     # ProjectDiscovery — same key subfinder uses
    144     ttl: 4320
    145     creds:
    146       account:
    147         apikey: CHAOS_API_KEY_HERE
    148 ```
    149 
    150 Some sources key differently — a named account, multiple accounts, or username+secret:
    151 
    152 ```yaml
    153   - name: GitHub                    # keyed by a custom account name, not "account"
    154     ttl: 4320
    155     creds:
    156       accountname:
    157         apikey: ghp_xxx
    158   - name: PassiveTotal              # username + apikey (CIRCL/FOFA/Yandex/ZoomEye are similar)
    159     creds:
    160       account:
    161         username: you@example.com
    162         apikey: PT_KEY
    163   - name: C99                       # multiple keys under account1/account2
    164     ttl: 4320
    165     creds:
    166       account1: { apikey: KEY1 }
    167       account2: { apikey: KEY2 }
    168 ```
    169 
    170 ```bash
    171 amass enum -config ./config.yaml -d example.com          # enum uses the configured keys
    172 amass enum -d example.com                                # uses the default-path config if present
    173 amass subs -config ./config.yaml -d example.com -names   # subs/track/assoc/viz also accept -config
    174 ```
    175 
    176 > [!tip] The `datasources` path is resolved relative to `config.yaml`, not your shell's cwd. Keep `config.yaml`, `datasources.yaml`, and `wordlists/` in the same directory, or use absolute paths.
    177 
    178 > [!info] The default OAM store is a local SQLite graph — `asset.db` (plus `asset.db-wal`/`asset.db-shm`) in the state dir. For a shared/team graph, set `options.database` to a Postgres (`postgres://...`) or Neo4j (`bolt://...`) URL instead.
    179 
    180 > [!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.
    181 
    182 ## Trusted vs untrusted resolvers
    183 
    184 ```bash
    185 # untrusted resolvers (bulk, for volume) from a file; trusted (reliable) inline
    186 amass enum -d example.com -rf untrusted-resolvers.txt -tr 1.1.1.1,8.8.8.8,9.9.9.9
    187 
    188 # a few untrusted resolvers inline instead of a file
    189 amass enum -d example.com -r 1.0.0.1,8.8.4.4
    190 ```
    191 
    192 | Flag | Class | Input | Use for |
    193 |---|---|---|---|
    194 | `-r value` | untrusted | inline IPs, comma-sep, repeatable | bulk resolvers, throughput |
    195 | `-rf file` | untrusted | file of resolver IPs | a large scraped public-resolver list |
    196 | `-tr value` | trusted | inline IPs, comma-sep, repeatable | reliable resolvers used to validate findings |
    197 
    198 > [!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 `-tr` a 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.
    199 
    200 ## Reading results back out
    201 
    202 Amass v5 doesn't dump to stdout the way older versions did — query the graph DB with `subs` after `enum` finishes:
    203 
    204 ```bash
    205 amass subs -d $DOMAIN -names            # just the discovered names, one per line
    206 amass subs -d $DOMAIN -ip               # names + IPs
    207 amass subs -d $DOMAIN -ipv4             # IPv4 only
    208 amass subs -d $DOMAIN -summary          # ASN table summary instead of names
    209 amass subs -d $DOMAIN -names > subs_amass.txt   # pipe into the union step alongside subfinder/assetfinder
    210 ```
    211 
    212 ## More `subs` reads
    213 
    214 ```bash
    215 amass subs -d example.com -ipv6            # IPv6 addresses only
    216 amass subs -d example.com -show            # full result set for the enumeration index + domains
    217 amass subs -df roots.txt -names            # read many root domains from a file
    218 amass subs -dir ./engagement-db -d example.com -names   # read a NON-default graph dir
    219 amass subs -d example.com -names -o subs.txt            # also tee terminal output to a file
    220 ```
    221 
    222 | Flag | Output |
    223 |---|---|
    224 | `-names` | discovered FQDNs, one per line |
    225 | `-ip` / `-ipv4` / `-ipv6` | names with resolved addresses (all / v4 / v6) |
    226 | `-summary` | ASN + netblock rollup instead of names |
    227 | `-show` | full results for the enumeration index + provided domains |
    228 | `-df file` | read root domains from a file |
    229 | `-dir path` | query a specific graph-DB directory (not the default state dir) |
    230 | `-o file` | tee stdout/stderr to a text file |
    231 | `-config file` | apply a YAML config while reading |
    232 
    233 ## `amass assoc` — association walks
    234 
    235 > [!info] `amass assoc` walks *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 old `intel` "find related orgs/domains" idea: enumerate first with `enum`, then walk the graph you built.
    236 
    237 ```bash
    238 # association walk over the default graph DB (one hop per -tN)
    239 amass assoc -t1 '<subject> <predicate> <object>'
    240 
    241 # chain up to ten hops (-t1 .. -t10), or load the triples from a file
    242 amass assoc -tf triples.txt
    243 
    244 # walk a specific (non-default) graph DB, or apply a config
    245 amass assoc -dir ./engagement-db -t1 '<triple>'
    246 amass assoc -config ./config.yaml -tf triples.txt
    247 ```
    248 
    249 | Flag | Meaning |
    250 |---|---|
    251 | `-t1` … `-t10` | up to 10 triples defining the walk (one hop each) |
    252 | `-tf file` | file containing the triples list |
    253 | `-dir path` | graph-DB directory to query |
    254 | `-config file` | YAML config to use |
    255 
    256 > [!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 -h` and the Open Asset Model docs before scripting a walk. Don't guess predicate names. OAM asset types you'll pivot between include `FQDN`, `IPAddress`, `Netblock`, `AutonomousSystem`, `TLSCertificate`, `DomainRecord`, and `Organization`.
    257 
    258 ## Diffing over time & visualizing
    259 
    260 ```bash
    261 # only assets discovered since a given time — good for re-scanning a target periodically
    262 amass track -d $DOMAIN -since '09/01 00:00:00 2026 UTC'
    263 
    264 # export the asset graph — viz REQUIRES -d (it exits "No root domain names were
    265 # provided" before it even reads the DB if you give only -dir)
    266 amass viz -d $DOMAIN -dir <graph-db-dir> -dot  -oA ./recon/amass_graph
    267 amass viz -d $DOMAIN -dir <graph-db-dir> -gexf -oA ./recon/amass_graph   # open the .gexf in Gephi
    268 ```
    269 
    270 > [!warning] Watch out
    271 > - `-active` sends 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's `amass enum -passive` note](/sheets/pentest-workflow/passive-external-recon), now spelled `-active`'s absence rather than a `-passive` flag's presence).
    272 > - API keys for VirusTotal/SecurityTrails/Shodan/Netlas/FullHunt etc. meaningfully increase yield — configure them in `datasources.yaml` and pass it with `-config` rather than relying on the free/keyless sources alone. There is no working "list sources" flag in v5.1.1 (`-list` is dead code — it neither lists nor errors usefully); the authoritative roster is the set of `- name:` entries in the shipped `datasources.yaml` (see above). Censys is **not** a v5.1.1 source — don't add a stanza for it.
    273 > - The background engine persists between runs; if a `subs`/`track` query looks stale, confirm you're pointed at the same `-dir` the `enum` run used, or that the engine process is even still the one you expect (`ps aux | grep amass`).
    274 
    275 ## `amass track` — periodic re-scan diffing
    276 
    277 `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.
    278 
    279 ```bash
    280 # names added since a timestamp (Go reference layout: 01/02 15:04:05 2006 MST)
    281 amass track -d example.com -since '09/01 00:00:00 2026 UTC'
    282 
    283 # many roots from a file, against a specific graph DB
    284 amass track -df roots.txt -dir ./engagement-db -since '09/01 00:00:00 2026 UTC'
    285 ```
    286 
    287 Weekly re-scan capturing only what's new since last run:
    288 
    289 ```bash
    290 amass enum -d example.com          # refresh the graph first (same -dir)
    291 # macOS date:
    292 amass track -d example.com -since "$(date -u -v-7d '+%m/%d %H:%M:%S %Y UTC')"
    293 # Linux date:
    294 # amass track -d example.com -since "$(date -u -d '7 days ago' '+%m/%d %H:%M:%S %Y UTC')"
    295 ```
    296 
    297 > [!tip] `track` only reports — it never enumerates. Run a fresh `enum` against the **same** `-dir` first, then `track -since <last run>` for the delta. If the graph isn't persisted between runs, the diff is meaningless. The `-since` string must match Go's reference layout `01/02 15:04:05 2006 MST` (month/day, then year, then zone).
    298 
    299 ## End-to-end recon pipeline (union + resolve)
    300 
    301 No single passive source is complete. Union amass with subfinder + assetfinder, then resolve the merged list wildcard-aware with puredns.
    302 
    303 ```bash
    304 DOMAIN=example.com
    305 UNTRUSTED=untrusted-resolvers.txt     # big scraped public-resolver list
    306 
    307 # 1) three passive engines (union beats any one source)
    308 amass enum -d "$DOMAIN" -tr 1.1.1.1,8.8.8.8,9.9.9.9 -rf "$UNTRUSTED"
    309 subfinder -d "$DOMAIN" -all -silent -o subfinder.txt
    310 assetfinder --subs-only "$DOMAIN" > assetfinder.txt
    311 
    312 # 2) pull amass names back out of the OAM graph
    313 amass subs -d "$DOMAIN" -names > amass.txt
    314 
    315 # 3) union + dedupe
    316 cat amass.txt subfinder.txt assetfinder.txt | sort -u > all_subs.txt
    317 
    318 # 4) wildcard-aware resolve — keep only names that actually resolve
    319 puredns resolve all_subs.txt \
    320   --resolvers "$UNTRUSTED" \
    321   --resolvers-trusted trusted-resolvers.txt \
    322   -w resolved.txt
    323 
    324 # 5) (optional) feed the union back to amass as seeds and re-run for depth
    325 amass enum -d "$DOMAIN" -nf all_subs.txt
    326 amass subs -d "$DOMAIN" -names > amass_round2.txt
    327 ```
    328 
    329 > [!tools] Pipeline pieces
    330 > [subfinder](https://github.com/projectdiscovery/subfinder) `-all` (every source), [assetfinder](https://github.com/tomnomnom/assetfinder) `--subs-only`, [puredns](https://github.com/d3mondev/puredns) (wildcard-aware mass resolver). The full unioning workflow lives in [Stage 00 — Passive External Recon](/sheets/pentest-workflow/passive-external-recon). Feeding the merged list back via `-nf` lets amass mine the graph around names the other tools found.
    331 
    332 ## Common v5 errors
    333 
    334 | Symptom | Cause | Fix |
    335 |---|---|---|
    336 | `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` |
    337 | `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` |
    338 | `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) |
    339 | 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 |
    340 | 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` |
    341 
    342 > [!warning] The graph DB is a real on-disk SQLite file — `asset.db` plus `asset.db-wal`/`asset.db-shm` — in the state dir, alongside per-run `session-<uuid>/` dirs and `amass_engine_<timestamp>.log`. When results look wrong, read the newest engine log and confirm which `-dir` you're actually hitting before blaming the sources.
    343 
    344 ## See Also
    345 
    346 - **[Passive External Recon](/sheets/pentest-workflow/passive-external-recon)** — where subdomain enumeration sits in the wider OSINT / attack-surface stage.
    347 - **[Recon & Host Discovery](/sheets/pentest-workflow/recon-and-host-discovery)** — turning resolved names into a live-host list to scan.
    348 - **[Nmap](/sheets/enumeration/nmap)** — port-scan the hosts `amass` resolves; feed its output with `-iL`.
    349 - **[Web Enumeration & Exploitation](/sheets/pentest-workflow/web-enumeration-and-exploitation)** — vhost and content discovery once you have the resolved web surface.
    350 
    351 ## Sources
    352 
    353 - https://github.com/owasp-amass/amass
    354 - `amass -h`, `amass enum -h`, `amass subs -h`, `amass track -h`, `amass viz -h` (v5.1.1, confirmed locally)