
Passive DNS server that detects exposed cloud storage buckets (AWS S3, GCP, Azure) by resolving DNS requests, tracing CNAME chains, and flagging potential subdomain takeovers during reconnaissance.
s3dns is a lightweight DNS server that helps uncover cloud storage buckets (AWS S3, Google Cloud Storage, and Azure Blob) by resolving DNS requests, tracing CNAMEs, and matching known bucket URL patterns.
It's a handy companion for pentesters, bug bounty hunters, and cloud security analysts who want to catch exposed cloud buckets during DNS traffic analysis.
If S3DNS saves you time on a recon session, consider giving it a ⭐️ — it helps others find the project.
CACHE_SIZE (default: 1000 entries, set to 0 to disable).RATE_LIMIT (default: 100 req/s, set to 0 to disable).NXDOMAIN, S3DNS flags it as a possible domain takeover. This indicates a dangling DNS record pointing to an unclaimed bucket that an attacker could register.max_cname_depth parameter.AZURE_IP_RANGES=false or AWS_IP_RANGES=false (default is true).regex_patterns and hardcoded patterns to the patterns folder as YAML files. You can add your own patterns.
regex_.53 (UDP and TCP)S3DNS listens on port 53 (UDP and TCP) for DNS queries. For every request it:
1.1.1.1) — over UDP for UDP clients, over TCP for TCP clientsIn parallel, it:
s3dns.log⚡ Use this as your DNS during recon, and it will passively surface cloud buckets and takeover candidates for every domain your tools or browser resolve.
You will only need one of the following:
Only needed if you want to run it locally with Python
git clone https://github.com/olizimmermann/s3dns.git
cd s3dns
(Using a virtual environment is recommended)
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Port 53 requires elevated privileges:
sudo python s3dns.py
If sudo claims a missing module, try: sudo venv/bin/python s3dns.py
docker build -t ozimmermann/s3dns:latest .The easiest way to get started with S3DNS.
docker pull ozimmermann/s3dns:latest
docker run --rm -p 53:53/udp -p 53:53/tcp \
-v "./bucket_findings/:/app/buckets/" \
--name "s3dns" \
ozimmermann/s3dns:latest
docker build -t ozimmermann/s3dns:latest .
docker run --rm -p 53:53/udp -p 53:53/tcp \
-v "./bucket_findings/:/app/buckets/" \
--name "s3dns" \
ozimmermann/s3dns:latest
Findings are saved:
./bucket_findings/When using S3DNS on the same machine where you perform analysis, it may help to set the --network host flag:
docker run --rm -p 53:53/udp -p 53:53/tcp \
-v "./bucket_findings/:/app/buckets/" \
--network host \
--name "s3dns" \
ozimmermann/s3dns:latest
Since port 53 requires elevated privileges, some users (e.g., Mac users) may need sudo:
sudo docker run --rm -p 53:53/udp -p 53:53/tcp \
-v "./bucket_findings/:/app/buckets/" \
--name "s3dns" \
ozimmermann/s3dns:latest
Set your system or tool's DNS resolver to your S3DNS instance.
While browsing or fuzzing your target, S3DNS analyzes every domain and tells you if it resolves to:
- An AWS S3 bucket
- A GCP bucket
- An Azure Blob container
- Any of 13 other supported cloud storage providers
It follows CNAMEs, so if a domain points to
cdn.example.com, which in turn points to a cloud bucket, it will catch that too.It also flags potential subdomain takeovers — if a domain matches a cloud storage pattern but the target does not exist (NXDOMAIN), the dangling record is highlighted as a possible takeover candidate.
Use it passively while analyzing a site to spot exposed buckets and takeover opportunities without active probing.
You can tweak behavior via command-line flags, environment variables, or by modifying s3dns.py.
Precedence for every option is: command-line flag > environment variable > interactive prompt / default. Running with no flags behaves exactly as before.
Run python s3dns.py -h for the full list:
Example:
sudo python s3dns.py -l 0.0.0.0 -u 1.1.1.1 --rate-limit 200 --no-azure-ip-ranges
Since Microsoft does not explicitly name their Azure Blob Storage IP ranges, S3DNS uses all publicly provided Azure Storage IP addresses. This may lead to false positives. Consider disabling this check if you encounter issues:
AZURE_IP_RANGES=false
Add YAML files to the patterns/ directory. Files prefixed with regex_ are treated as regex patterns; all others are treated as substring matches.
Python:
sudo su
export DEBUG=true
python s3dns.py
Docker:
docker run --rm -p 53:53/udp -p 53:53/tcp \
-v "./bucket_findings/:/app/buckets/" \
-e "DEBUG=true" \
--name "s3dns" \
ozimmermann/s3dns:latest
Setting multiple environment variables in Docker:
docker run --rm -p 53:53/udp -p 53:53/tcp \
-v "./bucket_findings/:/app/buckets/" \
-e "LOCAL_DNS_SERVER_IP=0.0.0.0" \
-e "REAL_DNS_SERVER_IP=1.1.1.1" \
-e "RATE_LIMIT=200" \
-e "CACHE_SIZE=2000" \
--name "s3dns" \
ozimmermann/s3dns:latest

Contributions are welcome — new cloud provider patterns, bug fixes, and improvements. See CONTRIBUTING.md for guidelines.
Pattern files live in patterns/. Adding support for a new provider is as simple as adding a YAML entry — no Python required.
MIT License — Free to use, improve, and share.
Use responsibly. Only scan domains you own or have explicit permission to analyze.
Unauthorized access or probing may be illegal.
| Flag | Equivalent env var | Description |
|---|
-h, --help | – | Show help and exit |
--version | – | Show version and exit |
-d, --debug | DEBUG | Enable verbose debug output |
-l, --listen IP | LOCAL_DNS_SERVER_IP | Local interface to listen on |
-u, --upstream IP | REAL_DNS_SERVER_IP | Upstream DNS resolver to forward to |
-b, --bucket-file PATH | BUCKET_FILE | Path to write discovered bucket domains |
--aws-ip-ranges / --no-aws-ip-ranges | AWS_IP_RANGES | Toggle AWS S3 IP range checks |
--azure-ip-ranges / --no-azure-ip-ranges | AZURE_IP_RANGES | Toggle Azure Storage IP range checks |
--rate-limit N | RATE_LIMIT | Max DNS requests/sec per client IP (0 = disabled) |
--cache-size N | CACHE_SIZE | Max cached DNS responses (0 = disabled) |
--max-cname-depth N | – | Max CNAME chain depth to follow (default: 10) |
| Variable | Default | Description |
|---|
DEBUG | false | Enable verbose debug output |
AWS_IP_RANGES | true | Enable AWS S3 IP range checks |
AZURE_IP_RANGES | true | Enable Azure Storage IP range checks |
REAL_DNS_SERVER_IP | 1.1.1.1 | Upstream DNS resolver to forward queries to |
LOCAL_DNS_SERVER_IP | 0.0.0.0 | Local interface to listen on |
BUCKET_FILE | buckets.txt | Path to write discovered bucket domains |
RATE_LIMIT | 100 | Max DNS requests per second per client IP (0 = disabled) |
CACHE_SIZE | 1000 | Max cached DNS responses (0 = disabled) |