Skip to content

Commit

Permalink
Merge pull request #65 from oussamaca/feat/role_privesc
Browse files Browse the repository at this point in the history
Feat/role privesc
  • Loading branch information
StanGirard committed Jan 11, 2023
2 parents 0774922 + 43f44a6 commit d1a9607
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 4 deletions.
96 changes: 96 additions & 0 deletions aws/iam/getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@ func GetAllUsers(s aws.Config) []types.User {
return users
}

func GetAllRoles(s aws.Config) []types.Role {
svc := iam.NewFromConfig(s)
var roles []types.Role
input := &iam.ListRolesInput{}
result, err := svc.ListRoles(context.TODO(), input)
roles = append(roles, result.Roles...)
if err != nil {
fmt.Println(err)
}
for {
if result.IsTruncated {
input.Marker = result.Marker
result, err = svc.ListRoles(context.TODO(), input)
roles = append(roles, result.Roles...)
if err != nil {
fmt.Println(err)
}
} else {
break
}
}
return roles
}

type MFAForUser struct {
UserName string
MFAs []types.MFADevice
Expand Down Expand Up @@ -213,3 +237,75 @@ func GetAllPolicyVersions(s aws.Config, policyArn *string) []types.PolicyVersion

return result.Versions
}

func GetRolePolicies(roles []types.Role, s aws.Config) []RolePolicies {
var wgPolicyForRole sync.WaitGroup
wgPolicyForRole.Add(len(roles))
queue := make(chan RolePolicies, 10)
for _, role := range roles {
go GetAllPolicyForRole(&wgPolicyForRole, queue, s, role)
}
var rolePolicies []RolePolicies
go func() {
for role := range queue {
rolePolicies = append(rolePolicies, role)
wgPolicyForRole.Done()
}

}()
wgPolicyForRole.Wait()
return rolePolicies
}

type RoleToPoliciesElevate struct {
RoleName string
Policies [][]string
}

func GetRoleToPoliciesElevate(rolePolicies []RolePolicies) []RoleToPoliciesElevate {
var rolesElevatedPolicies []RoleToPoliciesElevate
for _, role := range rolePolicies {
elevation := CheckPolicyForAllowInRequiredPermission(role.Policies, requiredPermissions)
if elevation != nil {
rolesElevatedPolicies = append(rolesElevatedPolicies, RoleToPoliciesElevate{
RoleName: role.RoleName,
Policies: elevation,
})
}

}

return rolesElevatedPolicies
}

func GetAllPolicyForRole(wg *sync.WaitGroup, queueCheck chan RolePolicies, s aws.Config, role types.Role) {
var policyList []Policy
var wgpolicy sync.WaitGroup
queue := make(chan *string, 100)
policies := GetPolicyAttachedToRole(s, role)
wgpolicy.Add(len(policies))
for _, policy := range policies {
go GetPolicyDocument(&wgpolicy, queue, s, policy.PolicyArn)

}
go func() {
for t := range queue {
policyList = append(policyList, JsonDecodePolicyDocument(t))
wgpolicy.Done()
}
}()
wgpolicy.Wait()
queueCheck <- RolePolicies{*role.RoleName, policyList}
}

func GetPolicyAttachedToRole(s aws.Config, role types.Role) []types.AttachedPolicy {
svc := iam.NewFromConfig(s)
input := &iam.ListAttachedRolePoliciesInput{
RoleName: role.RoleName,
}
result, err := svc.ListAttachedRolePolicies(context.TODO(), input)
if err != nil {
fmt.Println(err)
}
return result.AttachedPolicies
}
6 changes: 5 additions & 1 deletion aws/iam/iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ func RunChecks(wa *sync.WaitGroup, s aws.Config, c *commons.Config, queue chan [
accessKeysForUsers := GetAccessKeysForUsers(s, users)
UserToPolicies := GetUserPolicies(users, s)
UserToPoliciesElevated := GetUserToPoliciesElevate(UserToPolicies)
roles := GetAllRoles(s)
RoleToPolicies := GetRolePolicies(roles, s)
RoleToPoliciesElevated := GetRoleToPoliciesElevate(RoleToPolicies)

go commons.CheckTest(checkConfig.Wg, c, "AWS_IAM_001", CheckIf2FAActivated)(checkConfig, mfaForUsers, "AWS_IAM_001")
go commons.CheckTest(checkConfig.Wg, c, "AWS_IAM_002", CheckAgeAccessKeyLessThan90Days)(checkConfig, accessKeysForUsers, "AWS_IAM_002")
go commons.CheckTest(checkConfig.Wg, c, "AWS_IAM_003", CheckIfUserCanElevateRights)(checkConfig, UserToPoliciesElevated, "AWS_IAM_003")
go commons.CheckTest(checkConfig.Wg, c, "AWS_IAM_004", CheckIfUserLastPasswordUse120Days)(checkConfig, users, "AWS_IAM_004")
go commons.CheckTest(checkConfig.Wg, c, "AWS_IAM_004", CheckIfRoleCanElevateRights)(checkConfig, RoleToPoliciesElevated, "AWS_IAM_004")
go commons.CheckTest(checkConfig.Wg, c, "AWS_IAM_005", CheckIfUserLastPasswordUse120Days)(checkConfig, users, "AWS_IAM_005")
go func() {
for t := range checkConfig.Queue {
t.EndCheck()
Expand Down
23 changes: 23 additions & 0 deletions aws/iam/iamElevateRights.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,29 @@ func CheckIfUserCanElevateRights(checkConfig commons.CheckConfig, userToPolocies
checkConfig.Queue <- check
}

func CheckIfRoleCanElevateRights(checkConfig commons.CheckConfig, roleToPoliciesElevated []RoleToPoliciesElevate, testName string) {
var check commons.Check
check.InitCheck("IAM Role can't elevate rights", "Check if roles can elevate rights", testName, []string{"Security", "Good Practice"})
for _, rolePol := range roleToPoliciesElevated {
if len(rolePol.Policies) > 0 {
var Message string
if len(rolePol.Policies) > 3 {
Message = "Role " + rolePol.RoleName + " can elevate rights with " + fmt.Sprint(rolePol.Policies[len(rolePol.Policies)-3:]) + " only last 3 policies"
} else {
Message = "Role " + rolePol.RoleName + " can elevate rights with " + fmt.Sprint(rolePol.Policies)
}
result := commons.Result{Status: "FAIL", Message: Message, ResourceID: rolePol.RoleName}
check.AddResult(result)

} else {
Message := "Role " + rolePol.RoleName + " cannot elevate rights"
result := commons.Result{Status: "OK", Message: Message, ResourceID: rolePol.RoleName}
check.AddResult(result)
}
}
checkConfig.Queue <- check
}

func CheckPolicyForAllowInRequiredPermission(policies []Policy, requiredPermission [][]string) [][]string {
// Extract all allow statements from policy
allowStatements := make([]Statement, 0)
Expand Down
5 changes: 5 additions & 0 deletions aws/iam/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ type UserPolicies struct {
UserName string
Policies []Policy
}

type RolePolicies struct {
RoleName string
Policies []Policy
}
8 changes: 5 additions & 3 deletions aws/iam/userElevationConst.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@ var requiredPermissions = [][]string{
{"iam:UpdateAssumeRolePolicy", "sts:AssumeRole"},
{"iam:PassRole", "lambda:CreateFunction", "lambda:InvokeFunction"},
{"iam:PassRole", "lambda:CreateFunction", "lambda:AddPermission"},
{"iam:PassRole", "lambda:CreateFunction", "lambda:CreateEventSource"},
{"iam:PassRole", "lambda:CreateFunction", "lambda:CreateEventSourceMapping"},
{"lambda:UpdateFunctionCode"},
{"iam:PassRole", "glue:CreateDevEndpoint"},
{"glue:UpdateDevEndpoint"},
{"iam:PassRole", "cloudformation:CreateStack"},
{"iam:PassRole", "datapipeline:CreatePipeline", "datapipeline:PutPipeline"},
{"codestar:CreateProjectFromTemplate", "iam:PassRole"},
{"iam:PassRole", "datapipeline:CreatePipeline", "datapipeline:PutPipelineDefinition", "datapipeline:ActivatePipeline"},
{"codestar:CreateProjectFromTemplate"},
{"codestar:CreateProject", "iam:PassRole"},
{"codestar:CreateProject", "codeStar:AssociateTeamMember"},
{"lambda:UpdateFunctionConfiguration"},
{"sagemaker:CreateNotebookInstance", "sagemaker:CreatePresignedNotebookInstanceUrl", "iam:PassRole"},
{"sagemaker:CreatePresignedNotebookInstanceUrl"},
{"iam:PassRole", "glue:CreateJob"},
{"iam:PassRole", "glue:UpdateJob"},
}

0 comments on commit d1a9607

Please sign in to comment.