Add Security Analyze

This commit is contained in:
Narbeh 2018-04-22 14:44:04 +04:30
parent be8e039d30
commit 43ebb12f4c
2 changed files with 137 additions and 28 deletions

View File

@ -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

View File

@ -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')