diff --git a/.gitignore b/.gitignore index 31541b7..9ec36df 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,7 @@ venv.bak/ # mypy .mypy_cache/ + +# Artifacts and downloads +reports/ +tools/ \ No newline at end of file diff --git a/README.md b/README.md index e169fa0..33c43ca 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,6 @@ optional arguments: ``` ## Requirements * Operating System **OSX** or **Linux** only -* python 2.7 * pip * git * jq diff --git a/modules/awsaudit.py b/modules/awsaudit.py index a287306..f961946 100755 --- a/modules/awsaudit.py +++ b/modules/awsaudit.py @@ -12,7 +12,7 @@ def get_account_alias(): account_details = subprocess.check_output(['aws iam list-account-aliases'], shell=True) - account_details = json.loads(str(account_details)) + account_details = json.loads(account_details.decode('utf-8')) try: return account_details['AccountAliases'][0] except IndexError: @@ -20,7 +20,7 @@ def get_account_alias(): def get_account_id(): caller_identity = subprocess.check_output(['aws sts get-caller-identity'], shell=True) - caller_identity = json.loads(str(caller_identity)) + caller_identity = json.loads(caller_identity.decode('utf-8')) try: return caller_identity['Account'] except IndexError: @@ -35,7 +35,7 @@ def get_account_id(): script_json['account_info'].update({'aws_api_region':['us-east-1']}) script_json['account_info'].update({'aws_filter_region':['all']}) identity = subprocess.check_output(['aws', 'sts', 'get-caller-identity']) -identity = json.loads(str(identity)) +identity = json.loads(identity.decode('utf-8')) script_json['account_info'].update({'caller_identity':identity}) @@ -74,7 +74,7 @@ def multi_threaded_prowler(): final_json['account_info'].update({'aws_api_region':['us-east-1']}) final_json['account_info'].update({'aws_filter_region':['all']}) identity = subprocess.check_output(['aws', 'sts', 'get-caller-identity']) - identity = json.loads(str(identity)) + identity = json.loads(identity.decode('utf-8')) final_json['account_info'].update({'caller_identity':identity}) report = [] for check in checks: diff --git a/modules/azureaudit.py b/modules/azureaudit.py index 1f4102e..b6c1dcc 100755 --- a/modules/azureaudit.py +++ b/modules/azureaudit.py @@ -18,7 +18,7 @@ def json_to_html(file, new_file): f.write(line) with open(file, 'r') as json_data: for line in json_data: - line = str(line) + line = line.decode('utf-8') final = json.loads(line) f.write('
\n') f.write('
\n') @@ -64,10 +64,10 @@ def no_guest_user(): def custom_owner_role(): """ The response is huge need to break down and analyse """ definition_list = subprocess.check_output(['az role definition list'], shell=True) - print definition_list + print (definition_list) def automatic_provising_agent(): - print "2.2: Checking for Automatic Provising Agent\n\n" + print ("2.2: Checking for Automatic Provising Agent\n\n") agent_provising = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type:application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'| jq \'.properties.logCollection\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'AUTOMATIC_PROVISING_AGENT' @@ -96,7 +96,7 @@ def automatic_provising_agent(): def system_update(): - print "2.3: Checking if System Updates are enabled\n\n" + print ("2.3: Checking if System Updates are enabled\n\n") system_update = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type:application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'| jq \'.properties.recommendations.patch\' | tr -d \'"\' '], shell=True).strip() result = {} result['check'] = 'SYSTEM_UPDATES' @@ -124,7 +124,7 @@ def system_update(): f.write("\n") def security_configuration(): - print "2.4: Checking if Security Configurations are enabled\n\n" + print ("2.4: Checking if Security Configurations are enabled\n\n") sec_config = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.baseline\' | tr -d \'"\' '], shell=True).strip() result = {} result['check'] = 'SECURITY_CONFIGURATIONS' @@ -152,7 +152,7 @@ def security_configuration(): f.write("\n") def endpoint_protection(): - print "2.5: Checking if Endpoint protection is enabled\n\n" + print ("2.5: Checking if Endpoint protection is enabled\n\n") end_protect = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.antimalware\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'ENDPOINT_PROTECTION' @@ -180,7 +180,7 @@ def endpoint_protection(): f.write("\n") def disk_encryption(): - print "2.6: Checking if Disk Encryption is set On\n\n" + print ("2.6: Checking if Disk Encryption is set On\n\n") encrypt_disk = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.diskEncryption\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'DISK_ENCRYPTION' @@ -208,7 +208,7 @@ def disk_encryption(): f.write("\n") def network_security(): - print "2.7: Checking if Network security groups recommendations is enabled\n\n" + print ("2.7: Checking if Network security groups recommendations is enabled\n\n") nsg = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.nsgs\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'SECURITY_GROUPS' @@ -236,7 +236,7 @@ def network_security(): f.write("\n") def web_app_firewall(): - print "2.8: Checking if Web Application Firewall is Enabled\n\n" + print ("2.8: Checking if Web Application Firewall is Enabled\n\n") waf = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.waf\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'WEB_APPLICATION_FIREWALL' @@ -264,7 +264,7 @@ def web_app_firewall(): f.write("\n") def next_gen_firewall(): - print "2.9: Checking if Next generation firewall recommendations are Enabled\n\n" + print ("2.9: Checking if Next generation firewall recommendations are Enabled\n\n") ngfw = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.ngfw\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'NEXT_GENERATION_FIREWALL' @@ -292,7 +292,7 @@ def next_gen_firewall(): f.write("\n") def vuln_assessment(): - print "2.10: Checking if Vulnerability assessment recommendations are Enabled\n\n" + print ("2.10: Checking if Vulnerability assessment recommendations are Enabled\n\n") va = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.vulnerabilityAssessment\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'VULNERABILITY_ASSESSMENT' @@ -320,7 +320,7 @@ def vuln_assessment(): f.write("\n") def storage_encyption(): - print "2.11: Checking if Storage Encryption is Enabled\n\n" + print ("2.11: Checking if Storage Encryption is Enabled\n\n") encrypt_disk = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.storageEncryption\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'STORAGE_ENCRYPTION' @@ -348,7 +348,7 @@ def storage_encyption(): f.write("\n") def jit_network_access(): - print "2.12: Checking if JIT Network Access is set to ON\n\n" + print ("2.12: Checking if JIT Network Access is set to ON\n\n") jit_net_access = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.jitNetworkAccess\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'JIT_NETWORK_ACCESS' @@ -376,7 +376,7 @@ def jit_network_access(): f.write("\n") def adaptive_application_control(): - print "2.13: Checking if Adaptive Application Controls is set to ON\n\n" + print ("2.13: Checking if Adaptive Application Controls is set to ON\n\n") app_control = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.appWhitelisting\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'ADAPTIVE_APPLICATION_CONTROL' @@ -404,7 +404,7 @@ def adaptive_application_control(): f.write("\n") def sql_auditing(): - print "2.14: Checking if SQL auditing & Threat detection is set to ON\n\n" + print ("2.14: Checking if SQL auditing & Threat detection is set to ON\n\n") sql_detect = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.sqlAuditing\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'SQL_AUDITING_&_THREAT_DETECTION' @@ -432,7 +432,7 @@ def sql_auditing(): f.write("\n") def sql_encryption(): - print "2.15: Checking if SQL Encryption is set to ON\n\n" + print ("2.15: Checking if SQL Encryption is set to ON\n\n") encrypt_sql = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.recommendations.sqlTde\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'SQL_ENCRYPTION' @@ -460,7 +460,7 @@ def sql_encryption(): f.write("\n") def security_email_set(): - print "2.16: Checking if Security contact emails is SET\n\n" + print ("2.16: Checking if Security contact emails is SET\n\n") email_config = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.securityContactConfiguration.securityContactEmails\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'SECURITY_CONTACT_EMAIL' @@ -488,7 +488,7 @@ def security_email_set(): f.write("\n") def security_contact_phone(): - print "2.17: Checking if Security contact Phone Number is SET\n\n" + print ("2.17: Checking if Security contact Phone Number is SET\n\n") phone_config = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.securityContactConfiguration.securityContactPhone\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'SECURITY_CONTACT_PHONE' @@ -516,7 +516,7 @@ def security_contact_phone(): f.write("\n") def email_for_alert(): - print "2.18: Checking if security e-mail alerts are enabled\n\n" + print ("2.18: Checking if security e-mail alerts are enabled\n\n") alert_email = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.securityContactConfiguration.areNotificationsOn\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'SECURITY_EMAIL_ALERTS' @@ -544,7 +544,7 @@ def email_for_alert(): f.write("\n") def email_for_subs_owners(): - print "2.19: Checking if security alerts for subscription owners are enabled\n\n" + print ("2.19: Checking if security alerts for subscription owners are enabled\n\n") email_owner = subprocess.check_output(['az account get-access-token --query "{subscripton:subscription,accessToken:accessToken}" --out tsv | xargs -L1 bash -c \'curl -s -X GET -H "Authorization: Bearer $1" -H "Content-Type: application/json" https://management.azure.com/subscriptions/$0/providers/microsoft.Security/policies?api-version=2015-06-01-preview\' | jq \'.|.value[] | select(.name=="default")\'|jq \'.properties.securityContactConfiguration.sendToAdminOn\' | tr -d \'"\''], shell=True).strip() result = {} result['check'] = 'SECURITY EMAIL ALERTS TO OWNERS' @@ -572,7 +572,7 @@ def email_for_subs_owners(): f.write("\n") def secure_transfer(): - print "3.1: Checking if storage accounts have HTTPS only traffic enabled \n\n" + print ("3.1: Checking if storage accounts have HTTPS only traffic enabled \n\n") https_enabled = subprocess.check_output(['az storage account list --query \[*\].\[name,enableHttpsTrafficOnly,primaryLocation\] --output tsv'], shell=True).strip() result = {} result['check'] = 'SECURE TRANSFER STORAGE ACCOUNT' @@ -603,7 +603,7 @@ def secure_transfer(): f.write("\n") def storage_service_encryption(): - print "3.2: Checking if storage accounts has its associated BLOB service encryption enabled \n\n" + print ("3.2: Checking if storage accounts has its associated BLOB service encryption enabled \n\n") storage_encryption = subprocess.check_output(['az storage account list --query \[*\].\[name,encryption.services.blob.enabled,primaryLocation\] --output tsv'], shell=True).strip() result = {} result['check'] = 'STORAGE SERVICE ENCRYPTION BLOB' @@ -642,10 +642,10 @@ def access_key_rotation(): for id in set(ids): time_stmp = subprocess.check_output(['az monitor activity-log list --resource-id %s --query [*].[eventTimestamp,resourceGroup] --output tsv' % id], shell=True) if time_stmp: - print time_stmp.strip() + print (time_stmp.strip()) def encrption_file_service(): - print "3.6: Checking if storage accounts has its associated FILE service encryption enabled \n\n" + print ("3.6: Checking if storage accounts has its associated FILE service encryption enabled \n\n") file_encryption = subprocess.check_output(['az storage account list --query \[*\].\[name,encryption.services.file.enabled,primaryLocation\] --output tsv'], shell=True).strip() result = {} result['check'] = 'FILE_SERVICE_ENCRYPTION' @@ -676,7 +676,7 @@ def encrption_file_service(): def log_profile(): - print "5.1: Checking if Log profile exists or not\n\n" + print ("5.1: Checking if Log profile exists or not\n\n") check_profile = subprocess.check_output(['az monitor log-profiles list --query [*].[id,name]'], shell=True).strip() result = {} j_res = {} @@ -704,7 +704,7 @@ def log_profile(): f.write("\n") def log_retention(): - print "5.2: Checking the retention policy of the log profile\n\n" + print ("5.2: Checking the retention policy of the log profile\n\n") retention_policy = subprocess.check_output(['az monitor log-profiles list --query [*].retentionPolicy.enabled --output tsv'],shell=True).strip() result = {} j_res = {} @@ -738,7 +738,7 @@ def log_retention(): def alert_for_create_policy(): - print "5.3: Checking if alert for Create Policy Assignment event exists\n\n" + print ("5.3: Checking if alert for Create Policy Assignment event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'CREATE_POLICY_ASSIGNMENT' @@ -769,7 +769,7 @@ def alert_for_create_policy(): def alert_group_create_network(): - print "5.4: Checking if alert for Create or Update Network Security GROUP event exists\n\n" + print ("5.4: Checking if alert for Create or Update Network Security GROUP event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'CREATE_NETWORK_GROUP' @@ -800,7 +800,7 @@ def alert_group_create_network(): def alert_group_network_delete(): - print "5.5: Checking if alert for Delete Network Security GROUP event exists\n\n" + print ("5.5: Checking if alert for Delete Network Security GROUP event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'DELETE_NETWORK_GROUP' @@ -831,7 +831,7 @@ def alert_group_network_delete(): def alert_rule_network_create(): - print "5.6: Checking if alert for Create or Update Network Security GROUP RULE event exists\n\n" + print ("5.6: Checking if alert for Create or Update Network Security GROUP RULE event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'CREATE_NETWORK_RULES' @@ -862,7 +862,7 @@ def alert_rule_network_create(): def alert_rule_network_delete(): - print "5.7: Checking if alert for Delete Network Security GROUP RULE event exists\n\n" + print ("5.7: Checking if alert for Delete Network Security GROUP RULE event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'DELETE_NETWORK_RULES' @@ -894,7 +894,7 @@ def alert_rule_network_delete(): def alert_create_security(): - print "5.8: Checking if alert for Create/Update Security Solution event exists\n\n" + print ("5.8: Checking if alert for Create/Update Security Solution event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'CREATE_SECURITY_SOLUTION' @@ -924,7 +924,7 @@ def alert_create_security(): f.write("\n") def alert_delete_security(): - print "5.9: Checking if alert for DELETE Security Solution event exists\n\n" + print ("5.9: Checking if alert for DELETE Security Solution event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'DELETE_SECURITY_SOLUTION' @@ -954,7 +954,7 @@ def alert_delete_security(): f.write("\n") def alert_create_sql_rule(): - print "5.10: Checking if alert for Create or Update SQL Server Firewall Rule event exists\n\n" + print ("5.10: Checking if alert for Create or Update SQL Server Firewall Rule event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'CREATE_SQL_FIREWALL_RULE' @@ -984,7 +984,7 @@ def alert_create_sql_rule(): f.write("\n") def alert_delete_sql_rule(): - print "5.11: Checking if alert for Delete SQL Server Firewall Rule event exists\n\n" + print ("5.11: Checking if alert for Delete SQL Server Firewall Rule event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'DELETE_SQL_FIREWALL_RULE' @@ -1014,7 +1014,7 @@ def alert_delete_sql_rule(): f.write("\n") def alert_update_security_policy(): - print "5.12: Checking if alert for changes in Security Policy event exists\n\n" + print ("5.12: Checking if alert for changes in Security Policy event exists\n\n") resource_groups = subprocess.check_output(['az monitor activity-log alert list --query \[*\].\[resourceGroup\] --output tsv'], shell=True).strip() result = {} result['check'] = 'UPDATE_SECURITY_POLICY' @@ -1044,7 +1044,7 @@ def alert_update_security_policy(): f.write("\n") def rdp_public(): - print "6.1: Checking if any network group allows public access to RDP\n\n" + print ("6.1: Checking if any network group allows public access to RDP\n\n") network_list = subprocess.check_output([' az network nsg list --query [*].name --output tsv'], shell=True).strip() result = {} data =[] @@ -1085,7 +1085,7 @@ def rdp_public(): f.write("\n") def ssh_public(): - print "6.2: Checking if any network group allows public access to SSH\n\n" + print ("6.2: Checking if any network group allows public access to SSH\n\n") network_list = subprocess.check_output([' az network nsg list --query [*].name --output tsv'], shell=True).strip() result = {} data =[] @@ -1125,7 +1125,7 @@ def ssh_public(): f.write("\n") def network_watcher(): - print "6.5: Checking if network watcher is enabled\n\n" + print ("6.5: Checking if network watcher is enabled\n\n") check = subprocess.check_output(['az network watcher list'], shell=True).strip() result = {} data =[] @@ -1153,7 +1153,7 @@ def network_watcher(): f.write("\n") def vm_agent(): - print "7.1: Checking if virtual agent is enabled on Virtual Machines\n\n" + print ("7.1: Checking if virtual agent is enabled on Virtual Machines\n\n") lines = subprocess.check_output(['az vm list --query [*].[resourceGroup,name] --output tsv'], shell=True).strip() result = {} result['check'] = 'VM_AGENT' @@ -1186,7 +1186,7 @@ def vm_agent(): f.write("\n") def vm_os_disk(): - print "7.2: Checking if OS disk encryption is enabled\n\n" + print ("7.2: Checking if OS disk encryption is enabled\n\n") lines = subprocess.check_output(['az vm list --query [*].[resourceGroup,name] --output tsv'], shell=True).strip() result = {} result['check'] = 'VM_OS_DISK_ENCRYPTION' @@ -1217,7 +1217,7 @@ def vm_os_disk(): f.write("\n") def vm_data_disk(): - print "7.3: Checking if DATA disk encryption is enabled\n\n" + print ("7.3: Checking if DATA disk encryption is enabled\n\n") lines = subprocess.check_output(['az vm list --query [*].[resourceGroup,name] --output tsv'], shell=True).strip() result = {} result['check'] = 'VM_DATA_DISK_ENCRYPTION' @@ -1249,7 +1249,7 @@ def vm_data_disk(): def approved_extension(): - print "7.4: Checking if the extensions are approved\n\n" + print ("7.4: Checking if the extensions are approved\n\n") lines = subprocess.check_output(['az vm list --query [*].[resourceGroup,name] --output tsv'], shell=True).strip() result = {} result['check'] = 'APPROVED_EXTENSION' @@ -1283,7 +1283,7 @@ def approved_extension(): f.write("\n") def vault_key(): - print "8.1: Checking if expiry is enabled for vault keys\n\n" + print ("8.1: Checking if expiry is enabled for vault keys\n\n") result = {} result['check'] = 'VAULT_KEY_EXPIRY' data = [] @@ -1334,7 +1334,7 @@ def vault_key(): def vault_secret(): - print "8.2: Checking if expiry is enabled for vault secret\n\n" + print ("8.2: Checking if expiry is enabled for vault secret\n\n") result = {} result['check'] = 'VAULT_SECRET_EXPIRY' data = [] @@ -1385,7 +1385,7 @@ def vault_secret(): f.write("\n") def sql_db_audit(): - print "4.2.1: Checking if SQL DB has AUDIT policy enabled\n\n" + print ("4.2.1: Checking if SQL DB has AUDIT policy enabled\n\n") result = {} result['check'] = 'SQL_DB_AUDIT' data = [] @@ -1432,7 +1432,7 @@ def sql_db_audit(): f.write("\n") def sql_db_threat(): - print "4.2.2: Checking if SQL DB has Threat Detection enabled\n\n" + print ("4.2.2: Checking if SQL DB has Threat Detection enabled\n\n") result = {} result['check'] = 'SQL_DB_THREAT_DETECTION' data = [] @@ -1480,7 +1480,7 @@ def sql_db_threat(): f.write("\n") def sql_db_disabled_alert(): - print "4.2.3: Checking if SQL DB has any alerts disabled\n\n" + print ("4.2.3: Checking if SQL DB has any alerts disabled\n\n") result = {} result['check'] = 'SQL_DB_DISABLED_ALERT' data = [] @@ -1528,7 +1528,7 @@ def sql_db_disabled_alert(): f.write("\n") def sql_db_send_email(): - print "4.2.4: Checking if SQL DB has any email alerts enabled\n\n" + print ("4.2.4: Checking if SQL DB has any email alerts enabled\n\n") result = {} result['check'] = 'SQL_DB_EMAIL_ALERT' data = [] @@ -1576,7 +1576,7 @@ def sql_db_send_email(): f.write("\n") def sql_db_email_admin(): - print "4.2.5: Checking if SQL DB has any Admin email alerts enabled\n\n" + print ("4.2.5: Checking if SQL DB has any Admin email alerts enabled\n\n") result = {} result['check'] = 'SQL_DB_EMAIL_ADMIN' data = [] @@ -1624,7 +1624,7 @@ def sql_db_email_admin(): f.write("\n") def sql_db_encryption(): - print "4.2.6: Checking if SQL DB has Transparent Data Encryption enabled\n\n" + print ("4.2.6: Checking if SQL DB has Transparent Data Encryption enabled\n\n") result = {} result['check'] = 'SQL_DB_DATA_ENCRYPTION' data = [] @@ -1672,7 +1672,7 @@ def sql_db_encryption(): f.write("\n") def sql_db_audit_retention(): - print "4.2.7: Checking if SQL DB has AUDIT log retention policy greater than 90 days\n\n" + print ("4.2.7: Checking if SQL DB has AUDIT log retention policy greater than 90 days\n\n") result = {} result['check'] = 'SQL_DB_AUDIT_RETENTION' data = [] @@ -1720,7 +1720,7 @@ def sql_db_audit_retention(): f.write("\n") def sql_db_threat_retention(): - print "4.2.8: Checking if SQL DB has THREAT log retention policy greater than 90 days\n\n" + print ("4.2.8: Checking if SQL DB has THREAT log retention policy greater than 90 days\n\n") result = {} result['check'] = 'SQL_DB_THREAT_RETENTION' data = [] @@ -1826,7 +1826,7 @@ def persistent(latest, last): def persistent_files(): dirs = os.listdir("./reports/AZURE/%s/" % (account_name)) if len(dirs) == 1: - print "This is the first audit run for the account, diff will be shown in the next run" + print ("This is the first audit run for the account, diff will be shown in the next run") with open("./reports/AZURE/%s/%s/diff.html" %(account_name, timestmp), 'w') as f: f.write("This is the first audit run for the account, diff will be shown in the next run") else: diff --git a/modules/doaudit.py b/modules/doaudit.py index 24c6d5e..470ffbc 100644 --- a/modules/doaudit.py +++ b/modules/doaudit.py @@ -14,7 +14,7 @@ def spaces_audit(do_key, do_secret): # Initialize a session using DigitalOcean Spaces. session = boto3.session.Session() - print "\n\n*********** SPACES AUDIT **************\n\n" + print ("\n\n*********** SPACES AUDIT **************\n\n") # Regions available for DigitalOcean Spaces - 'nyc3', 'ams3', etc etc regions = ['nyc3', 'ams3', 'sgp1', 'sfo2', 'fra1'] result = {} @@ -39,11 +39,11 @@ def spaces_audit(do_key, do_secret): if resp.status_code == 200: j_res['type'] = 'WARNING' j_res['value'] = "WARNING! The space %s is open to the public in region %s" % (space['Name'], region) - print "WARNING! The space %s is open to the public in region %s\n" % (space['Name'], region) + print ("WARNING! The space %s is open to the public in region %s\n" % (space['Name'], region)) elif resp.status_code == 403: j_res['type'] = 'PASS' j_res['value'] = "OK! the space %s is not open to the public in region %s\n" % (space['Name'], region) - print "OK! the space %s is not open to the public in region %s" % (space['Name'], region) + print ("OK! the space %s is not open to the public in region %s" % (space['Name'], region)) data.append(j_res) result['data'] = data result['check'] = 'SPACES_AUDIT' @@ -60,7 +60,7 @@ def database_audit(do_api): response = json.loads(response.text) result = {} data = [] - print "\n\n*********** DATABASES AUDIT **************\n\n" + print ("\n\n*********** DATABASES AUDIT **************\n\n") for database in response['databases']: j_res = {} j_res['check_no'] = '1.2' @@ -76,11 +76,11 @@ def database_audit(do_api): if resp['eviction_policy'] == "noeviction": j_res['type'] = 'WARNING' j_res['value'] = "WARNING! The database %s has no eviction/firewall policy" % (database['name']) - print "WARNING! The redis cluster %s has no eviction policy\n" % (database['name']) + print ("WARNING! The redis cluster %s has no eviction policy\n" % (database['name'])) else: j_res['type'] = 'PASS' j_res['value'] = "OK! The redis cluster %s has a eviction/restriction policy" %(database['name']) - print "OK! The redis cluster %s has a eviction/restriction policy\n" %(database['name']) + print ("OK! The redis cluster %s has a eviction/restriction policy\n" %(database['name'])) elif database['engine'] == 'mysql' or database['engine'] == 'postgresql': ev_policy_url = url + '/' + id + '/firewall' @@ -89,11 +89,11 @@ def database_audit(do_api): if not resp['rules']: j_res['type'] = 'WARNING' j_res['value'] = "WARNING! The database %s has no eviction/firewall policy" % (database['name']) - print "WARNING! The database %s has no eviction/firewall policy\n" % (database['name']) + print ("WARNING! The database %s has no eviction/firewall policy\n" % (database['name'])) else: j_res['type'] = 'PASS' j_res['value'] = "OK! The database %s has a eviction/firewall policy" % (database['name']) - print "OK! The database %s has a eviction/firewall policy\n" % (database['name']) + print ("OK! The database %s has a eviction/firewall policy\n" % (database['name'])) data.append(j_res) result['data'] = data result['check'] = 'DATABASES_AUDIT' @@ -109,7 +109,7 @@ def firewall_audit(do_api): resp = json.loads(response.text) result = {} data = [] - print "\n\n*********** FIREWALL AUDIT **************\n\n" + print ("\n\n*********** FIREWALL AUDIT **************\n\n") for firewall in resp['firewalls']: j_res = {} j_res['check_no'] = '1.3' @@ -125,12 +125,12 @@ def firewall_audit(do_api): rules['ports'] = "1-65535" j_res['type'] = 'WARNING' j_res['value'] = "WARNING! The firewall %s has port %s accessible to the world" %(name, rules['ports']) - print "WARNING! The firewall %s has port %s accessible to the world\n" %(name, rules['ports']) + print ("WARNING! The firewall %s has port %s accessible to the world\n" %(name, rules['ports'])) break else: j_res['type'] = 'PASS' j_res['value'] = "OK! The firewall %s does not allow port %s accessible to the world" %(name, rules['ports']) - print "OK! The firewall %s does not allow port %s accessible to the world\n" %(name, rules['ports']) + print ("OK! The firewall %s does not allow port %s accessible to the world\n" %(name, rules['ports'])) data.append(j_res.copy()) result['data'] = data result['check'] = 'FIREWALL_AUDIT' @@ -146,7 +146,7 @@ def droplet_audit(do_api): resp = json.loads(response.text) result = {} data = [] - print "\n\n*********** DROPLET AUDIT **************\n\n" + print ("\n\n*********** DROPLET AUDIT **************\n\n") for droplet in resp['droplets']: j_res = {} j_res['check_no'] = '1.4' @@ -157,11 +157,11 @@ def droplet_audit(do_api): if droplet['image']['slug'] in ['ubuntu-19-x64', 'fedora-30-x64', 'freebsd-12-x64-zfs', 'debian-10-x64', 'centos-7.6-x64']: j_res['type'] = 'PASS' j_res['value'] = "OK! The droplet %s has the latest version of OS being used" % droplet['name'] - print "OK! The droplet %s has the latest version of OS being used\n" % droplet['name'] + print ("OK! The droplet %s has the latest version of OS being used\n" % droplet['name']) else: j_res['type'] = 'WARNING' j_res['value'] = "WARNING! The droplet %s has older version of OS being used" % droplet['name'] - print "WARNING! The droplet %s has older version of OS being used\n" % droplet['name'] + print ("WARNING! The droplet %s has older version of OS being used\n" % droplet['name']) data.append(j_res) result['data'] = data result['check'] = 'DROPLET_AUDIT' @@ -177,7 +177,7 @@ def load_balancer_audit(do_api): resp = json.loads(response.text) result = {} data = [] - print "\n\n*********** LOAD BALANCER AUDIT **************\n\n" + print ("\n\n*********** LOAD BALANCER AUDIT **************\n\n") for load_balancer in resp['load_balancers']: j_res = {} j_res['check_no'] = '1.4' @@ -191,28 +191,28 @@ def load_balancer_audit(do_api): if rule['entry_port'] == 443 and rule['tls_passthrough'] == True: j_res['type'] = 'WARNING' j_res['value'] = "WARNING! The load-balancer %s is running on https without SSL/TLS certificate\n" % load_balancer['name'] - print "WARNING! The load-balancer %s is running on https without SSL/TLS certificate" % load_balancer['name'] + print ("WARNING! The load-balancer %s is running on https without SSL/TLS certificate" % load_balancer['name']) data.append(j_res.copy()) elif rule['entry_port'] == 443 and rule['tls_passthrough'] == False: j_res['type'] = 'PASS' j_res['value'] = "OK! The load-balancer %s is running on https with a SSL/TLS certificate" % load_balancer['name'] - print "OK! The load-balancer %s is running on https with a SSL/TLS certificate\n" % load_balancer['name'] + print ("OK! The load-balancer %s is running on https with a SSL/TLS certificate\n" % load_balancer['name']) data.append(j_res.copy()) if 80 and 443 in port: if load_balancer['redirect_http_to_https']: j_res['type'] = 'PASS' j_res['value'] = "OK! The load-balancer %s is running on https with a SSL/TLS certificate" % load_balancer['name'] - print "OK! Port 80 and 443 are open for load-balancer %s and redirect http to https is set to True\n" % load_balancer['name'] + print ("OK! Port 80 and 443 are open for load-balancer %s and redirect http to https is set to True\n" % load_balancer['name']) data.append(j_res.copy()) else: j_res['type'] = 'WARNING' j_res['value'] = "WARNING! The load-balancer %s is running on https without SSL/TLS certificate" % load_balancer['name'] - print "WARNING! Port 80 and 443 are open for load-balancer %s and redirect http to https is set to False\n" % load_balancer['name'] + print ("WARNING! Port 80 and 443 are open for load-balancer %s and redirect http to https is set to False\n" % load_balancer['name']) data.append(j_res.copy()) if (80 in port) and (443 not in port): j_res['type'] = 'WARNING' j_res['value'] = "WARNING! The load-balancer %s is running on https without SSL/TLS certificate" % load_balancer['name'] - print "WARNING! The load balancer %s is running on http only\n" % load_balancer['name'] + print ("WARNING! The load balancer %s is running on http only\n" % load_balancer['name']) data.append(j_res.copy()) result['data'] = data result['check'] = 'LOAD_BALANCER_AUDIT' @@ -227,7 +227,7 @@ def json_to_html(file, new_file): f.write(line) with open(file, 'r') as json_data: for line in json_data: - line = str(line) + line = line.decode('utf-8') final = json.loads(line) f.write('
\n') f.write('
\n') diff --git a/modules/localaudit.py b/modules/localaudit.py index e35252e..e539e67 100755 --- a/modules/localaudit.py +++ b/modules/localaudit.py @@ -5,7 +5,7 @@ def get_account_alias(): account_details = subprocess.check_output(['aws iam list-account-aliases'], shell=True) - account_details = json.loads(str(account_details)) + account_details = json.loads(account_details.decode('utf-8')) try: return account_details['AccountAliases'][0] except IndexError: @@ -13,7 +13,7 @@ def get_account_alias(): def get_account_id(): caller_identity = subprocess.check_output(['aws sts get-caller-identity'], shell=True) - caller_identity = json.loads(str(caller_identity)) + caller_identity = json.loads(caller_identity.decode('utf-8')) try: return caller_identity['Account'] except IndexError: diff --git a/modules/merger.py b/modules/merger.py index 780a3f0..3dacc86 100755 --- a/modules/merger.py +++ b/modules/merger.py @@ -1,9 +1,11 @@ +from __future__ import print_function + import glob import json import os import webbrowser import subprocess -import awsaudit +from modules import awsaudit from modules import logger log = logger.get() @@ -157,7 +159,7 @@ def json_to_html_prowler(): log.info("aws prowler report", extra=i) f.write('
\n') f.write('
\n') - f.write('
\n') + f.write('
\n') flag = 0 for g in i['data']: if g['type'] == 'WARNING': @@ -187,7 +189,7 @@ def json_to_html(file, new_file): f.write(line) with open(file, 'r') as json_data: for line in json_data: - line = str(line) + line = line.decode('utf-8') final = json.loads(line) f.write('
\n') f.write('
\n') @@ -281,7 +283,7 @@ def persistent(latest, last): def persistent_files(): dirs = os.listdir("./reports/AWS/aws_audit/%s/" % (account_name)) if len(dirs) == 1: - print "This is the first audit run for the account, diff will be shown in the next run" + print( "This is the first audit run for the account, diff will be shown in the next run") with open('./reports/AWS/aws_audit/%s/%s/delta/diff.html' % (account_name, timestmp), 'w') as f: f.write("This is the first audit for the account, diff will be shown in the next run") else: @@ -314,4 +316,4 @@ def merge(): webbrowser.open('file://' + os.path.realpath("./reports/AWS/aws_audit/%s/%s/final_report/report.html") % (account_name, timestmp)) fin = os.path.realpath("./reports/AWS/aws_audit/%s/%s/final_report/report.html") % (account_name, timestmp) - print ("THE FINAL REPORT IS LOCATED AT --------> %s" % (fin)) \ No newline at end of file + print("THE FINAL REPORT IS LOCATED AT --------> %s" % (fin)) diff --git a/requirements.txt b/requirements.txt index 8e548a6..2cf4044 100755 --- a/requirements.txt +++ b/requirements.txt @@ -26,7 +26,7 @@ pyasn1-modules==0.2.5 python-dateutil==2.6.1 python-json-logger==0.1.11 pytz==2019.1 -PyYAML==3.12 +PyYAML>=3.12 requests==2.18.4 rm==2019.4.13 rsa==3.4.2 diff --git a/scripts/audit_aws_certs.py b/scripts/audit_aws_certs.py index d911894..ba2a435 100755 --- a/scripts/audit_aws_certs.py +++ b/scripts/audit_aws_certs.py @@ -9,14 +9,14 @@ epoch=int(time.time()) account=subprocess.check_output(['aws', 'sts', 'get-caller-identity', '--output', 'text', '--query', 'Account']) account=account.strip() -certs = subprocess.check_output(['aws', 'iam', 'list-server-certificates', '--region', 'us-east-1', '--query', 'ServerCertificateMetadataList[].ServerCertificateName', '--output', 'text']) -if certs: +certs = subprocess.check_output(['aws', 'iam', 'list-server-certificates', '--region', 'us-east-1', '--query', 'ServerCertificateMetadataList[].ServerCertificateName', '--output', 'text']).decode('utf-8') +if certs: for cert in certs.split('\t'): cert=str(cert).strip() - expire_date=subprocess.check_output(['aws', 'iam','--region','us-east-1', 'get-server-certificate', '--server-certificate-name', '%s'%(cert), '--query', 'ServerCertificate.ServerCertificateMetadata.Expiration', '--output', 'text']).strip() + expire_date=subprocess.check_output(['aws', 'iam','--region','us-east-1', 'get-server-certificate', '--server-certificate-name', '%s'%(cert), '--query', 'ServerCertificate.ServerCertificateMetadata.Expiration', '--output', 'text']).strip().decode('utf-8') expire_time=time.mktime(time.strptime(expire_date,'%Y-%m-%dT%H:%M:%SZ')) epoch=int(time.time()) if epoch > expire_time: - print ("default,%s,us-east-1,null,WARNING,Scored,null,CERT_AUDIT,certificate %s has expired") % (account,cert) + print("default,%s,us-east-1,null,WARNING,Scored,null,CERT_AUDIT,certificate %s has expired" % (account,cert)) else: - print ("default,%s,us-east-1,null,PASS,Scored,null,CERT_AUDIT,certificate %s not expired") % (account,cert) + print("default,%s,us-east-1,null,PASS,Scored,null,CERT_AUDIT,certificate %s not expired" % (account,cert))