From 760ebb2852b0a7bd09fcfd1b2d17c0ecd836a2bc Mon Sep 17 00:00:00 2001 From: TheArqsz <38382850+TheArqsz@users.noreply.github.com> Date: Wed, 23 Jul 2025 18:10:37 +0200 Subject: [PATCH] Added bashdog docstrings, updated and cleaned up the code --- .bashdog.yaml | 18 + README.md | 29 +- crt_v2.sh | 367 ++++++++++++------- docs/crt_v2.md | 158 ++++++++ {Screenshot => images}/Screenshot_Domain.png | Bin {Screenshot => images}/Screenshot_Help.png | Bin {Screenshot => images}/Screenshot_Org.png | Bin 7 files changed, 446 insertions(+), 126 deletions(-) create mode 100644 .bashdog.yaml create mode 100644 docs/crt_v2.md rename {Screenshot => images}/Screenshot_Domain.png (100%) rename {Screenshot => images}/Screenshot_Help.png (100%) rename {Screenshot => images}/Screenshot_Org.png (100%) diff --git a/.bashdog.yaml b/.bashdog.yaml new file mode 100644 index 0000000..916a5ad --- /dev/null +++ b/.bashdog.yaml @@ -0,0 +1,18 @@ +project_name: "crt.sh" + +output_directory: "./docs" + +exclude: + - "crt.sh" + +parsers: + tag_prefix: "@" + + module: + style: + char: "=" + min_length: 10 + + function: + start_marker: "##!" + end_marker: "#'" diff --git a/README.md b/README.md index 9fd384f..9fb7645 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,30 @@ +### Updated Docs after new changes ([@TheArqsz](https://github.com/TheArqsz)) + +The logic of the script was changed a little bit so one can use it more freely in the automated environment and it aligns more with popular security tools. + +Updated usage: + +```bash +A script to query the crt.sh certificate transparency log. + +Usage: ./crt_v2.sh [OPTIONS] + +Options: + -d, --domain Search for a specific domain name (e.g., hackerone.com) + --org Search for a specific organization name (e.g., 'HackerOne, Inc.') + -o, --output File to save results. If not set, results are printed to stdout. + -s, --silent Suppress banner and non-essential output. + -h, --help Display this help message + +Examples: + ./crt_v2.sh --domain hackerone.com + ./crt_v2.sh --org 'HackerOne, Inc.' --output ./results.txt + ./crt_v2.sh -d example.com -s | grep '.com' + ./crt_v2.sh -d example.com -s | httpx +``` + +All the original credits go to [az7rb](https://github.com/az7rb) + ### Updated Documentation for crt.sh v2.0 The **v2.0** version of the script, now named `crt_v2.sh`, introduces significant improvements in performance, reliability, and documentation. Below are the updated instructions for setting up and using both the original script `crt.sh` and the new `crt_v2.sh`: @@ -64,7 +91,7 @@ Both commands will enumerate subdomains for `hackerone.com` and output them in a For a quick visual guide, refer to the screenshot below: -![Help Screenshot](https://raw.githubusercontent.com/az7rb/crt.sh/main/Screenshot/Screenshot_Help.png) +![Help Screenshot](images/Screenshot_Help.png) --- ### Additional Resources diff --git a/crt_v2.sh b/crt_v2.sh index 770018b..1a58a97 100644 --- a/crt_v2.sh +++ b/crt_v2.sh @@ -1,152 +1,269 @@ -#!/bin/bash +#!/usr/bin/env bash + +# ============================================================================== +# @module crt_v2.sh +# @description +# This script queries the crt.sh certificate transparency log to retrieve domain names associated with specific domains or organizations. +# It processes the raw certificate data, cleaning and filtering it to provide unique and relevant domain results. +# +# Key features include: +# - Searching for domain names and subdomains. +# - Searching for domains associated with specific organizations. +# - Cleaning and de-duplicating search results. +# - Outputting results to standard output or a specified file. +# +# @author +# az7rb, Arqsz +# ============================================================================== # Display banner -echo " +banner=" +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ..| search crt.sh v 2.0 |.. | -+ site : crt.sh Certificate Search + -| Twitter: az7rb | +| ..| search crt.sh v2.4 |.. | ++ site: crt.sh Certificate Search + +| Twitter: az7rb | +| Modified by: Arqsz | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ " -# Function: Help -# Purpose: Display the help message with usage instructions. -Help() { - echo "Options:" +##! +# @description +# Displays the help message for the script, detailing its usage, +# available options, and examples. +# +# @example +# show_help +#' +show_help() { + echo "A script to query the crt.sh certificate transparency log." + echo "" + echo "Usage: $0 [OPTIONS]" echo "" - echo "-h Help" - echo "-d Search Domain Name | Example: $0 -d hackerone.com" - echo "-o Search Organization Name | Example: $0 -o hackerone+inc" + echo "Options:" + echo " -d, --domain Search for a specific domain name (e.g., hackerone.com)" + echo " --org Search for a specific organization name (e.g., 'HackerOne, Inc.')" + echo " -o, --output File to save results. If not set, results are printed to stdout." + echo " -s, --silent Suppress banner and non-essential output." + echo " -h, --help Display this help message" echo "" + echo "Examples:" + echo " $0 --domain hackerone.com" + echo " $0 --org 'HackerOne, Inc.' --output ./results.txt" + echo " $0 -d example.com -s | grep '.com'" + echo " $0 -d example.com -s | httpx" } -# Function: CleanResults -# Purpose: Clean and filter the results by removing unwanted characters and duplicates. -# - Converts escaped newlines to actual newlines. -# - Removes wildcard characters (*). -# - Filters out email addresses. -# - Sorts the results and removes duplicates. -CleanResults() { - sed 's/\\n/\n/g' | \ - sed 's/\*.//g' | \ - sed -r 's/([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})//g' | \ - sort | uniq +##! +# @description +# Cleans and filters input data, typically piped to this function, +# by removing unwanted characters and duplicates. It converts escaped +# newlines to actual newlines, removes wildcard characters (*), filters out +# email addresses and lines containing spaces, and ensures entries contain a dot. +# Finally, it sorts the results and removes duplicates. +# +# @returns {string} +# A multi-line string of cleaned, sorted, and unique domain names. +# +# @example +# echo "example.com\\n*.test.com\\nuser@example.com" | clean_results +#' +clean_results() { + sed 's/\\n/\n/g' | + sed 's/\*.//g' | + # Filter out entries that are likely email addresses + grep -v '@' | + # Filter out lines with spaces (e.g., certificate names) + grep -v ' ' | + # Filter out entries that do not contain a dot (i.e., not a full domain) + grep '\.' | + # Remove any leading/trailing whitespace + sed 's/^[ \t]*//;s/[ \t]*$//' | + sort -u } -# Function: Domain -# Purpose: Search for certificates associated with a specific domain name. -# - Sends a request to crt.sh with the specified domain. -# - Processes the JSON response to extract common names and domain values. -# - Cleans and filters the results using CleanResults function. -# - Saves the results to an output file and displays them. -Domain() { - # Check if the domain name is provided - if [ -z "$req" ]; then - echo "Error: Domain name is required." - exit 1 - fi - - # Perform the search request to crt.sh - response=$(curl -s "https://crt.sh?q=%.$req&output=json") - - # Check if the response is empty - if [ -z "$response" ]; then - echo "No results found for domain $req" - exit 1 +##! +# @description +# Searches the crt.sh certificate transparency log for certificates +# associated with a given domain name. It fetches common names and +# name values from the crt.sh JSON API, then cleans and filters the results. +# +# @arg {string} $1 - The domain name to search for (e.g., "example.com"). +# @arg {boolean} $2 - A flag indicating whether silent mode is enabled. +# If `true`, suppresses status messages printed to standard error. +# +# @returns {string} +# A multi-line string of unique and cleaned domain names found for the specified domain. +# Returns an empty string if no results are found or the request fails. +# +# @example +# domain_search "hackerone.com" false +#' +domain_search() { + local domain_req="$1" + local silent_mode="$2" + + if [[ "$silent_mode" = false ]]; then + # Print status messages to stderr to not interfere with stdout + echo "[*] Searching for domain: $domain_req" >&2 fi - - # Process the response, clean it, and store the results - results=$(echo "$response" | jq -r ".[].common_name,.[].name_value" | CleanResults) - - # Check if there are any valid results after cleaning - if [ -z "$results" ]; then - echo "No valid results found." - exit 1 + + local response + response=$(curl -fs "https://crt.sh?q=%.$domain_req&output=json") + + # If request fails or returns no data, return nothing. + if [[ $? -ne 0 || -z "$response" || "$response" == "[]" ]]; then + return fi - - # Define the output file name based on the domain - output_file="output/domain.$req.txt" - - # Save the results to the output file - echo "$results" > "$output_file" - - # Display the results and summary - echo "" + + local results + results=$(echo "$response" | jq -r '.[].common_name, .[].name_value' | clean_results) + echo "$results" - echo "" - echo -e "\e[32m[+]\e[0m Total Save will be \e[31m$(echo "$results" | wc -l)\e[0m Domain only" - echo -e "\e[32m[+]\e[0m Output saved in $output_file" } -# Function: Organization -# Purpose: Search for certificates associated with a specific organization name. -# - Sends a request to crt.sh with the specified organization name. -# - Processes the JSON response to extract common names. -# - Cleans and filters the results using CleanResults function. -# - Saves the results to an output file and displays them. -Organization() { - # Check if the organization name is provided - if [ -z "$req" ]; then - echo "Error: Organization name is required." - exit 1 - fi - - # Perform the search request to crt.sh - response=$(curl -s "https://crt.sh?q=$req&output=json") - - # Check if the response is empty - if [ -z "$response" ]; then - echo "No results found for organization $req" - exit 1 +##! +# @description +# Searches the crt.sh certificate transparency log for certificates +# associated with a given organization name. It fetches common names and +# name values from the crt.sh JSON API, then cleans and filters the results. +# +# @arg {string} $1 - The organization name to search for (e.g., "HackerOne, Inc."). +# This argument should be URL-encoded if it contains special characters. +# @arg {boolean} $2 - A flag indicating whether silent mode is enabled. +# If `true`, suppresses status messages printed to standard error. +# +# @returns {string} +# A multi-line string of unique and cleaned domain names found for the specified organization. +# Returns an empty string if no results are found or the request fails. +# +# @example +# org_search "HackerOne%2C%20Inc." false +#' +org_search() { + local org_req="$1" + local silent_mode="$2" + + if [[ "$silent_mode" = false ]]; then + echo "[*] Searching for organization: $org_req" >&2 fi - - # Process the response, clean it, and store the results - results=$(echo "$response" | jq -r ".[].common_name" | CleanResults) - - # Check if there are any valid results after cleaning - if [ -z "$results" ]; then - echo "No valid results found." - exit 1 + + local response + response=$(curl -fs "https://crt.sh?q=$org_req&output=json") + + # If request fails or returns no data, return nothing. + if [[ $? -ne 0 || -z "$response" || "$response" == "[]" ]]; then + return fi - - # Define the output file name based on the organization name - output_file="output/org.$req.txt" - - # Save the results to the output file - echo "$results" > "$output_file" - - # Display the results and summary - echo "" + + local results + results=$(echo "$response" | jq -r '.[].common_name, .[].name_value' | clean_results) + echo "$results" - echo "" - echo -e "\e[32m[+]\e[0m Total Save will be \e[31m$(echo "$results" | wc -l)\e[0m Domain only" - echo -e "\e[32m[+]\e[0m Output saved in $output_file" } -# Main Script Logic +DOMAIN_SEARCH="" +ORG_SEARCH="" +OUTPUT_FILE="" +SILENT_MODE=false -# If no arguments are provided, display the help message -if [ -z "$1" ]; then - Help - exit +if [[ "$#" -eq 0 ]]; then + show_help + exit 0 fi -# Parse command-line options using getopts -while getopts "h:d:o:" option; do - case $option in - h) # Display help - Help - ;; - d) # Search for domain name - req=$OPTARG - Domain - ;; - o) # Search for organization name - req=$OPTARG - Organization - ;; - *) # Invalid option, display help - Help - ;; +while [[ "$#" -gt 0 ]]; do + case "$1" in + -h | --help) + show_help + exit 0 + ;; + -s | --silent) + SILENT_MODE=true + ;; + -d | --domain) + if [[ -n "$2" && ! "$2" =~ ^- ]]; then + DOMAIN_SEARCH="$2" + shift + else + echo "Error: Missing argument for $1" >&2 + exit 1 + fi + ;; + --org) + if [[ -n "$2" && ! "$2" =~ ^- ]]; then + ORG_SEARCH="$2" + shift + else + echo "Error: Missing argument for $1" >&2 + exit 1 + fi + ;; + -o | --output) + if [[ -n "$2" && ! "$2" =~ ^- ]]; then + OUTPUT_FILE="$2" + shift + else + echo "Error: Missing argument for $1" >&2 + exit 1 + fi + ;; + *) + echo "Error: Unknown parameter passed: $1" >&2 + show_help + exit 1 + ;; esac + shift done + +if [[ "$SILENT_MODE" = false ]]; then + echo "${banner}" >&2 +fi + +if [[ -z "$DOMAIN_SEARCH" && -z "$ORG_SEARCH" ]]; then + show_help + exit 0 +fi + +if [[ -n "$DOMAIN_SEARCH" && -n "$ORG_SEARCH" ]]; then + echo "Error: Please specify either a domain (-d) or an organization (--org), not both." >&2 + exit 1 +elif [[ -z "$DOMAIN_SEARCH" && -z "$ORG_SEARCH" ]]; then + echo "Error: You must specify a domain (-d) or an organization (--org) to search." >&2 + show_help + exit 1 +fi + +RESULTS="" +if [[ -n "$DOMAIN_SEARCH" ]]; then + RESULTS=$(domain_search "$DOMAIN_SEARCH" "$SILENT_MODE") +elif [[ -n "$ORG_SEARCH" ]]; then + # URL-encode the organization string for the query + ORG_SEARCH_ENCODED=$(echo -n "$ORG_SEARCH" | jq -sRr @uri) + RESULTS=$(org_search "$ORG_SEARCH_ENCODED" "$SILENT_MODE") +fi + +if [[ -z "$RESULTS" ]]; then + if [[ "$SILENT_MODE" = false ]]; then + echo "[-] No results found." >&2 + fi + exit 1 +fi + +# Decide where to send the output based on whether -o was used +if [[ -n "$OUTPUT_FILE" ]]; then + output_dir=$(dirname "$OUTPUT_FILE") + mkdir -p "$output_dir" + if [[ ! -d "$output_dir" ]]; then + echo "Error: Could not create output directory for: $OUTPUT_FILE" >&2 + exit 1 + fi + echo "$RESULTS" >"$OUTPUT_FILE" + + if [[ "$SILENT_MODE" = false ]]; then + printf "[+] Total of %s unique domains found.\n" "$(echo "$RESULTS" | wc -l)" >&2 + printf "[+] Results saved to %s\n" "$OUTPUT_FILE" >&2 + fi +else + echo "$RESULTS" +fi diff --git a/docs/crt_v2.md b/docs/crt_v2.md new file mode 100644 index 0000000..fb38c0b --- /dev/null +++ b/docs/crt_v2.md @@ -0,0 +1,158 @@ +# crt.sh Documentation + +## Table of Contents +- [**crt_v2.sh**](#crt_v2sh-crt_v2sh) + + + +

Module: crt_v2.sh

+ +**Author:** az7rb, Arqsz + +### Description + +This script queries the crt.sh certificate transparency log to retrieve domain names associated with specific domains or organizations. + +It processes the raw certificate data, cleaning and filtering it to provide unique and relevant domain results. + + + +Key features include: + +- Searching for domain names and subdomains. + +- Searching for domains associated with specific organizations. + +- Cleaning and de-duplicating search results. + +- Outputting results to standard output or a specified file. + + + +## Functions + + +

show_help

+ + +Displays the help message for the script, detailing its usage, +available options, and examples. + + + + + +#### Example: + +```bash +show_help +``` + + + + +

clean_results

+ + +Cleans and filters input data, typically piped to this function, +by removing unwanted characters and duplicates. It converts escaped +newlines to actual newlines, removes wildcard characters (*), filters out +email addresses and lines containing spaces, and ensures entries contain a dot. +Finally, it sorts the results and removes duplicates. + + + + + +#### Example: + +```bash +echo "example.com\\n*.test.com\\nuser@example.com" | clean_results +``` + + + +#### Returns: + +

{string} +A multi-line string of cleaned, sorted, and unique domain names. +

+ + + + + + +Searches the crt.sh certificate transparency log for certificates +associated with a given domain name. It fetches common names and +name values from the crt.sh JSON API, then cleans and filters the results. + + + +#### Arguments + +| Name | Type | Description | +|------|-------------|-------------| +| `$1` | *string* | The domain name to search for (e.g., "example.com"). | +| `$2` | *boolean* | A flag indicating whether silent mode is enabled. If `true`, suppresses status messages printed to standard error. | + + + + +#### Example: + +```bash +domain_search "hackerone.com" false +``` + + + +#### Returns: + +

{string} +A multi-line string of unique and cleaned domain names found for the specified domain. +Returns an empty string if no results are found or the request fails. +

+ + + + + + +Searches the crt.sh certificate transparency log for certificates +associated with a given organization name. It fetches common names and +name values from the crt.sh JSON API, then cleans and filters the results. + + + +#### Arguments + +| Name | Type | Description | +|------|-------------|-------------| +| `$1` | *string* | The organization name to search for (e.g., "HackerOne, Inc."). This argument should be URL-encoded if it contains special characters. | +| `$2` | *boolean* | A flag indicating whether silent mode is enabled. If `true`, suppresses status messages printed to standard error. | + + + + +#### Example: + +```bash +org_search "HackerOne%2C%20Inc." false +``` + + + +#### Returns: + +

{string} +A multi-line string of unique and cleaned domain names found for the specified organization. +Returns an empty string if no results are found or the request fails. +

+ + diff --git a/Screenshot/Screenshot_Domain.png b/images/Screenshot_Domain.png similarity index 100% rename from Screenshot/Screenshot_Domain.png rename to images/Screenshot_Domain.png diff --git a/Screenshot/Screenshot_Help.png b/images/Screenshot_Help.png similarity index 100% rename from Screenshot/Screenshot_Help.png rename to images/Screenshot_Help.png diff --git a/Screenshot/Screenshot_Org.png b/images/Screenshot_Org.png similarity index 100% rename from Screenshot/Screenshot_Org.png rename to images/Screenshot_Org.png