From 43ebb12f4c209707f44563ff7939bd90985f2331 Mon Sep 17 00:00:00 2001 From: Narbeh Date: Sun, 22 Apr 2018 14:44:04 +0430 Subject: [PATCH] Add Security Analyze --- README.md | 86 ++++++++++++++++++++++++++++++++++++++++---------- ssl_checker.py | 79 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 137 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 4d28b42..80332e0 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ # SSL Checker -#### Simple Python script that collects SSL information from hosts +#### Python script that collects SSL information from hosts ## About It's a simple script running in python that collects SSL information then it returns the group of information in JSON. It can also connects trough your specified SOCKS server. +One of the good thing about this script, is that it will full analyze the SSL certificate for security issue's and will include the report in the output or CSV file. + ## Requirements You only need to installl pyOpenSSL: @@ -15,17 +17,20 @@ You only need to installl pyOpenSSL: ``` ./ssl_checker.py -h -usage: ssl_checker.py -H [HOSTS [HOSTS ...]] [-s HOST:PORT] [-j] - [-c FILENAME.CSV] [-p] [-h] +usage: ssl_checker.py -H [HOSTS [HOSTS ...]] [-s HOST:PORT] [-c FILENAME.CSV] + [-j] [-a] [-p] [-h] + +Collects useful information about given host's SSL certificates. optional arguments: -H [HOSTS [HOSTS ...]], --host [HOSTS [HOSTS ...]] Hosts as input separated by space -s HOST:PORT, --socks HOST:PORT Enable SOCKS proxy for connection - -j, --json Enable JSON in the output -c FILENAME.CSV, --csv FILENAME.CSV Enable CSV file export + -j, --json Enable JSON in the output + -a, --analyze Enable SSL security analysis on the host -p, --pretty Print pretty and more human readable Json -h, --help Show this help message and exit ``` @@ -38,9 +43,11 @@ Port is optional here. The script will use 443 if not specified. `-s, --socks ` Enable connection through SOCKS server +`-c, --csv ` Enable CSV file export by specifying filename.csv after this argument + `-j, --json ` Use this if you want to only have the result in JSON -`-c, --csv ` Enable CSV file export by specifying filename.csv after this argument +`-a, --analyze` This argument will include security analyze on the certificate. It will take more time. `-p, --pretty ` Use this with `-j` to print indented and human readable JSON @@ -87,41 +94,80 @@ Analyzing 1 host(s): ## Example ``` -narbeh@narbeh-xps:~/ssl-checker$ ./ssl_checker.py -H narbeh.org google.com:443 facebook.com -Analyzing 3 host(s): -------------------- +narbeh@narbeh-xps:~/ssl-checker$ ./ssl_checker.py -H narbeh.org google.com:443 +Analyzing 2 host(s): +--------------------- [+] narbeh.org Issued domain: narbeh.org - Issued by: Let's Encrypt + Issued to: None + Issued by: Let's Encrypt (US) Valid from: 2018-04-21 - Valid to: 2018-07-20 (89 days left) + Valid to: 2018-07-20 (88 days left) Validity days: 90 Certificate S/N: 338163108483756707389368573553026254634358 Certificate version: 2 Certificate algorithm: sha256WithRSAEncryption Expired: False - ---- + [+] google.com Issued domain: *.google.com - Issued by: Google Inc + Issued to: Google Inc + Issued by: Google Inc (US) Valid from: 2018-03-28 - Valid to: 2018-06-20 (59 days left) + Valid to: 2018-06-20 (58 days left) Validity days: 83 Certificate S/N: 2989116342670522968 Certificate version: 2 Certificate algorithm: sha256WithRSAEncryption Expired: False - ---- - [-] facebook.com Failed: [Errno 111] Connection refused - ---- -2 successful and 1 failed + +2 successful and 0 failed ``` + +## Security Analyze + +By passing `-a/--analyze` to the script, it will scan the certificate for security issues and vulnerabilities. It will also mark a grade for the certificate. **This will take more time to finish.** + +``` +Analyzing 1 host(s): +--------------------- + +Warning: -a/--analyze is enabled. It takes more time... + + [+] narbeh.org + + Issued domain: narbeh.org + Issued to: None + Issued by: Let's Encrypt (US) + Valid from: 2018-04-21 + Valid to: 2018-07-20 (88 days left) + Validity days: 90 + Certificate S/N: 338163108483756707389368573553026254634358 + Certificate version: 2 + Certificate algorithm: sha256WithRSAEncryption + Certificate grade: A + Poodle vulnerability: False + Heartbleed vulnerability: False + Hearbeat vulnerability: True + Freak vulnerability: False + Logjam vulnerability: False + Drown vulnerability: False + Expired: False + + +1 successful and 0 failed +``` + + + +##JSON And CSV Output + Example only with the `-j/--json` and `-p/--pretty` arguments which shows the JSON only. Perfect for piping to another tool. ``` @@ -130,6 +176,7 @@ narbeh@narbeh-xps:~/ssl-checker$ ./ssl_checker.py -j -p -H narbeh.org:443 test. 'cert_exp': False, 'cert_sn': 338163108483756707389368573553026254634358L, 'cert_ver': 2, + 'issued_o': None, 'issued_to': u'narbeh.org', 'issuer_c': u'US', 'issuer_cn': u"Let's Encrypt Authority X3", @@ -142,6 +189,7 @@ narbeh@narbeh-xps:~/ssl-checker$ ./ssl_checker.py -j -p -H narbeh.org:443 test. 'cert_exp': False, 'cert_sn': 73932709062103623902948514363737041075L, 'cert_ver': 2, + 'issued_o': None, 'issued_to': u'www.test.com', 'issuer_c': u'US', 'issuer_cn': u'Network Solutions DV Server CA 2', @@ -176,3 +224,7 @@ cert_sn,338163108483756707389368573553026254634358 +### Author + +Narbeh Arakil +http://narbeh.org \ No newline at end of file diff --git a/ssl_checker.py b/ssl_checker.py index 3b0b5b4..ccb08fc 100755 --- a/ssl_checker.py +++ b/ssl_checker.py @@ -43,6 +43,40 @@ def get_cert(host, port, user_args): return cert +def analyze_ssl(host, context): + """Analyze the security of the SSL certificate.""" + from json import loads + try: + from urllib.request import urlopen + except ImportError: + from urllib2 import urlopen + + api_url = 'https://api.ssllabs.com/api/v3/' + counter = 0 + + while True: + main_request = loads(urlopen(api_url + 'analyze?host={}'.format(host)).read().decode('utf-8')) + if main_request['status'] in ['DNS', 'IN_PROGRESS']: + print('Analyzing {}. Please wait'.format(host) + '.' * counter) + sys.stdout.write("\033[F") + counter += 1 + continue + elif main_request['status'] == 'READY': + break + + context[host]['grade'] = main_request['endpoints'][0]['grade'] + endpoint_data = loads(urlopen(api_url + 'getEndpointData?host={}&s={}'.format(host, main_request['endpoints'][0]['ipAddress'])).read().decode('utf-8')) + + context[host]['poodle_vuln'] = endpoint_data['details']['poodle'] + context[host]['heartbleed_vuln'] = endpoint_data['details']['heartbleed'] + context[host]['heartbeat_vuln'] = endpoint_data['details']['heartbeat'] + context[host]['freak_vuln'] = endpoint_data['details']['freak'] + context[host]['logjam_vuln'] = endpoint_data['details']['logjam'] + context[host]['drownVulnerable'] = endpoint_data['details']['drownVulnerable'] + + return context + + def get_cert_info(host, cert): """Get all the information about cert and create a JSON file.""" context = {} @@ -76,7 +110,7 @@ def get_cert_info(host, cert): return context -def print_status(host, context): +def print_status(host, context, analyze=False): """Print all the usefull info about host.""" days_left = (datetime.strptime(context[host]['valid_till'], '%Y-%m-%d') - datetime.now()).days @@ -90,8 +124,18 @@ def print_status(host, context): print('\t\tCertificate S/N: {}'.format(context[host]['cert_sn'])) print('\t\tCertificate version: {}'.format(context[host]['cert_ver'])) print('\t\tCertificate algorithm: {}'.format(context[host]['cert_alg'])) - print('\t\tExpired: {}'.format(context[host]['cert_exp'])) - print('\t----') + + if analyze: + print('\t\tCertificate grade: {}'.format(context[host]['grade'])) + print('\t\tPoodle vulnerability: {}'.format(context[host]['poodle_vuln'])) + print('\t\tHeartbleed vulnerability: {}'.format(context[host]['heartbleed_vuln'])) + print('\t\tHearbeat vulnerability: {}'.format(context[host]['heartbeat_vuln'])) + print('\t\tFreak vulnerability: {}'.format(context[host]['freak_vuln'])) + print('\t\tLogjam vulnerability: {}'.format(context[host]['logjam_vuln'])) + print('\t\tDrown vulnerability: {}'.format(context[host]['drownVulnerable'])) + + + print('\t\tExpired: {}\n'.format(context[host]['cert_exp'])) def show_result(user_args): @@ -103,6 +147,9 @@ def show_result(user_args): if not user_args.json_true: print('Analyzing {} host(s):\n{}\n'.format(len(hosts), '-' * 21)) + if not user_args.json_true and user_args.analyze: + print('{}Warning: -a/--analyze is enabled. It takes more time...{}\n'.format(Clr.YELLOW, Clr.RST)) + for host in hosts: host, port = filter_hostname(host) @@ -113,14 +160,21 @@ def show_result(user_args): try: cert = get_cert(host, port, user_args) context[host] = get_cert_info(host, cert) + + # Analyze the certificate if enabled + if user_args.analyze: + context = analyze_ssl(host, context) + if not user_args.json_true: - print_status(host, context) + print_status(host, context, user_args.analyze) except Exception as error: if not user_args.json_true: - print('\t{}[-]{} {:<20s} Failed: {}'.format(Clr.RED, Clr.RST, host, error)) - print('\t----') + print('\t{}[-]{} {:<20s} Failed: {}\n'.format(Clr.RED, Clr.RST, host, error)) + failed_cnt += 1 + except KeyboardInterrupt: + print('{}Canceling script...{}\n'.format(Clr.YELLOW, Clr.RST)) + sys.exit(1) - failed_cnt += 1 if not user_args.json_true: print('\n{} successful and {} failed\n'.format(len(hosts) - failed_cnt, failed_cnt)) @@ -160,18 +214,21 @@ def filter_hostname(host): def get_args(): """Set argparse options.""" parser = ArgumentParser(prog='ssl_checker.py', add_help=False, - description="""Collects useful information about given hosts SSL certificates.""") + description="""Collects useful information about given host's SSL certificates.""") parser.add_argument('-H', '--host', dest='hosts', nargs='*', required=True, help='Hosts as input separated by space') parser.add_argument('-s', '--socks', dest='socks', default=False, metavar='HOST:PORT', help='Enable SOCKS proxy for connection') - parser.add_argument('-j', '--json', dest='json_true', - action='store_true', default=False, - help='Enable JSON in the output') parser.add_argument('-c', '--csv', dest='csv_enabled', default=False, metavar='FILENAME.CSV', help='Enable CSV file export') + parser.add_argument('-j', '--json', dest='json_true', + action='store_true', default=False, + help='Enable JSON in the output') + parser.add_argument('-a', '--analyze', dest='analyze', + default=False, action='store_true', + help='Enable SSL security analysis on the host') parser.add_argument('-p', '--pretty', dest='pretty_output', action='store_true', default=False, help='Print pretty and more human readable Json')