Skip to content

Commit

Permalink
Merging with main + minor updates
Browse files Browse the repository at this point in the history
  • Loading branch information
wdahlenburg committed Nov 16, 2023
2 parents 17011f3 + f51c1e9 commit 5eff1c7
Show file tree
Hide file tree
Showing 161 changed files with 10,490 additions and 3,110 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/autorelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ jobs:

steps:

- name: Go 1.20
uses: actions/setup-go@v2
- name: Go 1.21
uses: actions/setup-go@v4
with:
go-version: ^1.20
id: go
Expand All @@ -28,7 +28,7 @@ jobs:
gpg --list-secret-keys --keyid-format LONG
- name: Check Out Code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/codespell.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This Action uses minimal steps to run in ~5 seconds to rapidly:
# Looks for typos in the codebase using codespell
# https://github.com/codespell-project/codespell#readme
name: codespell
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install --user codespell
- run: codespell --ignore-words-list="aks" # --skip="*.css,*.js,*.lock,*.po"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,5 @@ cloudfox
*.txt
*.json
*.csv
*.log
*.log
dist/
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ CloudFox helps you gain situational awareness in unfamiliar cloud environments.

## Demos, Examples, Walkthroughs
* [Blog - Introducing: CloudFox](https://bishopfox.com/blog/introducing-cloudfox)
* [Video - Penetration Testing with CloudFox](https://www.youtube.com/watch?v=Ljt_JUp5HbM)
* [Video - CloudFox Intro Demos](https://www.youtube.com/watch?v=ReWoUgpUuiQ)
* [Video - Tool Talk: CloudFox AWS sub-command walkthroughs](https://youtu.be/KKsYfL5uVU4?t=360)
* [Video - Tool Talk: CloudFox AWS sub-command walkthroughs](https://youtu.be/KKsYfL5uVU4?t=360)

## Intentionally Vulnerable Playground
* [CloudFoxable - A Gamified Cloud Hacking Sandbox](https://cloudfoxable.bishopfox.com/)

## Quick Start
CloudFox is modular (you can run one command at a time), but there is an `aws all-checks` command that will run the other aws commands for you with sane defaults:
Expand Down Expand Up @@ -49,11 +53,18 @@ For the full documentation please refer to our [wiki](https://github.com/BishopF

**Option 1:** Download the [latest binary release](https://github.com/BishopFox/cloudfox/releases) for your platform.

**Option 2:** [Install Go](https://golang.org/doc/install), clone the CloudFox repository and compile from source
**Option 2:** If you use homebrew: `brew install cloudfox`

**Option 3:** [Install Go](https://golang.org/doc/install), use `go install github.com/BishopFox/cloudfox@latest` to install from the remote source

**Option 4:** Developer mode:

[Install Go](https://golang.org/doc/install), clone the CloudFox repository and compile from source
```
# git clone https://github.com/BishopFox/cloudfox.git
...omitted for brevity...
# cd ./cloudfox
# Make any changes necessary
# go build .
# ./cloudfox
```
Expand All @@ -64,7 +75,7 @@ For the full documentation please refer to our [wiki](https://github.com/BishopF
### AWS
* AWS CLI installed
* Supports AWS profiles, AWS environment variables, or metadata retrieval (on an ec2 instance)
* To run commands on multiple profiles at once, you can specify the path to a file with a list of profile names seperated by a new line using the `-l` flag or pass all stored profiles with the `-a` flag.
* To run commands on multiple profiles at once, you can specify the path to a file with a list of profile names separated by a new line using the `-l` flag or pass all stored profiles with the `-a` flag.
* A principal with one recommended policies attached (described below)
* Recommended attached policies: **`SecurityAudit` + [CloudFox custom policy](./misc/aws/cloudfox-policy.json)**

Expand Down Expand Up @@ -138,7 +149,7 @@ CloudFox doesn't create any alerts or findings, and doesn't check your environme

**Why do I see errors in some CloudFox commands?**

* Services that don't exist in all regions - CloudFox tries a few ways to figure out what services are supported in each region. However some services don't support the methods CloudFox uses, so CloudFox defaults to just asking every region about the service. Regions that don't suppor the service will return errors.
* Services that don't exist in all regions - CloudFox tries a few ways to figure out what services are supported in each region. However some services don't support the methods CloudFox uses, so CloudFox defaults to just asking every region about the service. Regions that don't support the service will return errors.
* You don't have permission - Another reason you might see errors if you don't have permissions to make calls that CloudFox is making. Either because the policy doesn't allow it (e.g., SecurityAudit doesn't allow all of the permissions CloudFox needs. Or, it might be an SCP that is blocking you.

You can always look in the ~/.cloudfox/cloudfox-error.log file to get more information on errors.
Expand Down
46 changes: 37 additions & 9 deletions aws/access-keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"strconv"
"strings"

"github.com/BishopFox/cloudfox/aws/sdk"
"github.com/BishopFox/cloudfox/internal"
Expand All @@ -18,9 +19,10 @@ type AccessKeysModule struct {
IAMClient sdk.AWSIAMClientInterface
Caller sts.GetCallerIdentityOutput
AWSProfile string
OutputFormat string
Goroutines int
WrapTable bool
AWSOutputType string
AWSTableCols string
CommandCounter internal.CommandCounter

// Main module data
Expand All @@ -36,8 +38,8 @@ type UserKeys struct {
Key string
}

func (m *AccessKeysModule) PrintAccessKeys(filter string, outputFormat string, outputDirectory string, verbosity int) {
// These stuct values are used by the output module
func (m *AccessKeysModule) PrintAccessKeys(filter string, outputDirectory string, verbosity int) {
// These struct values are used by the output module
m.output.Verbosity = verbosity
m.output.Directory = outputDirectory
m.output.CallingModule = "access-keys"
Expand All @@ -55,6 +57,7 @@ func (m *AccessKeysModule) PrintAccessKeys(filter string, outputFormat string, o

// Variables used to draw table output
m.output.Headers = []string{
"Account",
"User Name",
"Access Key ID",
}
Expand All @@ -65,6 +68,7 @@ func (m *AccessKeysModule) PrintAccessKeys(filter string, outputFormat string, o
m.output.Body = append(
m.output.Body,
[]string{
aws.ToString(m.Caller.Account),
key.Username,
key.Key,
},
Expand All @@ -79,20 +83,44 @@ func (m *AccessKeysModule) PrintAccessKeys(filter string, outputFormat string, o
//fmt.Printf("[%s][%s] Preparing output.\n\n")

m.output.FilePath = filepath.Join(outputDirectory, "cloudfox-output", "aws", fmt.Sprintf("%s-%s", m.AWSProfile, aws.ToString(m.Caller.Account)))
//m.output.OutputSelector(outputFormat)
//utils.OutputSelector(verbosity, outputFormat, m.output.Headers, m.output.Body, m.output.FilePath, m.output.CallingModule, m.output.CallingModule)
//internal.OutputSelector(verbosity, outputFormat, m.output.Headers, m.output.Body, m.output.FilePath, m.output.CallingModule, m.output.CallingModule, m.WrapTable, m.AWSProfile)
o := internal.OutputClient{
Verbosity: verbosity,
CallingModule: m.output.CallingModule,
Table: internal.TableClient{
Wrap: m.WrapTable,
},
}

// If the user specified table columns, use those.
// If the user specified -o wide, use the wide default cols for this module.
// Otherwise, use the hardcoded default cols for this module.
var tableCols []string
// If the user specified table columns, use those.
if m.AWSTableCols != "" {
// remove any spaces between any commas and the first letter after the commas
m.AWSTableCols = strings.ReplaceAll(m.AWSTableCols, ", ", ",")
m.AWSTableCols = strings.ReplaceAll(m.AWSTableCols, ", ", ",")
tableCols = strings.Split(m.AWSTableCols, ",")
// If the user specified wide as the output format, use these columns.
} else if m.AWSOutputType == "wide" {
tableCols = []string{
"Account",
"User Name",
"Access Key ID",
}
// Otherwise, use the default columns.
} else {
tableCols = []string{
"User Name",
"Access Key ID",
}
}

o.Table.TableFiles = append(o.Table.TableFiles, internal.TableFile{
Header: m.output.Headers,
Body: m.output.Body,
Name: m.output.CallingModule,
Header: m.output.Headers,
Body: m.output.Body,
TableCols: tableCols,
Name: m.output.CallingModule,
})
o.PrefixIdentifier = m.AWSProfile
o.Table.DirectoryName = filepath.Join(outputDirectory, "cloudfox-output", "aws", fmt.Sprintf("%s-%s", m.AWSProfile, aws.ToString(m.Caller.Account)))
Expand Down
39 changes: 24 additions & 15 deletions aws/api-gws.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,18 @@ import (
"github.com/sirupsen/logrus"
)

var CURL_COMMAND string = "curl -k -X %s %s"
var CURL_COMMAND string = "curl -X %s %s"

type ApiGwModule struct {
// General configuration data
APIGatewayClient *apigateway.Client
APIGatewayv2Client *apigatewayv2.Client

Caller sts.GetCallerIdentityOutput
AWSRegions []string
OutputFormat string
Goroutines int
AWSProfile string
WrapTable bool
Caller sts.GetCallerIdentityOutput
AWSRegions []string
Goroutines int
AWSProfile string
WrapTable bool

// Main module data
Gateways []ApiGateway
Expand All @@ -55,7 +54,7 @@ type ApiGateway struct {
Method string
}

func (m *ApiGwModule) PrintApiGws(outputFormat string, outputDirectory string, verbosity int) {
func (m *ApiGwModule) PrintApiGws(outputDirectory string, verbosity int) {
// These stuct values are used by the output module
m.output.Verbosity = verbosity
m.output.Directory = outputDirectory
Expand Down Expand Up @@ -131,10 +130,7 @@ func (m *ApiGwModule) PrintApiGws(outputFormat string, outputDirectory string, v
}
if len(m.output.Body) > 0 {
m.output.FilePath = filepath.Join(outputDirectory, "cloudfox-output", "aws", fmt.Sprintf("%s-%s", m.AWSProfile, aws.ToString(m.Caller.Account)))
//m.output.OutputSelector(outputFormat)
//utils.OutputSelector(verbosity, outputFormat, m.output.Headers, m.output.Body, m.output.FilePath, m.output.CallingModule, m.output.CallingModule)
//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)

o := internal.OutputClient{
Verbosity: verbosity,
CallingModule: m.output.CallingModule,
Expand Down Expand Up @@ -218,12 +214,25 @@ func (m *ApiGwModule) writeLoot(outputDirectory string, verbosity int) {
var out string

for _, endpoint := range m.Gateways {
line := fmt.Sprintf(CURL_COMMAND, endpoint.Method, endpoint.Endpoint)
method := endpoint.Method
// Write a GET and POST for ANY
if endpoint.Method == "ANY" {
line := fmt.Sprintf(CURL_COMMAND, "GET", endpoint.Endpoint)
if endpoint.ApiKey != "" {
line += fmt.Sprintf(" -H 'X-Api-Key: %s'", endpoint.ApiKey)
}

out += line + "\n"

method = "POST"
}

line := fmt.Sprintf(CURL_COMMAND, method, endpoint.Endpoint)
if endpoint.ApiKey != "" {
line += fmt.Sprintf(" -H 'X-Api-Key: %s'", endpoint.ApiKey)
}

if endpoint.Method == "DELETE" || endpoint.Method == "PATCH" || endpoint.Method == "POST" || endpoint.Method == "PUT" {
if method == "DELETE" || method == "PATCH" || method == "POST" || method == "PUT" {
line += " -H 'Content-Type: application/json' -d '{}'"
}

Expand All @@ -239,7 +248,7 @@ func (m *ApiGwModule) writeLoot(outputDirectory string, verbosity int) {

if verbosity > 2 {
fmt.Println()
fmt.Printf("[%s][%s] %s \n", cyan(m.output.CallingModule), cyan(m.AWSProfile), green("Feed this endpoints into nmap and something like gowitness/aquatone for screenshots."))
fmt.Printf("[%s][%s] %s \n", cyan(m.output.CallingModule), cyan(m.AWSProfile), green("Send these requests through your favorite interception proxy"))
fmt.Print(out)
fmt.Printf("[%s][%s] %s \n\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), green("End of loot file."))
}
Expand Down
Loading

0 comments on commit 5eff1c7

Please sign in to comment.