A bash script to automatically discover and monitor subdomains for multiple domains. It sends notifications directly to your Discord channel whenever new subdomains or subdomain takeover vulnerabilities are identified.
Install quickly with Go:
go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
sudo apt install jqEnsure Go binaries are added to your PATH:
export PATH=$PATH:~/go/bingit clone https://github.com/themalwarenews/SubSpy/
cd SubSpy
chmod +x subspy.shThe primary way to configure SubSpy is through the domains.txt file and a config.sh file for more advanced settings.
- Create a file called
domains.txtin the same directory as the script. - Add your target domains line-by-line:
example.com
testsite.com
-
Create a Discord channel.
-
Create a webhook in your Discord channel:
- Go to
Channel Settings→Integrations→Webhooks - Click
New Webhook, give it a name, and copy the URL.
- Go to
-
On the first run, the script will prompt you to enter your Discord webhook URL. This URL is then stored in a hidden file (
.discord_webhook) in the script's directory for future runs.
For more fine-grained control, SubSpy uses a config.sh file.
- Creation: If
config.shdoes not exist when you runsubspy.sh, the script will automatically copyconfig.sh.exampletoconfig.sh. You should review and customize this file to suit your needs. - Variables: The following variables can be set in
config.sh:GOPATH_BIN: Specifies the path to your Go binaries (likesubfinderandnuclei).- Default:
~/go/bin - Example:
GOPATH_BIN="/custom/path/go/bin"
- Default:
LOG_FILE: Defines the path where the script's log file will be stored.- Default:
subspy.log(in the script's directory) - Example:
LOG_FILE="/var/log/subspy/activity.log"
- Default:
SUBFINDER_FLAGS: Allows you to pass custom flags to thesubfindercommand.- Default: None
- Example:
SUBFINDER_FLAGS="-recursive -all -timeout 30"
NUCLEI_FLAGS: Allows you to pass custom flags to thenucleicommand (for takeover checks).- Default: None
- Example:
NUCLEI_FLAGS="-retries 3 -severity critical,high"
NUCLEI_SCAN_NEW_ONLY: Determines if Nuclei should scan only newly discovered subdomains or all subdomains.- Default:
false(scans all subdomains intoday_list) - Set to
trueto scan only subdomains present indiff_file(newly found ones). If no new subdomains are found, it will scantoday_listas a fallback and notify you. - Example:
NUCLEI_SCAN_NEW_ONLY="true"
- Default:
Webhook Verification:
- The first time you run the script, it sends a test notification automatically.
To run manually:
./subspy.shRun the scan daily at 8:00 AM:
crontab -eAdd this line (ensure /path/to/subspy.sh is correct and consider using the configured LOG_FILE if you change it from the default subspy.log in the script's directory):
0 8 * * * /path/to/subspy.sh # Script now handles its own logging via LOG_FILE in config.shIf you want to capture cron's own output (e.g., if subspy.sh itself cannot be executed), you can still redirect:
0 8 * * * /path/to/subspy.sh >> /path/to/your/cron_specific.log 2>&1SubSpy now features more robust logging:
- Log File: All operations, informational messages, warnings, and errors are logged to a file.
- Default location:
subspy.login the script's directory. - Configurable via the
LOG_FILEvariable inconfig.sh.
- Default location:
- Log Format: Entries are timestamped and include a log level:
[YYYY-MM-DD HH:MM:SS] [LEVEL] Log message content- Example:
[2023-10-27 10:00:00] [INFO] SubSpy started by user. - Levels include
INFO,WARN(for non-critical issues or important notices), andERROR.
- Example:
- Dependency Check:
- At startup, SubSpy verifies that all required tools (
subfinder,nuclei,jq,curl) are installed and accessible in your PATH. - If any dependency is missing, the script will:
- Log an error message.
- Send a Discord notification (if
curlis available and webhook is configured). - Print the error to the console.
- Exit immediately.
- At startup, SubSpy verifies that all required tools (
- Tool Failures:
- If
subfinderornucleicommands fail during a scan for a specific domain (e.g., due to an invalid flag or tool error), SubSpy will:- Log the error.
- Send a Discord notification detailing the failure (e.g., "❌ ERROR: subfinder failed for domain example.com...").
- Skip processing for the current domain and move to the next one, ensuring the script doesn't halt completely.
- If
- Initialization:
- Sets up its environment and loads configuration from
config.sh(or creates one fromconfig.sh.example). - Performs a dependency check for
subfinder,nuclei,jq, andcurl. Exits if any are missing. - Verifies Discord webhook connectivity.
- Sets up its environment and loads configuration from
- Domain Processing: For each domain in
domains.txt:- Performs subdomain enumeration using
subfinder(with custom flags if provided inconfig.sh). - Compares the current scan's results (
today_list) against the previous scan's results (backup_list). - If new subdomains are found, they are stored in
diff_file.
- Performs subdomain enumeration using
- Vulnerability Scanning:
- Runs
nuclei(with custom flags if provided) to check for subdomain takeovers. - By default, scans all subdomains found in the current scan (
today_list). - If
NUCLEI_SCAN_NEW_ONLYis set totrueinconfig.shand new subdomains were found,nucleiwill only scan these new subdomains (diff_file). IfNUCLEI_SCAN_NEW_ONLYistruebut no new subdomains are found, it scanstoday_listand notifies about this behavior.
- Runs
- Notifications:
- Immediately sends alerts to your Discord channel for:
- Newly discovered subdomains.
- Detected subdomain takeover vulnerabilities.
- Errors during tool execution (e.g.,
subfinderornucleifailing).
- Provides clear updates about scan initiation, completion, and individual domain scanning.
- Immediately sends alerts to your Discord channel for:
- Logging: All actions, errors, and notifications are logged to the file specified by
LOG_FILEinconfig.sh(defaultsubspy.log), with timestamps and log levels.
- Webhook Verified:
✅ Webhook configured successfully! (Webhook verification)
- Scanning Started:
🔄 Subdomain Monitoring Scan Started!
- Scanning Domain:
🟡 Scanning: example.com
- Initial Scan Completed:
✅ Initial scan completed for example.com: Found 42 subdomains.
- New Subdomains Discovered:
🚨 New subdomains detected for example.com (2):
domain1.example.com
domain2.example.com
- Subdomain Takeover Detected:
🔥 Takeover detected!
Subdomain: vulnerable.example.com
Vulnerability: AWS Bucket Takeover
- No New Subdomains:
✅ No new subdomains found for example.com.
- Scan Completed:
🏁 Subdomain Monitoring Scan Completed for all domains!
Contributions are welcome! Feel free to open issues, submit pull requests, and improve documentation.
Happy Monitoring! 🔎