Google Dorking

Automate the process of google dorking searches in order to detect leaked data.

Data Enrichment & Threat Intelligence · Google Dorking

Details

IDGoogle Dorking
ProviderOpen Source
CategoryData Enrichment & Threat Intelligence
From Version6.2.0
Docker Imagedemisto/python3:3.12.8.3296088
Supported ModulesAgentix XSIAM

README

Automate the process of google dorking searches in order to detect leaked data.

Configure Google Dorking in Cortex

Parameter Description Required
Search engine ID   True
API Key   True
File Types to Search Comma separated file types that’ll be searched and downloaded. True
Search Keywords Comma separated keywords to look for in the files. False
Sites To Search Provide a single or comma separated list of sites from which to perform the search on. True
Fetch incidents   False
Incident type   False
Maximum number of incidents per fetch   False
First fetch time   False
Trust any certificate (not secure)   False
Use system proxy settings   False
Incidents Fetch Interval   False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

google-dorking-search


Use the google search engine to search a query.

Base Command

google-dorking-search

Input

Argument Name Description Required
after Search after this date. Expected format: YYYY-MM-DD. Optional
file_types Comma separated file types that’ll be searched and downloaded. Optional
keywords Comma separated keywords to look for in the files. Optional
urls Provide a single or comma separated list of sites from which to perform the search on. Optional

Context Output

There is no context output for this command.

Command Example

``````

Human Readable Output

Configuration parameters

  • apiKey — Search engine ID (required)
  • file_types — File Types to Search (required)
  • keywords — Search Keywords
  • urls — Sites To Search (required)
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • max_fetch — Maximum number of incidents per fetch
  • first_fetch — First fetch time
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • incidentFetchInterval — Incidents Fetch Interval

Commands (1)

  • google-dorking-search

    Use the google search engine to search a query.

import json
import math
import traceback
from collections.abc import Callable
from os import path

import dateparser
import demistomock as demisto  # noqa: F401
import urllib3
from CommonServerPython import *  # noqa: F401

# Disable insecure warnings
urllib3.disable_warnings()

""" CONSTANTS """

MAX_INCIDENTS_TO_FETCH = 100
MAX_RESULTS_PER_PAGE = 10
LAST_RUN_TIME_KEY = "last_date"
GOOGLE_TIME_FORMAT = "%Y-%m-%d"

""" CLIENT CLASS """


class Client(BaseClient):
    def __init__(self, urls, api_key, search_engine_id, search_file_types, keywords, max_results, **kwargs):
        super().__init__(**kwargs)
        self._urls = urls
        self._cx = search_engine_id
        self._api_key = api_key
        self._search_file_types = search_file_types
        self._keywords = keywords
        self._max_results = max_results
        self._after = None

    @property
    def max_results(self):
        return self._max_results

    @property
    def after(self):
        return self._after

    @after.setter
    def after(self, value):
        self._after = value

    @property
    def urls(self):
        return self._urls

    @urls.setter
    def urls(self, value):
        self._urls = value

    @property
    def file_types(self):
        return self._search_file_types

    @file_types.setter
    def file_types(self, value):
        self._search_file_types = value

    @property
    def keywords(self):
        return self._keywords

    @keywords.setter
    def keywords(self, value):
        self._keywords = value

    def search(self, q, start=0, num=10) -> dict:
        params = assign_params(cx=self._cx, key=self._api_key, q=q, filter=1, start=start, num=num)
        response = self._http_request("GET", params=params)
        return response

    def build_query(self) -> str:
        """Builds a google query in the format of "filetype:...allintext:...site:... after:... " """
        query = " OR ".join([f"filetype:{x}" for x in self._search_file_types])
        if self._keywords:
            query += " " + " OR ".join([f"allintext:{x}" for x in self._keywords])
        if self._urls:
            query += " " + " OR ".join([f"site:{x}" for x in self._urls])
        if self.after:
            query += f" after:{self.after}"
        return query


def calculate_page_size(current_page: int, max_results: int) -> int:
    results_so_far = current_page * MAX_RESULTS_PER_PAGE
    if (results_diff := max_results - results_so_far) < MAX_RESULTS_PER_PAGE:
        return results_diff
    return MAX_RESULTS_PER_PAGE


def get_search_results(client: Client, parser: Callable) -> list | str:
    """Searches google and returns a result using the parser"""
    results = []
    query = client.build_query()
    all_pages_found = False
    pages = math.ceil(client.max_results / MAX_RESULTS_PER_PAGE)
    current_page = 0
    start = 0
    while not all_pages_found and current_page < pages:
        results_in_page = calculate_page_size(current_page, client.max_results)
        page = client.search(query, start, results_in_page)
        items = page.get("items")
        if not items:
            break

        for item in items:
            results.extend(parser(client, item))

        # prepare next run
        current_page += 1
        start += results_in_page
        total = int(demisto.get(page, "searchInformation.totalResults", demisto.get(page, "queries.request.totalResults", 0)))
        all_pages_found = total <= start
    if not results:
        return "No results found"
    return results


def item_to_incident(client: Client, item: dict) -> list:
    files = []
    if link := item.get("link"):
        try:
            file_result = fileResult(path.basename(link), client._http_request("GET", full_url=link, resp_type="content"))
            files.append({"path": file_result["FileID"], "name": file_result["File"]})
        except Exception as e:
            demisto.debug(f"Failed fetching file from {link}. {e!s}")
    return [assign_params(name=item.get("title", ""), attachment=files, rawJSON=json.dumps(item))]


def item_to_result(client: Client, item: dict) -> list:
    results = []
    if link := item.get("link"):
        file_result = fileResult(path.basename(link), client._http_request("GET", full_url=link, resp_type="content"))
        results.append(file_result)
    results.append(CommandResults(outputs_prefix="GoogleDorking", outputs=item))
    return results


def test_module(client: Client) -> str:
    client.search("hello world")
    return "ok"


def google_search_command(
    client: Client,
    after: str = None,
    file_types: str = None,
    keywords: str = None,
    urls: str = None,
) -> list | str:
    if after:
        client.after = after
    if file_types:
        client.file_types = argToList(file_types)
    if keywords:
        client.keywords = argToList(keywords)
    if urls:
        client.urls = argToList(urls)
    return get_search_results(client, item_to_result)


def fetch_incidents(client: Client, last_run: dict | None) -> list:
    now = datetime.now()
    last_run_date = last_run.get(LAST_RUN_TIME_KEY) if last_run else None
    if last_run_date and (now - dateparser.parse(last_run_date)).days > 0:  # type: ignore
        client.after = last_run_date
    incidents = get_search_results(client, item_to_incident)
    if not isinstance(incidents, list):
        demisto.debug(f"Skipping incident creation. Received: {incidents}, expected list.")
        incidents = []

    demisto.setLastRun({LAST_RUN_TIME_KEY: (now - timedelta(days=1)).strftime(GOOGLE_TIME_FORMAT)})

    return incidents


""" MAIN FUNCTION """


def main() -> None:
    params = demisto.params()
    search_engine_id = params.get("apiKey").get("identifier")
    api_key = params.get("apiKey").get("password")
    verify_certificate = not params.get("insecure", False)
    proxy = params.get("proxy", False)

    search_urls = argToList(params.get("urls"))
    search_file_types = argToList(params.get("file_types"))
    keywords = argToList(params.get("keywords"))
    first_fetch_time = arg_to_datetime(arg=params.get("first_fetch"), arg_name="First fetch time", required=False)
    max_fetch = max(arg_to_number(params.get("max_fetch")) or MAX_INCIDENTS_TO_FETCH, MAX_INCIDENTS_TO_FETCH)
    command = demisto.command()
    args = demisto.args()
    demisto.info(f"Command being called is {command}")
    try:
        client = Client(
            base_url="https://customsearch.googleapis.com/customsearch/v1",
            verify=verify_certificate,
            proxy=proxy,
            urls=search_urls,
            api_key=api_key,
            search_engine_id=search_engine_id,
            search_file_types=search_file_types,
            keywords=keywords,
            max_results=max_fetch,
        )
        if first_fetch_time:
            client.after = first_fetch_time.strftime(GOOGLE_TIME_FORMAT)

        if command == "test-module":
            # This is the call made when pressing the integration Test button.
            result = test_module(client)
            return_results(result)

        elif command == "google-dorking-search":
            return_results(google_search_command(client, **args))

        elif command == "fetch-incidents":
            demisto.incidents(fetch_incidents(client, demisto.getLastRun()))

    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(f"Failed to execute {command} command.\nError:\n{e!s}")


""" ENTRY POINT """

if __name__ in ("__main__", "__builtin__", "builtins"):
    main()