Hold Tight...

0 %
Warith AL Maawali
Driving cybersecurity excellence
Innovator behind Linux Kodachi
  • Residence:
    ::0
  • Uptime Binary:
    101110
  • Mantra:
    Innovate, Secure, Repeat
ONS
EEDS
NSSG
Visual basic
Gambas
PHP
Delphi
Bash
  • Cybersecurity
  • Generative AI
  • Cloud & Automation
  • Cryptocurrency

Extracting SSL Fingerprints

13/05/2013

Extracting SSL Fingerprints: My Custom Scripts

I was looking for a script that can extract the SSL fingerprint from any SSL certificate, given you have the URL. I found a few scripts, but none of them did exactly what I expected, so I decided to write my own based on what I found. I created three versions of the script: one in Perl, one in Linux Shell scripting, and one in PHP. Note that all of them perform the same task and produce the same results.

The next plan was to develop an automated standalone application that could perform this task from multiple locations automatically (SSLEYE). It’s important to understand that secure browser connections can be intercepted and decrypted by anyone (Man-in-the-Middle, MITM) who could spoof the authentic site’s certificate and act on your behalf. This also allows them to read your traffic in clear text. Fortunately, the authentic site’s fingerprint cannot be duplicated, which is the main advantage of having such an application.

 

Perl script:

Perl
#!/usr/bin/perl
# Perl SSL Fingerprint Checker written by W. Al Maawali  
# (c) 2013 Founder of Eagle Eye Digital Solutions
# https://www.digi77.com
# http://www.om77.net
# script starts here:
# Usage: $perl sslf.pl -d yourdomain
# Example: $perl sslf.pl -d google.com

#libs used
use Net::SSLeay qw(get_https3);
use Getopt::Std;

# get args
getopts("o:i:d:s:e:hvb", \%args);

# set our input vars to easy names
$domain = $args{d};

# gotta have at least the domain and log file
if (!$args{d}) {
 print "\t Domain is blank google.com will be used\n\n";
 $domain ="google.com";

}

$host= $domain;
$port = 443;

($p, $resp, $hdrs, $server_cert) = get_https3($host, $port, '/');
#get finger print
print Net::SSLeay::X509_get_fingerprint($server_cert, "sha1");
print "\n";
Perl
Download

Shell script:

ShellScript
#!/bin/bash

# =========================================
# SSL Fingerprint Checker
# =========================================
#
# Version: 1.5
# Script written by Warith Al Maawali
#
# Discord channel: https://discord.gg/KEFErEx
# Twitter: http://twitter.com/warith2020
# Linkedin: http://www.linkedin.com/in/warith1977
# Website: https://www.digi77.com
# (c) 2024
#
# Description:
# This script retrieves the SSL fingerprint for one or multiple domains.
# It supports reading domains from command-line arguments or from a file (.txt or .csv).
# Includes fallback mechanisms and improved error handling for stability.
# Supports output in text or JSON format via the -o option without altering terminal output.
#
# Usage: ./sslfp.sh [options]
#
# Usage Examples:
# Check a Single Domain:
#   ./sslfp.sh -d google.com
# Check Multiple Domains via Command-Line:
#   ./sslfp.sh -d google.com -d example.com -d github.com
# Check Multiple Domains from a File:
#   Create a domains.txt file:
#     google.com
#     example.com
#     github.com
#
#   Run the script:
#     ./sslfp.sh -f domains.txt
# Output in JSON format to a file:
#   ./sslfp.sh -d google.com -o json
# Display Help:
#   ./sslfp.sh -h
# =========================================

# Enable debug mode (uncomment the next line for debugging)
# set -x

# Constants
SSL_PORT=443
RETRY_COUNT=3
TIMEOUT=15
DEFAULT_OUTPUT_FORMAT="text"

# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color

# Declare domains array globally
declare -a domains=()

# Functions

# Display usage instructions
usage() {
    cat <<EOF
Usage: $0 [options]

Options:
  -d DOMAIN       Specify a single domain to check. Can be used multiple times.
  -f FILE         Specify a file containing a list of domains (one per line).
  -o FORMAT       Specify output format for the file: 'text' or 'json'. Defaults to 'text'.
  -h, --help      Display this help message.

Examples:
  $0 -d google.com
  $0 -f domains.txt
  $0 -d google.com -o json
EOF
    exit 1
}

# Check if openssl is installed, if not, install it
install_openssl() {
    echo -e "${YELLOW}openssl is not installed. Installing now...${NC}"
    if command -v apt-get &>/dev/null; then
        sudo apt-get update
        sudo apt-get install -y openssl
    elif command -v yum &>/dev/null; then
        sudo yum install -y openssl
    else
        echo -e "${RED}Package manager not supported. Please install openssl manually.${NC}"
        exit 1
    fi

    if ! command -v openssl &>/dev/null; then
        echo -e "${RED}Failed to install openssl. Please install it manually and run this script again.${NC}"
        exit 1
    fi
}

# Function to fetch SSL fingerprint using openssl
get_fingerprint_openssl() {
    local domain="$1"
    local port="$2"
    local fingerprint

    fingerprint=$(timeout "${TIMEOUT}" bash -c "echo | openssl s_client -connect '${domain}:${port}' -servername '${domain}' 2>/dev/null" |
        openssl x509 -noout -fingerprint 2>/dev/null | cut -d'=' -f2)

    echo "$fingerprint"
}

# Function to fetch SSL fingerprint with retry mechanism
get_fingerprint() {
    local domain="$1"
    local port="$2"
    local attempt=1
    local fingerprint

    while [ "$attempt" -le "$RETRY_COUNT" ]; do
        fingerprint=$(get_fingerprint_openssl "$domain" "$port")
        if [ -n "$fingerprint" ]; then
            echo "$fingerprint"
            return 0
        else
            echo -e "${YELLOW}Attempt $attempt: Failed to retrieve fingerprint for $domain. Retrying...${NC}" >&2
            attempt=$((attempt + 1))
            sleep 1
        fi
    done

    return 1
}

# Parse command-line arguments
parse_arguments() {
    if [ "$#" -eq 0 ]; then
        usage
    fi

    OUTPUT_FORMAT="$DEFAULT_OUTPUT_FORMAT"

    while [[ "$#" -gt 0 ]]; do
        case "$1" in
            -d)
                if [ -n "$2" ] && [[ ! "$2" =~ ^- ]]; then
                    domains+=("$2")
                    shift 2
                else
                    echo -e "${RED}ERROR: -d requires a non-empty argument.${NC}"
                    usage
                fi
                ;;
            -f)
                if [ -n "$2" ] && [[ ! "$2" =~ ^- ]]; then
                    if [ -f "$2" ]; then
                        while IFS= read -r line || [ -n "$line" ]; do
                            # Trim whitespace
                            line=$(echo "$line" | xargs)
                            # Skip empty lines and comments
                            [[ -z "$line" || "$line" =~ ^# ]] && continue
                            domains+=("$line")
                        done < "$2"
                    else
                        echo -e "${RED}ERROR: File '$2' not found.${NC}"
                        exit 1
                    fi
                    shift 2
                else
                    echo -e "${RED}ERROR: -f requires a valid file path.${NC}"
                    usage
                fi
                ;;
            -o)
                if [ -n "$2" ] && [[ ! "$2" =~ ^- ]]; then
                    if [[ "$2" == "text" || "$2" == "json" ]]; then
                        OUTPUT_FORMAT="$2"
                    else
                        echo -e "${RED}ERROR: Invalid output format. Use 'text' or 'json'.${NC}"
                        usage
                    fi
                    shift 2
                else
                    echo -e "${RED}ERROR: -o requires a valid format (text or json).${NC}"
                    usage
                fi
                ;;
            -h|--help)
                usage
                ;;
            *)
                echo -e "${RED}ERROR: Unknown option: $1${NC}"
                usage
                ;;
        esac
    done

    # Remove duplicate domains
    unique_domains=($(printf "%s\n" "${domains[@]}" | sort -u))
    domains=("${unique_domains[@]}")

    # Check if domains are provided
    if [ "${#domains[@]}" -eq 0 ]; then
        echo -e "${RED}ERROR: No domains provided.${NC}"
        usage
    fi

    # Debugging statement (optional)
    # echo "DEBUG: OUTPUT_FORMAT is '$OUTPUT_FORMAT'"
}

# Output results to terminal with colors
output_to_terminal() {
    local domains_ref=("${!1}")
    declare -n results_ref=$2

    # Output header
    echo -e "${GREEN}Domain                         SSL Fingerprint${NC}"
    echo -e "${GREEN}------                         --------------${NC}"

    for domain in "${domains_ref[@]}"; do
        fingerprint="${results_ref[$domain]}"
        if [ "$fingerprint" != "FAILED" ]; then
            printf "%-30s ${GREEN}%-20s${NC}\n" "$domain" "$fingerprint"
        else
            printf "%-30s ${RED}%-20s${NC}\n" "$domain" "$fingerprint"
        fi
    done
}

# Save results to a file in specified format
save_to_file() {
    local domains_ref=("${!1}")
    declare -n results_ref=$2
    local format="$3"

    timestamp=$(date +%Y%m%d_%H%M%S)

    if [ "$format" == "json" ]; then
        output_file="ssl_fingerprints_${timestamp}.json"
        {
            echo "{"
            echo '  "domains": ['
            total=${#domains_ref[@]}
            for ((i=0; i < total; i++)); do
                domain="${domains_ref[$i]}"
                fingerprint="${results_ref[$domain]}"
                echo "    {"
                echo "      \"domain\": \"${domain}\","
                if [ "$fingerprint" != "FAILED" ]; then
                    echo "      \"fingerprint\": \"${fingerprint}\""
                else
                    echo "      \"fingerprint\": \"FAILED\""
                fi
                if [ "$i" -lt "$((total - 1))" ]; then
                    echo "    },"
                else
                    echo "    }"
                fi
            done
            echo '  ]'
            echo "}"
        } > "$output_file"
    elif [ "$format" == "text" ]; then
        output_file="ssl_fingerprints_${timestamp}.txt"
        {
            echo "Domain                         SSL Fingerprint"
            echo "------                         --------------"
            for domain in "${domains_ref[@]}"; do
                fingerprint="${results_ref[$domain]}"
                printf "%-30s %-20s\n" "$domain" "$fingerprint"
            done
        } > "$output_file"
    else
        echo -e "${RED}ERROR: Unsupported format '$format'. Use 'text' or 'json'.${NC}"
        exit 1
    fi

    echo -e "\n${GREEN}Results saved to $output_file${NC}"
}

# Main Execution

# Check if openssl is installed
if ! command -v openssl &>/dev/null; then
    install_openssl
fi

# Parse arguments and set global variables
parse_arguments "$@"

# Debugging statement (optional)
# echo "DEBUG: Parsed domains: ${domains[@]}"
# echo "DEBUG: Output format: $OUTPUT_FORMAT"

# Declare an associative array to store results
declare -A results

# Fetch fingerprints
for domain in "${domains[@]}"; do
    fingerprint=$(get_fingerprint "$domain" "$SSL_PORT")
    if [ "$?" -eq 0 ]; then
        results["$domain"]="$fingerprint"
    else
        results["$domain"]="FAILED"
    fi
done

# Output to terminal
output_to_terminal domains[@] results

# Save results to a file in the specified format
save_to_file domains[@] results "$OUTPUT_FORMAT"
ShellScript
Download

PHP script:

PHP
<?php 

# PHP SSL Fingerprint Checker written by W. Al Maawali  
# (c) 2013 Founder of Eagle Eye Digital Solutions
# https://www.digi77.com
# http://www.om77.net
# script starts here:
# Usage: http://www.yourdomain.com/sslf.php
# Example: https://www.digi77.com/software/fingerprint/fp-public.php?hosts=www.facebook.com

//avoid timeouts
set_time_limit(0);

//For String variable use prevent sql injections
function StringInputCleaner($data)
{
    $data = trim($data); 
    $data = stripslashes($data); 
    $data=(filter_var($data, FILTER_SANITIZE_STRING));
    return $data;
}    

function getSllCertificate($hostname, $port = 443)
{
    $context = stream_context_create(array("ssl" => array("capture_peer_cert" => true)));
    $socket = @stream_socket_client("ssl://$hostname:$port", $errno, $errstr, ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $context);

    if(!$socket)
        return array("md5" => "error", "sha1" => "error");

    $contextdata = stream_context_get_params($socket);
    $contextparams = $contextdata['options']['ssl']['peer_certificate'];

    fclose($socket);

    openssl_x509_export($contextparams, $cert, true);
    openssl_x509_free($contextparams);

    $repl = array("\r", "\n", "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
    $repw = array("", "", "", "");

    $cert = str_replace($repl, $repw, $cert);

    $decoded = base64_decode($cert);
    $fingerprints = array(
        "md5" => md5($decoded),
        "sha1" => sha1($decoded),
    );


    return $fingerprints ;
}

$host=$_REQUEST['hosts'];
//clean string safer coding
$host=StringInputCleaner($host);
$port=443;
$hashes = getSllCertificate($host, $port);

print_r($hashes['sha1']);


?>
PHP
Download

 

Posted in Tech BlogTags:
© 2024 Warith AL Maawali. All Rights Reserved.
Stay Secure, Stay Assured.