certgraph is a powerful reconnaissance tool for mapping relationships between SSL certificates using Certificate Transparency (CT) logs. It crawls CT logs to find all certificates issued for a domain, then queries those certificates to discover additional domains and subdomains. This creates a visual “graph” of the certificate infrastructure, revealing domains that may not be publicly listed.
# Prerequisites: Go 1.11+
go get -u github.com/lanrat/certgraph
# Or clone and build manually
git clone https://github.com/lanrat/certgraph.git
cd certgraph
go build
./certgraph -h
brew install certgraph
certgraph -version
# Install Go (if not present)
wget https://golang.org/dl/go1.21.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
# Build certgraph
git clone https://github.com/lanrat/certgraph.git
cd certgraph
/usr/local/go/bin/go build
sudo mv certgraph /usr/local/bin/
certgraph -version
certgraph -help
# Basic usage - discover all certificates for domain
certgraph example.com
# Output shows certificate chain and discovered domains
example.com (root domain)
├── Certificate: XXXXX (issued to example.com, www.example.com)
│ ├── domain: api.example.com
│ ├── domain: cdn.example.com
│ └── domain: mail.example.com
├── Certificate: YYYYY (wildcard *.example.com)
│ ├── domain: staging.example.com
│ ├── domain: dev.example.com
│ └── domain: test.example.com
└── Certificate: ZZZZZ (issued to example.com)
└── domain: internal.example.com
| Option | Description | Example |
|---|
-domain | Target domain | certgraph -domain example.com |
-depth | Graph traversal depth | certgraph -domain example.com -depth 2 |
-limit | Max certificates to fetch | certgraph -domain example.com -limit 1000 |
-verbose | Verbose output | certgraph -domain example.com -verbose |
-quiet | Minimal output | certgraph -domain example.com -quiet |
| Option | Description | Output Format |
|---|
-json | JSON output | { “domains”: […], “certificates”: […] } |
-dot | Graphviz DOT format | digraph { … } |
-csv | CSV format | domain,certificate,issuer |
-list | Simple domain list | api.example.com |
| Option | Description | Default |
|---|
-depth | How deep to traverse | 1 |
-timeout | CT log query timeout | 30s |
-parallel | Parallel queries | 4 |
-dns | Query DNS for verification | true |
# Find certificates directly issued for example.com
certgraph -domain example.com -depth 0
# Output: Only certificates with example.com in SAN
# Find certificates for example.com and domains found in those certificates
certgraph -domain example.com -depth 1
# Finds: example.com → [cert domains] → no further traversal
# Expand search to related domains found in depth 1 certificates
certgraph -domain example.com -depth 2
# Finds: example.com → [cert domains] → [their cert domains]
# WARNING: Depth > 3 can take a long time
certgraph -domain example.com -depth 3 -limit 5000
# Only use for organizations with many related domains
certgraph -domain example.com -json > results.json
{
"root": "example.com",
"domains": [
"example.com",
"api.example.com",
"cdn.example.com",
"staging.example.com"
],
"certificates": [
{
"fingerprint": "sha256:abc123...",
"issuedTo": ["example.com", "api.example.com"],
"issuer": "Let's Encrypt",
"notBefore": "2026-01-01T00:00:00Z",
"notAfter": "2027-01-01T00:00:00Z"
}
]
}
certgraph -domain example.com -csv > domains.csv
domain,certificate_fingerprint,issuer,valid_from,valid_to
example.com,sha256:abc123...,Let's Encrypt,2026-01-01,2027-01-01
api.example.com,sha256:abc123...,Let's Encrypt,2026-01-01,2027-01-01
cdn.example.com,sha256:def456...,Cloudflare,2026-02-01,2027-02-01
# Generate Graphviz format
certgraph -domain example.com -dot > domains.dot
# Convert to PNG
dot -Tpng domains.dot -o domains.png
digraph {
"example.com" -> "api.example.com"
"example.com" -> "cdn.example.com"
"api.example.com" -> "internal.api.example.com"
}
# Output just discovered domains
certgraph -domain example.com -list
# Output:
# example.com
# api.example.com
# cdn.example.com
# staging.example.com
Browser Issues Certificate
↓
Certificate Logged to CT Log
↓
certgraph Queries CT Log
↓
Discovers Certificate Details
↓
Extracts All Domains (SAN)
| CT Log | Operator | Coverage |
|---|
| Google Argon | Google | ~60% of CAs |
| Google Tesseract | Google | SSL/TLS certs |
| Sectigo CT Logs | Sectigo | Public CAs |
| DigiCert CT Logs | DigiCert | DigiCert issued |
# certgraph queries configured CT logs automatically
# Logs are hardcoded, no CLI override (yet)
# Typical: 4-6 major CT logs queried per domain
certgraph -domain example.com -verbose
# Output will show which logs are being queried
# Find *.example.com certificates
certgraph -domain example.com
# May reveal:
# *.example.com (wildcard cert)
# staging.example.com (issued to wildcard)
# dev.example.com
# test.example.com
# internal.example.com
certgraph -domain amazon.com -depth 1 | head -20
# Output may include:
# amazon.com
# www.amazon.com
# api.amazon.com
# s3.amazonaws.com
# ec2.amazonaws.com
# rds.amazonaws.com
# lambda.amazonaws.com
# For large organizations with multiple subdomains
certgraph -domain company.com -depth 2 -limit 2000
# Discovers: internal divisions, geographic branches, acquisitions
# Save to file and filter
certgraph -domain example.com > results.txt
# Keep only subdomains
grep "^\." results.txt
# Keep only specific pattern
certgraph -domain example.com | grep "api\|staging\|test"
# Exclude wildcards
certgraph -domain example.com | grep -v "\*"
# Verify discovered domains resolve (optional)
certgraph -domain example.com -dns
# Only shows domains that resolve via DNS
# Filters out dangling/inactive subdomains
# 1. Export DOT format
certgraph -domain example.com -dot > cert_graph.dot
# 2. Convert to PNG
dot -Tpng cert_graph.dot -o cert_graph.png
# 3. Convert to SVG (for web)
dot -Tsvg cert_graph.dot -o cert_graph.svg
# 4. View with graphviz tools
circo -Tpng cert_graph.dot -o circular.png # Circular layout
neato -Tpng cert_graph.dot -o spring.png # Spring layout
# Export as JSON for custom processing
certgraph -domain example.com -json | jq '.domains[]' > domains.txt
# Feed into other reconnaissance tools
cat domains.txt | while read domain; do
nmap -p 80,443 $domain
done
# Complement certgraph with subfinder
certgraph -domain example.com -list > cert_domains.txt
subfinder -d example.com -o subfinder_domains.txt
# Combine and deduplicate
cat cert_domains.txt subfinder_domains.txt | sort -u > all_domains.txt
# Use certgraph for CT-based discovery
certgraph -domain example.com -json > ct_results.json
# Cross-reference with assetfinder
assetfinder --subs-only example.com | sort -u > asset_domains.txt
# Find domains in cert but not in assetfinder (potential shadow IT)
comm -13 asset_domains.txt cert_domains.txt
# Enumerate domains
certgraph -domain example.com -list > targets.txt
# Scan discovered domains
nmap -sV -p 80,443 -iL targets.txt -oX results.xml
#!/bin/bash
DOMAIN=$1
echo "[*] Running certgraph..."
certgraph -domain $DOMAIN -json -limit 1000 > ct_results.json
echo "[*] Extracting domains..."
jq -r '.domains[]' ct_results.json | sort -u > domains.txt
echo "[*] Resolving domains..."
while read domain; do
if dig +short $domain &>/dev/null; then
echo "[+] Active: $domain"
else
echo "[-] Inactive: $domain"
fi
done < domains.txt > active_domains.txt
echo "[*] Port scanning..."
nmap -p 80,443 -iL active_domains.txt -oX nmap_results.xml
echo "[*] Done! Results in domains.txt, active_domains.txt, nmap_results.xml"
# Increase parallel queries for speed
certgraph -domain example.com -depth 1 -parallel 8
# Speed up large enumerations (caution: may hit rate limits)
# Default: 4, Range: 1-16
# Increase timeout for slow networks
certgraph -domain example.com -timeout 60s
# Default: 30s
# If hitting rate limits:
# 1. Reduce parallel queries
certgraph -domain example.com -parallel 2
# 2. Increase timeout
certgraph -domain example.com -timeout 90s
# 3. Wait and retry
sleep 300
certgraph -domain example.com
certgraph -domain example.com -csv | grep -E "cloudflare|aws|azure|gcp"
# May reveal cloud infrastructure usage
# Subdomains with different naming patterns may indicate:
# - Company acquisitions (product.acquired-company.com)
# - Third-party integrations
# - Regional operations (region.example.com)
certgraph -domain company.com -depth 2 | sort | uniq
certgraph -domain example.com -json | \
jq '.certificates[] | {issuer, notAfter}' | \
grep "2024\|2025" # Find soon-to-expire certs
# Initial reconnaissance
certgraph -domain target.com -depth 1 -list > in-scope.txt
# Find all subdomains
certgraph -domain target.com -depth 2 -list > all-subdomains.txt
# Filter likely in-scope
grep "target.com$" all-subdomains.txt > final-targets.txt
# Map organization's public SSL infrastructure
certgraph -domain company.com -depth 2 -json > company_certs.json
# Analyze coverage
jq '.certificates | length' company_certs.json
# List all public facing domains
jq -r '.domains[]' company_certs.json | grep -v "\*"
# Discover competitor's infrastructure
certgraph -domain competitor.com -depth 1 -list
# Reveals: services, acquisitions, integrations
# 1. Verify domain has SSL certificates
certgraph -domain example.com -verbose
# 2. Check if domain is in CT logs
# (New/obscure domains may not be logged yet)
# 3. Try with larger limit
certgraph -domain example.com -limit 5000
# 1. Reduce depth to save time
certgraph -domain example.com -depth 1
# 2. Reduce limit
certgraph -domain example.com -limit 500
# 3. Run without DNS verification
# (DNS lookup is slowest part)
# CT logs have rate limits (~100 queries/minute)
# Solutions:
# 1. Reduce parallel queries
certgraph -domain example.com -parallel 2
# 2. Wait before retrying
sleep 60
# 3. Use smaller limit
certgraph -domain example.com -limit 100
# 1. Quick initial scan
certgraph -domain example.com -depth 1 > quick_results.txt
# 2. Export for visualization
certgraph -domain example.com -dot > structure.dot
# 3. Detailed analysis
certgraph -domain example.com -depth 2 -json > detailed.json
# 4. Integration with other tools
certgraph -domain example.com -list | while read sub; do
echo "Testing: $sub"
# Run additional tests
done
# Multi-format export for sharing
certgraph -domain example.com -list > domains.txt
certgraph -domain example.com -json > domains.json
certgraph -domain example.com -csv > domains.csv
certgraph -domain example.com -dot > domains.dot
# Create timestamp-dated results
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
certgraph -domain example.com -json > results_$TIMESTAMP.json
certgraph -domain example.com -dot > graph_$TIMESTAMP.dot
# Version control
git add results_*.json
git commit -m "CT log enumeration for example.com"
| Tool | Purpose | Comparison |
|---|
| subfinder | DNS-based subdomain enumeration | Faster, broader |
| assetfinder | Multiple sources (CT, TLS, etc) | More comprehensive |
| crt.sh | Web interface to CT logs | Manual, slower |
| Shodan | Network device search | Different approach |
| Censys | Certificate database search | More detailed certs |