nmap-ciphers.py

import subprocess
import sys
import re
import os
import requests

# ANSI color codes
ANSI_RESET = "\033[0m"
ANSI_YELLOW = "\033[33m"
ANSI_RED = "\033[31m"
ANSI_BLUE = "\033[34m"
ANSI_GREEN = "\033[32m"
ANSI_WHITE = "\033[37m"

# Function to check cipher security using the API
def check_cipher_security(cipher_name):
    url = f"https://ciphersuite.info/api/cs/{cipher_name}/"
    response = requests.get(url)
    
    if response.status_code == 200:
        cipher_data = response.json()
        if cipher_name in cipher_data:
            security_status = cipher_data[cipher_name].get('security', 'unknown')
            return security_status
        else:
            return "Cipher suite information not found"
    else:
        return "Error"

# Function to display the cipher security status
def display_security_status(cipher_name, security_status):
    color_map = {
        'weak': ANSI_YELLOW,
        'insecure': ANSI_RED,
        'recommended': ANSI_BLUE,
        'secure': ANSI_GREEN
    }
    
    color = color_map.get(security_status.lower(), ANSI_WHITE)
    return f"{cipher_name} --> {color}{security_status.capitalize()}{ANSI_RESET}"

# Function to run nmap and parse the output
def run_nmap_ssl_enum(ip, port):
    result = ""
    
    try:
        result = subprocess.run(
            ["nmap", "--script", "ssl-enum-ciphers", "-p", port, ip],
            capture_output=True,
            text=True
        ).stdout
    except Exception as e:
        print(f"An error occurred while running nmap: {e}")
    
    formatted_output = parse_nmap_output(ip, port, result)
    return formatted_output

# Function to parse nmap output and combine it with security checks
def parse_nmap_output(ip, port, output):
    formatted_output = (
        f"IP/URL: {ANSI_BLUE}{ip}{ANSI_RESET}\n"
        f"Port: {ANSI_BLUE}{port}{ANSI_RESET}\n\n"
        "Ciphers:\n"
    )

    tls_version_re = re.compile(r"\|\s+(TLSv[0-9]\.[0-9]):")
    cipher_re = re.compile(r"\|\s+([A-Z0-9_]+(?:_[A-Z0-9]+)*)")

    tls_versions = tls_version_re.findall(output)
    ciphers_by_tls = {}

    for tls_version in tls_versions:
        ciphers_by_tls[tls_version] = []

    current_tls = None
    for line in output.splitlines():
        tls_match = tls_version_re.match(line)
        if tls_match:
            current_tls = tls_match.group(1)
        elif current_tls:
            cipher_match = cipher_re.match(line)
            if cipher_match:
                cipher = cipher_match.group(1)
                if "NULL" not in cipher and "64" not in cipher:
                    ciphers_by_tls[current_tls].append(cipher)

    for tls_version, ciphers in ciphers_by_tls.items():
        if ciphers:
            formatted_output += f"{tls_version}\n"
            for cipher in ciphers:
                security_status = check_cipher_security(cipher)
                formatted_output += f"{display_security_status(cipher, security_status)}\n"
            formatted_output += "\n"

    return formatted_output.strip()

# Function to process the input file with IP and port list
def process_ip_port_file(filename):
    if not os.path.isfile(filename):
        print(f"File {filename} not found.")
        return

    try:
        with open(filename, "r") as file:
            for line in file:
                if line.strip():
                    ip_port_pair = line.strip().split()
                    ports = ip_port_pair[0].split(',')
                    ip = ip_port_pair[1]
                    for port in ports:
                        formatted_output = run_nmap_ssl_enum(ip, port)
                        print(formatted_output + "\n" + "-"*50 + "\n")
    except Exception as e:
        print(f"An error occurred while processing the file: {e}")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python nmap_ciphers.py <ip_port_list.txt>")
        sys.exit(1)
    
    input_filename = sys.argv[1]
    
    process_ip_port_file(input_filename)

# By AdaniKamal

Last updated