initial draft of the orgs command

This commit is contained in:
sethsec-bf committed 2023-03-30 07:35:48 -04:00
1 parent 7490d1aaa1
commit 0276ce25a4
5 files changed
+232 -5

No files matched your search

+179
View File
@@ -0,0 +1,179 @@
package aws
import (
"context"
"fmt"
"path/filepath"
"strconv"
"github.com/BishopFox/cloudfox/internal"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/organizations"
"github.com/aws/aws-sdk-go-v2/service/organizations/types"
"github.com/aws/aws-sdk-go-v2/service/sts"
"github.com/sirupsen/logrus"
)
type OrgModule struct {
OrganizationsClient *organizations.Client
Caller sts.GetCallerIdentityOutput
AWSRegions []string
OutputFormat string
Goroutines int
AWSProfile string
SkipAdminCheck bool
WrapTable bool
// Main module data
Accounts []Account
CommandCounter internal.CommandCounter
// Used to store output data for pretty printing
output internal.OutputData2
modLog *logrus.Entry
}
type OrganizationsClientInterface interface {
ListAccounts(ctx context.Context, params *organizations.ListAccountsInput, optFns ...func(*organizations.Options)) (*organizations.ListAccountsOutput, error)
}
type Account struct {
isManagementAccount bool
Name string
Id string
Email string
Arn string
Status string
}
func (m *OrgModule) PrintOrgAccounts(outputFormat string, outputDirectory string, verbosity int) {
// These stuct values are used by the output module
m.output.Verbosity = verbosity
m.output.Directory = outputDirectory
m.output.CallingModule = "org"
m.modLog = internal.TxtLog.WithFields(logrus.Fields{
"module": m.output.CallingModule,
})
if m.AWSProfile == "" {
m.AWSProfile = internal.BuildAWSPath(m.Caller)
}
fmt.Printf("[%s][%s] Checking if account %s is the management account in an organization %s.\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), aws.ToString(m.Caller.Account))
// wg := new(sync.WaitGroup)
// semaphore := make(chan struct{}, m.Goroutines)
// // Create a channel to signal the spinner aka task status goroutine to finish
// spinnerDone := make(chan bool)
// //fire up the the task status spinner/updated
// go internal.SpinUntil(m.output.CallingModule, &m.CommandCounter, spinnerDone, "tasks")
// //create a channel to receive the objects
// dataReceiver := make(chan Project)
// // Create a channel to signal to stop
// receiverDone := make(chan bool)
// go m.Receiver(dataReceiver, receiverDone)
// // for _, region := range m.AWSRegions {
// // wg.Add(1)
// // m.CommandCounter.Pending++
// // go m.executeChecks(region, wg, semaphore, dataReceiver)
// // }
// wg.Wait()
// // Send a message to the spinner goroutine to close the channel and stop
// spinnerDone <- true
// <-spinnerDone
// receiverDone <- true
// <-receiverDone
m.addOrgAccounts()
m.output.Headers = []string{
"Name",
"ID",
"isManagementAccount?",
"Status",
"Email",
}
// Table rows
for i := range m.Accounts {
m.output.Body = append(
m.output.Body,
[]string{
m.Accounts[i].Name,
m.Accounts[i].Id,
strconv.FormatBool(m.Accounts[i].isManagementAccount),
m.Accounts[i].Status,
m.Accounts[i].Email,
},
)
}
if len(m.output.Body) > 0 {
m.output.FilePath = filepath.Join(outputDirectory, "cloudfox-output", "aws", m.AWSProfile)
internal.OutputSelector(verbosity, outputFormat, m.output.Headers, m.output.Body, m.output.FilePath, m.output.CallingModule, m.output.CallingModule, m.WrapTable, m.AWSProfile)
//m.writeLoot(m.output.FilePath, verbosity)
fmt.Printf("[%s][%s] %d accounts found.\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), len(m.output.Body))
fmt.Printf("[%s][%s] For context and next steps: https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#%s\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), m.output.CallingModule)
} else {
fmt.Printf("[%s][%s] No accounts found, skipping the creation of an output file.\n", cyan(m.output.CallingModule), cyan(m.AWSProfile))
}
}
func (m *OrgModule) addOrgAccounts() {
accounts, err := m.listAccounts()
if err != nil {
m.modLog.Errorf("Failed to list accounts: %s", err)
return
}
for _, account := range accounts {
m.Accounts = append(m.Accounts, Account{
isManagementAccount: false,
Name: aws.ToString(account.Name),
Id: aws.ToString(account.Id),
Email: aws.ToString(account.Email),
Arn: aws.ToString(account.Arn),
Status: string(account.Status),
})
}
}
func (m *OrgModule) listAccounts() ([]types.Account, error) {
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
var PaginationControl *string
var accounts []types.Account
for {
ListAccounts, err := m.OrganizationsClient.ListAccounts(
context.TODO(),
&organizations.ListAccountsInput{
NextToken: PaginationControl,
},
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
break
}
accounts = append(accounts, ListAccounts.Accounts...)
if ListAccounts.NextToken != nil {
PaginationControl = ListAccounts.NextToken
} else {
PaginationControl = nil
break
}
}
return accounts, nil
}
+29
View File
@@ -31,6 +31,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/lightsail"
"github.com/aws/aws-sdk-go-v2/service/mq"
"github.com/aws/aws-sdk-go-v2/service/opensearch"
"github.com/aws/aws-sdk-go-v2/service/organizations"
"github.com/aws/aws-sdk-go-v2/service/ram"
"github.com/aws/aws-sdk-go-v2/service/rds"
"github.com/aws/aws-sdk-go-v2/service/redshift"
@@ -272,6 +273,16 @@ var (
Run: runOutboundAssumedRolesCommand,
}
OrgsCommand = &cobra.Command{
Use: "orgs",
Aliases: []string{"org", "organizations", "accounts", "account"},
Short: "Enumerate accounts in an organization",
Long: "\nUse case examples:\n" +
os.Args[0] + " aws orgs --profile readonly_profile",
PreRun: awsPreRun,
Run: runOrgsCommand,
}
PermissionsPrincipal string
PermissionsCommand = &cobra.Command{
Use: "permissions",
@@ -457,6 +468,7 @@ func init() {
NetworkPortsCommand,
PmapperCommand,
ResourceTrustsCommand,
OrgsCommand,
)
}
@@ -864,6 +876,23 @@ func runOutboundAssumedRolesCommand(cmd *cobra.Command, args []string) {
}
}
func runOrgsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version)
if err != nil {
continue
}
m := aws.OrgModule{
OrganizationsClient: organizations.NewFromConfig(AWSConfig),
Caller: *caller,
AWSProfile: profile,
WrapTable: AWSWrapTable,
}
m.PrintOrgAccounts(AWSOutputFormat, AWSOutputDirectory, Verbosity)
}
}
func runPermissionsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version)
+4 -3
View File
@@ -10,7 +10,7 @@ require (
github.com/Azure/go-autorest/autorest v0.11.28
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
github.com/aquasecurity/table v1.8.0
github.com/aws/aws-sdk-go-v2 v1.17.5
github.com/aws/aws-sdk-go-v2 v1.17.7
github.com/aws/aws-sdk-go-v2/config v1.18.3
github.com/aws/aws-sdk-go-v2/service/apigateway v1.15.25
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.12.23
@@ -75,8 +75,8 @@ require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.3 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 // indirect
github.com/aws/aws-sdk-go-v2/service/codebuild v1.20.5 // indirect
@@ -85,6 +85,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.19 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect
github.com/aws/aws-sdk-go-v2/service/organizations v1.19.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
+8
View File
@@ -88,6 +88,8 @@ github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/Pg
github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2 v1.17.5 h1:TzCUW1Nq4H8Xscph5M/skINUitxM5UBAyvm2s7XBzL4=
github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg=
github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 h1:RKci2D7tMwpvGpDNZnGQw9wk6v7o/xSwFcUAuNPoB8k=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9/go.mod h1:vCmV1q1VK8eoQJ5+aYE7PkK1K6v41qJ5pJdK3ggCDvg=
github.com/aws/aws-sdk-go-v2/config v1.18.3 h1:3kfBKcX3votFX84dm00U8RGA1sCCh3eRMOGzg5dCWfU=
@@ -101,11 +103,15 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQ
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 h1:9/aKwwus0TQxppPXFmf010DFrE+ssSbzroLVYINA+xE=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 h1:5NbbMrIzmUn/TXFqAle6mgrH5m9cOvMLRGL7pnG8tRE=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 h1:b/Vn141DBuLVgXbhRWIrl9g+ww7G+ScV5SzniWR13jQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 h1:2EXB7dtGwRYIN3XQ9qwIW504DVbKIw3r89xQnonGdsQ=
@@ -168,6 +174,8 @@ github.com/aws/aws-sdk-go-v2/service/mq v1.13.15 h1:K0UbxNfaPHoIXo0T4L4jrbE+TKcV
github.com/aws/aws-sdk-go-v2/service/mq v1.13.15/go.mod h1:ycghPMXYItx5Y74iehFgGwDNUMXdq0xCxLaYC5uYZO0=
github.com/aws/aws-sdk-go-v2/service/opensearch v1.11.3 h1:ViGcWux+UbkS/JBLxPILq/Mevlf9RXSycGlPaVQON5Y=
github.com/aws/aws-sdk-go-v2/service/opensearch v1.11.3/go.mod h1:7mh4ks7MsQUuhHFCr10LIF9gKVS+0yylPUmCEM/kzJE=
github.com/aws/aws-sdk-go-v2/service/organizations v1.19.2 h1:8tikveMqrEqTIyMcevyeFNASIkffCuwuV+DAkMiXm8g=
github.com/aws/aws-sdk-go-v2/service/organizations v1.19.2/go.mod h1:MTKfY5PMwGkG9+tK451UCUpDm5jo1uyJwUkkvn7G1p4=
github.com/aws/aws-sdk-go-v2/service/ram v1.16.24 h1:pzB33ZEhd1szVKHkgYe4cXQ+kSLJEFGBLy+IpbAKY9Y=
github.com/aws/aws-sdk-go-v2/service/ram v1.16.24/go.mod h1:el3+/AiwdwKk5qZEcCQqm+t3b1A5QLZI2nr/OkhM/gc=
github.com/aws/aws-sdk-go-v2/service/rds v1.31.0 h1:lx8pflhN7oogISvAorwqPGFHN7eiVlGEwk21ThYcyoA=
+12 -2
View File
@@ -11,6 +11,9 @@
"cloudformation:ListStacks",
"cloudtrail:LookupEvents",
"cloudfront:ListDistributions",
"codebuild:ListProjects",
"codebuild:BatchGetProjects",
"codebuild:GetResourcePolicy",
"dynamodb:ListTables",
"ec2:DescribeInstanceAttribute",
"ec2:DescribeInstances",
@@ -21,7 +24,7 @@
"ecs:DescribeTaskDefinition",
"ecs:ListClusters",
"ecs:ListTaskDefinitions",
"ecs:ListTasks",
"ecs:ListTasks",
"eks:DescribeCluster",
"eks:DescribeNodegroup",
"eks:ListClusters",
@@ -47,11 +50,13 @@
"iam:ListRoles",
"iam:SimulatePrincipalPolicy",
"lambda:GetFunctionUrlConfig",
"lambda:ListFunctions",
"lambda:ListFunctions",
"lambda:GetPolicy",
"lightsail:GetContainerServices",
"lightsail:GetInstances",
"mq:DescribeBroker",
"mq:ListBrokers",
"organizations:ListAccounts",
"es:DescribeDomain",
"es:ListDomainNames",
"ram:GetResourceShares",
@@ -63,6 +68,9 @@
"s3:GetBucketPolicyStatus",
"s3:GetBucketWebsite",
"s3:ListAllMyBuckets",
"s3:GetAccountPublicAccessBlock",
"s3:GetBucketLocation",
"s3:GetBucketPolicy",
"ssm:DescribeParameters",
"sagemaker:ListProcessingJobs",
"sagemaker:DescribeProcessingJob",
@@ -74,7 +82,9 @@
"sagemaker:DescribeModel",
"secretsmanager:ListSecrets",
"sns:ListTopics",
"sns:GetTopicAttributes",
"sqs:ListQueues",
"sqs:GetQueueAttributes",
"tag:GetResources"
],