Skip to content

Commit fe84e38

Browse files
authored
Adds Credentials Exposure and Service Wildcard to the report (#124)
* Updated risk alert indicator and definitions * Fixed formatting in StandardRiskDetails v-bind IDs; updated order of risk details to display; made finding details only show up if they exist via v-if * Added the Credentials Exposure and Service Wildcard findings to the finding details per policy * Added alert indicators for the new risks * The new findings are present in the table now * Fixes #99 by adding support for Credentials Exposure and Fixes #82 by adding support for Service Wildcard. * Update javascript bundle and generate a new example report
1 parent 1d911d7 commit fe84e38

14 files changed

+163
-63
lines changed

cloudsplaining/output/dist/js/index.js

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloudsplaining/output/src/assets/glossary.md

+34
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,40 @@ Infrastructure Modification describes IAM actions with "modify" capabilities, an
2727

2828
Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as `s3:GetObject`, `ssm:GetParameter*`, or `secretsmanager:GetSecretValue`. Unrestricted `s3:GetObject` permissions has a long history of customer data leaks. `ssm:GetParameter*` and `secretsmanager:GetSecretValue` are both used to access secrets. `rds:CopyDBSnapshot` and `rds:CreateDBSnapshot` can be used to exfiltrate RDS database contents.
2929

30+
##### Service Wildcard
31+
32+
"Service Wildcard" is an unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like `s3:*`. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of high risk issues in the Cloudsplaining report.
33+
34+
##### Credentials Exposure
35+
36+
Credentials Exposure actions return credentials as part of the API response , such as `ecr:GetAuthorizationToken`, `iam:UpdateAccessKey`, and others. The full list is below.
37+
38+
- [codepipeline:pollforjobs](https://docs.aws.amazon.com/codepipeline/latest/APIReference/API_PollForJobs.html)
39+
- [cognito-identity:getopenidtoken](https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetOpenIdToken.html)
40+
- [cognito-identity:getopenidtokenfordeveloperidentity](https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetOpenIdTokenForDeveloperIdentity.html)
41+
- [cognito-identity:getcredentialsforidentity](https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetCredentialsForIdentity.html)
42+
- [connect:getfederationtoken](https://docs.aws.amazon.com/connect/latest/APIReference/API_GetFederationToken.html)
43+
- [connect:getfederationtokens](https://docs.aws.amazon.com/connect/latest/APIReference/API_GetFederationToken.html)
44+
- [ecr:getauthorizationtoken](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_GetAuthorizationToken.html)
45+
- [gamelift:requestuploadcredentials](https://docs.aws.amazon.com/gamelift/latest/apireference/API_RequestUploadCredentials.html)
46+
- [iam:createaccesskey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateAccessKey.html)
47+
- [iam:createloginprofile](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateLoginProfile.html)
48+
- [iam:createservicespecificcredential](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateServiceSpecificCredential.html)
49+
- [iam:resetservicespecificcredential](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ResetServiceSpecificCredential.html)
50+
- [iam:updateaccesskey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateAccessKey.html)
51+
- [lightsail:getinstanceaccessdetails](https://docs.aws.amazon.com/lightsail/2016-11-28/api-reference/API_GetInstanceAccessDetails.html)
52+
- [lightsail:getrelationaldatabasemasteruserpassword](https://docs.aws.amazon.com/lightsail/2016-11-28/api-reference/API_GetRelationalDatabaseMasterUserPassword.html)
53+
- [rds-db:connect](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html)
54+
- [redshift:getclustercredentials](https://docs.aws.amazon.com/redshift/latest/APIReference/API_GetClusterCredentials.html)
55+
- [sso:getrolecredentials](https://docs.aws.amazon.com/singlesignon/latest/PortalAPIReference/API_GetRoleCredentials.html)
56+
- [mediapackage:rotatechannelcredentials](https://docs.aws.amazon.com/mediapackage/latest/apireference/channels-id-credentials.html)
57+
- [mediapackage:rotateingestendpointcredentials](https://docs.aws.amazon.com/mediapackage/latest/apireference/channels-id-ingest_endpoints-ingest_endpoint_id-credentials.html)
58+
- [sts:assumerole](https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role.html)
59+
- [sts:assumerolewithsaml](https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-saml.html)
60+
- [sts:assumerolewithwebidentity](https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-web-identity.html)
61+
- [sts:getfederationtoken](https://docs.aws.amazon.com/cli/latest/reference/sts/get-federation-token.html)
62+
- [sts:getsessiontoken](https://docs.aws.amazon.com/cli/latest/reference/sts/get-session-token.html)
63+
3064
##### Roles Assumable by Compute Services
3165

3266
IAM Roles can be assumed by AWS Compute Services (such as EC2, ECS, EKS, or Lambda) can present greater risk than user-defined roles, especially if the AWS Compute service is on an instance that is directly or indirectly exposed to the internet. Flagging these roles is particularly useful to penetration testers (or attackers) under certain scenarios. For example, if an attacker obtains privileges to execute [ssm:SendCommand](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_SendCommand.html) and there are privileged EC2 instances with the SSM agent installed, they can effectively have the privileges of those EC2 instances. Remote Code Execution via AWS Systems Manager Agent was already a known escalation/exploitation path, but Cloudsplaining can make the process of identifying theses cases easier.

cloudsplaining/output/src/components/PolicyTable.vue

+14-9
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
</b-col>
2727

2828
</b-row>
29-
3029
<b-table
3130
:items="policyNameMapping"
3231
:fields="fields"
@@ -35,16 +34,20 @@
3534
:current-page="currentPage"
3635
:per-page="perPage"
3736
responsive="sm"
37+
:sticky-header=true
38+
:no-border-collapse=true
3839
small
3940
>
40-
<template v-slot:cell(attached_to_principals)="data">
41-
{{ data.item.attached_to_principals.length }}
42-
<!--{{ data.item.attached_to_principals.join(", ") }}-->
43-
</template>
41+
<template v-slot:cell(policy_name)="data">
42+
{{ data.item.policy_name }}
43+
</template>
44+
<template v-slot:cell(attached_to_principals)="data">
45+
{{ data.item.attached_to_principals.length }}
46+
</template>
4447

45-
<template v-slot:cell(compute_role)="data">
46-
{{ data.item.compute_role.join(", ") }}
47-
</template>
48+
<template v-slot:cell(compute_role)="data">
49+
{{ data.item.compute_role.join(", ") }}
50+
</template>
4851
</b-table>
4952
</b-container>
5053
<br>
@@ -70,9 +73,11 @@
7073
{key: 'attached_to_principals', sortable: true},
7174
{key: 'services', sortable: true},
7275
{key: 'infrastructure_modification', sortable: true},
76+
{key: 'service_wildcard', sortable: true},
7377
{key: 'privilege_escalation', sortable: true},
7478
{key: 'resource_exposure', sortable: true},
7579
{key: 'data_exfiltration', sortable: true},
80+
{key: 'credentials_exposure', sortable: true},
7681
{key: 'compute_role', sortable: true},
7782
],
7883
totalRows: 1,
@@ -90,4 +95,4 @@
9095

9196
<style scoped>
9297
93-
</style>
98+
</style>

cloudsplaining/output/src/components/Principals.vue

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
This page displays IAM Users, Groups, and Roles in the account, their associated policies, the risks associated with each principal, and various metadata that can be expanded per principal.
66
<br>
77
<br>
8-
<!--ROLES-->
98
<div v-bind:key="principalType" v-for="principalType in principalTypes">
109
<h3>{{ capitalizeFirstLetter(principalType) }}</h3>
1110
<div v-bind:key="principalId" v-for="principalId in principalTypeIds(principalType)">

cloudsplaining/output/src/components/Summary.vue

+24-4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@
6161
<b-td>{{ policyRisks.ResourceExposure }}</b-td>
6262
<b-td>med</b-td>
6363
</b-tr>
64+
<b-tr>
65+
<b-th>Credentials Exposure</b-th>
66+
<b-td>{{ policyRisks.CredentialsExposure }}</b-td>
67+
<b-td>med</b-td>
68+
</b-tr>
6469
<b-tr>
6570
<b-th>Infrastructure Modification</b-th>
6671
<b-td>{{ policyRisks.InfrastructureModification }}</b-td>
@@ -125,10 +130,25 @@ export default {
125130
}
126131
127132
return {
128-
"PrivilegeEscalation": this.inlinePolicyRisks.PrivilegeEscalation + this.awsManagedPolicyRisks.PrivilegeEscalation + this.customerManagedPolicyRisks.PrivilegeEscalation,
129-
"DataExfiltration": this.inlinePolicyRisks.DataExfiltration + this.awsManagedPolicyRisks.DataExfiltration + this.customerManagedPolicyRisks.DataExfiltration,
130-
"ResourceExposure": this.inlinePolicyRisks.ResourceExposure + this.awsManagedPolicyRisks.ResourceExposure + this.customerManagedPolicyRisks.ResourceExposure,
131-
"InfrastructureModification": this.inlinePolicyRisks.InfrastructureModification + this.awsManagedPolicyRisks.InfrastructureModification + this.customerManagedPolicyRisks.InfrastructureModification
133+
"PrivilegeEscalation":
134+
this.inlinePolicyRisks.PrivilegeEscalation
135+
+ this.awsManagedPolicyRisks.PrivilegeEscalation
136+
+ this.customerManagedPolicyRisks.PrivilegeEscalation,
137+
"DataExfiltration": this.inlinePolicyRisks.DataExfiltration
138+
+ this.awsManagedPolicyRisks.DataExfiltration
139+
+ this.customerManagedPolicyRisks.DataExfiltration,
140+
"ResourceExposure":
141+
this.inlinePolicyRisks.ResourceExposure
142+
+ this.awsManagedPolicyRisks.ResourceExposure
143+
+ this.customerManagedPolicyRisks.ResourceExposure,
144+
"CredentialsExposure":
145+
this.inlinePolicyRisks.CredentialsExposure
146+
+ this.awsManagedPolicyRisks.CredentialsExposure
147+
+ this.customerManagedPolicyRisks.CredentialsExposure,
148+
"InfrastructureModification":
149+
this.inlinePolicyRisks.InfrastructureModification
150+
+ this.awsManagedPolicyRisks.InfrastructureModification
151+
+ this.customerManagedPolicyRisks.InfrastructureModification
132152
}
133153
},
134154

cloudsplaining/output/src/components/charts/SummaryFindings.vue

+16-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@ import { Bar } from 'vue-chartjs'
55
export default {
66
name: "SummaryFindings",
77
extends: Bar,
8-
props: ["inlinePolicyRisks", "awsManagedPolicyRisks", "customerManagedPolicyRisks"],
8+
props: {
9+
inlinePolicyRisks: {
10+
type: Object
11+
},
12+
awsManagedPolicyRisks: {
13+
type: Object
14+
},
15+
customerManagedPolicyRisks: {
16+
type: Object
17+
},
18+
},
919
computed: {
1020
myStyles() {
1121
return {
@@ -21,7 +31,8 @@ export default {
2131
"Privilege Escalation",
2232
"Data Exfiltration",
2333
"Resource Exposure",
24-
"Infrastructure Modification"
34+
"Credentials Exposure",
35+
"Infrastructure Modification",
2536
],
2637
datasets: [{
2738
label: "Inline Policies",
@@ -31,6 +42,7 @@ export default {
3142
"#59575c",
3243
"#59575c",
3344
"#59575c",
45+
"#59575c",
3446
]
3547
},
3648
{
@@ -42,6 +54,7 @@ export default {
4254
"#215ca0",
4355
"#215ca0",
4456
"#215ca0",
57+
"#215ca0",
4558
]
4659
},{
4760
label: "Customer-managed Policies",
@@ -52,6 +65,7 @@ export default {
5265
"#00857d",
5366
"#00857d",
5467
"#00857d",
68+
"#00857d",
5569
]
5670
}
5771
]

cloudsplaining/output/src/components/finding/RiskAlertIndicators.vue

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div>
3-
<!--Alert for Risk Type: Privilege Escalation Exposure-->
3+
<!--Alert boxes for different risks-->
44
<div v-for="riskType in highRisksToDisplayAlertsFor" :key="riskType">
55
<template v-if="findings(policyId, riskType).length > 0">
66
<div v-bind:class="'alert alert-' + getRiskAlertIndicatorColor(riskType) + ' popovers'" data-html="true" data-placement="top"
@@ -31,9 +31,11 @@
3131
const managedPoliciesUtil = require('../../util/managed-policies');
3232
3333
var highRisksToDisplayAlertsFor = [
34-
"PrivilegeEscalation",
34+
"CredentialsExposure",
3535
"DataExfiltration",
36-
"ResourceExposure"
36+
"ResourceExposure",
37+
"ServiceWildcard",
38+
"PrivilegeEscalation",
3739
]
3840
3941
export default {

cloudsplaining/output/src/components/finding/StandardRiskDetails.vue

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<template>
22
<div>
33
<div v-for="risk in riskDetailsToDisplay" :key="risk.risk_type">
4-
<template v-show="findings(policyId, risk.risk_type).length > 0">
4+
<template v-if="findings(policyId, risk.risk_type).length > 0">
55
<div class="card-header">
66
<a class="card-link" data-toggle="collapse"
7-
v-bind:data-parent="'#' + inlineOrManaged.toLowerCase() + '-policy' + '-' + policyId + '-' + 'card-details'"
8-
v-bind:href="'#' + inlineOrManaged.toLowerCase() + '-policy' + '-' + policyId + '-' + convertStringToKebabCase(risk.risk_type)"
7+
v-bind:data-parent="`#${inlineOrManaged.toLowerCase()}-policy-${policyId}-card-details`"
8+
v-bind:href="`#${inlineOrManaged.toLowerCase()}-policy-${policyId}-${convertStringToKebabCase(risk.risk_type)}`"
99
>{{ convertStringToSpaceCase(risk.risk_type) }}</a>
1010
</div>
1111
</template>
12-
<template v-show="findings(policyId, risk.risk_type).length > 0">
12+
<template v-if="findings(policyId, risk.risk_type).length > 0">
1313
<div class="panel-collapse collapse"
14-
v-bind:id="inlineOrManaged.toLowerCase() + '-policy' + '-' + policyId + '-' + convertStringToKebabCase(risk.risk_type)">
14+
v-bind:id="`${inlineOrManaged.toLowerCase()}-policy-${policyId}-${convertStringToKebabCase(risk.risk_type)}`">
1515
<div class="card-body">
1616
<pre><code>
1717
{{ JSON.parse(JSON.stringify(findings(policyId, risk.risk_type), undefined, '\t')) }}

cloudsplaining/output/src/components/principals/RisksPerPrincipal.vue

+21-13
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<script>
3636
const principalsUtil = require('../../util/principals');
3737
const otherUtil = require('../../util/other');
38+
const glossary = require('../../util/glossary');
3839
3940
export default {
4041
name: "RisksPerPrincipal",
@@ -51,7 +52,13 @@
5152
},
5253
computed: {
5354
riskNames() {
54-
return ["DataExfiltration", "ResourceExposure", "PrivilegeEscalation", "InfrastructureModification"]
55+
let riskDetails = glossary.getRiskDetailsToDisplay();
56+
let riskNameArray = riskDetails.map(function (risk) { return risk.risk_type; });
57+
// console.log(`Risk names: ${riskNameArray}`);
58+
riskNameArray.push("PrivilegeEscalation");
59+
riskNameArray.sort();
60+
return riskNameArray;
61+
// return ["DataExfiltration", "ResourceExposure", "PrivilegeEscalation", "InfrastructureModification"]
5562
},
5663
},
5764
methods: {
@@ -62,18 +69,19 @@
6269
return principalsUtil.getRiskAssociatedWithPrincipal(this.iam_data, principalName, principalType, riskType)
6370
},
6471
getRiskLevel: function (riskType) {
65-
if (riskType === "DataExfiltration") {
66-
return "warning"
67-
}
68-
if (riskType === "PrivilegeEscalation") {
69-
return "danger"
70-
}
71-
if (riskType === "ResourceExposure") {
72-
return "warning"
73-
}
74-
if (riskType === "InfrastructureModification") {
75-
return "info"
76-
}
72+
return glossary.getRiskAlertIndicatorColor(riskType)
73+
// if (riskType === "DataExfiltration") {
74+
// return "warning"
75+
// }
76+
// if (riskType === "PrivilegeEscalation") {
77+
// return "danger"
78+
// }
79+
// if (riskType === "ResourceExposure") {
80+
// return "warning"
81+
// }
82+
// if (riskType === "InfrastructureModification") {
83+
// return "info"
84+
// }
7785
},
7886
addSpacesInPascalCaseString: function (s) {
7987
return otherUtil.addSpacesInPascalCaseString(s)

cloudsplaining/output/src/util/glossary.js

+16-10
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,52 @@ const privilegeEscalationDefinition = '<p>These policies allow a combination of
22
const dataExfiltrationDefinition = '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>'
33
const resourceExposureDefinition = '<p>Resource Exposure actions allow modification of Permissions to <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html">resource-based policies</a> or otherwise can expose AWS resources to the public via similar actions that can lead to resource exposure - for example, the ability to modify <a href="https://docs.aws.amazon.com/ram/latest/userguide/what-is.html">AWS Resource Access Manager</a>.</p>'
44
const assumableByComputeServiceDefinition = '<p>IAM Roles can be assumed by AWS Compute Services (such as EC2, ECS, EKS, or Lambda) can present greater risk than user-defined roles, especially if the AWS Compute service is on an instance that is directly or indirectly exposed to the internet. Flagging these roles is particularly useful to penetration testers (or attackers) under certain scenarios.<br>For example, if an attacker obtains privileges to execute <code>ssm:SendCommand</code> and there are privileged EC2 instances with the SSM agent installed, they can effectively have the privileges of those EC2 instances.</p>'
5+
const credentialsExposureDefinition = '<p>Credentials Exposure actions return credentials as part of the API response , such as ecr:GetAuthorizationToken, iam:UpdateAccessKey, and others. The full list is maintained here: https://gist.github.com/kmcquade/33860a617e651104d243c324ddf7992a</p>'
6+
const serviceWildcardDefinition = '<p>"Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.</p>'
57

68
let riskDefinitions = {
79
PrivilegeEscalation: privilegeEscalationDefinition,
810
DataExfiltration: dataExfiltrationDefinition,
911
ResourceExposure: resourceExposureDefinition,
1012
AssumableByComputeService: assumableByComputeServiceDefinition,
13+
CredentialsExposure: credentialsExposureDefinition,
14+
ServiceWildcard: serviceWildcardDefinition,
1115
}
1216

1317
let riskAlertIndicatorColors = {
1418
PrivilegeEscalation: 'danger',
1519
DataExfiltration: 'warning',
1620
ResourceExposure: 'danger',
1721
AssumableByComputeService: 'info',
22+
CredentialsExposure: 'secondary',
23+
ServiceWildcard: 'primary',
1824
}
1925

2026
let riskDetailsToDisplay = [
2127
// {
2228
// risk_type: "PrivilegeEscalation",
2329
// explanation: "Explanation!"
2430
// },
31+
{
32+
risk_type: "CredentialsExposure",
33+
explanation: "Explanation!"
34+
},
2535
{
2636
risk_type: "DataExfiltration",
2737
explanation: "Explanation!"
2838
},
29-
{
39+
{
3040
risk_type: "ResourceExposure",
3141
explanation: "Explanation!"
3242
},
33-
{
43+
{
44+
risk_type: "ServiceWildcard",
45+
explanation: "Explanation!"
46+
},
47+
{
3448
risk_type: "InfrastructureModification",
3549
explanation: "Explanation!"
3650
},
37-
// {
38-
// risk_type: "CredentialsExposure",
39-
// explanation: "Explanation!"
40-
// },
41-
// {
42-
// risk_type: "ServiceStar",
43-
// explanation: "Explanation!"
44-
// }
4551
]
4652

4753
function getRiskDefinition(riskType) {

0 commit comments

Comments
 (0)