From e1708af1bb8d44dbef05b9f495c4e276158238fb Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Thu, 13 Aug 2020 00:34:00 +0500 Subject: [PATCH 01/67] SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation --- collectors/aws/collector.js | 6 + exports.js | 388 +++++++++--------- .../aws/cloudformation/plainTextParameters.js | 70 ++++ 3 files changed, 270 insertions(+), 194 deletions(-) create mode 100644 plugins/aws/cloudformation/plainTextParameters.js diff --git a/collectors/aws/collector.js b/collectors/aws/collector.js index be291cf944..fe386d0b27 100644 --- a/collectors/aws/collector.js +++ b/collectors/aws/collector.js @@ -60,6 +60,12 @@ var calls = { } } }, + CloudFormation: { + describeStacks: { + property: 'Stacks', + paginate: 'NextToken' + } + }, CloudFront: { // TODO: Pagination is using an older format listDistributions: { diff --git a/exports.js b/exports.js index 912d562838..f8dac891a1 100644 --- a/exports.js +++ b/exports.js @@ -2,200 +2,200 @@ module.exports = { aws : { - 'acmValidation' : require(__dirname + '/plugins/aws/acm/acmValidation.js'), - 'acmCertificateExpiry' : require(__dirname + '/plugins/aws/acm/acmCertificateExpiry.js'), - 'asgMultiAz' : require(__dirname + '/plugins/aws/autoscaling/asgMultiAz.js'), - 'workgroupEncrypted' : require(__dirname + '/plugins/aws/athena/workgroupEncrypted.js'), - 'workgroupEnforceConfiguration' : require(__dirname + '/plugins/aws/athena/workgroupEnforceConfiguration.js'), - 'publicS3Origin' : require(__dirname + '/plugins/aws/cloudfront/publicS3Origin.js'), - 'secureOrigin' : require(__dirname + '/plugins/aws/cloudfront/secureOrigin.js'), - 'insecureProtocols' : require(__dirname + '/plugins/aws/cloudfront/insecureProtocols.js'), - 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), - 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), - 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), - - 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), - 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), - 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), - 'cloudtrailEncryption' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEncryption.js'), - 'cloudtrailFileValidation' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailFileValidation.js'), - 'cloudtrailToCloudwatch' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailToCloudwatch.js'), - 'cloudtrailBucketPrivate' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketPrivate.js'), - - 'configServiceEnabled' : require(__dirname + '/plugins/aws/configservice/configServiceEnabled.js'), - - 'dmsEncryptionEnabled' : require(__dirname + '/plugins/aws/dms/dmsEncryptionEnabled.js'), - - 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), - - 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), - 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), - 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), - 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), - 'instanceLimit' : require(__dirname + '/plugins/aws/ec2/instanceLimit.js'), - 'instanceVcpusLimit' : require(__dirname + '/plugins/aws/ec2/instanceVcpusLimit.js'), - 'instanceMaxCount' : require(__dirname + '/plugins/aws/ec2/instanceMaxCount.js'), - 'instanceKeyBasedLogin' : require(__dirname + '/plugins/aws/ec2/instanceKeyBasedLogin.js'), - 'openAllPortsProtocols' : require(__dirname + '/plugins/aws/ec2/openAllPortsProtocols.js'), - 'openCIFS' : require(__dirname + '/plugins/aws/ec2/openCIFS.js'), - 'openDNS' : require(__dirname + '/plugins/aws/ec2/openDNS.js'), - 'openDocker' : require(__dirname + '/plugins/aws/ec2/openDocker.js'), - 'openFTP' : require(__dirname + '/plugins/aws/ec2/openFTP.js'), - 'openHadoopNameNode' : require(__dirname + '/plugins/aws/ec2/openHadoopNameNode.js'), - 'openHadoopNameNodeWebUI' : require(__dirname + '/plugins/aws/ec2/openHadoopNameNodeWebUI.js'), - 'openKibana' : require(__dirname + '/plugins/aws/ec2/openKibana.js'), - 'openMySQL' : require(__dirname + '/plugins/aws/ec2/openMySQL.js'), - 'openOracle' : require(__dirname + '/plugins/aws/ec2/openOracle.js'), - 'openNetBIOS' : require(__dirname + '/plugins/aws/ec2/openNetBIOS.js'), - 'openPostgreSQL' : require(__dirname + '/plugins/aws/ec2/openPostgreSQL.js'), - 'openRDP' : require(__dirname + '/plugins/aws/ec2/openRDP.js'), - 'openRPC' : require(__dirname + '/plugins/aws/ec2/openRPC.js'), - 'openSalt' : require(__dirname + '/plugins/aws/ec2/openSalt.js'), - 'openSMBoTCP' : require(__dirname + '/plugins/aws/ec2/openSMBoTCP.js'), - 'openSMTP' : require(__dirname + '/plugins/aws/ec2/openSMTP.js'), - 'openSQLServer' : require(__dirname + '/plugins/aws/ec2/openSQLServer.js'), - 'openSSH' : require(__dirname + '/plugins/aws/ec2/openSSH.js'), - 'openTelnet' : require(__dirname + '/plugins/aws/ec2/openTelnet.js'), - 'openVNCClient' : require(__dirname + '/plugins/aws/ec2/openVNCClient.js'), - 'openVNCServer' : require(__dirname + '/plugins/aws/ec2/openVNCServer.js'), - 'openElasticsearch' : require(__dirname + '/plugins/aws/ec2/openElasticsearch.js'), - 'vpcElasticIpLimit' : require(__dirname + '/plugins/aws/ec2/vpcElasticIpLimit.js'), - 'classicInstances' : require(__dirname + '/plugins/aws/ec2/classicInstances.js'), - 'flowLogsEnabled' : require(__dirname + '/plugins/aws/ec2/flowLogsEnabled.js'), - 'vpcMultipleSubnets' : require(__dirname + '/plugins/aws/ec2/multipleSubnets.js'), - 'overlappingSecurityGroups' : require(__dirname + '/plugins/aws/ec2/overlappingSecurityGroups.js'), - 'publicAmi' : require(__dirname + '/plugins/aws/ec2/publicAmi.js'), - 'encryptedAmi' : require(__dirname + '/plugins/aws/ec2/encryptedAmi.js'), - 'instanceIamRole' : require(__dirname + '/plugins/aws/ec2/instanceIamRole.js'), - 'ebsEncryptionEnabled' : require(__dirname + '/plugins/aws/ec2/ebsEncryptionEnabled.js'), - 'ebsSnapshotPrivate' : require(__dirname + '/plugins/aws/ec2/ebsSnapshotPrivate.js'), - 'natMultiAz' : require(__dirname + '/plugins/aws/ec2/natMultiAz.js'), - 'defaultVpcInUse' : require(__dirname + '/plugins/aws/ec2/defaultVpcInUse.js'), - 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), - 'crossVpcPublicPrivate' : require(__dirname + '/plugins/aws/ec2/crossVpcPublicPrivate.js'), - 'ebsEncryptedSnapshots' : require(__dirname + '/plugins/aws/ec2/ebsEncryptedSnapshots.js'), - 'ec2MetadataOptions' : require(__dirname + '/plugins/aws/ec2/ec2MetadataOptions.js'), - - 'efsEncryptionEnabled' : require(__dirname + '/plugins/aws/efs/efsEncryptionEnabled.js'), - - 'ecrRepositoryPolicy' : require(__dirname + '/plugins/aws/ecr/ecrRepositoryPolicy.js'), - 'ecrRepositoryTagImmutability' : require(__dirname + '/plugins/aws/ecr/ecrRepositoryTagImmutability.js'), - - 'eksKubernetesVersion' : require(__dirname + '/plugins/aws/eks/eksKubernetesVersion.js'), - 'eksLoggingEnabled' : require(__dirname + '/plugins/aws/eks/eksLoggingEnabled.js'), - 'eksPrivateEndpoint' : require(__dirname + '/plugins/aws/eks/eksPrivateEndpoint.js'), - 'eksSecurityGroups' : require(__dirname + '/plugins/aws/eks/eksSecurityGroups.js'), - - 'insecureCiphers' : require(__dirname + '/plugins/aws/elb/insecureCiphers.js'), - 'elbHttpsOnly' : require(__dirname + '/plugins/aws/elb/elbHttpsOnly.js'), - 'elbLoggingEnabled' : require(__dirname + '/plugins/aws/elb/elbLoggingEnabled.js'), - 'elbNoInstances' : require(__dirname + '/plugins/aws/elb/elbNoInstances.js'), - - 'elbv2LoggingEnabled' : require(__dirname + '/plugins/aws/elbv2/elbv2LoggingEnabled.js'), - 'elbv2HttpsOnly' : require(__dirname + '/plugins/aws/elbv2/elbv2HttpsOnly.js'), - 'elbv2NoInstances' : require(__dirname + '/plugins/aws/elbv2/elbv2NoInstances.js'), - 'elbv2WafEnabled' : require(__dirname + '/plugins/aws/elbv2/elbv2WafEnabled.js'), - - 'esPublicEndpoint' : require(__dirname + '/plugins/aws/es/esPublicEndpoint.js'), - 'esRequireIAMAuth' : require(__dirname + '/plugins/aws/es/esRequireIAMAuth.js'), - 'esEncryptedDomain' : require(__dirname + '/plugins/aws/es/esEncryptedDomain.js'), - 'esNodeToNodeEncryption' : require(__dirname + '/plugins/aws/es/esNodeToNodeEncryption.js'), - 'esLoggingEnabled' : require(__dirname + '/plugins/aws/es/esLoggingEnabled.js'), - 'esUpgradeAvailable' : require(__dirname + '/plugins/aws/es/esUpgradeAvailable.js'), - 'esHttpsOnly' : require(__dirname + '/plugins/aws/es/esHttpsOnly.js'), - - 'accessKeysExtra' : require(__dirname + '/plugins/aws/iam/accessKeysExtra.js'), - 'accessKeysLastUsed' : require(__dirname + '/plugins/aws/iam/accessKeysLastUsed.js'), - 'accessKeysRotated' : require(__dirname + '/plugins/aws/iam/accessKeysRotated.js'), - 'certificateExpiry' : require(__dirname + '/plugins/aws/iam/certificateExpiry.js'), - 'emptyGroups' : require(__dirname + '/plugins/aws/iam/emptyGroups.js'), - 'iamUserAdmins' : require(__dirname + '/plugins/aws/iam/iamUserAdmins.js'), - 'iamUserNameRegex' : require(__dirname + '/plugins/aws/iam/iamUserNameRegex.js'), - 'iamRolePolicies' : require(__dirname + '/plugins/aws/iam/iamRolePolicies.js'), - 'maxPasswordAge' : require(__dirname + '/plugins/aws/iam/maxPasswordAge.js'), - 'minPasswordLength' : require(__dirname + '/plugins/aws/iam/minPasswordLength.js'), - 'noUserIamPolicies' : require(__dirname + '/plugins/aws/iam/noUserIamPolicies.js'), - 'passwordExpiration' : require(__dirname + '/plugins/aws/iam/passwordExpiration.js'), - 'passwordRequiresLowercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresLowercase.js'), - 'passwordRequiresNumbers' : require(__dirname + '/plugins/aws/iam/passwordRequiresNumbers.js'), - 'passwordRequiresSymbols' : require(__dirname + '/plugins/aws/iam/passwordRequiresSymbols.js'), - 'passwordRequiresUppercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresUppercase.js'), - 'passwordReusePrevention' : require(__dirname + '/plugins/aws/iam/passwordReusePrevention.js'), - 'rootAccessKeys' : require(__dirname + '/plugins/aws/iam/rootAccessKeys.js'), - 'rootAccountInUse' : require(__dirname + '/plugins/aws/iam/rootAccountInUse.js'), - 'rootHardwareMfa' : require(__dirname + '/plugins/aws/iam/rootHardwareMfa.js'), - 'rootMfaEnabled' : require(__dirname + '/plugins/aws/iam/rootMfaEnabled.js'), - 'sshKeysRotated' : require(__dirname + '/plugins/aws/iam/sshKeysRotated.js'), - 'usersMfaEnabled' : require(__dirname + '/plugins/aws/iam/usersMfaEnabled.js'), - 'usersPasswordAndKeys' : require(__dirname + '/plugins/aws/iam/usersPasswordAndKeys.js'), - 'usersPasswordLastUsed' : require(__dirname + '/plugins/aws/iam/usersPasswordLastUsed.js'), - 'canaryKeysUsed' : require(__dirname + '/plugins/aws/iam/canaryKeysUsed.js'), - 'kinesisEncrypted' : require(__dirname + '/plugins/aws/kinesis/kinesisEncrypted.js'), - 'firehoseEncrypted' : require(__dirname + '/plugins/aws/firehose/firehoseEncrypted.js'), - 'kmsKeyRotation' : require(__dirname + '/plugins/aws/kms/kmsKeyRotation.js'), - 'kmsScheduledDeletion' : require(__dirname + '/plugins/aws/kms/kmsScheduledDeletion.js'), - 'kmsKeyPolicy' : require(__dirname + '/plugins/aws/kms/kmsKeyPolicy.js'), - 'kmsDefaultKeyUsage' : require(__dirname + '/plugins/aws/kms/kmsDefaultKeyUsage.js'), - - 'rdsAutomatedBackups' : require(__dirname + '/plugins/aws/rds/rdsAutomatedBackups.js'), - 'rdsEncryptionEnabled' : require(__dirname + '/plugins/aws/rds/rdsEncryptionEnabled.js'), - 'rdsLoggingEnabled' : require(__dirname + '/plugins/aws/rds/rdsLoggingEnabled.js'), - 'rdsPubliclyAccessible' : require(__dirname + '/plugins/aws/rds/rdsPubliclyAccessible.js'), - 'rdsRestorable' : require(__dirname + '/plugins/aws/rds/rdsRestorable.js'), - 'rdsMultiAz' : require(__dirname + '/plugins/aws/rds/rdsMultiAz.js'), - 'rdsSnapshotEncryption' : require(__dirname + '/plugins/aws/rds/rdsSnapshotEncryption.js'), - 'rdsMinorVersionUpgrade' : require(__dirname + '/plugins/aws/rds/rdsMinorVersionUpgrade.js'), - - 'domainAutoRenew' : require(__dirname + '/plugins/aws/route53/domainAutoRenew.js'), - 'domainExpiry' : require(__dirname + '/plugins/aws/route53/domainExpiry.js'), - 'domainTransferLock' : require(__dirname + '/plugins/aws/route53/domainTransferLock.js'), - - 'bucketEncryptionInTransit' : require(__dirname + '/plugins/aws/s3/bucketEncryptionInTransit.js'), - 'bucketAllUsersPolicy' : require(__dirname + '/plugins/aws/s3/bucketAllUsersPolicy.js'), - 'bucketAllUsersAcl' : require(__dirname + '/plugins/aws/s3/bucketAllUsersAcl.js'), - 'bucketVersioning' : require(__dirname + '/plugins/aws/s3/bucketVersioning.js'), - 'bucketLogging' : require(__dirname + '/plugins/aws/s3/bucketLogging.js'), - 's3Encryption' : require(__dirname + '/plugins/aws/s3/s3Encryption.js'), - 'bucketPublicAccessBlock' : require(__dirname + '/plugins/aws/s3/bucketPublicAccessBlock.js'), - 'bucketEncryption' : require(__dirname + '/plugins/aws/s3/bucketEncryption.js'), - 'bucketWebsiteEnabled' : require(__dirname + '/plugins/aws/s3/bucketWebsiteEnabled.js'), - 'bucketEnforceEncryption' : require(__dirname + '/plugins/aws/s3/bucketEnforceEncryption.js'), - - 'notebookDataEncrypted' : require(__dirname + '/plugins/aws/sagemaker/notebookDataEncrypted.js'), - 'notebookDirectInternetAccess' : require(__dirname + '/plugins/aws/sagemaker/notebookDirectInternetAccess.js'), - - 'dkimEnabled' : require(__dirname + '/plugins/aws/ses/dkimEnabled.js'), - - 'topicPolicies' : require(__dirname + '/plugins/aws/sns/topicPolicies.js'), - 'sqsCrossAccount' : require(__dirname + '/plugins/aws/sqs/sqsCrossAccount.js'), - 'sqsEncrypted' : require(__dirname + '/plugins/aws/sqs/sqsEncrypted.js'), - - 'ssmEncryptedParameters' : require(__dirname + '/plugins/aws/ssm/ssmEncryptedParameters.js'), - 'ssmActiveOnAllInstances' : require(__dirname + '/plugins/aws/ssm/ssmActiveOnAllInstances.js'), - 'ssmAgentLatestVersion' : require(__dirname + '/plugins/aws/ssm/ssmAgentLatestVersion.js'), - - 'lambdaOldRuntimes' : require(__dirname + '/plugins/aws/lambda/lambdaOldRuntimes.js'), - 'lambdaVpcConfig' : require(__dirname + '/plugins/aws/lambda/lambdaVpcConfig.js'), - 'lambdaPublicAccess' : require(__dirname + '/plugins/aws/lambda/lambdaPublicAccess.js'), - 'lambdaLogGroups' : require(__dirname + '/plugins/aws/lambda/lambdaLogGroups.js'), - - 'monitoringMetrics' : require(__dirname + '/plugins/aws/cloudwatchlogs/monitoringMetrics.js'), - - 'redshiftEncryptionEnabled' : require(__dirname + '/plugins/aws/redshift/redshiftEncryptionEnabled.js'), - 'redshiftPubliclyAccessible' : require(__dirname + '/plugins/aws/redshift/redshiftPubliclyAccessible.js'), - - 'transferLoggingEnabled' : require(__dirname + '/plugins/aws/transfer/transferLoggingEnabled.js'), - - 'shieldAdvancedEnabled' : require(__dirname + '/plugins/aws/shield/shieldAdvancedEnabled.js'), - 'shieldEmergencyContacts' : require(__dirname + '/plugins/aws/shield/shieldEmergencyContacts.js'), - 'shieldProtections' : require(__dirname + '/plugins/aws/shield/shieldProtections.js'), - - 'enableAllFeatures' : require(__dirname + '/plugins/aws/organizations/enableAllFeatures.js'), - 'organizationInvite' : require(__dirname + '/plugins/aws/organizations/organizationInvite.js'), - 'guardDutyEnabled' : require(__dirname + '/plugins/aws/guardduty/guarddutyEnabled.js'), - 'guardDutyMaster' : require(__dirname + '/plugins/aws/guardduty/guarddutyMaster.js'), - - 'xrayEncryptionEnabled' : require(__dirname + '/plugins/aws/xray/xrayEncryptionEnabled.js') + // 'acmValidation' : require(__dirname + '/plugins/aws/acm/acmValidation.js'), + // 'acmCertificateExpiry' : require(__dirname + '/plugins/aws/acm/acmCertificateExpiry.js'), + // 'asgMultiAz' : require(__dirname + '/plugins/aws/autoscaling/asgMultiAz.js'), + // 'workgroupEncrypted' : require(__dirname + '/plugins/aws/athena/workgroupEncrypted.js'), + // 'workgroupEnforceConfiguration' : require(__dirname + '/plugins/aws/athena/workgroupEnforceConfiguration.js'), + // 'publicS3Origin' : require(__dirname + '/plugins/aws/cloudfront/publicS3Origin.js'), + // 'secureOrigin' : require(__dirname + '/plugins/aws/cloudfront/secureOrigin.js'), + // 'insecureProtocols' : require(__dirname + '/plugins/aws/cloudfront/insecureProtocols.js'), + // 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), + // 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), + // 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), + 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), + // 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), + // 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), + // 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), + // 'cloudtrailEncryption' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEncryption.js'), + // 'cloudtrailFileValidation' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailFileValidation.js'), + // 'cloudtrailToCloudwatch' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailToCloudwatch.js'), + // 'cloudtrailBucketPrivate' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketPrivate.js'), + + // 'configServiceEnabled' : require(__dirname + '/plugins/aws/configservice/configServiceEnabled.js'), + + // 'dmsEncryptionEnabled' : require(__dirname + '/plugins/aws/dms/dmsEncryptionEnabled.js'), + + // 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), + + // 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), + // 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), + // 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), + // 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), + // 'instanceLimit' : require(__dirname + '/plugins/aws/ec2/instanceLimit.js'), + // 'instanceVcpusLimit' : require(__dirname + '/plugins/aws/ec2/instanceVcpusLimit.js'), + // 'instanceMaxCount' : require(__dirname + '/plugins/aws/ec2/instanceMaxCount.js'), + // 'instanceKeyBasedLogin' : require(__dirname + '/plugins/aws/ec2/instanceKeyBasedLogin.js'), + // 'openAllPortsProtocols' : require(__dirname + '/plugins/aws/ec2/openAllPortsProtocols.js'), + // 'openCIFS' : require(__dirname + '/plugins/aws/ec2/openCIFS.js'), + // 'openDNS' : require(__dirname + '/plugins/aws/ec2/openDNS.js'), + // 'openDocker' : require(__dirname + '/plugins/aws/ec2/openDocker.js'), + // 'openFTP' : require(__dirname + '/plugins/aws/ec2/openFTP.js'), + // 'openHadoopNameNode' : require(__dirname + '/plugins/aws/ec2/openHadoopNameNode.js'), + // 'openHadoopNameNodeWebUI' : require(__dirname + '/plugins/aws/ec2/openHadoopNameNodeWebUI.js'), + // 'openKibana' : require(__dirname + '/plugins/aws/ec2/openKibana.js'), + // 'openMySQL' : require(__dirname + '/plugins/aws/ec2/openMySQL.js'), + // 'openOracle' : require(__dirname + '/plugins/aws/ec2/openOracle.js'), + // 'openNetBIOS' : require(__dirname + '/plugins/aws/ec2/openNetBIOS.js'), + // 'openPostgreSQL' : require(__dirname + '/plugins/aws/ec2/openPostgreSQL.js'), + // 'openRDP' : require(__dirname + '/plugins/aws/ec2/openRDP.js'), + // 'openRPC' : require(__dirname + '/plugins/aws/ec2/openRPC.js'), + // 'openSalt' : require(__dirname + '/plugins/aws/ec2/openSalt.js'), + // 'openSMBoTCP' : require(__dirname + '/plugins/aws/ec2/openSMBoTCP.js'), + // 'openSMTP' : require(__dirname + '/plugins/aws/ec2/openSMTP.js'), + // 'openSQLServer' : require(__dirname + '/plugins/aws/ec2/openSQLServer.js'), + // 'openSSH' : require(__dirname + '/plugins/aws/ec2/openSSH.js'), + // 'openTelnet' : require(__dirname + '/plugins/aws/ec2/openTelnet.js'), + // 'openVNCClient' : require(__dirname + '/plugins/aws/ec2/openVNCClient.js'), + // 'openVNCServer' : require(__dirname + '/plugins/aws/ec2/openVNCServer.js'), + // 'openElasticsearch' : require(__dirname + '/plugins/aws/ec2/openElasticsearch.js'), + // 'vpcElasticIpLimit' : require(__dirname + '/plugins/aws/ec2/vpcElasticIpLimit.js'), + // 'classicInstances' : require(__dirname + '/plugins/aws/ec2/classicInstances.js'), + // 'flowLogsEnabled' : require(__dirname + '/plugins/aws/ec2/flowLogsEnabled.js'), + // 'vpcMultipleSubnets' : require(__dirname + '/plugins/aws/ec2/multipleSubnets.js'), + // 'overlappingSecurityGroups' : require(__dirname + '/plugins/aws/ec2/overlappingSecurityGroups.js'), + // 'publicAmi' : require(__dirname + '/plugins/aws/ec2/publicAmi.js'), + // 'encryptedAmi' : require(__dirname + '/plugins/aws/ec2/encryptedAmi.js'), + // 'instanceIamRole' : require(__dirname + '/plugins/aws/ec2/instanceIamRole.js'), + // 'ebsEncryptionEnabled' : require(__dirname + '/plugins/aws/ec2/ebsEncryptionEnabled.js'), + // 'ebsSnapshotPrivate' : require(__dirname + '/plugins/aws/ec2/ebsSnapshotPrivate.js'), + // 'natMultiAz' : require(__dirname + '/plugins/aws/ec2/natMultiAz.js'), + // 'defaultVpcInUse' : require(__dirname + '/plugins/aws/ec2/defaultVpcInUse.js'), + // 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), + // 'crossVpcPublicPrivate' : require(__dirname + '/plugins/aws/ec2/crossVpcPublicPrivate.js'), + // 'ebsEncryptedSnapshots' : require(__dirname + '/plugins/aws/ec2/ebsEncryptedSnapshots.js'), + // 'ec2MetadataOptions' : require(__dirname + '/plugins/aws/ec2/ec2MetadataOptions.js'), + + // 'efsEncryptionEnabled' : require(__dirname + '/plugins/aws/efs/efsEncryptionEnabled.js'), + + // 'ecrRepositoryPolicy' : require(__dirname + '/plugins/aws/ecr/ecrRepositoryPolicy.js'), + // 'ecrRepositoryTagImmutability' : require(__dirname + '/plugins/aws/ecr/ecrRepositoryTagImmutability.js'), + + // 'eksKubernetesVersion' : require(__dirname + '/plugins/aws/eks/eksKubernetesVersion.js'), + // 'eksLoggingEnabled' : require(__dirname + '/plugins/aws/eks/eksLoggingEnabled.js'), + // 'eksPrivateEndpoint' : require(__dirname + '/plugins/aws/eks/eksPrivateEndpoint.js'), + // 'eksSecurityGroups' : require(__dirname + '/plugins/aws/eks/eksSecurityGroups.js'), + + // 'insecureCiphers' : require(__dirname + '/plugins/aws/elb/insecureCiphers.js'), + // 'elbHttpsOnly' : require(__dirname + '/plugins/aws/elb/elbHttpsOnly.js'), + // 'elbLoggingEnabled' : require(__dirname + '/plugins/aws/elb/elbLoggingEnabled.js'), + // 'elbNoInstances' : require(__dirname + '/plugins/aws/elb/elbNoInstances.js'), + + // 'elbv2LoggingEnabled' : require(__dirname + '/plugins/aws/elbv2/elbv2LoggingEnabled.js'), + // 'elbv2HttpsOnly' : require(__dirname + '/plugins/aws/elbv2/elbv2HttpsOnly.js'), + // 'elbv2NoInstances' : require(__dirname + '/plugins/aws/elbv2/elbv2NoInstances.js'), + // 'elbv2WafEnabled' : require(__dirname + '/plugins/aws/elbv2/elbv2WafEnabled.js'), + + // 'esPublicEndpoint' : require(__dirname + '/plugins/aws/es/esPublicEndpoint.js'), + // 'esRequireIAMAuth' : require(__dirname + '/plugins/aws/es/esRequireIAMAuth.js'), + // 'esEncryptedDomain' : require(__dirname + '/plugins/aws/es/esEncryptedDomain.js'), + // 'esNodeToNodeEncryption' : require(__dirname + '/plugins/aws/es/esNodeToNodeEncryption.js'), + // 'esLoggingEnabled' : require(__dirname + '/plugins/aws/es/esLoggingEnabled.js'), + // 'esUpgradeAvailable' : require(__dirname + '/plugins/aws/es/esUpgradeAvailable.js'), + // 'esHttpsOnly' : require(__dirname + '/plugins/aws/es/esHttpsOnly.js'), + + // 'accessKeysExtra' : require(__dirname + '/plugins/aws/iam/accessKeysExtra.js'), + // 'accessKeysLastUsed' : require(__dirname + '/plugins/aws/iam/accessKeysLastUsed.js'), + // 'accessKeysRotated' : require(__dirname + '/plugins/aws/iam/accessKeysRotated.js'), + // 'certificateExpiry' : require(__dirname + '/plugins/aws/iam/certificateExpiry.js'), + // 'emptyGroups' : require(__dirname + '/plugins/aws/iam/emptyGroups.js'), + // 'iamUserAdmins' : require(__dirname + '/plugins/aws/iam/iamUserAdmins.js'), + // 'iamUserNameRegex' : require(__dirname + '/plugins/aws/iam/iamUserNameRegex.js'), + // 'iamRolePolicies' : require(__dirname + '/plugins/aws/iam/iamRolePolicies.js'), + // 'maxPasswordAge' : require(__dirname + '/plugins/aws/iam/maxPasswordAge.js'), + // 'minPasswordLength' : require(__dirname + '/plugins/aws/iam/minPasswordLength.js'), + // 'noUserIamPolicies' : require(__dirname + '/plugins/aws/iam/noUserIamPolicies.js'), + // 'passwordExpiration' : require(__dirname + '/plugins/aws/iam/passwordExpiration.js'), + // 'passwordRequiresLowercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresLowercase.js'), + // 'passwordRequiresNumbers' : require(__dirname + '/plugins/aws/iam/passwordRequiresNumbers.js'), + // 'passwordRequiresSymbols' : require(__dirname + '/plugins/aws/iam/passwordRequiresSymbols.js'), + // 'passwordRequiresUppercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresUppercase.js'), + // 'passwordReusePrevention' : require(__dirname + '/plugins/aws/iam/passwordReusePrevention.js'), + // 'rootAccessKeys' : require(__dirname + '/plugins/aws/iam/rootAccessKeys.js'), + // 'rootAccountInUse' : require(__dirname + '/plugins/aws/iam/rootAccountInUse.js'), + // 'rootHardwareMfa' : require(__dirname + '/plugins/aws/iam/rootHardwareMfa.js'), + // 'rootMfaEnabled' : require(__dirname + '/plugins/aws/iam/rootMfaEnabled.js'), + // 'sshKeysRotated' : require(__dirname + '/plugins/aws/iam/sshKeysRotated.js'), + // 'usersMfaEnabled' : require(__dirname + '/plugins/aws/iam/usersMfaEnabled.js'), + // 'usersPasswordAndKeys' : require(__dirname + '/plugins/aws/iam/usersPasswordAndKeys.js'), + // 'usersPasswordLastUsed' : require(__dirname + '/plugins/aws/iam/usersPasswordLastUsed.js'), + // 'canaryKeysUsed' : require(__dirname + '/plugins/aws/iam/canaryKeysUsed.js'), + // 'kinesisEncrypted' : require(__dirname + '/plugins/aws/kinesis/kinesisEncrypted.js'), + // 'firehoseEncrypted' : require(__dirname + '/plugins/aws/firehose/firehoseEncrypted.js'), + // 'kmsKeyRotation' : require(__dirname + '/plugins/aws/kms/kmsKeyRotation.js'), + // 'kmsScheduledDeletion' : require(__dirname + '/plugins/aws/kms/kmsScheduledDeletion.js'), + // 'kmsKeyPolicy' : require(__dirname + '/plugins/aws/kms/kmsKeyPolicy.js'), + // 'kmsDefaultKeyUsage' : require(__dirname + '/plugins/aws/kms/kmsDefaultKeyUsage.js'), + + // 'rdsAutomatedBackups' : require(__dirname + '/plugins/aws/rds/rdsAutomatedBackups.js'), + // 'rdsEncryptionEnabled' : require(__dirname + '/plugins/aws/rds/rdsEncryptionEnabled.js'), + // 'rdsLoggingEnabled' : require(__dirname + '/plugins/aws/rds/rdsLoggingEnabled.js'), + // 'rdsPubliclyAccessible' : require(__dirname + '/plugins/aws/rds/rdsPubliclyAccessible.js'), + // 'rdsRestorable' : require(__dirname + '/plugins/aws/rds/rdsRestorable.js'), + // 'rdsMultiAz' : require(__dirname + '/plugins/aws/rds/rdsMultiAz.js'), + // 'rdsSnapshotEncryption' : require(__dirname + '/plugins/aws/rds/rdsSnapshotEncryption.js'), + // 'rdsMinorVersionUpgrade' : require(__dirname + '/plugins/aws/rds/rdsMinorVersionUpgrade.js'), + + // 'domainAutoRenew' : require(__dirname + '/plugins/aws/route53/domainAutoRenew.js'), + // 'domainExpiry' : require(__dirname + '/plugins/aws/route53/domainExpiry.js'), + // 'domainTransferLock' : require(__dirname + '/plugins/aws/route53/domainTransferLock.js'), + + // 'bucketEncryptionInTransit' : require(__dirname + '/plugins/aws/s3/bucketEncryptionInTransit.js'), + // 'bucketAllUsersPolicy' : require(__dirname + '/plugins/aws/s3/bucketAllUsersPolicy.js'), + // 'bucketAllUsersAcl' : require(__dirname + '/plugins/aws/s3/bucketAllUsersAcl.js'), + // 'bucketVersioning' : require(__dirname + '/plugins/aws/s3/bucketVersioning.js'), + // 'bucketLogging' : require(__dirname + '/plugins/aws/s3/bucketLogging.js'), + // 's3Encryption' : require(__dirname + '/plugins/aws/s3/s3Encryption.js'), + // 'bucketPublicAccessBlock' : require(__dirname + '/plugins/aws/s3/bucketPublicAccessBlock.js'), + // 'bucketEncryption' : require(__dirname + '/plugins/aws/s3/bucketEncryption.js'), + // 'bucketWebsiteEnabled' : require(__dirname + '/plugins/aws/s3/bucketWebsiteEnabled.js'), + // 'bucketEnforceEncryption' : require(__dirname + '/plugins/aws/s3/bucketEnforceEncryption.js'), + + // 'notebookDataEncrypted' : require(__dirname + '/plugins/aws/sagemaker/notebookDataEncrypted.js'), + // 'notebookDirectInternetAccess' : require(__dirname + '/plugins/aws/sagemaker/notebookDirectInternetAccess.js'), + + // 'dkimEnabled' : require(__dirname + '/plugins/aws/ses/dkimEnabled.js'), + + // 'topicPolicies' : require(__dirname + '/plugins/aws/sns/topicPolicies.js'), + // 'sqsCrossAccount' : require(__dirname + '/plugins/aws/sqs/sqsCrossAccount.js'), + // 'sqsEncrypted' : require(__dirname + '/plugins/aws/sqs/sqsEncrypted.js'), + + // 'ssmEncryptedParameters' : require(__dirname + '/plugins/aws/ssm/ssmEncryptedParameters.js'), + // 'ssmActiveOnAllInstances' : require(__dirname + '/plugins/aws/ssm/ssmActiveOnAllInstances.js'), + // 'ssmAgentLatestVersion' : require(__dirname + '/plugins/aws/ssm/ssmAgentLatestVersion.js'), + + // 'lambdaOldRuntimes' : require(__dirname + '/plugins/aws/lambda/lambdaOldRuntimes.js'), + // 'lambdaVpcConfig' : require(__dirname + '/plugins/aws/lambda/lambdaVpcConfig.js'), + // 'lambdaPublicAccess' : require(__dirname + '/plugins/aws/lambda/lambdaPublicAccess.js'), + // 'lambdaLogGroups' : require(__dirname + '/plugins/aws/lambda/lambdaLogGroups.js'), + + // 'monitoringMetrics' : require(__dirname + '/plugins/aws/cloudwatchlogs/monitoringMetrics.js'), + + // 'redshiftEncryptionEnabled' : require(__dirname + '/plugins/aws/redshift/redshiftEncryptionEnabled.js'), + // 'redshiftPubliclyAccessible' : require(__dirname + '/plugins/aws/redshift/redshiftPubliclyAccessible.js'), + + // 'transferLoggingEnabled' : require(__dirname + '/plugins/aws/transfer/transferLoggingEnabled.js'), + + // 'shieldAdvancedEnabled' : require(__dirname + '/plugins/aws/shield/shieldAdvancedEnabled.js'), + // 'shieldEmergencyContacts' : require(__dirname + '/plugins/aws/shield/shieldEmergencyContacts.js'), + // 'shieldProtections' : require(__dirname + '/plugins/aws/shield/shieldProtections.js'), + + // 'enableAllFeatures' : require(__dirname + '/plugins/aws/organizations/enableAllFeatures.js'), + // 'organizationInvite' : require(__dirname + '/plugins/aws/organizations/organizationInvite.js'), + // 'guardDutyEnabled' : require(__dirname + '/plugins/aws/guardduty/guarddutyEnabled.js'), + // 'guardDutyMaster' : require(__dirname + '/plugins/aws/guardduty/guarddutyMaster.js'), + + // 'xrayEncryptionEnabled' : require(__dirname + '/plugins/aws/xray/xrayEncryptionEnabled.js') }, azure : { 'fileServiceEncryption' : require(__dirname + '/plugins/azure/storageaccounts/fileServiceEncryption.js'), diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js new file mode 100644 index 0000000000..658dc42f3d --- /dev/null +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -0,0 +1,70 @@ +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'CloudFormation Plaintext Parameters', + category: 'CloudFormation', + description: 'Ensures CloudFormation parameters that reference sensitive values are configured to use NoEcho.', + more_info: 'CloudFormation supports the NoEcho property for sensitive values, which should be used to ensure secrets are not exposed in the CloudFormation UI and APIs.', + link: 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html', + recommended_action: 'Update the sensitive parameters to use the NoEcho property.', + apis: ['CloudFormation:describeStacks'], + compliance: { + hipaa: 'HIPAA requires all data to be transmitted over secure channels. ' + + 'CloudFront HTTPS redirection should be used to ensure site visitors ' + + 'are always connecting over a secure channel.' + }, + // settings : { secretWords : ["password", "privatekey", "secret"] }, + + run: function(cache, settings, callback) { + + var results = []; + var source = {}; + + var region = helpers.defaultRegion(settings); + + var describeStacks = helpers.addSource(cache, source, + ['cloudformation', 'describeStacks', region]); + + console.log(describeStacks); + console.log("results received"); + // if (!describeStacks) return callback(null, results, source); + + // if (describeStacks.err || !describeStacks.data) { + // helpers.addResult(results, 3, + // 'Unable to describe stacks: ' + helpers.addError(describeStacks)); + // return callback(null, results, source); + // } + + // if (!describeStacks.data.length) { + // helpers.addResult(results, 0, 'No stacks descriptions found'); + // return callback(null, results, source); + // } + // console.log(describeStacks.data); + // loop through stacks for every template retrieval + // describeStacks.data.forEach(function(Distribution){ + // var stackTemplate = helpers.addSource(cache, source, + // ['cloudformation', 'getTemplate', region]); + + // if (!describeStacks) return callback(null, results, source); + + // if (describeStacks.err || !describeStacks.data) { + // helpers.addResult(results, 3, + // 'Unable to describe stacks: ' + helpers.addError(describeStacks)); + // return callback(null, results, source); + // } + + // if (Distribution.DefaultCacheBehavior.ViewerProtocolPolicy == 'redirect-to-https') { + // helpers.addResult(results, 0, 'CloudFront distribution ' + + // 'is configured to redirect non-HTTPS traffic to HTTPS', 'global', Distribution.ARN); + // } else if (Distribution.DefaultCacheBehavior.ViewerProtocolPolicy == 'https-only') { + // helpers.addResult(results, 0, 'The CloudFront ' + + // 'distribution is set to use HTTPS only.', 'global', Distribution.ARN); + // } else { + // helpers.addResult(results, 2, 'CloudFront distribution ' + + // 'is not configured to use HTTPS', 'global', Distribution.ARN); + // } + // }); + + callback(null, results, source); + } +}; \ No newline at end of file From 2122ade6414d7ce065c47a3e5841b9ca454a493a Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Thu, 13 Aug 2020 19:59:59 +0500 Subject: [PATCH 02/67] Added vpcEndpointAcceptance plugin and spec file --- collectors/aws/collector.js | 4 + plugins/aws/ec2/vpcEndpointAcceptance.js | 57 +++++++ plugins/aws/ec2/vpcEndpointAcceptance.spec.js | 141 ++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 plugins/aws/ec2/vpcEndpointAcceptance.js create mode 100644 plugins/aws/ec2/vpcEndpointAcceptance.spec.js diff --git a/collectors/aws/collector.js b/collectors/aws/collector.js index be291cf944..20a75b5269 100644 --- a/collectors/aws/collector.js +++ b/collectors/aws/collector.js @@ -230,6 +230,10 @@ var calls = { ] } }, + describeVpcEndpointServices: { + property: 'ServiceDetails', + paginate: 'NextToken' + }, describeRouteTables: { property: 'RouteTables', paginate: 'NextToken' diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.js b/plugins/aws/ec2/vpcEndpointAcceptance.js new file mode 100644 index 0000000000..9d0530bd7e --- /dev/null +++ b/plugins/aws/ec2/vpcEndpointAcceptance.js @@ -0,0 +1,57 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'VPC PrivateLink Endpoint Acceptance Required', + category: 'EC2', + description: 'Ensures VPC PrivateLink endpoints require acceptance', + more_info: 'VPC PrivateLink endpoints should be configured to require acceptance so that access to the endpoint is controlled on a case-by-case basis.', + recommended_action: 'Update the VPC PrivateLink endpoint to require acceptance', + link: 'https://docs.aws.amazon.com/vpc/latest/userguide/accept-reject-endpoint-requests.html', + apis: ['EC2:describeVpcEndpointServices'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + + async.each(regions.ec2, function(region, rcb){ + var describeVpcEndpointServices = helpers.addSource(cache, source, + ['ec2', 'describeVpcEndpointServices', region]); + + if (!describeVpcEndpointServices) return rcb(); + + if (describeVpcEndpointServices.err || !describeVpcEndpointServices.data) { + helpers.addResult(results, 3, + 'Unable to query for VPC endpoint services: ' + helpers.addError(describeVpcEndpointServices), region); + return rcb(); + } + + describeVpcEndpointServices.data = describeVpcEndpointServices.data.filter(service => service.Owner != 'amazon'); + + if (!describeVpcEndpointServices.data.length) { + helpers.addResult(results, 0, + 'No user owned VPC endpoint services present', region); + return rcb(); + } + + for (var s in describeVpcEndpointServices.data) { + var service = describeVpcEndpointServices.data[s]; + var resource = service.ServiceName; + if (service.AcceptanceRequired) { + helpers.addResult(results, 0, + 'VPC endpoint service ' + (service.ServiceId) + ' requires acceptance by the service owner', + region, resource); + } else { + helpers.addResult(results, 2, + 'VPC endpoint service ' + (service.ServiceId) + ' does not require acceptance by the service owner', + region, resource); + } + } + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js new file mode 100644 index 0000000000..0946f5a682 --- /dev/null +++ b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js @@ -0,0 +1,141 @@ +var expect = require('chai').expect; +const vpcEndpointAcceptance = require('./vpcEndpointAcceptance'); + +const vpcEndpointServices = [ + { + "ServiceName": "com.amazonaws.vpce.us-east-1.vpce-svc-09d3a6a098dce6e8c", + "ServiceId": "vpce-svc-09d3a6a098dce6e8c", + "ServiceType": [ + { + "ServiceType": "Interface" + } + ], + "AvailabilityZones": [ + "us-east-1a", + "us-east-1b" + ], + "Owner": "560213429563", + "BaseEndpointDnsNames": [ + "vpce-svc-09d3a6a098dce6e8c.us-east-1.vpce.amazonaws.com" + ], + "VpcEndpointPolicySupported": false, + "AcceptanceRequired": true, + "ManagesVpcEndpoints": false, + "Tags": [] + }, + { + "ServiceName": "com.amazonaws.vpce.us-east-1.vpce-svc-09145867a106679a3", + "ServiceId": "vpce-svc-09145867a106679a3", + "ServiceType": [ + { + "ServiceType": "Interface" + } + ], + "AvailabilityZones": [ + "us-east-1a", + "us-east-1b", + "us-east-1c" + ], + "Owner": "560213429563", + "BaseEndpointDnsNames": [ + "vpce-svc-09145867a106679a3.us-east-1.vpce.amazonaws.com" + ], + "VpcEndpointPolicySupported": false, + "AcceptanceRequired": false, + "ManagesVpcEndpoints": false, + "Tags": [] + }, +] + +const createCache = (ServiceDetails) => { + return { + ec2: { + describeVpcEndpointServices: { + 'us-east-1': { + data: ServiceDetails + }, + }, + }, + }; +}; + +const createErrorCache = () => { + return { + ec2: { + describeVpcEndpointServices: { + 'us-east-1': { + err: { + message: 'error describing VPC endpoint services' + }, + }, + }, + }, + }; +}; + +const createNullCache = () => { + return { + ec2: { + describeVpcEndpointServices: { + 'us-east-1': null, + }, + }, + }; +}; + +describe('vpcEndpointAcceptance', function () { + describe('run', function () { + it('should PASS if VPC endpoint service requires acceptance by the service owner', function (done) { + const cache = createCache([vpcEndpointServices[0]]); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should FAIL if VPC endpoint service does not require acceptance by the service owner', function (done) { + const cache = createCache([vpcEndpointServices[1]]); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + done(); + }); + }); + + it('should PASS if no VPC endpoint service is detected', function (done) { + const cache = createCache([]); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should PASS if no VPC endpoint services are detected', function (done) { + const cache = createCache([]); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should UNKNOWN if there was an error querying for VPC endpoint services', function (done) { + const cache = createErrorCache(); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + done(); + }); + }); + + it('should not return any results if unable to query for VPC endpoint services', function (done) { + const cache = createNullCache(); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(0); + done(); + }); + }); + }); +}); From 306d7218921e93751176dc09b524f8fa18639608 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Fri, 14 Aug 2020 05:55:55 +0500 Subject: [PATCH 03/67] SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation --- exports.js | 386 +++++++++--------- helpers/aws/regions.js | 1 + index.js | 8 +- .../aws/cloudformation/plainTextParameters.js | 91 ++--- .../plainTextParameters.spec.js | 161 ++++++++ 5 files changed, 406 insertions(+), 241 deletions(-) create mode 100644 plugins/aws/cloudformation/plainTextParameters.spec.js diff --git a/exports.js b/exports.js index f8dac891a1..fa901a2af7 100644 --- a/exports.js +++ b/exports.js @@ -2,200 +2,200 @@ module.exports = { aws : { - // 'acmValidation' : require(__dirname + '/plugins/aws/acm/acmValidation.js'), - // 'acmCertificateExpiry' : require(__dirname + '/plugins/aws/acm/acmCertificateExpiry.js'), - // 'asgMultiAz' : require(__dirname + '/plugins/aws/autoscaling/asgMultiAz.js'), - // 'workgroupEncrypted' : require(__dirname + '/plugins/aws/athena/workgroupEncrypted.js'), - // 'workgroupEnforceConfiguration' : require(__dirname + '/plugins/aws/athena/workgroupEnforceConfiguration.js'), - // 'publicS3Origin' : require(__dirname + '/plugins/aws/cloudfront/publicS3Origin.js'), - // 'secureOrigin' : require(__dirname + '/plugins/aws/cloudfront/secureOrigin.js'), - // 'insecureProtocols' : require(__dirname + '/plugins/aws/cloudfront/insecureProtocols.js'), - // 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), - // 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), - // 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), + 'acmValidation' : require(__dirname + '/plugins/aws/acm/acmValidation.js'), + 'acmCertificateExpiry' : require(__dirname + '/plugins/aws/acm/acmCertificateExpiry.js'), + 'asgMultiAz' : require(__dirname + '/plugins/aws/autoscaling/asgMultiAz.js'), + 'workgroupEncrypted' : require(__dirname + '/plugins/aws/athena/workgroupEncrypted.js'), + 'workgroupEnforceConfiguration' : require(__dirname + '/plugins/aws/athena/workgroupEnforceConfiguration.js'), + 'publicS3Origin' : require(__dirname + '/plugins/aws/cloudfront/publicS3Origin.js'), + 'secureOrigin' : require(__dirname + '/plugins/aws/cloudfront/secureOrigin.js'), + 'insecureProtocols' : require(__dirname + '/plugins/aws/cloudfront/insecureProtocols.js'), + 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), + 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), + 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), - // 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), - // 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), - // 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), - // 'cloudtrailEncryption' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEncryption.js'), - // 'cloudtrailFileValidation' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailFileValidation.js'), - // 'cloudtrailToCloudwatch' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailToCloudwatch.js'), - // 'cloudtrailBucketPrivate' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketPrivate.js'), - - // 'configServiceEnabled' : require(__dirname + '/plugins/aws/configservice/configServiceEnabled.js'), - - // 'dmsEncryptionEnabled' : require(__dirname + '/plugins/aws/dms/dmsEncryptionEnabled.js'), - - // 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), - - // 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), - // 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), - // 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), - // 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), - // 'instanceLimit' : require(__dirname + '/plugins/aws/ec2/instanceLimit.js'), - // 'instanceVcpusLimit' : require(__dirname + '/plugins/aws/ec2/instanceVcpusLimit.js'), - // 'instanceMaxCount' : require(__dirname + '/plugins/aws/ec2/instanceMaxCount.js'), - // 'instanceKeyBasedLogin' : require(__dirname + '/plugins/aws/ec2/instanceKeyBasedLogin.js'), - // 'openAllPortsProtocols' : require(__dirname + '/plugins/aws/ec2/openAllPortsProtocols.js'), - // 'openCIFS' : require(__dirname + '/plugins/aws/ec2/openCIFS.js'), - // 'openDNS' : require(__dirname + '/plugins/aws/ec2/openDNS.js'), - // 'openDocker' : require(__dirname + '/plugins/aws/ec2/openDocker.js'), - // 'openFTP' : require(__dirname + '/plugins/aws/ec2/openFTP.js'), - // 'openHadoopNameNode' : require(__dirname + '/plugins/aws/ec2/openHadoopNameNode.js'), - // 'openHadoopNameNodeWebUI' : require(__dirname + '/plugins/aws/ec2/openHadoopNameNodeWebUI.js'), - // 'openKibana' : require(__dirname + '/plugins/aws/ec2/openKibana.js'), - // 'openMySQL' : require(__dirname + '/plugins/aws/ec2/openMySQL.js'), - // 'openOracle' : require(__dirname + '/plugins/aws/ec2/openOracle.js'), - // 'openNetBIOS' : require(__dirname + '/plugins/aws/ec2/openNetBIOS.js'), - // 'openPostgreSQL' : require(__dirname + '/plugins/aws/ec2/openPostgreSQL.js'), - // 'openRDP' : require(__dirname + '/plugins/aws/ec2/openRDP.js'), - // 'openRPC' : require(__dirname + '/plugins/aws/ec2/openRPC.js'), - // 'openSalt' : require(__dirname + '/plugins/aws/ec2/openSalt.js'), - // 'openSMBoTCP' : require(__dirname + '/plugins/aws/ec2/openSMBoTCP.js'), - // 'openSMTP' : require(__dirname + '/plugins/aws/ec2/openSMTP.js'), - // 'openSQLServer' : require(__dirname + '/plugins/aws/ec2/openSQLServer.js'), - // 'openSSH' : require(__dirname + '/plugins/aws/ec2/openSSH.js'), - // 'openTelnet' : require(__dirname + '/plugins/aws/ec2/openTelnet.js'), - // 'openVNCClient' : require(__dirname + '/plugins/aws/ec2/openVNCClient.js'), - // 'openVNCServer' : require(__dirname + '/plugins/aws/ec2/openVNCServer.js'), - // 'openElasticsearch' : require(__dirname + '/plugins/aws/ec2/openElasticsearch.js'), - // 'vpcElasticIpLimit' : require(__dirname + '/plugins/aws/ec2/vpcElasticIpLimit.js'), - // 'classicInstances' : require(__dirname + '/plugins/aws/ec2/classicInstances.js'), - // 'flowLogsEnabled' : require(__dirname + '/plugins/aws/ec2/flowLogsEnabled.js'), - // 'vpcMultipleSubnets' : require(__dirname + '/plugins/aws/ec2/multipleSubnets.js'), - // 'overlappingSecurityGroups' : require(__dirname + '/plugins/aws/ec2/overlappingSecurityGroups.js'), - // 'publicAmi' : require(__dirname + '/plugins/aws/ec2/publicAmi.js'), - // 'encryptedAmi' : require(__dirname + '/plugins/aws/ec2/encryptedAmi.js'), - // 'instanceIamRole' : require(__dirname + '/plugins/aws/ec2/instanceIamRole.js'), - // 'ebsEncryptionEnabled' : require(__dirname + '/plugins/aws/ec2/ebsEncryptionEnabled.js'), - // 'ebsSnapshotPrivate' : require(__dirname + '/plugins/aws/ec2/ebsSnapshotPrivate.js'), - // 'natMultiAz' : require(__dirname + '/plugins/aws/ec2/natMultiAz.js'), - // 'defaultVpcInUse' : require(__dirname + '/plugins/aws/ec2/defaultVpcInUse.js'), - // 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), - // 'crossVpcPublicPrivate' : require(__dirname + '/plugins/aws/ec2/crossVpcPublicPrivate.js'), - // 'ebsEncryptedSnapshots' : require(__dirname + '/plugins/aws/ec2/ebsEncryptedSnapshots.js'), - // 'ec2MetadataOptions' : require(__dirname + '/plugins/aws/ec2/ec2MetadataOptions.js'), - - // 'efsEncryptionEnabled' : require(__dirname + '/plugins/aws/efs/efsEncryptionEnabled.js'), - - // 'ecrRepositoryPolicy' : require(__dirname + '/plugins/aws/ecr/ecrRepositoryPolicy.js'), - // 'ecrRepositoryTagImmutability' : require(__dirname + '/plugins/aws/ecr/ecrRepositoryTagImmutability.js'), - - // 'eksKubernetesVersion' : require(__dirname + '/plugins/aws/eks/eksKubernetesVersion.js'), - // 'eksLoggingEnabled' : require(__dirname + '/plugins/aws/eks/eksLoggingEnabled.js'), - // 'eksPrivateEndpoint' : require(__dirname + '/plugins/aws/eks/eksPrivateEndpoint.js'), - // 'eksSecurityGroups' : require(__dirname + '/plugins/aws/eks/eksSecurityGroups.js'), - - // 'insecureCiphers' : require(__dirname + '/plugins/aws/elb/insecureCiphers.js'), - // 'elbHttpsOnly' : require(__dirname + '/plugins/aws/elb/elbHttpsOnly.js'), - // 'elbLoggingEnabled' : require(__dirname + '/plugins/aws/elb/elbLoggingEnabled.js'), - // 'elbNoInstances' : require(__dirname + '/plugins/aws/elb/elbNoInstances.js'), - - // 'elbv2LoggingEnabled' : require(__dirname + '/plugins/aws/elbv2/elbv2LoggingEnabled.js'), - // 'elbv2HttpsOnly' : require(__dirname + '/plugins/aws/elbv2/elbv2HttpsOnly.js'), - // 'elbv2NoInstances' : require(__dirname + '/plugins/aws/elbv2/elbv2NoInstances.js'), - // 'elbv2WafEnabled' : require(__dirname + '/plugins/aws/elbv2/elbv2WafEnabled.js'), - - // 'esPublicEndpoint' : require(__dirname + '/plugins/aws/es/esPublicEndpoint.js'), - // 'esRequireIAMAuth' : require(__dirname + '/plugins/aws/es/esRequireIAMAuth.js'), - // 'esEncryptedDomain' : require(__dirname + '/plugins/aws/es/esEncryptedDomain.js'), - // 'esNodeToNodeEncryption' : require(__dirname + '/plugins/aws/es/esNodeToNodeEncryption.js'), - // 'esLoggingEnabled' : require(__dirname + '/plugins/aws/es/esLoggingEnabled.js'), - // 'esUpgradeAvailable' : require(__dirname + '/plugins/aws/es/esUpgradeAvailable.js'), - // 'esHttpsOnly' : require(__dirname + '/plugins/aws/es/esHttpsOnly.js'), - - // 'accessKeysExtra' : require(__dirname + '/plugins/aws/iam/accessKeysExtra.js'), - // 'accessKeysLastUsed' : require(__dirname + '/plugins/aws/iam/accessKeysLastUsed.js'), - // 'accessKeysRotated' : require(__dirname + '/plugins/aws/iam/accessKeysRotated.js'), - // 'certificateExpiry' : require(__dirname + '/plugins/aws/iam/certificateExpiry.js'), - // 'emptyGroups' : require(__dirname + '/plugins/aws/iam/emptyGroups.js'), - // 'iamUserAdmins' : require(__dirname + '/plugins/aws/iam/iamUserAdmins.js'), - // 'iamUserNameRegex' : require(__dirname + '/plugins/aws/iam/iamUserNameRegex.js'), - // 'iamRolePolicies' : require(__dirname + '/plugins/aws/iam/iamRolePolicies.js'), - // 'maxPasswordAge' : require(__dirname + '/plugins/aws/iam/maxPasswordAge.js'), - // 'minPasswordLength' : require(__dirname + '/plugins/aws/iam/minPasswordLength.js'), - // 'noUserIamPolicies' : require(__dirname + '/plugins/aws/iam/noUserIamPolicies.js'), - // 'passwordExpiration' : require(__dirname + '/plugins/aws/iam/passwordExpiration.js'), - // 'passwordRequiresLowercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresLowercase.js'), - // 'passwordRequiresNumbers' : require(__dirname + '/plugins/aws/iam/passwordRequiresNumbers.js'), - // 'passwordRequiresSymbols' : require(__dirname + '/plugins/aws/iam/passwordRequiresSymbols.js'), - // 'passwordRequiresUppercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresUppercase.js'), - // 'passwordReusePrevention' : require(__dirname + '/plugins/aws/iam/passwordReusePrevention.js'), - // 'rootAccessKeys' : require(__dirname + '/plugins/aws/iam/rootAccessKeys.js'), - // 'rootAccountInUse' : require(__dirname + '/plugins/aws/iam/rootAccountInUse.js'), - // 'rootHardwareMfa' : require(__dirname + '/plugins/aws/iam/rootHardwareMfa.js'), - // 'rootMfaEnabled' : require(__dirname + '/plugins/aws/iam/rootMfaEnabled.js'), - // 'sshKeysRotated' : require(__dirname + '/plugins/aws/iam/sshKeysRotated.js'), - // 'usersMfaEnabled' : require(__dirname + '/plugins/aws/iam/usersMfaEnabled.js'), - // 'usersPasswordAndKeys' : require(__dirname + '/plugins/aws/iam/usersPasswordAndKeys.js'), - // 'usersPasswordLastUsed' : require(__dirname + '/plugins/aws/iam/usersPasswordLastUsed.js'), - // 'canaryKeysUsed' : require(__dirname + '/plugins/aws/iam/canaryKeysUsed.js'), - // 'kinesisEncrypted' : require(__dirname + '/plugins/aws/kinesis/kinesisEncrypted.js'), - // 'firehoseEncrypted' : require(__dirname + '/plugins/aws/firehose/firehoseEncrypted.js'), - // 'kmsKeyRotation' : require(__dirname + '/plugins/aws/kms/kmsKeyRotation.js'), - // 'kmsScheduledDeletion' : require(__dirname + '/plugins/aws/kms/kmsScheduledDeletion.js'), - // 'kmsKeyPolicy' : require(__dirname + '/plugins/aws/kms/kmsKeyPolicy.js'), - // 'kmsDefaultKeyUsage' : require(__dirname + '/plugins/aws/kms/kmsDefaultKeyUsage.js'), - - // 'rdsAutomatedBackups' : require(__dirname + '/plugins/aws/rds/rdsAutomatedBackups.js'), - // 'rdsEncryptionEnabled' : require(__dirname + '/plugins/aws/rds/rdsEncryptionEnabled.js'), - // 'rdsLoggingEnabled' : require(__dirname + '/plugins/aws/rds/rdsLoggingEnabled.js'), - // 'rdsPubliclyAccessible' : require(__dirname + '/plugins/aws/rds/rdsPubliclyAccessible.js'), - // 'rdsRestorable' : require(__dirname + '/plugins/aws/rds/rdsRestorable.js'), - // 'rdsMultiAz' : require(__dirname + '/plugins/aws/rds/rdsMultiAz.js'), - // 'rdsSnapshotEncryption' : require(__dirname + '/plugins/aws/rds/rdsSnapshotEncryption.js'), - // 'rdsMinorVersionUpgrade' : require(__dirname + '/plugins/aws/rds/rdsMinorVersionUpgrade.js'), - - // 'domainAutoRenew' : require(__dirname + '/plugins/aws/route53/domainAutoRenew.js'), - // 'domainExpiry' : require(__dirname + '/plugins/aws/route53/domainExpiry.js'), - // 'domainTransferLock' : require(__dirname + '/plugins/aws/route53/domainTransferLock.js'), - - // 'bucketEncryptionInTransit' : require(__dirname + '/plugins/aws/s3/bucketEncryptionInTransit.js'), - // 'bucketAllUsersPolicy' : require(__dirname + '/plugins/aws/s3/bucketAllUsersPolicy.js'), - // 'bucketAllUsersAcl' : require(__dirname + '/plugins/aws/s3/bucketAllUsersAcl.js'), - // 'bucketVersioning' : require(__dirname + '/plugins/aws/s3/bucketVersioning.js'), - // 'bucketLogging' : require(__dirname + '/plugins/aws/s3/bucketLogging.js'), - // 's3Encryption' : require(__dirname + '/plugins/aws/s3/s3Encryption.js'), - // 'bucketPublicAccessBlock' : require(__dirname + '/plugins/aws/s3/bucketPublicAccessBlock.js'), - // 'bucketEncryption' : require(__dirname + '/plugins/aws/s3/bucketEncryption.js'), - // 'bucketWebsiteEnabled' : require(__dirname + '/plugins/aws/s3/bucketWebsiteEnabled.js'), - // 'bucketEnforceEncryption' : require(__dirname + '/plugins/aws/s3/bucketEnforceEncryption.js'), - - // 'notebookDataEncrypted' : require(__dirname + '/plugins/aws/sagemaker/notebookDataEncrypted.js'), - // 'notebookDirectInternetAccess' : require(__dirname + '/plugins/aws/sagemaker/notebookDirectInternetAccess.js'), - - // 'dkimEnabled' : require(__dirname + '/plugins/aws/ses/dkimEnabled.js'), - - // 'topicPolicies' : require(__dirname + '/plugins/aws/sns/topicPolicies.js'), - // 'sqsCrossAccount' : require(__dirname + '/plugins/aws/sqs/sqsCrossAccount.js'), - // 'sqsEncrypted' : require(__dirname + '/plugins/aws/sqs/sqsEncrypted.js'), - - // 'ssmEncryptedParameters' : require(__dirname + '/plugins/aws/ssm/ssmEncryptedParameters.js'), - // 'ssmActiveOnAllInstances' : require(__dirname + '/plugins/aws/ssm/ssmActiveOnAllInstances.js'), - // 'ssmAgentLatestVersion' : require(__dirname + '/plugins/aws/ssm/ssmAgentLatestVersion.js'), - - // 'lambdaOldRuntimes' : require(__dirname + '/plugins/aws/lambda/lambdaOldRuntimes.js'), - // 'lambdaVpcConfig' : require(__dirname + '/plugins/aws/lambda/lambdaVpcConfig.js'), - // 'lambdaPublicAccess' : require(__dirname + '/plugins/aws/lambda/lambdaPublicAccess.js'), - // 'lambdaLogGroups' : require(__dirname + '/plugins/aws/lambda/lambdaLogGroups.js'), - - // 'monitoringMetrics' : require(__dirname + '/plugins/aws/cloudwatchlogs/monitoringMetrics.js'), - - // 'redshiftEncryptionEnabled' : require(__dirname + '/plugins/aws/redshift/redshiftEncryptionEnabled.js'), - // 'redshiftPubliclyAccessible' : require(__dirname + '/plugins/aws/redshift/redshiftPubliclyAccessible.js'), - - // 'transferLoggingEnabled' : require(__dirname + '/plugins/aws/transfer/transferLoggingEnabled.js'), - - // 'shieldAdvancedEnabled' : require(__dirname + '/plugins/aws/shield/shieldAdvancedEnabled.js'), - // 'shieldEmergencyContacts' : require(__dirname + '/plugins/aws/shield/shieldEmergencyContacts.js'), - // 'shieldProtections' : require(__dirname + '/plugins/aws/shield/shieldProtections.js'), - - // 'enableAllFeatures' : require(__dirname + '/plugins/aws/organizations/enableAllFeatures.js'), - // 'organizationInvite' : require(__dirname + '/plugins/aws/organizations/organizationInvite.js'), - // 'guardDutyEnabled' : require(__dirname + '/plugins/aws/guardduty/guarddutyEnabled.js'), - // 'guardDutyMaster' : require(__dirname + '/plugins/aws/guardduty/guarddutyMaster.js'), - - // 'xrayEncryptionEnabled' : require(__dirname + '/plugins/aws/xray/xrayEncryptionEnabled.js') + 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), + 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), + 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), + 'cloudtrailEncryption' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEncryption.js'), + 'cloudtrailFileValidation' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailFileValidation.js'), + 'cloudtrailToCloudwatch' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailToCloudwatch.js'), + 'cloudtrailBucketPrivate' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketPrivate.js'), + + 'configServiceEnabled' : require(__dirname + '/plugins/aws/configservice/configServiceEnabled.js'), + + 'dmsEncryptionEnabled' : require(__dirname + '/plugins/aws/dms/dmsEncryptionEnabled.js'), + + 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), + + 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), + 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), + 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), + 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), + 'instanceLimit' : require(__dirname + '/plugins/aws/ec2/instanceLimit.js'), + 'instanceVcpusLimit' : require(__dirname + '/plugins/aws/ec2/instanceVcpusLimit.js'), + 'instanceMaxCount' : require(__dirname + '/plugins/aws/ec2/instanceMaxCount.js'), + 'instanceKeyBasedLogin' : require(__dirname + '/plugins/aws/ec2/instanceKeyBasedLogin.js'), + 'openAllPortsProtocols' : require(__dirname + '/plugins/aws/ec2/openAllPortsProtocols.js'), + 'openCIFS' : require(__dirname + '/plugins/aws/ec2/openCIFS.js'), + 'openDNS' : require(__dirname + '/plugins/aws/ec2/openDNS.js'), + 'openDocker' : require(__dirname + '/plugins/aws/ec2/openDocker.js'), + 'openFTP' : require(__dirname + '/plugins/aws/ec2/openFTP.js'), + 'openHadoopNameNode' : require(__dirname + '/plugins/aws/ec2/openHadoopNameNode.js'), + 'openHadoopNameNodeWebUI' : require(__dirname + '/plugins/aws/ec2/openHadoopNameNodeWebUI.js'), + 'openKibana' : require(__dirname + '/plugins/aws/ec2/openKibana.js'), + 'openMySQL' : require(__dirname + '/plugins/aws/ec2/openMySQL.js'), + 'openOracle' : require(__dirname + '/plugins/aws/ec2/openOracle.js'), + 'openNetBIOS' : require(__dirname + '/plugins/aws/ec2/openNetBIOS.js'), + 'openPostgreSQL' : require(__dirname + '/plugins/aws/ec2/openPostgreSQL.js'), + 'openRDP' : require(__dirname + '/plugins/aws/ec2/openRDP.js'), + 'openRPC' : require(__dirname + '/plugins/aws/ec2/openRPC.js'), + 'openSalt' : require(__dirname + '/plugins/aws/ec2/openSalt.js'), + 'openSMBoTCP' : require(__dirname + '/plugins/aws/ec2/openSMBoTCP.js'), + 'openSMTP' : require(__dirname + '/plugins/aws/ec2/openSMTP.js'), + 'openSQLServer' : require(__dirname + '/plugins/aws/ec2/openSQLServer.js'), + 'openSSH' : require(__dirname + '/plugins/aws/ec2/openSSH.js'), + 'openTelnet' : require(__dirname + '/plugins/aws/ec2/openTelnet.js'), + 'openVNCClient' : require(__dirname + '/plugins/aws/ec2/openVNCClient.js'), + 'openVNCServer' : require(__dirname + '/plugins/aws/ec2/openVNCServer.js'), + 'openElasticsearch' : require(__dirname + '/plugins/aws/ec2/openElasticsearch.js'), + 'vpcElasticIpLimit' : require(__dirname + '/plugins/aws/ec2/vpcElasticIpLimit.js'), + 'classicInstances' : require(__dirname + '/plugins/aws/ec2/classicInstances.js'), + 'flowLogsEnabled' : require(__dirname + '/plugins/aws/ec2/flowLogsEnabled.js'), + 'vpcMultipleSubnets' : require(__dirname + '/plugins/aws/ec2/multipleSubnets.js'), + 'overlappingSecurityGroups' : require(__dirname + '/plugins/aws/ec2/overlappingSecurityGroups.js'), + 'publicAmi' : require(__dirname + '/plugins/aws/ec2/publicAmi.js'), + 'encryptedAmi' : require(__dirname + '/plugins/aws/ec2/encryptedAmi.js'), + 'instanceIamRole' : require(__dirname + '/plugins/aws/ec2/instanceIamRole.js'), + 'ebsEncryptionEnabled' : require(__dirname + '/plugins/aws/ec2/ebsEncryptionEnabled.js'), + 'ebsSnapshotPrivate' : require(__dirname + '/plugins/aws/ec2/ebsSnapshotPrivate.js'), + 'natMultiAz' : require(__dirname + '/plugins/aws/ec2/natMultiAz.js'), + 'defaultVpcInUse' : require(__dirname + '/plugins/aws/ec2/defaultVpcInUse.js'), + 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), + 'crossVpcPublicPrivate' : require(__dirname + '/plugins/aws/ec2/crossVpcPublicPrivate.js'), + 'ebsEncryptedSnapshots' : require(__dirname + '/plugins/aws/ec2/ebsEncryptedSnapshots.js'), + 'ec2MetadataOptions' : require(__dirname + '/plugins/aws/ec2/ec2MetadataOptions.js'), + + 'efsEncryptionEnabled' : require(__dirname + '/plugins/aws/efs/efsEncryptionEnabled.js'), + + 'ecrRepositoryPolicy' : require(__dirname + '/plugins/aws/ecr/ecrRepositoryPolicy.js'), + 'ecrRepositoryTagImmutability' : require(__dirname + '/plugins/aws/ecr/ecrRepositoryTagImmutability.js'), + + 'eksKubernetesVersion' : require(__dirname + '/plugins/aws/eks/eksKubernetesVersion.js'), + 'eksLoggingEnabled' : require(__dirname + '/plugins/aws/eks/eksLoggingEnabled.js'), + 'eksPrivateEndpoint' : require(__dirname + '/plugins/aws/eks/eksPrivateEndpoint.js'), + 'eksSecurityGroups' : require(__dirname + '/plugins/aws/eks/eksSecurityGroups.js'), + + 'insecureCiphers' : require(__dirname + '/plugins/aws/elb/insecureCiphers.js'), + 'elbHttpsOnly' : require(__dirname + '/plugins/aws/elb/elbHttpsOnly.js'), + 'elbLoggingEnabled' : require(__dirname + '/plugins/aws/elb/elbLoggingEnabled.js'), + 'elbNoInstances' : require(__dirname + '/plugins/aws/elb/elbNoInstances.js'), + + 'elbv2LoggingEnabled' : require(__dirname + '/plugins/aws/elbv2/elbv2LoggingEnabled.js'), + 'elbv2HttpsOnly' : require(__dirname + '/plugins/aws/elbv2/elbv2HttpsOnly.js'), + 'elbv2NoInstances' : require(__dirname + '/plugins/aws/elbv2/elbv2NoInstances.js'), + 'elbv2WafEnabled' : require(__dirname + '/plugins/aws/elbv2/elbv2WafEnabled.js'), + + 'esPublicEndpoint' : require(__dirname + '/plugins/aws/es/esPublicEndpoint.js'), + 'esRequireIAMAuth' : require(__dirname + '/plugins/aws/es/esRequireIAMAuth.js'), + 'esEncryptedDomain' : require(__dirname + '/plugins/aws/es/esEncryptedDomain.js'), + 'esNodeToNodeEncryption' : require(__dirname + '/plugins/aws/es/esNodeToNodeEncryption.js'), + 'esLoggingEnabled' : require(__dirname + '/plugins/aws/es/esLoggingEnabled.js'), + 'esUpgradeAvailable' : require(__dirname + '/plugins/aws/es/esUpgradeAvailable.js'), + 'esHttpsOnly' : require(__dirname + '/plugins/aws/es/esHttpsOnly.js'), + + 'accessKeysExtra' : require(__dirname + '/plugins/aws/iam/accessKeysExtra.js'), + 'accessKeysLastUsed' : require(__dirname + '/plugins/aws/iam/accessKeysLastUsed.js'), + 'accessKeysRotated' : require(__dirname + '/plugins/aws/iam/accessKeysRotated.js'), + 'certificateExpiry' : require(__dirname + '/plugins/aws/iam/certificateExpiry.js'), + 'emptyGroups' : require(__dirname + '/plugins/aws/iam/emptyGroups.js'), + 'iamUserAdmins' : require(__dirname + '/plugins/aws/iam/iamUserAdmins.js'), + 'iamUserNameRegex' : require(__dirname + '/plugins/aws/iam/iamUserNameRegex.js'), + 'iamRolePolicies' : require(__dirname + '/plugins/aws/iam/iamRolePolicies.js'), + 'maxPasswordAge' : require(__dirname + '/plugins/aws/iam/maxPasswordAge.js'), + 'minPasswordLength' : require(__dirname + '/plugins/aws/iam/minPasswordLength.js'), + 'noUserIamPolicies' : require(__dirname + '/plugins/aws/iam/noUserIamPolicies.js'), + 'passwordExpiration' : require(__dirname + '/plugins/aws/iam/passwordExpiration.js'), + 'passwordRequiresLowercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresLowercase.js'), + 'passwordRequiresNumbers' : require(__dirname + '/plugins/aws/iam/passwordRequiresNumbers.js'), + 'passwordRequiresSymbols' : require(__dirname + '/plugins/aws/iam/passwordRequiresSymbols.js'), + 'passwordRequiresUppercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresUppercase.js'), + 'passwordReusePrevention' : require(__dirname + '/plugins/aws/iam/passwordReusePrevention.js'), + 'rootAccessKeys' : require(__dirname + '/plugins/aws/iam/rootAccessKeys.js'), + 'rootAccountInUse' : require(__dirname + '/plugins/aws/iam/rootAccountInUse.js'), + 'rootHardwareMfa' : require(__dirname + '/plugins/aws/iam/rootHardwareMfa.js'), + 'rootMfaEnabled' : require(__dirname + '/plugins/aws/iam/rootMfaEnabled.js'), + 'sshKeysRotated' : require(__dirname + '/plugins/aws/iam/sshKeysRotated.js'), + 'usersMfaEnabled' : require(__dirname + '/plugins/aws/iam/usersMfaEnabled.js'), + 'usersPasswordAndKeys' : require(__dirname + '/plugins/aws/iam/usersPasswordAndKeys.js'), + 'usersPasswordLastUsed' : require(__dirname + '/plugins/aws/iam/usersPasswordLastUsed.js'), + 'canaryKeysUsed' : require(__dirname + '/plugins/aws/iam/canaryKeysUsed.js'), + 'kinesisEncrypted' : require(__dirname + '/plugins/aws/kinesis/kinesisEncrypted.js'), + 'firehoseEncrypted' : require(__dirname + '/plugins/aws/firehose/firehoseEncrypted.js'), + 'kmsKeyRotation' : require(__dirname + '/plugins/aws/kms/kmsKeyRotation.js'), + 'kmsScheduledDeletion' : require(__dirname + '/plugins/aws/kms/kmsScheduledDeletion.js'), + 'kmsKeyPolicy' : require(__dirname + '/plugins/aws/kms/kmsKeyPolicy.js'), + 'kmsDefaultKeyUsage' : require(__dirname + '/plugins/aws/kms/kmsDefaultKeyUsage.js'), + + 'rdsAutomatedBackups' : require(__dirname + '/plugins/aws/rds/rdsAutomatedBackups.js'), + 'rdsEncryptionEnabled' : require(__dirname + '/plugins/aws/rds/rdsEncryptionEnabled.js'), + 'rdsLoggingEnabled' : require(__dirname + '/plugins/aws/rds/rdsLoggingEnabled.js'), + 'rdsPubliclyAccessible' : require(__dirname + '/plugins/aws/rds/rdsPubliclyAccessible.js'), + 'rdsRestorable' : require(__dirname + '/plugins/aws/rds/rdsRestorable.js'), + 'rdsMultiAz' : require(__dirname + '/plugins/aws/rds/rdsMultiAz.js'), + 'rdsSnapshotEncryption' : require(__dirname + '/plugins/aws/rds/rdsSnapshotEncryption.js'), + 'rdsMinorVersionUpgrade' : require(__dirname + '/plugins/aws/rds/rdsMinorVersionUpgrade.js'), + + 'domainAutoRenew' : require(__dirname + '/plugins/aws/route53/domainAutoRenew.js'), + 'domainExpiry' : require(__dirname + '/plugins/aws/route53/domainExpiry.js'), + 'domainTransferLock' : require(__dirname + '/plugins/aws/route53/domainTransferLock.js'), + + 'bucketEncryptionInTransit' : require(__dirname + '/plugins/aws/s3/bucketEncryptionInTransit.js'), + 'bucketAllUsersPolicy' : require(__dirname + '/plugins/aws/s3/bucketAllUsersPolicy.js'), + 'bucketAllUsersAcl' : require(__dirname + '/plugins/aws/s3/bucketAllUsersAcl.js'), + 'bucketVersioning' : require(__dirname + '/plugins/aws/s3/bucketVersioning.js'), + 'bucketLogging' : require(__dirname + '/plugins/aws/s3/bucketLogging.js'), + 's3Encryption' : require(__dirname + '/plugins/aws/s3/s3Encryption.js'), + 'bucketPublicAccessBlock' : require(__dirname + '/plugins/aws/s3/bucketPublicAccessBlock.js'), + 'bucketEncryption' : require(__dirname + '/plugins/aws/s3/bucketEncryption.js'), + 'bucketWebsiteEnabled' : require(__dirname + '/plugins/aws/s3/bucketWebsiteEnabled.js'), + 'bucketEnforceEncryption' : require(__dirname + '/plugins/aws/s3/bucketEnforceEncryption.js'), + + 'notebookDataEncrypted' : require(__dirname + '/plugins/aws/sagemaker/notebookDataEncrypted.js'), + 'notebookDirectInternetAccess' : require(__dirname + '/plugins/aws/sagemaker/notebookDirectInternetAccess.js'), + + 'dkimEnabled' : require(__dirname + '/plugins/aws/ses/dkimEnabled.js'), + + 'topicPolicies' : require(__dirname + '/plugins/aws/sns/topicPolicies.js'), + 'sqsCrossAccount' : require(__dirname + '/plugins/aws/sqs/sqsCrossAccount.js'), + 'sqsEncrypted' : require(__dirname + '/plugins/aws/sqs/sqsEncrypted.js'), + + 'ssmEncryptedParameters' : require(__dirname + '/plugins/aws/ssm/ssmEncryptedParameters.js'), + 'ssmActiveOnAllInstances' : require(__dirname + '/plugins/aws/ssm/ssmActiveOnAllInstances.js'), + 'ssmAgentLatestVersion' : require(__dirname + '/plugins/aws/ssm/ssmAgentLatestVersion.js'), + + 'lambdaOldRuntimes' : require(__dirname + '/plugins/aws/lambda/lambdaOldRuntimes.js'), + 'lambdaVpcConfig' : require(__dirname + '/plugins/aws/lambda/lambdaVpcConfig.js'), + 'lambdaPublicAccess' : require(__dirname + '/plugins/aws/lambda/lambdaPublicAccess.js'), + 'lambdaLogGroups' : require(__dirname + '/plugins/aws/lambda/lambdaLogGroups.js'), + + 'monitoringMetrics' : require(__dirname + '/plugins/aws/cloudwatchlogs/monitoringMetrics.js'), + + 'redshiftEncryptionEnabled' : require(__dirname + '/plugins/aws/redshift/redshiftEncryptionEnabled.js'), + 'redshiftPubliclyAccessible' : require(__dirname + '/plugins/aws/redshift/redshiftPubliclyAccessible.js'), + + 'transferLoggingEnabled' : require(__dirname + '/plugins/aws/transfer/transferLoggingEnabled.js'), + + 'shieldAdvancedEnabled' : require(__dirname + '/plugins/aws/shield/shieldAdvancedEnabled.js'), + 'shieldEmergencyContacts' : require(__dirname + '/plugins/aws/shield/shieldEmergencyContacts.js'), + 'shieldProtections' : require(__dirname + '/plugins/aws/shield/shieldProtections.js'), + + 'enableAllFeatures' : require(__dirname + '/plugins/aws/organizations/enableAllFeatures.js'), + 'organizationInvite' : require(__dirname + '/plugins/aws/organizations/organizationInvite.js'), + 'guardDutyEnabled' : require(__dirname + '/plugins/aws/guardduty/guarddutyEnabled.js'), + 'guardDutyMaster' : require(__dirname + '/plugins/aws/guardduty/guarddutyMaster.js'), + + 'xrayEncryptionEnabled' : require(__dirname + '/plugins/aws/xray/xrayEncryptionEnabled.js') }, azure : { 'fileServiceEncryption' : require(__dirname + '/plugins/azure/storageaccounts/fileServiceEncryption.js'), diff --git a/helpers/aws/regions.js b/helpers/aws/regions.js index 4609df93b3..3749d0093f 100644 --- a/helpers/aws/regions.js +++ b/helpers/aws/regions.js @@ -35,6 +35,7 @@ module.exports = { route53: ['us-east-1'], route53domains: ['us-east-1'], s3: ['us-east-1'], + cloudformation: regions, cloudtrail: regions, cloudwatchlogs: regions, configservice: regions, diff --git a/index.js b/index.js index 3b97033a22..cceed66ab0 100644 --- a/index.js +++ b/index.js @@ -113,7 +113,13 @@ if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ } // Custom settings - place plugin-specific settings here -var settings = {}; +var settings = { + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] + } +}; // If running in GovCloud, uncomment the following // settings.govcloud = true; diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 658dc42f3d..6075fd59f7 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -1,3 +1,4 @@ +var async = require('async'); var helpers = require('../../../helpers/aws'); module.exports = { @@ -8,63 +9,59 @@ module.exports = { link: 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html', recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], - compliance: { - hipaa: 'HIPAA requires all data to be transmitted over secure channels. ' + - 'CloudFront HTTPS redirection should be used to ensure site visitors ' + - 'are always connecting over a secure channel.' - }, - // settings : { secretWords : ["password", "privatekey", "secret"] }, run: function(cache, settings, callback) { - var results = []; var source = {}; + var regions = helpers.regions(settings); + secretWords = settings.plainTextParameters.secretWords; - var region = helpers.defaultRegion(settings); + async.each(regions.cloudformation, function(region, rcb){ - var describeStacks = helpers.addSource(cache, source, - ['cloudformation', 'describeStacks', region]); + var describeStacks = helpers.addSource(cache, source, + ['cloudformation', 'describeStacks', region]); + + if (!describeStacks) return rcb(); - console.log(describeStacks); - console.log("results received"); - // if (!describeStacks) return callback(null, results, source); + if (describeStacks.err || !describeStacks.data) { + helpers.addResult(results, 3, + 'Unable to describe stacks: ' + helpers.addError(describeStacks), region); + return rcb(); + } - // if (describeStacks.err || !describeStacks.data) { - // helpers.addResult(results, 3, - // 'Unable to describe stacks: ' + helpers.addError(describeStacks)); - // return callback(null, results, source); - // } + if (!describeStacks.data.length) { + helpers.addResult(results, 0, 'No stack description found', region); + return rcb(); + } + + var parameterFound; + describeStacks.data.forEach(function(stack){ + parameterFound = false; - // if (!describeStacks.data.length) { - // helpers.addResult(results, 0, 'No stacks descriptions found'); - // return callback(null, results, source); - // } - // console.log(describeStacks.data); - // loop through stacks for every template retrieval - // describeStacks.data.forEach(function(Distribution){ - // var stackTemplate = helpers.addSource(cache, source, - // ['cloudformation', 'getTemplate', region]); - - // if (!describeStacks) return callback(null, results, source); - - // if (describeStacks.err || !describeStacks.data) { - // helpers.addResult(results, 3, - // 'Unable to describe stacks: ' + helpers.addError(describeStacks)); - // return callback(null, results, source); - // } + if(!stack.Parameters.length) { + helpers.addResult(results, 0, + 'The template did not contain any potentially-sensitive parameters', region); + return; + } - // if (Distribution.DefaultCacheBehavior.ViewerProtocolPolicy == 'redirect-to-https') { - // helpers.addResult(results, 0, 'CloudFront distribution ' + - // 'is configured to redirect non-HTTPS traffic to HTTPS', 'global', Distribution.ARN); - // } else if (Distribution.DefaultCacheBehavior.ViewerProtocolPolicy == 'https-only') { - // helpers.addResult(results, 0, 'The CloudFront ' + - // 'distribution is set to use HTTPS only.', 'global', Distribution.ARN); - // } else { - // helpers.addResult(results, 2, 'CloudFront distribution ' + - // 'is not configured to use HTTPS', 'global', Distribution.ARN); - // } - // }); + stack.Parameters.forEach(function(parameter){ + if(secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameterFound) { + parameterFound = true; + helpers.addResult(results, 1, + 'The template contained one of the following potentially-sensitive parameters: secret, key, password', region); + return; + } + }); + + if(!parameterFound) { + helpers.addResult(results, 0, + 'The template did not contain any potentially-sensitive parameters', region); + } - callback(null, results, source); + }); + rcb(); + }, function(){ + callback(null, results, source); + }); } }; \ No newline at end of file diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js new file mode 100644 index 0000000000..792f454333 --- /dev/null +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -0,0 +1,161 @@ +var expect = require('chai').expect; +const plainTextParameters = require('./plainTextParameters'); +const settings = { + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] + } +}; +const describeStacks = [ + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [ + { + ParameterKey: 'Secret', + ParameterValue: 'bucketwithsecretparameter1' + }, + { + ParameterKey: 'Password', + ParameterValue: 'bucketwithsecretparameter1' + } + ], + CreationTime: '2020-08-13T13:34:52.435Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + }, + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [ + { + ParameterKey: 'S3BucketName', + ParameterValue: 'testbucketplaintext1' + } + ], + CreationTime: '2020-08-12T09:42:04.803Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + }, + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [], + CreationTime: '2020-08-12T09:42:04.803Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + } +] + +const createCache = (stacks) => { + return { + cloudformation: { + describeStacks: { + 'us-east-1': { + data: stacks + }, + }, + }, + }; +}; + +const createErrorCache = () => { + return { + cloudformation: { + describeStacks: { + 'us-east-1': { + err: { + message: 'error describing cloudformation stacks' + }, + }, + }, + }, + }; +}; + +const createNullCache = () => { + return { + cloudformation: { + describeStacks: { + 'us-east-1': null, + }, + }, + }; +}; + +describe('plainTextParameters', function () { + describe('run', function () { + it('should FAIL if Stack parameters contain one of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[0]]); + plainTextParameters.run(cache, settings, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(1); + done(); + }); + }); + + it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[1]]); + plainTextParameters.run(cache, settings, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should PASS if unable to describe stacks', function (done) { + const cache = createCache([]); + plainTextParameters.run(cache, settings, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should PASS if there is no parameter in the stack', function (done) { + const cache = createCache([describeStacks[2]]); + plainTextParameters.run(cache, settings, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should not return any results if unable to fetch any stack description', function (done) { + const cache = createNullCache(); + plainTextParameters.run(cache, settings, (err, results) => { + expect(results.length).to.equal(0); + done(); + }); + }); + + it('should UNKNOWN if error occurs while fetching stack description', function (done) { + const cache = createErrorCache(); + plainTextParameters.run(cache, settings, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + done(); + }); + }); + + }); +}); \ No newline at end of file From 7c8616c9c54503cb3c9e2f7b565fd89478a21bef Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 15:30:57 +0500 Subject: [PATCH 04/67] Added plugin and spec file for launch wizard security groups --- exports.js | 4 +- plugins/aws/ec2/launchWizardSecurityGroups.js | 55 +++++++ .../ec2/launchWizardSecurityGroups.spec.js | 153 ++++++++++++++++++ plugins/aws/ec2/vpcEndpointAcceptance.spec.js | 9 -- 4 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 plugins/aws/ec2/launchWizardSecurityGroups.js create mode 100644 plugins/aws/ec2/launchWizardSecurityGroups.spec.js diff --git a/exports.js b/exports.js index 912d562838..0c8b893a09 100644 --- a/exports.js +++ b/exports.js @@ -29,6 +29,7 @@ module.exports = { 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), + 'launchWizardSecurityGroups' : require(__dirname + '/plugins/aws/ec2/launchWizardSecurityGroups'), 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), @@ -71,8 +72,9 @@ module.exports = { 'ebsSnapshotPrivate' : require(__dirname + '/plugins/aws/ec2/ebsSnapshotPrivate.js'), 'natMultiAz' : require(__dirname + '/plugins/aws/ec2/natMultiAz.js'), 'defaultVpcInUse' : require(__dirname + '/plugins/aws/ec2/defaultVpcInUse.js'), - 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), + 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), 'crossVpcPublicPrivate' : require(__dirname + '/plugins/aws/ec2/crossVpcPublicPrivate.js'), + 'vpcEndpointAcceptance' : require(__dirname + '/plugins/aws/ec2/vpcEndpointAcceptance'), 'ebsEncryptedSnapshots' : require(__dirname + '/plugins/aws/ec2/ebsEncryptedSnapshots.js'), 'ec2MetadataOptions' : require(__dirname + '/plugins/aws/ec2/ec2MetadataOptions.js'), diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js new file mode 100644 index 0000000000..252cabd11c --- /dev/null +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -0,0 +1,55 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'EC2 LaunchWizard Security Groups', + category: 'EC2', + description: 'Ensures security groups created by the EC2 launch wizard are not used', + more_info: 'The EC2 launch wizard frequently creates insecure security groups that are exposed publicly. These groups should not be used and custom security groups should be created instead.', + link: 'https://docs.aws.amazon.com/launchwizard/latest/userguide/launch-wizard-sap-security-groups.html', + recommended_action: 'Delete the launch wizard security group and replace it with a custom security group.', + apis: ['EC2:describeSecurityGroups'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + + async.each(regions.ec2, function(region, rcb){ + var describeSecurityGroups = helpers.addSource(cache, source, + ['ec2', 'describeSecurityGroups', region]); + + if (!describeSecurityGroups) return rcb(); + + if (describeSecurityGroups.err || !describeSecurityGroups.data) { + helpers.addResult(results, 3, + 'Unable to query for security groups: ' + helpers.addError(describeSecurityGroups), region); + return rcb(); + } + + if (!describeSecurityGroups.data.length) { + helpers.addResult(results, 0, 'No security groups present', region); + return rcb(); + } + + for (var s in describeSecurityGroups.data) { + var sg = describeSecurityGroups.data[s]; + var resource = sg.GroupId; + + if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { + helpers.addResult(results, 2, + 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', + region, resource); + } else { + helpers.addResult(results, 0, + 'Security Group ' + sg.GroupName + ' was not launched using EC2 launch wizard', + region, resource); + } + } + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.spec.js b/plugins/aws/ec2/launchWizardSecurityGroups.spec.js new file mode 100644 index 0000000000..a2b8baa2e9 --- /dev/null +++ b/plugins/aws/ec2/launchWizardSecurityGroups.spec.js @@ -0,0 +1,153 @@ +var expect = require('chai').expect; +const launchWizardSecurityGroups = require('./launchWizardSecurityGroups'); + +const securityGroups = [ + { + "Description": "launch-wizard-1 created 2020-08-10T14:28:09.271+05:00", + "GroupName": "launch-wizard-1", + "IpPermissions": [ + { + "FromPort": 22, + "IpProtocol": "tcp", + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "Ipv6Ranges": [], + "PrefixListIds": [], + "ToPort": 22, + "UserIdGroupPairs": [] + } + ], + "OwnerId": "560213429563", + "GroupId": "sg-0ff1642cae23c309a", + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "Ipv6Ranges": [], + "PrefixListIds": [], + "UserIdGroupPairs": [] + } + ], + "Tags": [], + "VpcId": "vpc-99de2fe4" + }, + { + "Description": "Allows SSh access to developer", + "GroupName": "spec-test-sg", + "IpPermissions": [], + "OwnerId": "560213429563", + "GroupId": "sg-0b5f2771716acfee4", + "IpPermissionsEgress": [ + { + "FromPort": 22, + "IpProtocol": "tcp", + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "Ipv6Ranges": [ + { + "CidrIpv6": "::/0" + } + ], + "PrefixListIds": [], + "ToPort": 22, + "UserIdGroupPairs": [] + } + ], + "Tags": [], + "VpcId": "vpc-99de2fe4" + } + ]; + +const createCache = (securityGroups) => { + return { + ec2: { + describeSecurityGroups: { + 'us-east-1': { + data: securityGroups + }, + }, + }, + }; +}; + +const createErrorCache = () => { + return { + ec2: { + describeSecurityGroups: { + 'us-east-1': { + err: { + message: 'error describing security groups' + }, + }, + }, + }, + }; +}; + +const createNullCache = () => { + return { + ec2: { + describeSecurityGroups: { + 'us-east-1': null, + }, + }, + }; +}; + +describe('launchWizardSecurityGroups', function () { + describe('run', function () { + it('should PASS if security groups was not created using EC2 launch wizard', function (done) { + const cache = createCache([securityGroups[1]]); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should FAIL if security groups was created using EC2 launch wizard', function (done) { + const cache = createCache([securityGroups[0]]); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + done(); + }); + }); + + it('should PASS if no security groups are detected', function (done) { + const cache = createCache([]); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should UNKNOWN if there was an error describing security groups', function (done) { + const cache = createErrorCache(); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + done(); + }); + }); + + it('should not return any results if unable to query for security groups', function (done) { + const cache = createNullCache(); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(0); + done(); + }); + }); + }); +}); diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js index 0946f5a682..62053b7238 100644 --- a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js +++ b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js @@ -112,15 +112,6 @@ describe('vpcEndpointAcceptance', function () { }); }); - it('should PASS if no VPC endpoint services are detected', function (done) { - const cache = createCache([]); - vpcEndpointAcceptance.run(cache, {}, (err, results) => { - expect(results.length).to.equal(1); - expect(results[0].status).to.equal(0); - done(); - }); - }); - it('should UNKNOWN if there was an error querying for VPC endpoint services', function (done) { const cache = createErrorCache(); vpcEndpointAcceptance.run(cache, {}, (err, results) => { From 3da6672d99647eeb68b4966e069826edf6319e4c Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 16:50:46 +0500 Subject: [PATCH 05/67] Refactored code in plaintextParameters plugin and spec file --- exports.js | 4 ++- index.js | 8 +----- .../aws/cloudformation/plainTextParameters.js | 28 +++++++++++++------ .../plainTextParameters.spec.js | 28 ++++++++----------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/exports.js b/exports.js index 56084148d3..ee2b81f9ee 100644 --- a/exports.js +++ b/exports.js @@ -13,7 +13,9 @@ module.exports = { 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), - 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), + + 'plaintextParameters' : require(__dirname + '/plugins/aws/cloudformation/plaintextParameters.js'), + 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), diff --git a/index.js b/index.js index cceed66ab0..3b97033a22 100644 --- a/index.js +++ b/index.js @@ -113,13 +113,7 @@ if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ } // Custom settings - place plugin-specific settings here -var settings = { - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] - } -}; +var settings = {}; // If running in GovCloud, uncomment the following // settings.govcloud = true; diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 6075fd59f7..2ed03af7f0 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -9,12 +9,19 @@ module.exports = { link: 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html', recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], + settings: { + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] + } + }, run: function(cache, settings, callback) { var results = []; var source = {}; var regions = helpers.regions(settings); - secretWords = settings.plainTextParameters.secretWords; + secretWords = this.settings.plainTextParameters.secretWords; async.each(regions.cloudformation, function(region, rcb){ @@ -35,30 +42,33 @@ module.exports = { } var parameterFound; - describeStacks.data.forEach(function(stack){ + for (var s in describeStacks.data){ + // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id + var stack = describeStacks.data[s]; + var resource = stack.StackId; parameterFound = false; if(!stack.Parameters.length) { helpers.addResult(results, 0, - 'The template did not contain any potentially-sensitive parameters', region); - return; + 'The template does not contain any potentially-sensitive parameters', region, resource); + return rcb(); } stack.Parameters.forEach(function(parameter){ - if(secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameterFound) { + if(!parameterFound && secretWords.includes(parameter.ParameterKey.toLowerCase())) { parameterFound = true; helpers.addResult(results, 1, - 'The template contained one of the following potentially-sensitive parameters: secret, key, password', region); - return; + 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); } }); if(!parameterFound) { helpers.addResult(results, 0, - 'The template did not contain any potentially-sensitive parameters', region); + 'Template does not contain any potentially-sensitive parameters', region, resource); } - }); + } + rcb(); }, function(){ callback(null, results, source); diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index 792f454333..490d978002 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -1,12 +1,6 @@ var expect = require('chai').expect; -const plainTextParameters = require('./plainTextParameters'); -const settings = { - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] - } -}; +const plaintextParameters = require('./plaintextParameters'); + const describeStacks = [ { StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', @@ -102,20 +96,20 @@ const createNullCache = () => { }; }; -describe('plainTextParameters', function () { +describe('plaintextParameters', function () { describe('run', function () { - it('should FAIL if Stack parameters contain one of secret words ["password" , "privatekey", "secret"]', function (done) { + it('should WARN if template contains one of secret words ["password" , "privatekey", "secret"]', function (done) { const cache = createCache([describeStacks[0]]); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(1); done(); }); }); - it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { + it('should PASS if template does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { const cache = createCache([describeStacks[1]]); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -124,7 +118,7 @@ describe('plainTextParameters', function () { it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -133,7 +127,7 @@ describe('plainTextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -142,7 +136,7 @@ describe('plainTextParameters', function () { it('should not return any results if unable to fetch any stack description', function (done) { const cache = createNullCache(); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(0); done(); }); @@ -150,7 +144,7 @@ describe('plainTextParameters', function () { it('should UNKNOWN if error occurs while fetching stack description', function (done) { const cache = createErrorCache(); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(3); done(); From ce6532523dca0f672a0824cfd3cc1e8161d9984c Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Fri, 14 Aug 2020 18:09:45 +0500 Subject: [PATCH 06/67] SPLOIT-113: Updated custom settings --- plugins/aws/cloudformation/plainTextParameters.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 2ed03af7f0..0a53028425 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -10,10 +10,11 @@ module.exports = { recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], settings: { - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] + plain_text_parameters: { + name: "CloudFormation Plaintext Parameters", + description: "A comma-delimited list of parameter strings that indicate a sensitive value", + regex: "[a-zA-Z0-9,]", + default: "secret,password,privatekey" } }, @@ -21,8 +22,7 @@ module.exports = { var results = []; var source = {}; var regions = helpers.regions(settings); - secretWords = this.settings.plainTextParameters.secretWords; - + secretWords = this.settings.plain_text_parameters.default; async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, From e70b96aac28a75ed99c4f51b9d89e0003d0e5b0b Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 21:24:30 +0500 Subject: [PATCH 07/67] Made PR requested changes --- plugins/aws/cloudformation/plainTextParameters.js | 8 ++++---- plugins/aws/ec2/launchWizardSecurityGroups.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 0a53028425..30da85236a 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -22,7 +22,7 @@ module.exports = { var results = []; var source = {}; var regions = helpers.regions(settings); - secretWords = this.settings.plain_text_parameters.default; + var secretWords = this.settings.plain_text_parameters.default; async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, @@ -48,14 +48,14 @@ module.exports = { var resource = stack.StackId; parameterFound = false; - if(!stack.Parameters.length) { + if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'The template does not contain any potentially-sensitive parameters', region, resource); + 'Template does not contain any potentially-sensitive parameters', region, resource); return rcb(); } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && secretWords.includes(parameter.ParameterKey.toLowerCase())) { + if((!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()))) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js index 252cabd11c..0e028778a7 100644 --- a/plugins/aws/ec2/launchWizardSecurityGroups.js +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -36,7 +36,7 @@ module.exports = { var sg = describeSecurityGroups.data[s]; var resource = sg.GroupId; - if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { + if (sg.GroupName && sg.GroupName.toLowerCase().startsWith('launch-wizard')) { helpers.addResult(results, 2, 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', region, resource); From f62a1d5037ebd20dda78959f5d2b0a073bb4abee Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Sat, 15 Aug 2020 01:07:50 +0500 Subject: [PATCH 08/67] SPLOIT-113: Added regex to check if NoEcho is enabled --- plugins/aws/cloudformation/plainTextParameters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 30da85236a..f6a5ce193a 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -55,7 +55,7 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if((!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()))) { + if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match("^[\*]+$")) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); From 1b80ac47565110c4ba276805f233d1aa11620a40 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 04:13:40 +0500 Subject: [PATCH 09/67] Accommodated PR changes --- exports.js | 2 +- plugins/aws/cloudformation/plainTextParameters.js | 6 +++--- .../aws/cloudformation/plainTextParameters.spec.js | 2 +- plugins/aws/ec2/launchWizardSecurityGroups.js | 11 +++++++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/exports.js b/exports.js index ee2b81f9ee..a61fddd2cc 100644 --- a/exports.js +++ b/exports.js @@ -14,7 +14,7 @@ module.exports = { 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), - 'plaintextParameters' : require(__dirname + '/plugins/aws/cloudformation/plaintextParameters.js'), + 'plaintextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index f6a5ce193a..5e5f227feb 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -46,12 +46,12 @@ module.exports = { // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id var stack = describeStacks.data[s]; var resource = stack.StackId; - parameterFound = false; + let parameterFound = false; if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'Template does not contain any potentially-sensitive parameters', region, resource); - return rcb(); + 'Template does not contain any parameters', region, resource); + continue; } stack.Parameters.forEach(function(parameter){ diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index 490d978002..cdad731db6 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -1,5 +1,5 @@ var expect = require('chai').expect; -const plaintextParameters = require('./plaintextParameters'); +const plaintextParameters = require('./plainTextParameters'); const describeStacks = [ { diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js index 0e028778a7..48f040b7ed 100644 --- a/plugins/aws/ec2/launchWizardSecurityGroups.js +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -28,7 +28,7 @@ module.exports = { } if (!describeSecurityGroups.data.length) { - helpers.addResult(results, 0, 'No security groups present', region); + helpers.addResult(results, 0, 'No security groups found', region); return rcb(); } @@ -36,7 +36,14 @@ module.exports = { var sg = describeSecurityGroups.data[s]; var resource = sg.GroupId; - if (sg.GroupName && sg.GroupName.toLowerCase().startsWith('launch-wizard')) { + if(!sg.GroupName) { + helpers.addResult(results, 2, + 'Unable to get group name of security group', + region, resource); + continue; + } + + if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { helpers.addResult(results, 2, 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', region, resource); From c0dc834c5739260ca9acfc7f11ef78bf73987535 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 06:09:46 +0500 Subject: [PATCH 10/67] Fixed eslint issues --- plugins/aws/cloudformation/plainTextParameters.js | 15 +++++++-------- plugins/aws/ec2/launchWizardSecurityGroups.js | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 5e5f227feb..5f9906591c 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -11,10 +11,10 @@ module.exports = { apis: ['CloudFormation:describeStacks'], settings: { plain_text_parameters: { - name: "CloudFormation Plaintext Parameters", - description: "A comma-delimited list of parameter strings that indicate a sensitive value", - regex: "[a-zA-Z0-9,]", - default: "secret,password,privatekey" + name: 'CloudFormation Plaintext Parameters', + description: 'A comma-delimited list of parameter strings that indicate a sensitive value', + regex: '[a-zA-Z0-9,]', + default: 'secret,password,privatekey' } }, @@ -33,7 +33,7 @@ module.exports = { if (describeStacks.err || !describeStacks.data) { helpers.addResult(results, 3, 'Unable to describe stacks: ' + helpers.addError(describeStacks), region); - return rcb(); + return rcb(); } if (!describeStacks.data.length) { @@ -41,7 +41,6 @@ module.exports = { return rcb(); } - var parameterFound; for (var s in describeStacks.data){ // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id var stack = describeStacks.data[s]; @@ -55,7 +54,7 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match("^[\*]+$")) { + if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); @@ -64,7 +63,7 @@ module.exports = { if(!parameterFound) { helpers.addResult(results, 0, - 'Template does not contain any potentially-sensitive parameters', region, resource); + 'Template does not contain any potentially-sensitive parameters', region, resource); } } diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js index 48f040b7ed..caa173be82 100644 --- a/plugins/aws/ec2/launchWizardSecurityGroups.js +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -45,8 +45,8 @@ module.exports = { if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { helpers.addResult(results, 2, - 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', - region, resource); + 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', + region, resource); } else { helpers.addResult(results, 0, 'Security Group ' + sg.GroupName + ' was not launched using EC2 launch wizard', From 7d457bd2c6def38589b805cb7de4d2cb8340b95d Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:38:01 +0500 Subject: [PATCH 11/67] Update exports.js --- exports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exports.js b/exports.js index a61fddd2cc..5a338cfa5e 100644 --- a/exports.js +++ b/exports.js @@ -14,7 +14,7 @@ module.exports = { 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), - 'plaintextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), + 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), From 8c2466c91d58ce0de34eb75c62bcb02e844efd32 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:41:20 +0500 Subject: [PATCH 12/67] Fixed eslint issues --- index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 3b97033a22..262b4c8c73 100644 --- a/index.js +++ b/index.js @@ -10,12 +10,12 @@ var GoogleConfig; // OPTION 1: Configure service provider credentials through hard-coded config objects -// AWSConfig = { -// accessKeyId: '', -// secretAccessKey: '', -// sessionToken: '', -// region: 'us-east-1' -// }; +AWSConfig = { + accessKeyId: 'AKIAYE32SRU5XWXGIMV3', + secretAccessKey: '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', + sessionToken: '', + region: 'us-east-1' +}; // AzureConfig = { // ApplicationID: '', // A.K.A ClientID From ccb92eef611140d3c36698417db0755e6483ea74 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:42:00 +0500 Subject: [PATCH 13/67] Update index.js --- index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 262b4c8c73..019fc78f81 100644 --- a/index.js +++ b/index.js @@ -10,12 +10,12 @@ var GoogleConfig; // OPTION 1: Configure service provider credentials through hard-coded config objects -AWSConfig = { - accessKeyId: 'AKIAYE32SRU5XWXGIMV3', - secretAccessKey: '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', - sessionToken: '', - region: 'us-east-1' -}; +// AWSConfig = { +// accessKeyId: '', +// secretAccessKey: '', +// sessionToken: '', +// region: '' +// }; // AzureConfig = { // ApplicationID: '', // A.K.A ClientID From 93c553d4c7be0b44e7553149f7a2f3f461103008 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:48:02 +0500 Subject: [PATCH 14/67] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 019fc78f81..6f61d149a8 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ var GoogleConfig; // accessKeyId: '', // secretAccessKey: '', // sessionToken: '', -// region: '' +// region: 'us-east-1' // }; // AzureConfig = { From cf21d1d1513bef533823eb547389a0d3ede895cf Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 15:59:26 +0500 Subject: [PATCH 15/67] Added cloudformation in china and gov regions --- helpers/aws/regions_china.js | 1 + helpers/aws/regions_gov.js | 1 + 2 files changed, 2 insertions(+) diff --git a/helpers/aws/regions_china.js b/helpers/aws/regions_china.js index 18c482aca6..3d82dca40c 100644 --- a/helpers/aws/regions_china.js +++ b/helpers/aws/regions_china.js @@ -18,6 +18,7 @@ module.exports = { s3: regions, cloudtrail: regions, cloudwatchlogs: regions, + cloudformation: regions, configservice: regions, dms: regions, dynamodb: regions, diff --git a/helpers/aws/regions_gov.js b/helpers/aws/regions_gov.js index f84f8f923d..c55424fce6 100644 --- a/helpers/aws/regions_gov.js +++ b/helpers/aws/regions_gov.js @@ -18,6 +18,7 @@ module.exports = { s3: regions, cloudtrail: regions, cloudwatchlogs: regions, + cloudformation: regions, configservice: regions, dms: regions, dynamodb: regions, From aac8ece7116bcc8bf98a826339f543ecb69a5e10 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 20:15:26 +0500 Subject: [PATCH 16/67] Accomodated PR changes --- .../aws/cloudformation/plainTextParameters.js | 18 +-- .../plainTextParameters.spec.js | 144 +++++++++++------- 2 files changed, 95 insertions(+), 67 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 5f9906591c..e6e899268f 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -27,7 +27,6 @@ module.exports = { var describeStacks = helpers.addSource(cache, source, ['cloudformation', 'describeStacks', region]); - if (!describeStacks) return rcb(); if (describeStacks.err || !describeStacks.data) { @@ -45,7 +44,7 @@ module.exports = { // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id var stack = describeStacks.data[s]; var resource = stack.StackId; - let parameterFound = false; + let foundStrings = []; if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, @@ -54,18 +53,19 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { - parameterFound = true; - helpers.addResult(results, 1, - 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); + if(parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { + foundStrings.push(parameter.ParameterKey); } }); - - if(!parameterFound) { + + if(foundStrings && foundStrings.length) { + helpers.addResult(results, 1, + 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); + } + else { helpers.addResult(results, 0, 'Template does not contain any potentially-sensitive parameters', region, resource); } - } rcb(); diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index cdad731db6..d471a555f3 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -2,62 +2,81 @@ var expect = require('chai').expect; const plaintextParameters = require('./plainTextParameters'); const describeStacks = [ - { - StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', - StackName: 'TestStack', - Parameters: [ - { - ParameterKey: 'Secret', - ParameterValue: 'bucketwithsecretparameter1' - }, - { - ParameterKey: 'Password', - ParameterValue: 'bucketwithsecretparameter1' - } - ], - CreationTime: '2020-08-13T13:34:52.435Z', - RollbackConfiguration: { RollbackTriggers: [] }, - StackStatus: 'CREATE_COMPLETE', - DisableRollback: false, - NotificationARNs: [], - Capabilities: [], - Outputs: [], - Tags: [], - DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } - }, - { - StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', - StackName: 'TestStack', - Parameters: [ - { - ParameterKey: 'S3BucketName', - ParameterValue: 'testbucketplaintext1' - } - ], - CreationTime: '2020-08-12T09:42:04.803Z', - RollbackConfiguration: { RollbackTriggers: [] }, - StackStatus: 'CREATE_COMPLETE', - DisableRollback: false, - NotificationARNs: [], - Capabilities: [], - Outputs: [], - Tags: [], - DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } - }, - { - StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', - StackName: 'TestStack', - Parameters: [], - CreationTime: '2020-08-12T09:42:04.803Z', - RollbackConfiguration: { RollbackTriggers: [] }, - StackStatus: 'CREATE_COMPLETE', - DisableRollback: false, - NotificationARNs: [], - Capabilities: [], - Outputs: [], - Tags: [], - DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } - } + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [ + { + ParameterKey: 'Secret', + ParameterValue: 'bucketwithsecretparameter1' + }, + { + ParameterKey: 'Password', + ParameterValue: 'bucketwithsecretparameter1' + } + ], + CreationTime: '2020-08-13T13:34:52.435Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + }, + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [ + { + ParameterKey: 'S3BucketName', + ParameterValue: 'testbucketplaintext1' + } + ], + CreationTime: '2020-08-12T09:42:04.803Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + }, + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [ + { + ParameterKey: 'Secret', + ParameterValue: '****' + } + ], + CreationTime: '2020-08-13T13:34:52.435Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + }, + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [], + CreationTime: '2020-08-12T09:42:04.803Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + } ] const createCache = (stacks) => { @@ -98,7 +117,7 @@ const createNullCache = () => { describe('plaintextParameters', function () { describe('run', function () { - it('should WARN if template contains one of secret words ["password" , "privatekey", "secret"]', function (done) { + it('should WARN if template contains one of secret words', function (done) { const cache = createCache([describeStacks[0]]); plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); @@ -107,7 +126,7 @@ describe('plaintextParameters', function () { }); }); - it('should PASS if template does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { + it('should PASS if template does not contain any of secret words', function (done) { const cache = createCache([describeStacks[1]]); plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); @@ -116,6 +135,15 @@ describe('plaintextParameters', function () { }); }); + it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { + const cache = createCache([describeStacks[2]]); + plaintextParameters.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); plaintextParameters.run(cache, {}, (err, results) => { From 7707dbd49add468d82ae24466b8bda804e9c2f4b Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 21:12:35 +0500 Subject: [PATCH 17/67] Updated status in result of failure --- plugins/aws/cloudformation/plainTextParameters.js | 2 +- plugins/aws/cloudformation/plainTextParameters.spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index e6e899268f..6803911fef 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -59,7 +59,7 @@ module.exports = { }); if(foundStrings && foundStrings.length) { - helpers.addResult(results, 1, + helpers.addResult(results, 2, 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); } else { diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index d471a555f3..03e8abf7e9 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -117,11 +117,11 @@ const createNullCache = () => { describe('plaintextParameters', function () { describe('run', function () { - it('should WARN if template contains one of secret words', function (done) { + it('should FAIL if template contains one of secret words', function (done) { const cache = createCache([describeStacks[0]]); plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); - expect(results[0].status).to.equal(1); + expect(results[0].status).to.equal(2); done(); }); }); From a4ea92f1b8c5baa7867659a7315805b15b2bf203 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Fri, 14 Aug 2020 05:55:55 +0500 Subject: [PATCH 18/67] SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation --- exports.js | 7 ++++ index.js | 8 ++++- .../plainTextParameters.spec.js | 32 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/exports.js b/exports.js index 5a338cfa5e..b3eca51f7d 100644 --- a/exports.js +++ b/exports.js @@ -13,9 +13,13 @@ module.exports = { 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), +<<<<<<< HEAD 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), +======= + 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), @@ -31,7 +35,10 @@ module.exports = { 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), +<<<<<<< HEAD 'launchWizardSecurityGroups' : require(__dirname + '/plugins/aws/ec2/launchWizardSecurityGroups'), +======= +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), diff --git a/index.js b/index.js index 6f61d149a8..2f90a29fa4 100644 --- a/index.js +++ b/index.js @@ -113,7 +113,13 @@ if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ } // Custom settings - place plugin-specific settings here -var settings = {}; +var settings = { + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] + } +}; // If running in GovCloud, uncomment the following // settings.govcloud = true; diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index 03e8abf7e9..cdf14fb564 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -115,6 +115,7 @@ const createNullCache = () => { }; }; +<<<<<<< HEAD describe('plaintextParameters', function () { describe('run', function () { it('should FAIL if template contains one of secret words', function (done) { @@ -122,10 +123,20 @@ describe('plaintextParameters', function () { plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); +======= +describe('plainTextParameters', function () { + describe('run', function () { + it('should FAIL if Stack parameters contain one of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[0]]); + plainTextParameters.run(cache, settings, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(1); +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation done(); }); }); +<<<<<<< HEAD it('should PASS if template does not contain any of secret words', function (done) { const cache = createCache([describeStacks[1]]); plaintextParameters.run(cache, {}, (err, results) => { @@ -138,6 +149,11 @@ describe('plaintextParameters', function () { it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { const cache = createCache([describeStacks[2]]); plaintextParameters.run(cache, {}, (err, results) => { +======= + it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[1]]); + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -146,7 +162,11 @@ describe('plaintextParameters', function () { it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); +<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { +======= + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -155,7 +175,11 @@ describe('plaintextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); +<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { +======= + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -164,7 +188,11 @@ describe('plaintextParameters', function () { it('should not return any results if unable to fetch any stack description', function (done) { const cache = createNullCache(); +<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { +======= + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(0); done(); }); @@ -172,7 +200,11 @@ describe('plaintextParameters', function () { it('should UNKNOWN if error occurs while fetching stack description', function (done) { const cache = createErrorCache(); +<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { +======= + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(3); done(); From 8e5b6be04baa584ba2e3aafc64076ad49175f6ef Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 15:30:57 +0500 Subject: [PATCH 19/67] Added plugin and spec file for launch wizard security groups --- exports.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/exports.js b/exports.js index b3eca51f7d..5a338cfa5e 100644 --- a/exports.js +++ b/exports.js @@ -13,13 +13,9 @@ module.exports = { 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), -<<<<<<< HEAD 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), -======= - 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), @@ -35,10 +31,7 @@ module.exports = { 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), -<<<<<<< HEAD 'launchWizardSecurityGroups' : require(__dirname + '/plugins/aws/ec2/launchWizardSecurityGroups'), -======= ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), From a9afe440de80c185bdd8df63bad1c28c990daa99 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Thu, 13 Aug 2020 19:59:59 +0500 Subject: [PATCH 20/67] Added vpcEndpointAcceptance plugin and spec file --- plugins/aws/ec2/vpcEndpointAcceptance.spec.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js index 62053b7238..0946f5a682 100644 --- a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js +++ b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js @@ -112,6 +112,15 @@ describe('vpcEndpointAcceptance', function () { }); }); + it('should PASS if no VPC endpoint services are detected', function (done) { + const cache = createCache([]); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + it('should UNKNOWN if there was an error querying for VPC endpoint services', function (done) { const cache = createErrorCache(); vpcEndpointAcceptance.run(cache, {}, (err, results) => { From 0323a988487eb779a7897c75f464d38217877c19 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 16:50:46 +0500 Subject: [PATCH 21/67] Refactored code in plaintextParameters plugin and spec file --- index.js | 8 +--- .../aws/cloudformation/plainTextParameters.js | 22 +++++++++-- .../plainTextParameters.spec.js | 38 ++++++------------- 3 files changed, 31 insertions(+), 37 deletions(-) diff --git a/index.js b/index.js index 2f90a29fa4..6f61d149a8 100644 --- a/index.js +++ b/index.js @@ -113,13 +113,7 @@ if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ } // Custom settings - place plugin-specific settings here -var settings = { - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] - } -}; +var settings = {}; // If running in GovCloud, uncomment the following // settings.govcloud = true; diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 6803911fef..912e7f4eda 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -10,11 +10,18 @@ module.exports = { recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], settings: { +<<<<<<< HEAD plain_text_parameters: { name: 'CloudFormation Plaintext Parameters', description: 'A comma-delimited list of parameter strings that indicate a sensitive value', regex: '[a-zA-Z0-9,]', default: 'secret,password,privatekey' +======= + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] +>>>>>>> 3da6672... Refactored code in plaintextParameters plugin and spec file } }, @@ -22,7 +29,12 @@ module.exports = { var results = []; var source = {}; var regions = helpers.regions(settings); +<<<<<<< HEAD var secretWords = this.settings.plain_text_parameters.default; +======= + secretWords = this.settings.plainTextParameters.secretWords; + +>>>>>>> 3da6672... Refactored code in plaintextParameters plugin and spec file async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, @@ -48,13 +60,15 @@ module.exports = { if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'Template does not contain any parameters', region, resource); - continue; + 'The template does not contain any potentially-sensitive parameters', region, resource); + return rcb(); } stack.Parameters.forEach(function(parameter){ - if(parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { - foundStrings.push(parameter.ParameterKey); + if(!parameterFound && secretWords.includes(parameter.ParameterKey.toLowerCase())) { + parameterFound = true; + helpers.addResult(results, 1, + 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); } }); diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index cdf14fb564..d7ac6fed08 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -115,7 +115,7 @@ const createNullCache = () => { }; }; -<<<<<<< HEAD + describe('plaintextParameters', function () { describe('run', function () { it('should FAIL if template contains one of secret words', function (done) { @@ -123,20 +123,18 @@ describe('plaintextParameters', function () { plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); -======= -describe('plainTextParameters', function () { - describe('run', function () { - it('should FAIL if Stack parameters contain one of secret words ["password" , "privatekey", "secret"]', function (done) { + }); + }); + + it('should WARN if template contains one of secret words ["password" , "privatekey", "secret"]', function (done) { const cache = createCache([describeStacks[0]]); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(1); ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation done(); }); }); -<<<<<<< HEAD it('should PASS if template does not contain any of secret words', function (done) { const cache = createCache([describeStacks[1]]); plaintextParameters.run(cache, {}, (err, results) => { @@ -149,11 +147,12 @@ describe('plainTextParameters', function () { it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { const cache = createCache([describeStacks[2]]); plaintextParameters.run(cache, {}, (err, results) => { -======= it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { const cache = createCache([describeStacks[1]]); plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation + it('should PASS if template does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[1]]); + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -162,11 +161,8 @@ describe('plainTextParameters', function () { it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); -<<<<<<< HEAD + plaintextParameters.run(cache, {}, (err, results) => { -======= - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -175,11 +171,8 @@ describe('plainTextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); -<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { -======= - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -188,11 +181,8 @@ describe('plainTextParameters', function () { it('should not return any results if unable to fetch any stack description', function (done) { const cache = createNullCache(); -<<<<<<< HEAD + plaintextParameters.run(cache, {}, (err, results) => { -======= - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(0); done(); }); @@ -200,11 +190,7 @@ describe('plainTextParameters', function () { it('should UNKNOWN if error occurs while fetching stack description', function (done) { const cache = createErrorCache(); -<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { -======= - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(3); done(); From aab9f79d36b4ead3765e8f14871f9e7b54959990 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Fri, 14 Aug 2020 18:09:45 +0500 Subject: [PATCH 22/67] SPLOIT-113: Updated custom settings --- plugins/aws/cloudformation/plainTextParameters.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 912e7f4eda..487cac1ccc 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -10,18 +10,12 @@ module.exports = { recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], settings: { -<<<<<<< HEAD + plain_text_parameters: { name: 'CloudFormation Plaintext Parameters', description: 'A comma-delimited list of parameter strings that indicate a sensitive value', regex: '[a-zA-Z0-9,]', default: 'secret,password,privatekey' -======= - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] ->>>>>>> 3da6672... Refactored code in plaintextParameters plugin and spec file } }, @@ -29,12 +23,8 @@ module.exports = { var results = []; var source = {}; var regions = helpers.regions(settings); -<<<<<<< HEAD var secretWords = this.settings.plain_text_parameters.default; -======= - secretWords = this.settings.plainTextParameters.secretWords; ->>>>>>> 3da6672... Refactored code in plaintextParameters plugin and spec file async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, From 12d88c1f2b7f80c945494189d9df30615e60a929 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 21:24:30 +0500 Subject: [PATCH 23/67] Made PR requested changes --- plugins/aws/cloudformation/plainTextParameters.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 487cac1ccc..b41ada95bc 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -24,7 +24,6 @@ module.exports = { var source = {}; var regions = helpers.regions(settings); var secretWords = this.settings.plain_text_parameters.default; - async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, @@ -50,12 +49,12 @@ module.exports = { if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'The template does not contain any potentially-sensitive parameters', region, resource); + 'Template does not contain any potentially-sensitive parameters', region, resource); return rcb(); } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && secretWords.includes(parameter.ParameterKey.toLowerCase())) { + if((!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()))) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); From 7dd1a5b4c70e20e199b066877fef1a606e508b3d Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Sat, 15 Aug 2020 01:07:50 +0500 Subject: [PATCH 24/67] SPLOIT-113: Added regex to check if NoEcho is enabled --- plugins/aws/cloudformation/plainTextParameters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index b41ada95bc..3b1eeb2f8b 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -54,7 +54,7 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if((!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()))) { + if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match("^[\*]+$")) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); From c8a23c3104275291d6fccd34ce4007beb2bbd90a Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 04:13:40 +0500 Subject: [PATCH 25/67] Accommodated PR changes --- plugins/aws/cloudformation/plainTextParameters.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 3b1eeb2f8b..ee646df8dd 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -49,8 +49,8 @@ module.exports = { if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'Template does not contain any potentially-sensitive parameters', region, resource); - return rcb(); + 'Template does not contain any parameters', region, resource); + continue; } stack.Parameters.forEach(function(parameter){ From 92821dd47008f13bc10143dd8c3b64db692b1f55 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 06:09:46 +0500 Subject: [PATCH 26/67] Fixed eslint issues --- plugins/aws/cloudformation/plainTextParameters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index ee646df8dd..32db53c891 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -54,7 +54,7 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match("^[\*]+$")) { + if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); From e32accc18389dc0e73db708f5bf184738bdab68c Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:42:00 +0500 Subject: [PATCH 27/67] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 6f61d149a8..019fc78f81 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ var GoogleConfig; // accessKeyId: '', // secretAccessKey: '', // sessionToken: '', -// region: 'us-east-1' +// region: '' // }; // AzureConfig = { From 90094a2c0401ac04f24fd08c5c7309596ae77200 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:48:02 +0500 Subject: [PATCH 28/67] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 019fc78f81..6f61d149a8 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ var GoogleConfig; // accessKeyId: '', // secretAccessKey: '', // sessionToken: '', -// region: '' +// region: 'us-east-1' // }; // AzureConfig = { From c29ab07cfdc4dde85c3d6b5468f3c69738643286 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 20:15:26 +0500 Subject: [PATCH 29/67] Accomodated PR changes --- plugins/aws/cloudformation/plainTextParameters.js | 10 ++++++---- .../cloudformation/plainTextParameters.spec.js | 15 ++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 32db53c891..e98c754121 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -54,15 +54,17 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { - parameterFound = true; - helpers.addResult(results, 1, - 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); + if(parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { + foundStrings.push(parameter.ParameterKey); } }); if(foundStrings && foundStrings.length) { +<<<<<<< HEAD helpers.addResult(results, 2, +======= + helpers.addResult(results, 1, +>>>>>>> aac8ece... Accomodated PR changes 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); } else { diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index d7ac6fed08..7493e245b3 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -147,11 +147,14 @@ describe('plaintextParameters', function () { it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { const cache = createCache([describeStacks[2]]); plaintextParameters.run(cache, {}, (err, results) => { - it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { - const cache = createCache([describeStacks[1]]); - plainTextParameters.run(cache, settings, (err, results) => { - it('should PASS if template does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { - const cache = createCache([describeStacks[1]]); + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { + const cache = createCache([describeStacks[2]]); plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); @@ -161,7 +164,6 @@ describe('plaintextParameters', function () { it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); - plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); @@ -171,7 +173,6 @@ describe('plaintextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); - plaintextParameters.run(cache, {}, (err, results) => { plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); From 49f12025532e2a62511d4a7bf60af22af0060f9d Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 21:12:35 +0500 Subject: [PATCH 30/67] Updated status in result of failure --- plugins/aws/cloudformation/plainTextParameters.js | 4 ---- plugins/aws/cloudformation/plainTextParameters.spec.js | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index e98c754121..00289847cb 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -60,11 +60,7 @@ module.exports = { }); if(foundStrings && foundStrings.length) { -<<<<<<< HEAD helpers.addResult(results, 2, -======= - helpers.addResult(results, 1, ->>>>>>> aac8ece... Accomodated PR changes 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); } else { diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index 7493e245b3..c590d10ce9 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -130,7 +130,7 @@ describe('plaintextParameters', function () { const cache = createCache([describeStacks[0]]); plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); - expect(results[0].status).to.equal(1); + expect(results[0].status).to.equal(2); done(); }); }); From 357cd0b45590f5b8c80966660fbbc6ac55e29ff8 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Fri, 14 Aug 2020 05:55:55 +0500 Subject: [PATCH 31/67] SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation --- exports.js | 7 +++++ index.js | 16 ++++++++++ .../plainTextParameters.spec.js | 29 +++++++------------ 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/exports.js b/exports.js index 7139c7640e..c29e867d52 100644 --- a/exports.js +++ b/exports.js @@ -14,9 +14,13 @@ module.exports = { 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), +<<<<<<< HEAD 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), +======= + 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), @@ -32,7 +36,10 @@ module.exports = { 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), +<<<<<<< HEAD 'launchWizardSecurityGroups' : require(__dirname + '/plugins/aws/ec2/launchWizardSecurityGroups'), +======= +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), diff --git a/index.js b/index.js index 26e612ef56..993593d97f 100755 --- a/index.js +++ b/index.js @@ -96,6 +96,22 @@ try { console.error('ERROR: Config file could not be loaded. Please ensure you have copied the config_example.js file to config.js'); process.exit(1); } +<<<<<<< HEAD +======= +if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ + GoogleConfig = require(process.env.GOOGLE_APPLICATION_CREDENTIALS); + GoogleConfig.project = GoogleConfig.project_id; +} + +// Custom settings - place plugin-specific settings here +var settings = { + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] + } +}; +>>>>>>> a4ea92f... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation function loadHelperFile(path) { try { diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index 03e8abf7e9..b75a66ddb5 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -115,29 +115,20 @@ const createNullCache = () => { }; }; -describe('plaintextParameters', function () { +describe('plainTextParameters', function () { describe('run', function () { - it('should FAIL if template contains one of secret words', function (done) { + it('should FAIL if Stack parameters contain one of secret words ["password" , "privatekey", "secret"]', function (done) { const cache = createCache([describeStacks[0]]); - plaintextParameters.run(cache, {}, (err, results) => { + plainTextParameters.run(cache, settings, (err, results) => { expect(results.length).to.equal(1); - expect(results[0].status).to.equal(2); + expect(results[0].status).to.equal(1); done(); }); }); - it('should PASS if template does not contain any of secret words', function (done) { + it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { const cache = createCache([describeStacks[1]]); - plaintextParameters.run(cache, {}, (err, results) => { - expect(results.length).to.equal(1); - expect(results[0].status).to.equal(0); - done(); - }); - }); - - it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { - const cache = createCache([describeStacks[2]]); - plaintextParameters.run(cache, {}, (err, results) => { + plainTextParameters.run(cache, settings, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -146,7 +137,7 @@ describe('plaintextParameters', function () { it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); - plaintextParameters.run(cache, {}, (err, results) => { + plainTextParameters.run(cache, settings, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -155,7 +146,7 @@ describe('plaintextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); - plaintextParameters.run(cache, {}, (err, results) => { + plainTextParameters.run(cache, settings, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -164,7 +155,7 @@ describe('plaintextParameters', function () { it('should not return any results if unable to fetch any stack description', function (done) { const cache = createNullCache(); - plaintextParameters.run(cache, {}, (err, results) => { + plainTextParameters.run(cache, settings, (err, results) => { expect(results.length).to.equal(0); done(); }); @@ -172,7 +163,7 @@ describe('plaintextParameters', function () { it('should UNKNOWN if error occurs while fetching stack description', function (done) { const cache = createErrorCache(); - plaintextParameters.run(cache, {}, (err, results) => { + plainTextParameters.run(cache, settings, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(3); done(); From 77ca002dbdc1dcaac51452167b071eb1dd9178cf Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 15:30:57 +0500 Subject: [PATCH 32/67] Added plugin and spec file for launch wizard security groups --- exports.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/exports.js b/exports.js index c29e867d52..7139c7640e 100644 --- a/exports.js +++ b/exports.js @@ -14,13 +14,9 @@ module.exports = { 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), -<<<<<<< HEAD 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), -======= - 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), @@ -36,10 +32,7 @@ module.exports = { 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), -<<<<<<< HEAD 'launchWizardSecurityGroups' : require(__dirname + '/plugins/aws/ec2/launchWizardSecurityGroups'), -======= ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), From 73172b8eb8842afc4f6a69ba82aa763f9d8eacdf Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Thu, 13 Aug 2020 19:59:59 +0500 Subject: [PATCH 33/67] Added vpcEndpointAcceptance plugin and spec file --- plugins/aws/ec2/vpcEndpointAcceptance.spec.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js index 62053b7238..0946f5a682 100644 --- a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js +++ b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js @@ -112,6 +112,15 @@ describe('vpcEndpointAcceptance', function () { }); }); + it('should PASS if no VPC endpoint services are detected', function (done) { + const cache = createCache([]); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + it('should UNKNOWN if there was an error querying for VPC endpoint services', function (done) { const cache = createErrorCache(); vpcEndpointAcceptance.run(cache, {}, (err, results) => { From 7b448ff450d02aeda95714087905d9b060421bd1 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 16:50:46 +0500 Subject: [PATCH 34/67] Refactored code in plaintextParameters plugin and spec file --- .../aws/cloudformation/plainTextParameters.js | 22 +++++----- .../plainTextParameters.spec.js | 41 +++++++++++++++---- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index e03a98bd08..0b3e156b8a 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -10,11 +10,10 @@ module.exports = { recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], settings: { - plain_text_parameters: { - name: 'CloudFormation Plaintext Parameters', - description: 'A comma-delimited list of parameter strings that indicate a sensitive value', - regex: '[a-zA-Z0-9,]', - default: 'secret,password,privatekey' + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] } }, @@ -22,7 +21,8 @@ module.exports = { var results = []; var source = {}; var regions = helpers.regions(settings); - var secretWords = this.settings.plain_text_parameters.default; + secretWords = this.settings.plainTextParameters.secretWords; + async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, @@ -48,13 +48,15 @@ module.exports = { if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'Template does not contain any parameters', region, resource); - continue; + 'The template does not contain any potentially-sensitive parameters', region, resource); + return rcb(); } stack.Parameters.forEach(function(parameter){ - if(parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { - foundStrings.push(parameter.ParameterKey); + if(!parameterFound && secretWords.includes(parameter.ParameterKey.toLowerCase())) { + parameterFound = true; + helpers.addResult(results, 1, + 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); } }); diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index b75a66ddb5..d7ac6fed08 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -115,20 +115,44 @@ const createNullCache = () => { }; }; -describe('plainTextParameters', function () { + +describe('plaintextParameters', function () { describe('run', function () { - it('should FAIL if Stack parameters contain one of secret words ["password" , "privatekey", "secret"]', function (done) { + it('should FAIL if template contains one of secret words', function (done) { const cache = createCache([describeStacks[0]]); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + }); + }); + + it('should WARN if template contains one of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[0]]); + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(1); done(); }); }); + it('should PASS if template does not contain any of secret words', function (done) { + const cache = createCache([describeStacks[1]]); + plaintextParameters.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { + const cache = createCache([describeStacks[2]]); + plaintextParameters.run(cache, {}, (err, results) => { it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { const cache = createCache([describeStacks[1]]); plainTextParameters.run(cache, settings, (err, results) => { + it('should PASS if template does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[1]]); + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -137,7 +161,8 @@ describe('plainTextParameters', function () { it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); - plainTextParameters.run(cache, settings, (err, results) => { + + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -146,7 +171,8 @@ describe('plainTextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -155,7 +181,8 @@ describe('plainTextParameters', function () { it('should not return any results if unable to fetch any stack description', function (done) { const cache = createNullCache(); - plainTextParameters.run(cache, settings, (err, results) => { + + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(0); done(); }); @@ -163,7 +190,7 @@ describe('plainTextParameters', function () { it('should UNKNOWN if error occurs while fetching stack description', function (done) { const cache = createErrorCache(); - plainTextParameters.run(cache, settings, (err, results) => { + plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(3); done(); From 50d9d70715bd00ba3b8e3b76269f2d8e97ea19f4 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Fri, 14 Aug 2020 18:09:45 +0500 Subject: [PATCH 35/67] SPLOIT-113: Updated custom settings --- index.js | 3 --- plugins/aws/cloudformation/plainTextParameters.js | 12 +++++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 993593d97f..b9e7b029ab 100755 --- a/index.js +++ b/index.js @@ -96,8 +96,6 @@ try { console.error('ERROR: Config file could not be loaded. Please ensure you have copied the config_example.js file to config.js'); process.exit(1); } -<<<<<<< HEAD -======= if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ GoogleConfig = require(process.env.GOOGLE_APPLICATION_CREDENTIALS); GoogleConfig.project = GoogleConfig.project_id; @@ -111,7 +109,6 @@ var settings = { ] } }; ->>>>>>> a4ea92f... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation function loadHelperFile(path) { try { diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 0b3e156b8a..c9d9f83f33 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -10,10 +10,12 @@ module.exports = { recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], settings: { - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] + + plain_text_parameters: { + name: 'CloudFormation Plaintext Parameters', + description: 'A comma-delimited list of parameter strings that indicate a sensitive value', + regex: '[a-zA-Z0-9,]', + default: 'secret,password,privatekey' } }, @@ -21,7 +23,7 @@ module.exports = { var results = []; var source = {}; var regions = helpers.regions(settings); - secretWords = this.settings.plainTextParameters.secretWords; + var secretWords = this.settings.plain_text_parameters.default; async.each(regions.cloudformation, function(region, rcb){ From 46ff92cf64080381f122946d5ea4ef79df76f0ec Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 21:24:30 +0500 Subject: [PATCH 36/67] Made PR requested changes --- plugins/aws/cloudformation/plainTextParameters.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index c9d9f83f33..e396861897 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -24,7 +24,6 @@ module.exports = { var source = {}; var regions = helpers.regions(settings); var secretWords = this.settings.plain_text_parameters.default; - async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, @@ -50,12 +49,12 @@ module.exports = { if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'The template does not contain any potentially-sensitive parameters', region, resource); + 'Template does not contain any potentially-sensitive parameters', region, resource); return rcb(); } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && secretWords.includes(parameter.ParameterKey.toLowerCase())) { + if((!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()))) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); From ec1e5efe8b96f6cbf75cb6f73df79de25008cc97 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Sat, 15 Aug 2020 01:07:50 +0500 Subject: [PATCH 37/67] SPLOIT-113: Added regex to check if NoEcho is enabled --- plugins/aws/cloudformation/plainTextParameters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index e396861897..c51ac0dcf4 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -54,7 +54,7 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if((!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()))) { + if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match("^[\*]+$")) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); From e89dd5e81b5e61bbbce3be203de259815b53a023 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 04:13:40 +0500 Subject: [PATCH 38/67] Accommodated PR changes --- plugins/aws/cloudformation/plainTextParameters.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index c51ac0dcf4..19ac1eed53 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -49,8 +49,8 @@ module.exports = { if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'Template does not contain any potentially-sensitive parameters', region, resource); - return rcb(); + 'Template does not contain any parameters', region, resource); + continue; } stack.Parameters.forEach(function(parameter){ From 4d7ee30cc8604f2fdb0fe778ffcb3c35502cfa62 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 06:09:46 +0500 Subject: [PATCH 39/67] Fixed eslint issues --- plugins/aws/cloudformation/plainTextParameters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 19ac1eed53..5bda4d33b1 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -54,7 +54,7 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match("^[\*]+$")) { + if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); From f5c9bf0799a1bcd75b9c7648ceea7140a6498fcd Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:42:00 +0500 Subject: [PATCH 40/67] Update index.js --- index.js | 138 +++++++++++++++++++++++++++---------------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/index.js b/index.js index b9e7b029ab..0484fec705 100755 --- a/index.js +++ b/index.js @@ -1,74 +1,74 @@ #!/usr/bin/env node -const { ArgumentParser } = require('argparse'); -const engine = require('./engine'); - -console.log(` - _____ _ _ _____ _ _ _ - / ____| | | |/ ____| | | (_) | - | | | | ___ _ _ __| | (___ _ __ | | ___ _| |_ - | | | |/ _ \\| | | |/ _\` |\\___ \\| '_ \\| |/ _ \\| | __| - | |____| | (_) | |_| | (_| |____) | |_) | | (_) | | |_ - \\_____|_|\\___/ \\__,_|\\__,_|_____/| .__/|_|\\___/|_|\\__| - | | - |_| - - CloudSploit by Aqua Security, Ltd. - Cloud security auditing for AWS, Azure, GCP, Oracle, and GitHub -`); - -const parser = new ArgumentParser({}); - -parser.add_argument('--config', { - help: 'The path to a CloudSploit config file containing cloud credentials. See config_example.js' -}); - -parser.add_argument('--compliance', { - help: 'Compliance mode. Only return results applicable to the selected program.', - choices: ['hipaa', 'cis', 'cis1', 'cis2', 'pci'], - action: 'append' -}); -parser.add_argument('--plugin', { - help: 'A specific plugin to run. If none provided, all plugins will be run. Obtain from the exports.js file. E.g. acmValidation' -}); -parser.add_argument('--govcloud', { - help: 'AWS only. Enables GovCloud mode.', - action: 'store_true' -}); -parser.add_argument('--china', { - help: 'AWS only. Enables AWS China mode.', - action: 'store_true' -}); -parser.add_argument('--csv', { help: 'Output: CSV file' }); -parser.add_argument('--json', { help: 'Output: JSON file' }); -parser.add_argument('--junit', { help: 'Output: Junit file' }); -parser.add_argument('--console', { - help: 'Console output format. Default: table', - choices: ['none', 'text', 'table'], - default: 'table' -}); -parser.add_argument('--collection', { help: 'Output: full collection JSON as file' }); -parser.add_argument('--ignore-ok', { - help: 'Ignore passing (OK) results', - action: 'store_true' -}); -parser.add_argument('--exit-code', { - help: 'Exits with a non-zero status code if non-passing results are found', - action: 'store_true' -}); -parser.add_argument('--skip-paginate', { - help: 'AWS only. Skips pagination (for debugging).', - action: 'store_false' -}); -parser.add_argument('--suppress', { - help: 'Suppress results matching the provided Regex. Format: pluginId:region:resourceId', - action: 'append' -}); - -let settings = parser.parse_args(); -let cloudConfig = {}; - -settings.cloud = 'aws'; +var engine = require('./engine'); + +var AWSConfig; +var AzureConfig; +var GitHubConfig; +var OracleConfig; +var GoogleConfig; + +// OPTION 1: Configure service provider credentials through hard-coded config objects + +// AWSConfig = { +// accessKeyId: '', +// secretAccessKey: '', +// sessionToken: '', +// region: '' +// }; + +// AzureConfig = { +// ApplicationID: '', // A.K.A ClientID +// KeyValue: '', // Secret +// DirectoryID: '', // A.K.A TenantID or Domain +// SubscriptionID: '', +// location: 'East US' +// }; + +// GitHubConfig = { +// token: '', // GitHub app token +// url: 'https://api.github.com', // BaseURL if not using public GitHub +// organization: false, // Set to true if the login is an organization +// login: '' // The login id for the user or organization +// }; + +// Oracle Important Note: +// Please read Oracle API's key generation instructions: config/_oracle/keys/Readme.md +// You will want an API signing key to fill the keyFingerprint and privateKey params +// OracleConfig = { +// RESTversion: '/20160918', +// tenancyId: 'ocid1.tenancy.oc1..', +// compartmentId: 'ocid1.compartment.oc1..', +// userId: 'ocid1.user.oc1..', +// keyFingerprint: 'YOURKEYFINGERPRINT', +// keyValue: "-----BEGIN PRIVATE KEY-----\nYOUR-PRIVATE-KEY-GOES-HERE\n-----END PRIVATE KEY-----\n", +// region: 'us-ashburn-1', +// }; + +// GoogleConfig = { +// "type": "service_account", +// "project": "your-project-name", +// "client_email": "cloudsploit@your-project-name.iam.gserviceaccount.com", +// "private_key": "-----BEGIN PRIVATE KEY-----\nYOUR-PRIVATE-KEY-GOES-HERE\n-----END PRIVATE KEY-----\n", +// }; + +// OPTION 2: Import a service provider config file containing credentials + +// AWSConfig = require(__dirname + '/aws_credentials.json'); +// AzureConfig = require(__dirname + '/azure_credentials.json'); +// GitHubConfig = require(__dirname + '/github_credentials.json'); +// OracleConfig = require(__dirname + '/oracle_credentials.json'); +// GoogleConfig = require(__dirname + '/google_credentials.json'); + +// OPTION 3: ENV configuration with service provider env vars +if(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY){ + AWSConfig = { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + sessionToken: process.env.AWS_SESSION_TOKEN, + region: process.env.AWS_DEFAULT_REGION || 'us-east-1' + }; +} // Now execute the scans using the defined configuration information. if (!settings.config) { From 53e18b8d6f575caa387507c1dcc5e1fa59914c58 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:48:02 +0500 Subject: [PATCH 41/67] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 0484fec705..de6616b22a 100755 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ var GoogleConfig; // accessKeyId: '', // secretAccessKey: '', // sessionToken: '', -// region: '' +// region: 'us-east-1' // }; // AzureConfig = { From 6ec73bc80abccbaaa104aa932fc6e48d7ae6f436 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 20:15:26 +0500 Subject: [PATCH 42/67] Accomodated PR changes --- plugins/aws/cloudformation/plainTextParameters.js | 10 ++++++---- .../cloudformation/plainTextParameters.spec.js | 15 ++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 5bda4d33b1..94e7f92cff 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -54,15 +54,17 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { - parameterFound = true; - helpers.addResult(results, 1, - 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); + if(parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { + foundStrings.push(parameter.ParameterKey); } }); if(foundStrings && foundStrings.length) { +<<<<<<< HEAD helpers.addResult(results, 2, +======= + helpers.addResult(results, 1, +>>>>>>> aac8ece... Accomodated PR changes 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); } else { diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index d7ac6fed08..7493e245b3 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -147,11 +147,14 @@ describe('plaintextParameters', function () { it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { const cache = createCache([describeStacks[2]]); plaintextParameters.run(cache, {}, (err, results) => { - it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { - const cache = createCache([describeStacks[1]]); - plainTextParameters.run(cache, settings, (err, results) => { - it('should PASS if template does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { - const cache = createCache([describeStacks[1]]); + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { + const cache = createCache([describeStacks[2]]); plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); @@ -161,7 +164,6 @@ describe('plaintextParameters', function () { it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); - plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); @@ -171,7 +173,6 @@ describe('plaintextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); - plaintextParameters.run(cache, {}, (err, results) => { plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); From 2f55a118e1ad6692c2ea78209ec6852cb7782354 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 21:12:35 +0500 Subject: [PATCH 43/67] Updated status in result of failure --- plugins/aws/cloudformation/plainTextParameters.js | 4 ---- plugins/aws/cloudformation/plainTextParameters.spec.js | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 94e7f92cff..133fa51b6b 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -60,11 +60,7 @@ module.exports = { }); if(foundStrings && foundStrings.length) { -<<<<<<< HEAD helpers.addResult(results, 2, -======= - helpers.addResult(results, 1, ->>>>>>> aac8ece... Accomodated PR changes 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); } else { diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index 7493e245b3..c590d10ce9 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -130,7 +130,7 @@ describe('plaintextParameters', function () { const cache = createCache([describeStacks[0]]); plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); - expect(results[0].status).to.equal(1); + expect(results[0].status).to.equal(2); done(); }); }); From 0ba2fbf09b4518ed41903f7a68809b6a3179cf6b Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Thu, 13 Aug 2020 00:34:00 +0500 Subject: [PATCH 44/67] SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation --- exports.js | 3 - .../aws/cloudformation/plainTextParameters.js | 99 +++++++++---------- 2 files changed, 46 insertions(+), 56 deletions(-) diff --git a/exports.js b/exports.js index 7139c7640e..d2ab19673e 100644 --- a/exports.js +++ b/exports.js @@ -14,9 +14,7 @@ module.exports = { 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), - 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), - 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), @@ -32,7 +30,6 @@ module.exports = { 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), - 'launchWizardSecurityGroups' : require(__dirname + '/plugins/aws/ec2/launchWizardSecurityGroups'), 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 133fa51b6b..0b4863765c 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -1,4 +1,3 @@ -var async = require('async'); var helpers = require('../../../helpers/aws'); module.exports = { @@ -9,69 +8,63 @@ module.exports = { link: 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html', recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], - settings: { - - plain_text_parameters: { - name: 'CloudFormation Plaintext Parameters', - description: 'A comma-delimited list of parameter strings that indicate a sensitive value', - regex: '[a-zA-Z0-9,]', - default: 'secret,password,privatekey' - } + compliance: { + hipaa: 'HIPAA requires all data to be transmitted over secure channels. ' + + 'CloudFront HTTPS redirection should be used to ensure site visitors ' + + 'are always connecting over a secure channel.' }, + // settings : { secretWords : ["password", "privatekey", "secret"] }, run: function(cache, settings, callback) { + var results = []; var source = {}; - var regions = helpers.regions(settings); - var secretWords = this.settings.plain_text_parameters.default; - async.each(regions.cloudformation, function(region, rcb){ - var describeStacks = helpers.addSource(cache, source, - ['cloudformation', 'describeStacks', region]); - if (!describeStacks) return rcb(); + var region = helpers.defaultRegion(settings); - if (describeStacks.err || !describeStacks.data) { - helpers.addResult(results, 3, - 'Unable to describe stacks: ' + helpers.addError(describeStacks), region); - return rcb(); - } + var describeStacks = helpers.addSource(cache, source, + ['cloudformation', 'describeStacks', region]); - if (!describeStacks.data.length) { - helpers.addResult(results, 0, 'No CloudFormation stacks found', region); - return rcb(); - } - - for (var s in describeStacks.data){ - // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id - var stack = describeStacks.data[s]; - var resource = stack.StackId; - let foundStrings = []; + console.log(describeStacks); + console.log("results received"); + // if (!describeStacks) return callback(null, results, source); - if(!stack.Parameters || !stack.Parameters.length) { - helpers.addResult(results, 0, - 'Template does not contain any parameters', region, resource); - continue; - } + // if (describeStacks.err || !describeStacks.data) { + // helpers.addResult(results, 3, + // 'Unable to describe stacks: ' + helpers.addError(describeStacks)); + // return callback(null, results, source); + // } - stack.Parameters.forEach(function(parameter){ - if(parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { - foundStrings.push(parameter.ParameterKey); - } - }); + // if (!describeStacks.data.length) { + // helpers.addResult(results, 0, 'No stacks descriptions found'); + // return callback(null, results, source); + // } + // console.log(describeStacks.data); + // loop through stacks for every template retrieval + // describeStacks.data.forEach(function(Distribution){ + // var stackTemplate = helpers.addSource(cache, source, + // ['cloudformation', 'getTemplate', region]); + + // if (!describeStacks) return callback(null, results, source); + + // if (describeStacks.err || !describeStacks.data) { + // helpers.addResult(results, 3, + // 'Unable to describe stacks: ' + helpers.addError(describeStacks)); + // return callback(null, results, source); + // } - if(foundStrings && foundStrings.length) { - helpers.addResult(results, 2, - 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); - } - else { - helpers.addResult(results, 0, - 'Template does not contain any potentially-sensitive parameters', region, resource); - } - } + // if (Distribution.DefaultCacheBehavior.ViewerProtocolPolicy == 'redirect-to-https') { + // helpers.addResult(results, 0, 'CloudFront distribution ' + + // 'is configured to redirect non-HTTPS traffic to HTTPS', 'global', Distribution.ARN); + // } else if (Distribution.DefaultCacheBehavior.ViewerProtocolPolicy == 'https-only') { + // helpers.addResult(results, 0, 'The CloudFront ' + + // 'distribution is set to use HTTPS only.', 'global', Distribution.ARN); + // } else { + // helpers.addResult(results, 2, 'CloudFront distribution ' + + // 'is not configured to use HTTPS', 'global', Distribution.ARN); + // } + // }); - rcb(); - }, function(){ - callback(null, results, source); - }); + callback(null, results, source); } }; From e9415b917bd99069cbf1fb8c3a9423ae127fb51b Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Fri, 14 Aug 2020 05:55:55 +0500 Subject: [PATCH 45/67] SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation --- exports.js | 6 +- index.js | 15 +-- .../aws/cloudformation/plainTextParameters.js | 91 ++++++++-------- .../plainTextParameters.spec.js | 100 ++++++++++++++++++ 4 files changed, 150 insertions(+), 62 deletions(-) diff --git a/exports.js b/exports.js index d2ab19673e..fa901a2af7 100644 --- a/exports.js +++ b/exports.js @@ -5,7 +5,6 @@ module.exports = { 'acmValidation' : require(__dirname + '/plugins/aws/acm/acmValidation.js'), 'acmCertificateExpiry' : require(__dirname + '/plugins/aws/acm/acmCertificateExpiry.js'), 'asgMultiAz' : require(__dirname + '/plugins/aws/autoscaling/asgMultiAz.js'), - 'emptyASG' : require(__dirname + '/plugins/aws/autoscaling/emptyASG.js'), 'workgroupEncrypted' : require(__dirname + '/plugins/aws/athena/workgroupEncrypted.js'), 'workgroupEnforceConfiguration' : require(__dirname + '/plugins/aws/athena/workgroupEnforceConfiguration.js'), 'publicS3Origin' : require(__dirname + '/plugins/aws/cloudfront/publicS3Origin.js'), @@ -72,9 +71,8 @@ module.exports = { 'ebsSnapshotPrivate' : require(__dirname + '/plugins/aws/ec2/ebsSnapshotPrivate.js'), 'natMultiAz' : require(__dirname + '/plugins/aws/ec2/natMultiAz.js'), 'defaultVpcInUse' : require(__dirname + '/plugins/aws/ec2/defaultVpcInUse.js'), - 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), + 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), 'crossVpcPublicPrivate' : require(__dirname + '/plugins/aws/ec2/crossVpcPublicPrivate.js'), - 'vpcEndpointAcceptance' : require(__dirname + '/plugins/aws/ec2/vpcEndpointAcceptance'), 'ebsEncryptedSnapshots' : require(__dirname + '/plugins/aws/ec2/ebsEncryptedSnapshots.js'), 'ec2MetadataOptions' : require(__dirname + '/plugins/aws/ec2/ec2MetadataOptions.js'), @@ -114,7 +112,6 @@ module.exports = { 'iamUserAdmins' : require(__dirname + '/plugins/aws/iam/iamUserAdmins.js'), 'iamUserNameRegex' : require(__dirname + '/plugins/aws/iam/iamUserNameRegex.js'), 'iamRolePolicies' : require(__dirname + '/plugins/aws/iam/iamRolePolicies.js'), - 'iamRoleLastUsed' : require(__dirname + '/plugins/aws/iam/iamRoleLastUsed.js'), 'maxPasswordAge' : require(__dirname + '/plugins/aws/iam/maxPasswordAge.js'), 'minPasswordLength' : require(__dirname + '/plugins/aws/iam/minPasswordLength.js'), 'noUserIamPolicies' : require(__dirname + '/plugins/aws/iam/noUserIamPolicies.js'), @@ -125,7 +122,6 @@ module.exports = { 'passwordRequiresUppercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresUppercase.js'), 'passwordReusePrevention' : require(__dirname + '/plugins/aws/iam/passwordReusePrevention.js'), 'rootAccessKeys' : require(__dirname + '/plugins/aws/iam/rootAccessKeys.js'), - 'rootSigningCertificate' : require(__dirname + '/plugins/aws/iam/rootSigningCertificate.js'), 'rootAccountInUse' : require(__dirname + '/plugins/aws/iam/rootAccountInUse.js'), 'rootHardwareMfa' : require(__dirname + '/plugins/aws/iam/rootHardwareMfa.js'), 'rootMfaEnabled' : require(__dirname + '/plugins/aws/iam/rootMfaEnabled.js'), diff --git a/index.js b/index.js index de6616b22a..45aa3d7df9 100755 --- a/index.js +++ b/index.js @@ -110,16 +110,11 @@ var settings = { } }; -function loadHelperFile(path) { - try { - var contents = require(path); - } catch (e) { - console.error(`ERROR: The credential file could not be loaded ${path}`); - console.error(e); - process.exit(1); - } - return contents; -} +// If running in GovCloud, uncomment the following +// settings.govcloud = true; + +// If running in AWS China, uncomment the following +// settings.china = true; function checkRequiredKeys(obj, keys) { keys.forEach(function(key){ diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 0b4863765c..f57b6ec2b7 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -1,3 +1,4 @@ +var async = require('async'); var helpers = require('../../../helpers/aws'); module.exports = { @@ -8,63 +9,59 @@ module.exports = { link: 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html', recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], - compliance: { - hipaa: 'HIPAA requires all data to be transmitted over secure channels. ' + - 'CloudFront HTTPS redirection should be used to ensure site visitors ' + - 'are always connecting over a secure channel.' - }, - // settings : { secretWords : ["password", "privatekey", "secret"] }, run: function(cache, settings, callback) { - var results = []; var source = {}; + var regions = helpers.regions(settings); + secretWords = settings.plainTextParameters.secretWords; - var region = helpers.defaultRegion(settings); + async.each(regions.cloudformation, function(region, rcb){ - var describeStacks = helpers.addSource(cache, source, - ['cloudformation', 'describeStacks', region]); + var describeStacks = helpers.addSource(cache, source, + ['cloudformation', 'describeStacks', region]); + + if (!describeStacks) return rcb(); - console.log(describeStacks); - console.log("results received"); - // if (!describeStacks) return callback(null, results, source); + if (describeStacks.err || !describeStacks.data) { + helpers.addResult(results, 3, + 'Unable to describe stacks: ' + helpers.addError(describeStacks), region); + return rcb(); + } - // if (describeStacks.err || !describeStacks.data) { - // helpers.addResult(results, 3, - // 'Unable to describe stacks: ' + helpers.addError(describeStacks)); - // return callback(null, results, source); - // } + if (!describeStacks.data.length) { + helpers.addResult(results, 0, 'No stack description found', region); + return rcb(); + } + + var parameterFound; + describeStacks.data.forEach(function(stack){ + parameterFound = false; - // if (!describeStacks.data.length) { - // helpers.addResult(results, 0, 'No stacks descriptions found'); - // return callback(null, results, source); - // } - // console.log(describeStacks.data); - // loop through stacks for every template retrieval - // describeStacks.data.forEach(function(Distribution){ - // var stackTemplate = helpers.addSource(cache, source, - // ['cloudformation', 'getTemplate', region]); - - // if (!describeStacks) return callback(null, results, source); - - // if (describeStacks.err || !describeStacks.data) { - // helpers.addResult(results, 3, - // 'Unable to describe stacks: ' + helpers.addError(describeStacks)); - // return callback(null, results, source); - // } + if(!stack.Parameters.length) { + helpers.addResult(results, 0, + 'The template did not contain any potentially-sensitive parameters', region); + return; + } - // if (Distribution.DefaultCacheBehavior.ViewerProtocolPolicy == 'redirect-to-https') { - // helpers.addResult(results, 0, 'CloudFront distribution ' + - // 'is configured to redirect non-HTTPS traffic to HTTPS', 'global', Distribution.ARN); - // } else if (Distribution.DefaultCacheBehavior.ViewerProtocolPolicy == 'https-only') { - // helpers.addResult(results, 0, 'The CloudFront ' + - // 'distribution is set to use HTTPS only.', 'global', Distribution.ARN); - // } else { - // helpers.addResult(results, 2, 'CloudFront distribution ' + - // 'is not configured to use HTTPS', 'global', Distribution.ARN); - // } - // }); + stack.Parameters.forEach(function(parameter){ + if(secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameterFound) { + parameterFound = true; + helpers.addResult(results, 1, + 'The template contained one of the following potentially-sensitive parameters: secret, key, password', region); + return; + } + }); + + if(!parameterFound) { + helpers.addResult(results, 0, + 'The template did not contain any potentially-sensitive parameters', region); + } - callback(null, results, source); + }); + rcb(); + }, function(){ + callback(null, results, source); + }); } }; diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index c590d10ce9..238ff315a9 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -1,4 +1,5 @@ var expect = require('chai').expect; +<<<<<<< HEAD const plaintextParameters = require('./plainTextParameters'); const describeStacks = [ @@ -77,6 +78,73 @@ const describeStacks = [ Tags: [], DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } } +======= +const plainTextParameters = require('./plainTextParameters'); +const settings = { + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] + } +}; +const describeStacks = [ + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [ + { + ParameterKey: 'Secret', + ParameterValue: 'bucketwithsecretparameter1' + }, + { + ParameterKey: 'Password', + ParameterValue: 'bucketwithsecretparameter1' + } + ], + CreationTime: '2020-08-13T13:34:52.435Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + }, + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [ + { + ParameterKey: 'S3BucketName', + ParameterValue: 'testbucketplaintext1' + } + ], + CreationTime: '2020-08-12T09:42:04.803Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + }, + { + StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', + StackName: 'TestStack', + Parameters: [], + CreationTime: '2020-08-12T09:42:04.803Z', + RollbackConfiguration: { RollbackTriggers: [] }, + StackStatus: 'CREATE_COMPLETE', + DisableRollback: false, + NotificationARNs: [], + Capabilities: [], + Outputs: [], + Tags: [], + DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } + } +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation ] const createCache = (stacks) => { @@ -115,6 +183,7 @@ const createNullCache = () => { }; }; +<<<<<<< HEAD describe('plaintextParameters', function () { describe('run', function () { @@ -131,10 +200,20 @@ describe('plaintextParameters', function () { plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); +======= +describe('plainTextParameters', function () { + describe('run', function () { + it('should FAIL if Stack parameters contain one of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[0]]); + plainTextParameters.run(cache, settings, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(1); +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation done(); }); }); +<<<<<<< HEAD it('should PASS if template does not contain any of secret words', function (done) { const cache = createCache([describeStacks[1]]); plaintextParameters.run(cache, {}, (err, results) => { @@ -156,6 +235,11 @@ describe('plaintextParameters', function () { it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { const cache = createCache([describeStacks[2]]); plaintextParameters.run(cache, {}, (err, results) => { +======= + it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { + const cache = createCache([describeStacks[1]]); + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -164,7 +248,11 @@ describe('plaintextParameters', function () { it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); +<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { +======= + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -173,7 +261,11 @@ describe('plaintextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); +<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { +======= + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -182,8 +274,12 @@ describe('plaintextParameters', function () { it('should not return any results if unable to fetch any stack description', function (done) { const cache = createNullCache(); +<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { +======= + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(0); done(); }); @@ -191,7 +287,11 @@ describe('plaintextParameters', function () { it('should UNKNOWN if error occurs while fetching stack description', function (done) { const cache = createErrorCache(); +<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { +======= + plainTextParameters.run(cache, settings, (err, results) => { +>>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(3); done(); From 882077517afe5da597b13ec40e4d705ae7613872 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 15:30:57 +0500 Subject: [PATCH 46/67] Added plugin and spec file for launch wizard security groups --- exports.js | 4 +++- plugins/aws/ec2/launchWizardSecurityGroups.js | 15 ++++----------- plugins/aws/ec2/vpcEndpointAcceptance.spec.js | 9 --------- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/exports.js b/exports.js index fa901a2af7..56084148d3 100644 --- a/exports.js +++ b/exports.js @@ -29,6 +29,7 @@ module.exports = { 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), + 'launchWizardSecurityGroups' : require(__dirname + '/plugins/aws/ec2/launchWizardSecurityGroups'), 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), @@ -71,8 +72,9 @@ module.exports = { 'ebsSnapshotPrivate' : require(__dirname + '/plugins/aws/ec2/ebsSnapshotPrivate.js'), 'natMultiAz' : require(__dirname + '/plugins/aws/ec2/natMultiAz.js'), 'defaultVpcInUse' : require(__dirname + '/plugins/aws/ec2/defaultVpcInUse.js'), - 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), + 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), 'crossVpcPublicPrivate' : require(__dirname + '/plugins/aws/ec2/crossVpcPublicPrivate.js'), + 'vpcEndpointAcceptance' : require(__dirname + '/plugins/aws/ec2/vpcEndpointAcceptance'), 'ebsEncryptedSnapshots' : require(__dirname + '/plugins/aws/ec2/ebsEncryptedSnapshots.js'), 'ec2MetadataOptions' : require(__dirname + '/plugins/aws/ec2/ec2MetadataOptions.js'), diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js index 5c73babd28..252cabd11c 100644 --- a/plugins/aws/ec2/launchWizardSecurityGroups.js +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -28,25 +28,18 @@ module.exports = { } if (!describeSecurityGroups.data.length) { - helpers.addResult(results, 0, 'No security groups found', region); + helpers.addResult(results, 0, 'No security groups present', region); return rcb(); } for (var s in describeSecurityGroups.data) { var sg = describeSecurityGroups.data[s]; - var resource = 'arn:aws:ec2:' + region + ':' + sg.OwnerId + ':security-group/' + sg.GroupId; + var resource = sg.GroupId; - if(!sg.GroupName) { - helpers.addResult(results, 2, - 'Unable to get group name of security group', - region, resource); - continue; - } - if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { helpers.addResult(results, 2, - 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', - region, resource); + 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', + region, resource); } else { helpers.addResult(results, 0, 'Security Group ' + sg.GroupName + ' was not launched using EC2 launch wizard', diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js index 0946f5a682..62053b7238 100644 --- a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js +++ b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js @@ -112,15 +112,6 @@ describe('vpcEndpointAcceptance', function () { }); }); - it('should PASS if no VPC endpoint services are detected', function (done) { - const cache = createCache([]); - vpcEndpointAcceptance.run(cache, {}, (err, results) => { - expect(results.length).to.equal(1); - expect(results[0].status).to.equal(0); - done(); - }); - }); - it('should UNKNOWN if there was an error querying for VPC endpoint services', function (done) { const cache = createErrorCache(); vpcEndpointAcceptance.run(cache, {}, (err, results) => { From 8e6b23b5ad41c0a70bfabff1276416718c9039d1 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Thu, 13 Aug 2020 19:59:59 +0500 Subject: [PATCH 47/67] Added vpcEndpointAcceptance plugin and spec file --- plugins/aws/ec2/vpcEndpointAcceptance.spec.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js index 62053b7238..0946f5a682 100644 --- a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js +++ b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js @@ -112,6 +112,15 @@ describe('vpcEndpointAcceptance', function () { }); }); + it('should PASS if no VPC endpoint services are detected', function (done) { + const cache = createCache([]); + vpcEndpointAcceptance.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + it('should UNKNOWN if there was an error querying for VPC endpoint services', function (done) { const cache = createErrorCache(); vpcEndpointAcceptance.run(cache, {}, (err, results) => { From 82d840671935c1139fabb28f8f786918e4b02a13 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 16:50:46 +0500 Subject: [PATCH 48/67] Refactored code in plaintextParameters plugin and spec file --- exports.js | 4 +- index.js | 8 +- .../aws/cloudformation/plainTextParameters.js | 28 +++-- .../plainTextParameters.spec.js | 119 ------------------ 4 files changed, 23 insertions(+), 136 deletions(-) diff --git a/exports.js b/exports.js index 56084148d3..ee2b81f9ee 100644 --- a/exports.js +++ b/exports.js @@ -13,7 +13,9 @@ module.exports = { 'cloudfrontHttpsOnly' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontHttpsOnly.js'), 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), - 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), + + 'plaintextParameters' : require(__dirname + '/plugins/aws/cloudformation/plaintextParameters.js'), + 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), 'cloudtrailEnabled' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailEnabled.js'), diff --git a/index.js b/index.js index 45aa3d7df9..53b6b4fb75 100755 --- a/index.js +++ b/index.js @@ -102,13 +102,7 @@ if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ } // Custom settings - place plugin-specific settings here -var settings = { - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] - } -}; +var settings = {}; // If running in GovCloud, uncomment the following // settings.govcloud = true; diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index f57b6ec2b7..8e538c23d4 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -9,12 +9,19 @@ module.exports = { link: 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html', recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], + settings: { + plainTextParameters: { + secretWords: [ + 'secret', 'password', 'privatekey' + ] + } + }, run: function(cache, settings, callback) { var results = []; var source = {}; var regions = helpers.regions(settings); - secretWords = settings.plainTextParameters.secretWords; + secretWords = this.settings.plainTextParameters.secretWords; async.each(regions.cloudformation, function(region, rcb){ @@ -35,30 +42,33 @@ module.exports = { } var parameterFound; - describeStacks.data.forEach(function(stack){ + for (var s in describeStacks.data){ + // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id + var stack = describeStacks.data[s]; + var resource = stack.StackId; parameterFound = false; if(!stack.Parameters.length) { helpers.addResult(results, 0, - 'The template did not contain any potentially-sensitive parameters', region); - return; + 'The template does not contain any potentially-sensitive parameters', region, resource); + return rcb(); } stack.Parameters.forEach(function(parameter){ - if(secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameterFound) { + if(!parameterFound && secretWords.includes(parameter.ParameterKey.toLowerCase())) { parameterFound = true; helpers.addResult(results, 1, - 'The template contained one of the following potentially-sensitive parameters: secret, key, password', region); - return; + 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); } }); if(!parameterFound) { helpers.addResult(results, 0, - 'The template did not contain any potentially-sensitive parameters', region); + 'Template does not contain any potentially-sensitive parameters', region, resource); } - }); + } + rcb(); }, function(){ callback(null, results, source); diff --git a/plugins/aws/cloudformation/plainTextParameters.spec.js b/plugins/aws/cloudformation/plainTextParameters.spec.js index 238ff315a9..03e8abf7e9 100644 --- a/plugins/aws/cloudformation/plainTextParameters.spec.js +++ b/plugins/aws/cloudformation/plainTextParameters.spec.js @@ -1,5 +1,4 @@ var expect = require('chai').expect; -<<<<<<< HEAD const plaintextParameters = require('./plainTextParameters'); const describeStacks = [ @@ -78,73 +77,6 @@ const describeStacks = [ Tags: [], DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } } -======= -const plainTextParameters = require('./plainTextParameters'); -const settings = { - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] - } -}; -const describeStacks = [ - { - StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', - StackName: 'TestStack', - Parameters: [ - { - ParameterKey: 'Secret', - ParameterValue: 'bucketwithsecretparameter1' - }, - { - ParameterKey: 'Password', - ParameterValue: 'bucketwithsecretparameter1' - } - ], - CreationTime: '2020-08-13T13:34:52.435Z', - RollbackConfiguration: { RollbackTriggers: [] }, - StackStatus: 'CREATE_COMPLETE', - DisableRollback: false, - NotificationARNs: [], - Capabilities: [], - Outputs: [], - Tags: [], - DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } - }, - { - StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', - StackName: 'TestStack', - Parameters: [ - { - ParameterKey: 'S3BucketName', - ParameterValue: 'testbucketplaintext1' - } - ], - CreationTime: '2020-08-12T09:42:04.803Z', - RollbackConfiguration: { RollbackTriggers: [] }, - StackStatus: 'CREATE_COMPLETE', - DisableRollback: false, - NotificationARNs: [], - Capabilities: [], - Outputs: [], - Tags: [], - DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } - }, - { - StackId: 'arn:aws:cloudformation:us-east-1:55005500:stack/TestStack/1493b310-dc80-11ea-b8ab-1214c28caebf', - StackName: 'TestStack', - Parameters: [], - CreationTime: '2020-08-12T09:42:04.803Z', - RollbackConfiguration: { RollbackTriggers: [] }, - StackStatus: 'CREATE_COMPLETE', - DisableRollback: false, - NotificationARNs: [], - Capabilities: [], - Outputs: [], - Tags: [], - DriftInformation: { StackDriftStatus: 'NOT_CHECKED' } - } ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation ] const createCache = (stacks) => { @@ -183,8 +115,6 @@ const createNullCache = () => { }; }; -<<<<<<< HEAD - describe('plaintextParameters', function () { describe('run', function () { it('should FAIL if template contains one of secret words', function (done) { @@ -192,28 +122,10 @@ describe('plaintextParameters', function () { plaintextParameters.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); - }); - }); - - it('should WARN if template contains one of secret words ["password" , "privatekey", "secret"]', function (done) { - const cache = createCache([describeStacks[0]]); - plaintextParameters.run(cache, {}, (err, results) => { - expect(results.length).to.equal(1); - expect(results[0].status).to.equal(2); -======= -describe('plainTextParameters', function () { - describe('run', function () { - it('should FAIL if Stack parameters contain one of secret words ["password" , "privatekey", "secret"]', function (done) { - const cache = createCache([describeStacks[0]]); - plainTextParameters.run(cache, settings, (err, results) => { - expect(results.length).to.equal(1); - expect(results[0].status).to.equal(1); ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation done(); }); }); -<<<<<<< HEAD it('should PASS if template does not contain any of secret words', function (done) { const cache = createCache([describeStacks[1]]); plaintextParameters.run(cache, {}, (err, results) => { @@ -232,27 +144,9 @@ describe('plainTextParameters', function () { }); }); - it('should PASS if template contains any of secret words but with NoEcho enabled', function (done) { - const cache = createCache([describeStacks[2]]); - plaintextParameters.run(cache, {}, (err, results) => { -======= - it('should PASS if Stack parameters does not contain any of secret words ["password" , "privatekey", "secret"]', function (done) { - const cache = createCache([describeStacks[1]]); - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation - expect(results.length).to.equal(1); - expect(results[0].status).to.equal(0); - done(); - }); - }); - it('should PASS if unable to describe stacks', function (done) { const cache = createCache([]); -<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { -======= - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -261,11 +155,7 @@ describe('plainTextParameters', function () { it('should PASS if there is no parameter in the stack', function (done) { const cache = createCache([describeStacks[2]]); -<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { -======= - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); done(); @@ -274,12 +164,7 @@ describe('plainTextParameters', function () { it('should not return any results if unable to fetch any stack description', function (done) { const cache = createNullCache(); -<<<<<<< HEAD - plaintextParameters.run(cache, {}, (err, results) => { -======= - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(0); done(); }); @@ -287,11 +172,7 @@ describe('plainTextParameters', function () { it('should UNKNOWN if error occurs while fetching stack description', function (done) { const cache = createErrorCache(); -<<<<<<< HEAD plaintextParameters.run(cache, {}, (err, results) => { -======= - plainTextParameters.run(cache, settings, (err, results) => { ->>>>>>> 306d721... SPLOIT-113: Added Plain Text Parameters plugin for CloudFormation expect(results.length).to.equal(1); expect(results[0].status).to.equal(3); done(); From b022a527f8eb642304b4e38cdd5c082f060e448b Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Fri, 14 Aug 2020 18:09:45 +0500 Subject: [PATCH 49/67] SPLOIT-113: Updated custom settings --- plugins/aws/cloudformation/plainTextParameters.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 8e538c23d4..7f1cd285ae 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -10,10 +10,11 @@ module.exports = { recommended_action: 'Update the sensitive parameters to use the NoEcho property.', apis: ['CloudFormation:describeStacks'], settings: { - plainTextParameters: { - secretWords: [ - 'secret', 'password', 'privatekey' - ] + plain_text_parameters: { + name: "CloudFormation Plaintext Parameters", + description: "A comma-delimited list of parameter strings that indicate a sensitive value", + regex: "[a-zA-Z0-9,]", + default: "secret,password,privatekey" } }, @@ -21,8 +22,7 @@ module.exports = { var results = []; var source = {}; var regions = helpers.regions(settings); - secretWords = this.settings.plainTextParameters.secretWords; - + secretWords = this.settings.plain_text_parameters.default; async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, From d3ee38043531013576170b657eb1fe429231cec8 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Aug 2020 21:24:30 +0500 Subject: [PATCH 50/67] Made PR requested changes --- plugins/aws/cloudformation/plainTextParameters.js | 8 ++++---- plugins/aws/ec2/launchWizardSecurityGroups.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 7f1cd285ae..9b91b0d2e6 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -22,7 +22,7 @@ module.exports = { var results = []; var source = {}; var regions = helpers.regions(settings); - secretWords = this.settings.plain_text_parameters.default; + var secretWords = this.settings.plain_text_parameters.default; async.each(regions.cloudformation, function(region, rcb){ var describeStacks = helpers.addSource(cache, source, @@ -48,14 +48,14 @@ module.exports = { var resource = stack.StackId; parameterFound = false; - if(!stack.Parameters.length) { + if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'The template does not contain any potentially-sensitive parameters', region, resource); + 'Template does not contain any potentially-sensitive parameters', region, resource); return rcb(); } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && secretWords.includes(parameter.ParameterKey.toLowerCase())) { + if((!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()))) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js index 252cabd11c..0e028778a7 100644 --- a/plugins/aws/ec2/launchWizardSecurityGroups.js +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -36,7 +36,7 @@ module.exports = { var sg = describeSecurityGroups.data[s]; var resource = sg.GroupId; - if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { + if (sg.GroupName && sg.GroupName.toLowerCase().startsWith('launch-wizard')) { helpers.addResult(results, 2, 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', region, resource); From 560d273d4265e8eddd90de4da7768b174326281c Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Sat, 15 Aug 2020 01:07:50 +0500 Subject: [PATCH 51/67] SPLOIT-113: Added regex to check if NoEcho is enabled --- plugins/aws/cloudformation/plainTextParameters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 9b91b0d2e6..e2890bc58e 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -55,7 +55,7 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if((!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()))) { + if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match("^[\*]+$")) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); From 9195d32e992bf53a2b81447e2290fa71e9f8ae58 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 04:13:40 +0500 Subject: [PATCH 52/67] Accommodated PR changes --- exports.js | 2 +- plugins/aws/cloudformation/plainTextParameters.js | 6 +++--- plugins/aws/ec2/launchWizardSecurityGroups.js | 11 +++++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/exports.js b/exports.js index ee2b81f9ee..a61fddd2cc 100644 --- a/exports.js +++ b/exports.js @@ -14,7 +14,7 @@ module.exports = { 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), - 'plaintextParameters' : require(__dirname + '/plugins/aws/cloudformation/plaintextParameters.js'), + 'plaintextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index e2890bc58e..f5ebb6898b 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -46,12 +46,12 @@ module.exports = { // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id var stack = describeStacks.data[s]; var resource = stack.StackId; - parameterFound = false; + let parameterFound = false; if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, - 'Template does not contain any potentially-sensitive parameters', region, resource); - return rcb(); + 'Template does not contain any parameters', region, resource); + continue; } stack.Parameters.forEach(function(parameter){ diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js index 0e028778a7..48f040b7ed 100644 --- a/plugins/aws/ec2/launchWizardSecurityGroups.js +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -28,7 +28,7 @@ module.exports = { } if (!describeSecurityGroups.data.length) { - helpers.addResult(results, 0, 'No security groups present', region); + helpers.addResult(results, 0, 'No security groups found', region); return rcb(); } @@ -36,7 +36,14 @@ module.exports = { var sg = describeSecurityGroups.data[s]; var resource = sg.GroupId; - if (sg.GroupName && sg.GroupName.toLowerCase().startsWith('launch-wizard')) { + if(!sg.GroupName) { + helpers.addResult(results, 2, + 'Unable to get group name of security group', + region, resource); + continue; + } + + if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { helpers.addResult(results, 2, 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', region, resource); From 0287cc54eb44d1b44e77f7750837cbe8878773b5 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 06:09:46 +0500 Subject: [PATCH 53/67] Fixed eslint issues --- plugins/aws/cloudformation/plainTextParameters.js | 15 +++++++-------- plugins/aws/ec2/launchWizardSecurityGroups.js | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index f5ebb6898b..52be0d6ea8 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -11,10 +11,10 @@ module.exports = { apis: ['CloudFormation:describeStacks'], settings: { plain_text_parameters: { - name: "CloudFormation Plaintext Parameters", - description: "A comma-delimited list of parameter strings that indicate a sensitive value", - regex: "[a-zA-Z0-9,]", - default: "secret,password,privatekey" + name: 'CloudFormation Plaintext Parameters', + description: 'A comma-delimited list of parameter strings that indicate a sensitive value', + regex: '[a-zA-Z0-9,]', + default: 'secret,password,privatekey' } }, @@ -33,7 +33,7 @@ module.exports = { if (describeStacks.err || !describeStacks.data) { helpers.addResult(results, 3, 'Unable to describe stacks: ' + helpers.addError(describeStacks), region); - return rcb(); + return rcb(); } if (!describeStacks.data.length) { @@ -41,7 +41,6 @@ module.exports = { return rcb(); } - var parameterFound; for (var s in describeStacks.data){ // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id var stack = describeStacks.data[s]; @@ -55,7 +54,7 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match("^[\*]+$")) { + if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { parameterFound = true; helpers.addResult(results, 1, 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); @@ -64,7 +63,7 @@ module.exports = { if(!parameterFound) { helpers.addResult(results, 0, - 'Template does not contain any potentially-sensitive parameters', region, resource); + 'Template does not contain any potentially-sensitive parameters', region, resource); } } diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js index 48f040b7ed..caa173be82 100644 --- a/plugins/aws/ec2/launchWizardSecurityGroups.js +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -45,8 +45,8 @@ module.exports = { if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { helpers.addResult(results, 2, - 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', - region, resource); + 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', + region, resource); } else { helpers.addResult(results, 0, 'Security Group ' + sg.GroupName + ' was not launched using EC2 launch wizard', From 1315ccdc619767cbdd12284ecc534a185fa3994a Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:38:01 +0500 Subject: [PATCH 54/67] Update exports.js --- exports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exports.js b/exports.js index a61fddd2cc..5a338cfa5e 100644 --- a/exports.js +++ b/exports.js @@ -14,7 +14,7 @@ module.exports = { 'cloudfrontLoggingEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontLoggingEnabled.js'), 'cloudfrontWafEnabled' : require(__dirname + '/plugins/aws/cloudfront/cloudfrontWafEnabled.js'), - 'plaintextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), + 'plainTextParameters' : require(__dirname + '/plugins/aws/cloudformation/plainTextParameters.js'), 'cloudtrailBucketAccessLogging' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js'), 'cloudtrailBucketDelete' : require(__dirname + '/plugins/aws/cloudtrail/cloudtrailBucketDelete.js'), From 229461ce784cc135fe4d9ebacea68cacd1523551 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:42:00 +0500 Subject: [PATCH 55/67] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 53b6b4fb75..94b3d7af71 100755 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ var GoogleConfig; // accessKeyId: '', // secretAccessKey: '', // sessionToken: '', -// region: 'us-east-1' +// region: '' // }; // AzureConfig = { From f5a3b8b09786882bc807deb980e9b4e7ca9b5451 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 14:48:02 +0500 Subject: [PATCH 56/67] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 94b3d7af71..53b6b4fb75 100755 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ var GoogleConfig; // accessKeyId: '', // secretAccessKey: '', // sessionToken: '', -// region: '' +// region: 'us-east-1' // }; // AzureConfig = { From c574f76cb8f427d08ad5f4fcf258d16a16bf0ddb Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Tue, 18 Aug 2020 20:15:26 +0500 Subject: [PATCH 57/67] Accomodated PR changes --- .../aws/cloudformation/plainTextParameters.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 52be0d6ea8..d05776bf37 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -27,7 +27,6 @@ module.exports = { var describeStacks = helpers.addSource(cache, source, ['cloudformation', 'describeStacks', region]); - if (!describeStacks) return rcb(); if (describeStacks.err || !describeStacks.data) { @@ -45,7 +44,7 @@ module.exports = { // arn:aws:cloudformation:region:account-id:stack/stack-name/stack-id var stack = describeStacks.data[s]; var resource = stack.StackId; - let parameterFound = false; + let foundStrings = []; if(!stack.Parameters || !stack.Parameters.length) { helpers.addResult(results, 0, @@ -54,18 +53,19 @@ module.exports = { } stack.Parameters.forEach(function(parameter){ - if(!parameterFound && parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { - parameterFound = true; - helpers.addResult(results, 1, - 'Template contains one of the following potentially-sensitive parameters: secret, key, password', region, resource); + if(parameter.ParameterKey && secretWords.includes(parameter.ParameterKey.toLowerCase()) && !parameter.ParameterValue.match('^[*]+$')) { + foundStrings.push(parameter.ParameterKey); } }); - - if(!parameterFound) { + + if(foundStrings && foundStrings.length) { + helpers.addResult(results, 1, + 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); + } + else { helpers.addResult(results, 0, 'Template does not contain any potentially-sensitive parameters', region, resource); } - } rcb(); From 1a4b495fa18e3447c906128d6c1fb3575e5a775e Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 18 Aug 2020 21:12:35 +0500 Subject: [PATCH 58/67] Updated status in result of failure --- plugins/aws/cloudformation/plainTextParameters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index d05776bf37..3bd118572e 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -59,7 +59,7 @@ module.exports = { }); if(foundStrings && foundStrings.length) { - helpers.addResult(results, 1, + helpers.addResult(results, 2, 'Template contains the following potentially-sensitive parameters: ' + foundStrings, region, resource); } else { From 156d027c478cec36931628878e885b85dc0891a0 Mon Sep 17 00:00:00 2001 From: AkhtarAmir <31914988+AkhtarAmir@users.noreply.github.com> Date: Sat, 29 Aug 2020 02:44:42 +0500 Subject: [PATCH 59/67] Removed unnecesary rebase changes --- exports.js | 3 + index.js | 160 +++++++++--------- .../aws/cloudformation/plainTextParameters.js | 2 +- plugins/aws/ec2/launchWizardSecurityGroups.js | 2 +- plugins/aws/ec2/vpcEndpointAcceptance.spec.js | 9 - 5 files changed, 84 insertions(+), 92 deletions(-) diff --git a/exports.js b/exports.js index 5a338cfa5e..7139c7640e 100644 --- a/exports.js +++ b/exports.js @@ -5,6 +5,7 @@ module.exports = { 'acmValidation' : require(__dirname + '/plugins/aws/acm/acmValidation.js'), 'acmCertificateExpiry' : require(__dirname + '/plugins/aws/acm/acmCertificateExpiry.js'), 'asgMultiAz' : require(__dirname + '/plugins/aws/autoscaling/asgMultiAz.js'), + 'emptyASG' : require(__dirname + '/plugins/aws/autoscaling/emptyASG.js'), 'workgroupEncrypted' : require(__dirname + '/plugins/aws/athena/workgroupEncrypted.js'), 'workgroupEnforceConfiguration' : require(__dirname + '/plugins/aws/athena/workgroupEnforceConfiguration.js'), 'publicS3Origin' : require(__dirname + '/plugins/aws/cloudfront/publicS3Origin.js'), @@ -116,6 +117,7 @@ module.exports = { 'iamUserAdmins' : require(__dirname + '/plugins/aws/iam/iamUserAdmins.js'), 'iamUserNameRegex' : require(__dirname + '/plugins/aws/iam/iamUserNameRegex.js'), 'iamRolePolicies' : require(__dirname + '/plugins/aws/iam/iamRolePolicies.js'), + 'iamRoleLastUsed' : require(__dirname + '/plugins/aws/iam/iamRoleLastUsed.js'), 'maxPasswordAge' : require(__dirname + '/plugins/aws/iam/maxPasswordAge.js'), 'minPasswordLength' : require(__dirname + '/plugins/aws/iam/minPasswordLength.js'), 'noUserIamPolicies' : require(__dirname + '/plugins/aws/iam/noUserIamPolicies.js'), @@ -126,6 +128,7 @@ module.exports = { 'passwordRequiresUppercase' : require(__dirname + '/plugins/aws/iam/passwordRequiresUppercase.js'), 'passwordReusePrevention' : require(__dirname + '/plugins/aws/iam/passwordReusePrevention.js'), 'rootAccessKeys' : require(__dirname + '/plugins/aws/iam/rootAccessKeys.js'), + 'rootSigningCertificate' : require(__dirname + '/plugins/aws/iam/rootSigningCertificate.js'), 'rootAccountInUse' : require(__dirname + '/plugins/aws/iam/rootAccountInUse.js'), 'rootHardwareMfa' : require(__dirname + '/plugins/aws/iam/rootHardwareMfa.js'), 'rootMfaEnabled' : require(__dirname + '/plugins/aws/iam/rootMfaEnabled.js'), diff --git a/index.js b/index.js index 53b6b4fb75..26e612ef56 100755 --- a/index.js +++ b/index.js @@ -1,74 +1,74 @@ #!/usr/bin/env node -var engine = require('./engine'); - -var AWSConfig; -var AzureConfig; -var GitHubConfig; -var OracleConfig; -var GoogleConfig; - -// OPTION 1: Configure service provider credentials through hard-coded config objects - -// AWSConfig = { -// accessKeyId: '', -// secretAccessKey: '', -// sessionToken: '', -// region: 'us-east-1' -// }; - -// AzureConfig = { -// ApplicationID: '', // A.K.A ClientID -// KeyValue: '', // Secret -// DirectoryID: '', // A.K.A TenantID or Domain -// SubscriptionID: '', -// location: 'East US' -// }; - -// GitHubConfig = { -// token: '', // GitHub app token -// url: 'https://api.github.com', // BaseURL if not using public GitHub -// organization: false, // Set to true if the login is an organization -// login: '' // The login id for the user or organization -// }; - -// Oracle Important Note: -// Please read Oracle API's key generation instructions: config/_oracle/keys/Readme.md -// You will want an API signing key to fill the keyFingerprint and privateKey params -// OracleConfig = { -// RESTversion: '/20160918', -// tenancyId: 'ocid1.tenancy.oc1..', -// compartmentId: 'ocid1.compartment.oc1..', -// userId: 'ocid1.user.oc1..', -// keyFingerprint: 'YOURKEYFINGERPRINT', -// keyValue: "-----BEGIN PRIVATE KEY-----\nYOUR-PRIVATE-KEY-GOES-HERE\n-----END PRIVATE KEY-----\n", -// region: 'us-ashburn-1', -// }; - -// GoogleConfig = { -// "type": "service_account", -// "project": "your-project-name", -// "client_email": "cloudsploit@your-project-name.iam.gserviceaccount.com", -// "private_key": "-----BEGIN PRIVATE KEY-----\nYOUR-PRIVATE-KEY-GOES-HERE\n-----END PRIVATE KEY-----\n", -// }; - -// OPTION 2: Import a service provider config file containing credentials - -// AWSConfig = require(__dirname + '/aws_credentials.json'); -// AzureConfig = require(__dirname + '/azure_credentials.json'); -// GitHubConfig = require(__dirname + '/github_credentials.json'); -// OracleConfig = require(__dirname + '/oracle_credentials.json'); -// GoogleConfig = require(__dirname + '/google_credentials.json'); - -// OPTION 3: ENV configuration with service provider env vars -if(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY){ - AWSConfig = { - accessKeyId: process.env.AWS_ACCESS_KEY_ID, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, - sessionToken: process.env.AWS_SESSION_TOKEN, - region: process.env.AWS_DEFAULT_REGION || 'us-east-1' - }; -} +const { ArgumentParser } = require('argparse'); +const engine = require('./engine'); + +console.log(` + _____ _ _ _____ _ _ _ + / ____| | | |/ ____| | | (_) | + | | | | ___ _ _ __| | (___ _ __ | | ___ _| |_ + | | | |/ _ \\| | | |/ _\` |\\___ \\| '_ \\| |/ _ \\| | __| + | |____| | (_) | |_| | (_| |____) | |_) | | (_) | | |_ + \\_____|_|\\___/ \\__,_|\\__,_|_____/| .__/|_|\\___/|_|\\__| + | | + |_| + + CloudSploit by Aqua Security, Ltd. + Cloud security auditing for AWS, Azure, GCP, Oracle, and GitHub +`); + +const parser = new ArgumentParser({}); + +parser.add_argument('--config', { + help: 'The path to a CloudSploit config file containing cloud credentials. See config_example.js' +}); + +parser.add_argument('--compliance', { + help: 'Compliance mode. Only return results applicable to the selected program.', + choices: ['hipaa', 'cis', 'cis1', 'cis2', 'pci'], + action: 'append' +}); +parser.add_argument('--plugin', { + help: 'A specific plugin to run. If none provided, all plugins will be run. Obtain from the exports.js file. E.g. acmValidation' +}); +parser.add_argument('--govcloud', { + help: 'AWS only. Enables GovCloud mode.', + action: 'store_true' +}); +parser.add_argument('--china', { + help: 'AWS only. Enables AWS China mode.', + action: 'store_true' +}); +parser.add_argument('--csv', { help: 'Output: CSV file' }); +parser.add_argument('--json', { help: 'Output: JSON file' }); +parser.add_argument('--junit', { help: 'Output: Junit file' }); +parser.add_argument('--console', { + help: 'Console output format. Default: table', + choices: ['none', 'text', 'table'], + default: 'table' +}); +parser.add_argument('--collection', { help: 'Output: full collection JSON as file' }); +parser.add_argument('--ignore-ok', { + help: 'Ignore passing (OK) results', + action: 'store_true' +}); +parser.add_argument('--exit-code', { + help: 'Exits with a non-zero status code if non-passing results are found', + action: 'store_true' +}); +parser.add_argument('--skip-paginate', { + help: 'AWS only. Skips pagination (for debugging).', + action: 'store_false' +}); +parser.add_argument('--suppress', { + help: 'Suppress results matching the provided Regex. Format: pluginId:region:resourceId', + action: 'append' +}); + +let settings = parser.parse_args(); +let cloudConfig = {}; + +settings.cloud = 'aws'; // Now execute the scans using the defined configuration information. if (!settings.config) { @@ -96,19 +96,17 @@ try { console.error('ERROR: Config file could not be loaded. Please ensure you have copied the config_example.js file to config.js'); process.exit(1); } -if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ - GoogleConfig = require(process.env.GOOGLE_APPLICATION_CREDENTIALS); - GoogleConfig.project = GoogleConfig.project_id; -} - -// Custom settings - place plugin-specific settings here -var settings = {}; -// If running in GovCloud, uncomment the following -// settings.govcloud = true; - -// If running in AWS China, uncomment the following -// settings.china = true; +function loadHelperFile(path) { + try { + var contents = require(path); + } catch (e) { + console.error(`ERROR: The credential file could not be loaded ${path}`); + console.error(e); + process.exit(1); + } + return contents; +} function checkRequiredKeys(obj, keys) { keys.forEach(function(key){ diff --git a/plugins/aws/cloudformation/plainTextParameters.js b/plugins/aws/cloudformation/plainTextParameters.js index 3bd118572e..e03a98bd08 100644 --- a/plugins/aws/cloudformation/plainTextParameters.js +++ b/plugins/aws/cloudformation/plainTextParameters.js @@ -36,7 +36,7 @@ module.exports = { } if (!describeStacks.data.length) { - helpers.addResult(results, 0, 'No stack description found', region); + helpers.addResult(results, 0, 'No CloudFormation stacks found', region); return rcb(); } diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js index caa173be82..5c73babd28 100644 --- a/plugins/aws/ec2/launchWizardSecurityGroups.js +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -34,7 +34,7 @@ module.exports = { for (var s in describeSecurityGroups.data) { var sg = describeSecurityGroups.data[s]; - var resource = sg.GroupId; + var resource = 'arn:aws:ec2:' + region + ':' + sg.OwnerId + ':security-group/' + sg.GroupId; if(!sg.GroupName) { helpers.addResult(results, 2, diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js index 0946f5a682..62053b7238 100644 --- a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js +++ b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js @@ -112,15 +112,6 @@ describe('vpcEndpointAcceptance', function () { }); }); - it('should PASS if no VPC endpoint services are detected', function (done) { - const cache = createCache([]); - vpcEndpointAcceptance.run(cache, {}, (err, results) => { - expect(results.length).to.equal(1); - expect(results[0].status).to.equal(0); - done(); - }); - }); - it('should UNKNOWN if there was an error querying for VPC endpoint services', function (done) { const cache = createErrorCache(); vpcEndpointAcceptance.run(cache, {}, (err, results) => { From 4c73161cd1bdb1c5a5ab38709d21443797a87a36 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Tue, 26 Jan 2021 13:20:58 +0500 Subject: [PATCH 60/67] Added superlinter --- .github/workflows/superlinter.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/superlinter.yml diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml new file mode 100644 index 0000000000..a54f356670 --- /dev/null +++ b/.github/workflows/superlinter.yml @@ -0,0 +1,25 @@ +name: Super-Linter + +# Run this workflow every time a new commit pushed to your repository +on: push + +jobs: + # Set the job key. The key is displayed as the job name + # when a job name is not provided + super-lint: + # Name the Job + name: Lint code base + # Set the type of machine to run on + runs-on: ubuntu-latest + + steps: + # Checks out a copy of your repository on the ubuntu-latest machine + - name: Checkout code + uses: actions/checkout@v2 + + # Runs the Super-Linter action + - name: Run Super-Linter + uses: github/super-linter@v3 + env: + DEFAULT_BRANCH: master + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 6cda1ef5a2319c8f52ce08023af97f9018d493d7 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 27 Jan 2021 14:19:02 +0500 Subject: [PATCH 61/67] Added scans ci --- .github/workflows/scan_ci.yml | 23 +++++++++++++++++++++++ .github/workflows/superlinter.yml | 25 ------------------------- 2 files changed, 23 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/scan_ci.yml delete mode 100644 .github/workflows/superlinter.yml diff --git a/.github/workflows/scan_ci.yml b/.github/workflows/scan_ci.yml new file mode 100644 index 0000000000..be35f61457 --- /dev/null +++ b/.github/workflows/scan_ci.yml @@ -0,0 +1,23 @@ +name: +on: [push, pull_request, create, delete] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js + uses: actions/setup-node@v1 + with: + node-version: 'stable' + - run: npm install + + - name: NPM test + - run: npm test + + - name: Lint + - run: npm run lint + + - name: Spell-check + - run: npm run spellcheck \ No newline at end of file diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml deleted file mode 100644 index a54f356670..0000000000 --- a/.github/workflows/superlinter.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Super-Linter - -# Run this workflow every time a new commit pushed to your repository -on: push - -jobs: - # Set the job key. The key is displayed as the job name - # when a job name is not provided - super-lint: - # Name the Job - name: Lint code base - # Set the type of machine to run on - runs-on: ubuntu-latest - - steps: - # Checks out a copy of your repository on the ubuntu-latest machine - - name: Checkout code - uses: actions/checkout@v2 - - # Runs the Super-Linter action - - name: Run Super-Linter - uses: github/super-linter@v3 - env: - DEFAULT_BRANCH: master - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 072a98a7887b3b74c41a16b2e1616f409448db31 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 27 Jan 2021 14:21:38 +0500 Subject: [PATCH 62/67] Updated Ci file --- .github/workflows/scan_ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/scan_ci.yml b/.github/workflows/scan_ci.yml index be35f61457..c302c43ad4 100644 --- a/.github/workflows/scan_ci.yml +++ b/.github/workflows/scan_ci.yml @@ -12,12 +12,6 @@ jobs: with: node-version: 'stable' - run: npm install - - - name: NPM test - run: npm test - - - name: Lint - run: npm run lint - - - name: Spell-check - run: npm run spellcheck \ No newline at end of file From cb40648178a99af6b32e7bec078a15433b3ce8a6 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 27 Jan 2021 14:23:13 +0500 Subject: [PATCH 63/67] Updated Node version in CI file --- .github/workflows/scan_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scan_ci.yml b/.github/workflows/scan_ci.yml index c302c43ad4..87cc5ce349 100644 --- a/.github/workflows/scan_ci.yml +++ b/.github/workflows/scan_ci.yml @@ -10,7 +10,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: 'stable' + node-version: '14.x' - run: npm install - run: npm test - run: npm run lint From b0138cbe60c4acd887ab9eb2aa6bf28a5b1f8ae8 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 27 Jan 2021 14:27:40 +0500 Subject: [PATCH 64/67] removed spech check command --- .github/workflows/scan_ci.yml | 11 +-- package-lock.json | 122 ++++++++++++++++++++++++---------- package.json | 6 +- 3 files changed, 98 insertions(+), 41 deletions(-) diff --git a/.github/workflows/scan_ci.yml b/.github/workflows/scan_ci.yml index 87cc5ce349..201d2ce74c 100644 --- a/.github/workflows/scan_ci.yml +++ b/.github/workflows/scan_ci.yml @@ -1,5 +1,5 @@ name: -on: [push, pull_request, create, delete] +on: [push, pull_request, create, delete, issue_comment, repository_dispatch] jobs: build: @@ -12,6 +12,9 @@ jobs: with: node-version: '14.x' - run: npm install - - run: npm test - - run: npm run lint - - run: npm run spellcheck \ No newline at end of file + + - name: NPM Test + run: npm test + + - name: Lint + run: npm run lint \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4c5ad9591f..f1188339ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -144,11 +144,22 @@ } }, "@octokit/auth-token": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.0.tgz", - "integrity": "sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", + "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", "requires": { - "@octokit/types": "^2.0.0" + "@octokit/types": "^6.0.3" + }, + "dependencies": { + "@octokit/types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.6.0.tgz", + "integrity": "sha512-nmFoU3HCbw1AmnZU/eto2VvzV06+N7oAqXwMmAHGlNDF+KFykksh/VlAl85xc1P5T7Mw8fKYvXNaImNHCCH/rg==", + "requires": { + "@octokit/openapi-types": "^3.3.0", + "@types/node": ">= 8" + } + } } }, "@octokit/endpoint": { @@ -161,6 +172,11 @@ "universal-user-agent": "^5.0.0" } }, + "@octokit/openapi-types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-3.3.0.tgz", + "integrity": "sha512-s3dd32gagPmKaSLNJ9aPNok7U+tl69YLESf6DgQz5Ml/iipPZtif3GLvWpNXoA6qspFm1LFUZX+C3SqWX/Y/TQ==" + }, "@octokit/plugin-paginate-rest": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", @@ -170,9 +186,9 @@ } }, "@octokit/plugin-request-log": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz", - "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz", + "integrity": "sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==" }, "@octokit/plugin-rest-endpoint-methods": { "version": "2.4.0", @@ -242,9 +258,9 @@ } }, "@octokit/rest": { - "version": "16.43.1", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz", - "integrity": "sha512-gfFKwRT/wFxq5qlNjnW2dh+qh74XgTQ2B179UX5K1HYCluioWj8Ndbgqw2PVqa1NnVJkGHp2ovMpVn/DImlmkw==", + "version": "16.43.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", + "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", "requires": { "@octokit/auth-token": "^2.4.0", "@octokit/plugin-paginate-rest": "^1.1.1", @@ -264,38 +280,52 @@ "universal-user-agent": "^4.0.0" }, "dependencies": { + "@octokit/endpoint": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz", + "integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==", + "requires": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + }, + "dependencies": { + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + } + } + }, "@octokit/request": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.4.tgz", - "integrity": "sha512-qyj8G8BxQyXjt9Xu6NvfvOr1E0l35lsXtwm3SopsYg/JWXjlsnwqLc8rsD2OLguEL/JjLfBvrXr4az7z8Lch2A==", + "version": "5.4.13", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.13.tgz", + "integrity": "sha512-WcNRH5XPPtg7i1g9Da5U9dvZ6YbTffw9BN2rVezYiE7couoSyaRsw0e+Tl8uk1fArHE7Dn14U7YqUDy59WaqEw==", "requires": { - "@octokit/endpoint": "^6.0.0", + "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.0.0", - "@octokit/types": "^2.0.0", + "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", - "is-plain-object": "^3.0.0", - "node-fetch": "^2.3.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.1", "once": "^1.4.0", - "universal-user-agent": "^5.0.0" + "universal-user-agent": "^6.0.0" }, "dependencies": { "@octokit/request-error": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.0.tgz", - "integrity": "sha512-rtYicB4Absc60rUv74Rjpzek84UbVHGHJRu4fNVlZ1mCcyUPPuzFfG9Rn6sjHrd95DEsmjSt1Axlc699ZlbDkw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz", + "integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==", "requires": { - "@octokit/types": "^2.0.0", + "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "universal-user-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", - "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", - "requires": { - "os-name": "^3.1.0" - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" } } }, @@ -307,8 +337,32 @@ "@octokit/types": "^2.0.0", "deprecation": "^2.0.0", "once": "^1.4.0" + }, + "dependencies": { + "@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "requires": { + "@types/node": ">= 8" + } + } + } + }, + "@octokit/types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.6.0.tgz", + "integrity": "sha512-nmFoU3HCbw1AmnZU/eto2VvzV06+N7oAqXwMmAHGlNDF+KFykksh/VlAl85xc1P5T7Mw8fKYvXNaImNHCCH/rg==", + "requires": { + "@octokit/openapi-types": "^3.3.0", + "@types/node": ">= 8" } }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, "universal-user-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz", @@ -489,9 +543,9 @@ "dev": true }, "argparse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.0.tgz", - "integrity": "sha512-mEKF1/WpTsblaqx7NIkcsTxwDzvJuGH5sdUqDNcJS+vXCWe+yM/o4cs/Q2/GFESAYg+O7UouEmz+iBqmKofI/Q==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "arr-diff": { "version": "4.0.0", @@ -593,9 +647,9 @@ "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=" }, "aws-sdk": { - "version": "2.740.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.740.0.tgz", - "integrity": "sha512-cSedIe7g5/S5o23jHvm9+vWhcYysmuKrmbML1Z0pO9KxlqOA9s4Z5f6Il7ZmvAktfmrxu1SyQu4YEoP5DL4/zw==", + "version": "2.831.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.831.0.tgz", + "integrity": "sha512-lrOjbGFpjk2xpESyUx2PGsTZgptCy5xycZazPeakNbFO19cOoxjHx3xyxOHsMCYb3pQwns35UvChQT60B4u6cw==", "requires": { "buffer": "4.9.2", "events": "1.1.1", diff --git a/package.json b/package.json index e206ef6a32..84933aab13 100644 --- a/package.json +++ b/package.json @@ -41,10 +41,10 @@ "dependencies": { "@octokit/app": "^3.0.0", "@octokit/request": "^3.0.3", - "@octokit/rest": "^16.3.2", - "argparse": "^2.0.0", + "@octokit/rest": "^16.43.2", + "argparse": "^2.0.1", "async": "^2.6.1", - "aws-sdk": "^2.740.0", + "aws-sdk": "^2.831.0", "azure-storage": "^2.10.3", "csv-write-stream": "^2.0.0", "fast-safe-stringify": "^2.0.6", From 239b8a635edd28126f446c9ef107760909f0d816 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 27 Jan 2021 17:07:26 +0500 Subject: [PATCH 65/67] Delete scan_ci.yml --- .github/workflows/scan_ci.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/scan_ci.yml diff --git a/.github/workflows/scan_ci.yml b/.github/workflows/scan_ci.yml deleted file mode 100644 index 201d2ce74c..0000000000 --- a/.github/workflows/scan_ci.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: -on: [push, pull_request, create, delete, issue_comment, repository_dispatch] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Use Node.js - uses: actions/setup-node@v1 - with: - node-version: '14.x' - - run: npm install - - - name: NPM Test - run: npm test - - - name: Lint - run: npm run lint \ No newline at end of file From 46cfe9df6ad915fcea0dd06c061b874193613767 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Mon, 1 Feb 2021 23:23:55 +0500 Subject: [PATCH 66/67] Added spellcheck --- .github/workflows/scans_ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/scans_ci.yml b/.github/workflows/scans_ci.yml index 7fd69312b9..2e1ac859a7 100644 --- a/.github/workflows/scans_ci.yml +++ b/.github/workflows/scans_ci.yml @@ -11,6 +11,11 @@ jobs: uses: actions/setup-node@v1 with: node-version: '12.x' + - uses: codespell-project/actions-codespell@master + with: + check_filenames: true + skip: ./.github/*,.git,./package.json,./node_modules,./tests,./config,*.png,Dockerfile,./scripts,*.spec.js,./plugins/azure/storageaccounts/storageAccountsAADEnabled.js,./plugins/aws/cloudtrail/cloudtrailBucketAccessLogging.js,./helpers/google/index.js,*zip + ignore_words_list: iam,\"tRe\",AKS,aks,optin,callInt,callInt - run: npm install - name: NPM Test @@ -19,4 +24,5 @@ jobs: - name: Lint run: npm run lint + \ No newline at end of file From 820a4d8a4a33a090460ce5bf5566ef0743bc349f Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sun, 14 Mar 2021 21:53:09 +0500 Subject: [PATCH 67/67] AWS Glue Data Catalog CMK Encrypted remediated --- plugins/aws/glue/dataCatalogCmkEncrypted.js | 81 +++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/plugins/aws/glue/dataCatalogCmkEncrypted.js b/plugins/aws/glue/dataCatalogCmkEncrypted.js index c40251d304..91b46a8309 100644 --- a/plugins/aws/glue/dataCatalogCmkEncrypted.js +++ b/plugins/aws/glue/dataCatalogCmkEncrypted.js @@ -9,6 +9,26 @@ module.exports = { recommended_action: 'Modify Glue data catalog to use CMK instead of AWS-managed Key to encrypt Metadata', link: 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-glue-data-catalog.html', apis: ['Glue:getDataCatalogEncryptionSettings', 'KMS:listKeys', 'KMS:describeKey'], + remediation_description: 'Glue data catalog Encryption for the affected regions will be enabled.', + remediation_min_version: '202114032330', + apis_remediate: ['Glue:getDataCatalogEncryptionSettings'], + remediation_inputs: { + kmsKeyIdforSqs: { + name: '(Mandatory) KMS Key ID', + description: 'The KMS Key ID used for encryption', + regex: '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$', + required: true + } + }, + actions: { + remediate: ['Glue:putDataCatalogEncryptionSettings'], + rollback: ['Glue:putDataCatalogEncryptionSettings'] + }, + permissions: { + remediate: ['glue:PutDataCatalogEncryptionSettings+'], + rollback: ['glue:PutDataCatalogEncryptionSettings'] + }, + realtime_triggers: ['glue:PutDataCatalogEncryptionSettings'], run: function(cache, settings, callback) { var results = []; @@ -66,5 +86,66 @@ module.exports = { }, function(){ callback(null, results, source); }); + }, + + remediate: function(config, cache, settings, resource, callback) { + var putCall = this.actions.remediate; + var pluginName = 'dataCatalogCmkEncrypted'; + + // add the location of the Queue to the config + config.region = queueLocation; + var params = {}; + // create the params necessary for the remediation + if (settings.input && + settings.input.kmsKeyIdforSqs) { + params = { + Attributes: { + 'KmsMasterKeyId': settings.input.kmsKeyIdforSqs + }, + QueueUrl: queueUrl + }; + } else { + let defaultKmsKeyId = helpers.getDefaultKeyId(cache, config.region, defaultKeyDesc); + if (!defaultKmsKeyId) return callback(`No default SQS key for the region ${config.region}`); + params = { + Attributes: { + 'KmsMasterKeyId': defaultKmsKeyId + }, + QueueUrl: queueUrl + }; + + } + + var remediation_file = settings.remediation_file; + + remediation_file['pre_remediate']['actions'][pluginName][resource] = { + 'Encryption': 'Disabled', + 'Queue': queueName + }; + + // passes the config, put call, and params to the remediate helper function + helpers.remediatePlugin(config, putCall[0], params, function(err) { + if (err) { + remediation_file['remediate']['actions'][pluginName]['error'] = err; + return callback(err, null); + } + + let action = params; + action.action = putCall; + + remediation_file['post_remediate']['actions'][pluginName][resource] = action; + remediation_file['remediate']['actions'][pluginName][resource] = { + 'Action': 'ENCRYPTED', + 'Queue': queueName + }; + settings.remediation_file = remediation_file; + return callback(null, action); + }); + }, + + rollback: function(config, cache, settings, resource, callback) { + console.log('Rollback support for this plugin has not yet been implemented'); + console.log(config, cache, settings, resource); + callback(); } }; \ No newline at end of file