seads (Search Engine ADs Scanner) is a utility designed to automatically detect advertisements displayed on most popular search engines when searching for a user-submitted keywords.
Cybercriminals are increasingly using search engines ads to drive traffic to phishing sites, malware downloads, and other harmful content. seads aims to help security researchers and incident response teams identify these ads quickly and efficiently.
- Multiple search engines support: Currently supports Google, Bing, DuckDuckGo, Yahoo, Aol, Syndicated and AdSense (see note below).
- Automated reporting: Send reports of findings via email, Slack, Discord or Telegram.
- Concurrent search: Specify multiple headless instances to gather as many ads as possible concurrently.
- Screenshots: Capture screenshots of ads found in search engines for evidence.
- Docker support: Run
seadsusing Docker. - Export in JSON: Export results of the execution in JSON format.
- Custom User-Agent: Provide your User-Agent string to be used to click on ads found.
- Redirect chain detection: Tracks URLs through redirects to detect and log chains.
- URLScan submission: Submit the link to URLScan using your API key.
- Advertiser name detection: Print the advertiser name and location (only for Google, Syndicated and AdSense).
- Defanging: Defang URLs in notifications to prevent accidental clicks.
- HTML page saving: Save the HTML page of the search engine result for later analysis.
- Expected domains: Specify expected domains to filter out known advertisers from notifications.
- Global Domain Exclusion: Specify list of domains to be globally excluded instead of repeating on config list.
- Search Engine Selection: Command line option to select desired search engine.
- DirectQuery": Command line option to use single query.
Note
Currently, the Google search detection doesn't always work because the automated browser is often prompted by a CAPTCHA. As a workaround, Syndicated and AdSense are used to gather ads from Google (see here). This may not be 100% accurate, but it is the best available option as of now.
- Due to the nature of search engine ads, a single search may not reveal all ads. Using concurrent headless browsers might slow down detection but ensures comprehensive ad gathering.
- Notifications on Slack, Telegram and Discord have character limits. Messages exceeding the limit won't be sent.
Caution
seads will click on dangerous links, and potentially expose your IP address to malicious sites. Consider using a VPN/proxy or running seads in a VPS to avoid this risk.
You can download seads from the releases section.
Or using go:
go install github.com/andpalmier/seads@latest
seads -hFor Docker, you need to clone the GitHub repo and run:
docker build -t seads .
docker run -v "$(pwd)":/mnt seads -hCreate a config.yaml file with the following structure (be sure to check out the full example in the repo!):
urlscan:
token: "APIKEY"
scanurl: "https://urlscan.io/api/v1/scan/"
visibility: "unlisted"
tags: "seads_ads_tracker"
global-domain-exclusion:
exclusion-list: [ebay.com, amazon.com]
queries:
- query: "ipad"
expected-domains: [apple.com]
- query: "as roma"
expected-domains: []This config will search for ads related to ipad and as roma.
The field expected-domains is used to specify domains we are expecting to appear in the ads of search engines while searching for the specified keywords.
Domains in expected-domains and in global-domain-exclusion will still appear in the output of seads, but wonβt be sent in the notification.
The urlscan section is used to specify the API key and the URLScan API endpoint. The visibility field can be set to public, unlisted, or private. The tags field is used to specify tags for the scan.
Running seads with the provided config, storing the results in results.json, and sending notifications via the channels configured in the config:
seads -config config.yaml -out results.json -notifySame as above, but in Docker:
docker run -v "$(pwd)":/mnt seads -config /mnt/config.yaml -out /mnt/results.json -notifyRunning with redirection chain handled by URLScan, and save HTML page and screenshot:
seads -config config.yaml -urlscan -noredirect -screenshot ./screenshots -html ./htmlsSame as above, but in Docker:
docker run -v "$(pwd)":/mnt seads -config /mnt/config.yaml -urlscan -noredirect -screenshot /mnt/screenshots -html /mnt/htmlsExtended to example above with single keyword on certain with desired search engine:
seads -config config.yaml -urlscan -noredirect -screenshot ./screenshots -html ./htmls -directquery "as roma" -selectedengine "duckduckgo,syndicated"and, in Docker:
docker run -v "$(pwd)":/mnt seads -config /mnt/config.yaml -urlscan -noredirect -screenshot /mnt/screenshots -html /mnt/htmls -directquery "as roma" -selectedengine "duckduckgo,syndicated"You can leverage the notification feature by automating the execution of seads using a cron job or a task scheduler.
For example, in a Linux machine you can set up a cron job to run seads every day at 9 AM by adding the following line to your crontab:
0 9 * * * /path/to/seads -config /path/to/config.yaml -screenshot /path/to/screenshots -notifyBe sure to update the command to reflect the correct paths for the seads binary and the configuration file.
If using Docker, adjust the command accordingly for Docker execution.
On Windows and macOS, you can achieve similar scheduling using Task Scheduler or launchd.
-config (string) [REQUIRED]
path to config file (default "config.yaml") (default "config.yaml")
-cleanlinks
print clear links in output (links will remain defanged in notifications)
-concurrency int
number of concurrent headless browsers (default 4) (default 4)
-directquery string
Direct query from command line and not using queries on config file
-html string
path to store search engine result html page (if empty, the htmlPath feature will be disabled)
-log
enable detailed logging, VERY VERBOSE!
-noredirect
do not follow redirection; if "urlscan" is enabled, submit advertisement link to resolve by URLScan instead
-notify
notify if unexpected domains are found (requires notifications fields in config.yaml)
-out string
path of JSON file containing links of gathered ads
-printredirect
print redirection chain for ad links found
-screenshot string
path to store screenshots (if empty, the screenshot feature will be disabled)
-selectedengine string
Available search engine(s) selections separated by comma: google,bing,duckduckgo,yahoo,syndicated,adsenseads,aol (Default is all engines)
-ua string
User-Agent string to be used to click on ads
-urlscan
submit url to urlscan.io for analysis
- Rod: GitHub repo, documentation
- Shoutrrr: GitHub repo, documentation
- Fatih/color: GitHub repo, Go reference
- Carlmjohnson/requests GitHub repo, Go reference
I'd like to thank @raufridzuan for his help and contribution to this project!