├── README.md ├── internal └── runner │ ├── doc.go │ ├── banner.go │ ├── options.go │ └── runner.go ├── .gitignore ├── biid ├── intercept_windows.go ├── intercept.go └── intercept_unix.go ├── util.go ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── workflows │ ├── lint-test.yml │ ├── build-test.yml │ ├── codeql-analysis.yml │ └── release-binary.yml └── dependabot.yml ├── pkg └── types │ ├── types.go │ └── default.go ├── .goreleaser ├── linux.yml ├── mac.yml └── windows.yml ├── go.mod ├── LICENSE.md ├── cmd ├── intercept │ └── intercept.go └── collab │ └── collab.go ├── burp.go └── go.sum /README.md: -------------------------------------------------------------------------------- 1 | # collaborator 2 | BurpSuite Standard/Private Collaborator Library 3 | -------------------------------------------------------------------------------- /internal/runner/doc.go: -------------------------------------------------------------------------------- 1 | // Package runner contains the internal logic 2 | package runner 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cmd/collab/collab 2 | cmd/intercept/intercept 3 | cacert.pem 4 | cakey.pem 5 | vendor -------------------------------------------------------------------------------- /biid/intercept_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package biid 4 | 5 | // requires root 6 | func dumpBIID(stop *bool) string { 7 | return "" 8 | } 9 | -------------------------------------------------------------------------------- /util.go: -------------------------------------------------------------------------------- 1 | package collaborator 2 | 3 | import ( 4 | "encoding/base64" 5 | ) 6 | 7 | func Base64Encode(str string) string { 8 | return base64.StdEncoding.EncodeToString([]byte(str)) 9 | } 10 | 11 | func Base64Decode(str string) (string, error) { 12 | data, err := base64.StdEncoding.DecodeString(str) 13 | if err != nil { 14 | return "", err 15 | } 16 | return string(data), nil 17 | } 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[Bug] " 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 | 16 | **Screenshots** 17 | If applicable, add screenshots to help explain your problem. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[feature] " 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 | -------------------------------------------------------------------------------- /.github/workflows/lint-test.yml: -------------------------------------------------------------------------------- 1 | name: 🙏🏻 Lint Test 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | lint: 9 | name: Lint Test 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | 15 | - name: Run golangci-lint 16 | uses: golangci/golangci-lint-action@v2 17 | with: 18 | version: latest 19 | args: --timeout 5m 20 | working-directory: . -------------------------------------------------------------------------------- /pkg/types/types.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Options struct { 4 | BIID string `yaml:"burp_biid,omitempty"` 5 | 6 | Verbose bool `yaml:"verbose,omitempty"` 7 | Silent bool `yaml:"silent,omitempty"` 8 | Version bool `yaml:"version,omitempty"` 9 | Interval int `yaml:"interval,omitempty"` 10 | 11 | HTTPMessage string `yaml:"http_message,omitempty"` 12 | DNSMessage string `yaml:"dns_message,omitempty"` 13 | CLIMessage string `yaml:"cli_message,omitempty"` 14 | SMTPMessage string `yaml:"smtp_message,omitempty"` 15 | } 16 | -------------------------------------------------------------------------------- /pkg/types/default.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | const ( 4 | DefaultHTTPMessage = "The collaborator server received an {{protocol}} request from {{from}} at {{time}}:\n```\n{{request}}\n{{response}}```" 5 | DefaultDNSMessage = "The collaborator server received a DNS lookup of type {{type}} for the domain name {{domain}} from {{from}} at {{time}}:\n```{{request}}```" 6 | DefaultSMTPMessage = "The collaborator server received an SMTP connection from IP address {{from}} at {{time}}\n\nThe email details were:\n\nFrom:\n{{sender}}\n\nTo:\n{{recipients}}\n\nMessage:\n{{message}}\n\nSMTP Conversation:\n{{conversation}}" 7 | DefaultCLIMessage = "{{data}}" 8 | ) 9 | -------------------------------------------------------------------------------- /.goreleaser/linux.yml: -------------------------------------------------------------------------------- 1 | env: 2 | - GO111MODULE=on 3 | before: 4 | hooks: 5 | - go mod tidy 6 | project_name: intercept 7 | builds: 8 | - id: intercept-linux 9 | ldflags: 10 | - -s -w 11 | binary: intercept 12 | env: 13 | - CGO_ENABLED=1 14 | main: cmd/intercept/intercept.go 15 | goos: 16 | - linux 17 | goarch: 18 | - amd64 19 | - id: collab-linux 20 | ldflags: 21 | - -s -w 22 | binary: collab 23 | env: 24 | - CGO_ENABLED=1 25 | main: cmd/collab/collab.go 26 | goos: 27 | - linux 28 | goarch: 29 | - amd64 30 | archives: 31 | - format: zip 32 | 33 | checksum: 34 | name_template: "{{ .ProjectName }}-linux-checksums.txt" 35 | -------------------------------------------------------------------------------- /.goreleaser/mac.yml: -------------------------------------------------------------------------------- 1 | env: 2 | - GO111MODULE=on 3 | before: 4 | hooks: 5 | - go mod tidy 6 | project_name: intercept 7 | builds: 8 | - id: intercept-darwin 9 | ldflags: 10 | - -s -w 11 | binary: intercept 12 | env: 13 | - CGO_ENABLED=1 14 | main: cmd/intercept/intercept.go 15 | goos: 16 | - darwin 17 | goarch: 18 | - amd64 19 | - id: collab-darwin 20 | ldflags: 21 | - -s -w 22 | binary: collab 23 | env: 24 | - CGO_ENABLED=1 25 | main: cmd/collab/collab.go 26 | goos: 27 | - darwin 28 | goarch: 29 | - amd64 30 | 31 | archives: 32 | - format: zip 33 | replacements: 34 | darwin: macOS 35 | 36 | checksum: 37 | name_template: "{{ .ProjectName }}-mac-checksums.txt" 38 | -------------------------------------------------------------------------------- /internal/runner/banner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "github.com/projectdiscovery/gologger" 5 | ) 6 | 7 | const banner = ` 8 | ____ __ 9 | _________ / / /___ / /_ 10 | / ___/ __ \/ / / __ \/ __ \ 11 | / /__/ /_/ / / / /_/ / /_/ / 12 | \___/\____/_/_/\__,_/_.___/ 0.0.3 13 | ` 14 | 15 | // Version is the current version 16 | const Version = `0.0.3` 17 | 18 | // showBanner is used to show the banner to the user 19 | func showBanner() { 20 | gologger.Print().Msgf("%s\n", banner) 21 | gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n") 22 | 23 | gologger.Print().Msgf("Use with caution. You are responsible for your actions\n") 24 | gologger.Print().Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n") 25 | } 26 | -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: 🔨 Build Test 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | 8 | jobs: 9 | build: 10 | name: Build Test 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Set up Go 14 | uses: actions/setup-go@v2 15 | with: 16 | go-version: 1.17 17 | 18 | - name: Install libpcap-dev 19 | run: sudo apt install libpcap-dev 20 | 21 | - name: Check out code 22 | uses: actions/checkout@v2 23 | 24 | - name: Test 25 | run: go test ./... 26 | working-directory: . 27 | 28 | - name: Build Intercept 29 | run: go build . 30 | working-directory: cmd/intercept/ 31 | 32 | - name: Build Collab 33 | run: go build . 34 | working-directory: cmd/collab/ 35 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | 9 | # Maintain dependencies for GitHub Actions 10 | - package-ecosystem: "github-actions" 11 | directory: "/" 12 | schedule: 13 | interval: "weekly" 14 | target-branch: "dev" 15 | commit-message: 16 | prefix: "chore" 17 | include: "scope" 18 | 19 | # Maintain dependencies for go modules 20 | - package-ecosystem: "gomod" 21 | directory: "/" 22 | schedule: 23 | interval: "weekly" 24 | target-branch: "dev" 25 | commit-message: 26 | prefix: "chore" 27 | include: "scope" -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/projectdiscovery/collaborator 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/google/gopacket v1.1.19 7 | github.com/miekg/dns v1.1.43 8 | github.com/projectdiscovery/goflags v0.0.5 9 | github.com/projectdiscovery/gologger v1.1.4 10 | github.com/projectdiscovery/retryablehttp-go v1.0.2 11 | golang.org/x/net v0.0.0-20211008194852-3b03d305991f // indirect 12 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect 13 | golang.org/x/text v0.3.7 // indirect 14 | ) 15 | 16 | require ( 17 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect 18 | github.com/json-iterator/go v1.1.10 // indirect 19 | github.com/logrusorgru/aurora v2.0.3+incompatible // indirect 20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 21 | github.com/modern-go/reflect2 v1.0.1 // indirect 22 | github.com/pkg/errors v0.9.1 // indirect 23 | gopkg.in/yaml.v2 v2.4.0 // indirect 24 | ) 25 | -------------------------------------------------------------------------------- /.goreleaser/windows.yml: -------------------------------------------------------------------------------- 1 | env: 2 | - GO111MODULE=on 3 | before: 4 | hooks: 5 | - go mod tidy 6 | project_name: intercept 7 | builds: 8 | - id: intercept-windows 9 | ldflags: 10 | - -s -w 11 | binary: intercept 12 | env: 13 | - CGO_ENABLED=1 14 | - CC=x86_64-w64-mingw32-gcc 15 | - CXX=x86_64-w64-mingw32-g++ 16 | main: cmd/intercept/intercept.go 17 | goos: 18 | - windows 19 | goarch: 20 | - amd64 21 | - 386 22 | - arm 23 | - arm64 24 | - id: collab-windows 25 | ldflags: 26 | - -s -w 27 | binary: collab 28 | env: 29 | - CGO_ENABLED=1 30 | - CC=x86_64-w64-mingw32-gcc 31 | - CXX=x86_64-w64-mingw32-g++ 32 | main: cmd/collab/collab.go 33 | goos: 34 | - windows 35 | goarch: 36 | - amd64 37 | - 386 38 | - arm 39 | - arm64 40 | 41 | archives: 42 | - format: zip 43 | 44 | checksum: 45 | name_template: "{{ .ProjectName }}-windows-checksums.txt" 46 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: 🚨 CodeQL Analysis 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | branches: 7 | - dev 8 | 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | runs-on: ubuntu-latest 13 | permissions: 14 | actions: read 15 | contents: read 16 | security-events: write 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | language: [ 'go' ] 22 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 23 | 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v2 27 | 28 | # Initializes the CodeQL tools for scanning. 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v1 31 | with: 32 | languages: ${{ matrix.language }} 33 | 34 | - name: Autobuild 35 | uses: github/codeql-action/autobuild@v1 36 | 37 | - name: Perform CodeQL Analysis 38 | uses: github/codeql-action/analyze@v1 -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ProjectDiscovery, 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 | -------------------------------------------------------------------------------- /cmd/intercept/intercept.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | "time" 10 | 11 | "github.com/projectdiscovery/collaborator/biid" 12 | "github.com/projectdiscovery/gologger" 13 | ) 14 | 15 | // Options to handle intercept 16 | type Options struct { 17 | InterceptBIIDTimeout int 18 | } 19 | 20 | func main() { 21 | var options Options 22 | flag.IntVar(&options.InterceptBIIDTimeout, "intercept-biid-timeout", 600, "Automatic BIID intercept Timeout") 23 | 24 | // Setup close handler 25 | go func() { 26 | c := make(chan os.Signal) 27 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) 28 | go func() { 29 | <-c 30 | fmt.Println("\r- Ctrl+C pressed in Terminal") 31 | os.Exit(0) 32 | }() 33 | }() 34 | 35 | if os.Getuid() != 0 { 36 | gologger.Fatal().Msgf("Intercept needs to run as root to access raw sockets") 37 | } 38 | gologger.Print().Msgf("Attempting to intercept BIID") 39 | // attempt to retrieve biid 40 | interceptedBiid, err := biid.Intercept(time.Duration(options.InterceptBIIDTimeout) * time.Second) 41 | if err != nil { 42 | gologger.Fatal().Msgf("%s", err) 43 | } 44 | if interceptedBiid == "" { 45 | gologger.Fatal().Msgf("BIID not found") 46 | } 47 | gologger.Print().Msgf("BIID found: %s", interceptedBiid) 48 | } 49 | -------------------------------------------------------------------------------- /internal/runner/options.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | 7 | "github.com/projectdiscovery/collaborator/pkg/types" 8 | "github.com/projectdiscovery/gologger" 9 | "github.com/projectdiscovery/gologger/levels" 10 | ) 11 | 12 | // ParseOptions parses the command line flags provided by a user 13 | func ParseOptions(options *types.Options) { 14 | 15 | // Read the inputs and configure the logging 16 | configureOutput(options) 17 | 18 | // Show the user the banner 19 | showBanner() 20 | 21 | if options.Version { 22 | gologger.Info().Msgf("Current Version: %s\n", Version) 23 | os.Exit(0) 24 | } 25 | 26 | // Validate the options passed by the user and if any 27 | // invalid options have been used, exit. 28 | if err := validateOptions(options); err != nil { 29 | gologger.Fatal().Msgf("Program exiting: %s\n", err) 30 | } 31 | } 32 | 33 | // configureOutput configures the output on the screen 34 | func configureOutput(options *types.Options) { 35 | if options.Verbose { 36 | gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose) 37 | } 38 | if options.Silent { 39 | gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent) 40 | } 41 | } 42 | 43 | // validateOptions validates the configuration options passed 44 | func validateOptions(options *types.Options) error { 45 | // Both verbose and silent flags were used 46 | if options.Verbose && options.Silent { 47 | return errors.New("both verbose and silent mode specified") 48 | } 49 | return nil 50 | } 51 | -------------------------------------------------------------------------------- /biid/intercept.go: -------------------------------------------------------------------------------- 1 | package biid 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/google/gopacket" 9 | "github.com/google/gopacket/layers" 10 | ) 11 | 12 | const ( 13 | privateKeyPattern = "burpresults?biid=" 14 | snaplen = 1600 15 | dstPort = 80 16 | ebpFilter = "tcp and dst port 80" 17 | externalIpProbeTarget = "8.8.8.8" 18 | ) 19 | 20 | func extractbiid(data []byte) string { 21 | // just crawl without decoding 22 | begin := bytes.Index(data, []byte(privateKeyPattern)) 23 | if begin > 0 { 24 | begin += len(privateKeyPattern) 25 | end := bytes.Index(data[begin:], []byte(" ")) 26 | if end > 0 { 27 | return string(data[begin : begin+end]) 28 | } 29 | } 30 | 31 | return "" 32 | } 33 | 34 | func Intercept(timeout time.Duration) (string, error) { 35 | c1 := make(chan string, 1) 36 | var stop bool 37 | 38 | go func() { 39 | c1 <- dumpBIID(&stop) 40 | }() 41 | 42 | select { 43 | case biid := <-c1: 44 | return biid, nil 45 | case <-time.After(timeout): 46 | stop = true 47 | return "", fmt.Errorf("Timeout") 48 | } 49 | } 50 | 51 | func checkPacket(packet gopacket.Packet) bool { 52 | if packet == nil { 53 | return false 54 | } 55 | if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP || packet.ApplicationLayer() == nil { 56 | return false 57 | } 58 | 59 | tcp, ok := packet.TransportLayer().(*layers.TCP) 60 | if !ok { 61 | return false 62 | } 63 | if tcp.DstPort != layers.TCPPort(dstPort) { 64 | return false 65 | } 66 | 67 | return true 68 | } 69 | -------------------------------------------------------------------------------- /.github/workflows/release-binary.yml: -------------------------------------------------------------------------------- 1 | name: 🎉 Release Binary 2 | on: 3 | create: 4 | tags: 5 | - v* 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build-mac: 10 | runs-on: macos-latest 11 | steps: 12 | - name: Code checkout 13 | uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | - name: Set up Go 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.17 20 | - name: Install Dependences 21 | run: brew install libpcap 22 | - name: Run GoReleaser 23 | uses: goreleaser/goreleaser-action@v2 24 | with: 25 | version: latest 26 | args: release -f .goreleaser/mac.yml --rm-dist 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | 30 | build-linux: 31 | runs-on: ubuntu-latest 32 | steps: 33 | - name: Code checkout 34 | uses: actions/checkout@v2 35 | with: 36 | fetch-depth: 0 37 | - name: Set up Go 38 | uses: actions/setup-go@v2 39 | with: 40 | go-version: 1.17 41 | - name: Install Dependences 42 | run: sudo apt install libpcap-dev 43 | 44 | - name: Run GoReleaser 45 | uses: goreleaser/goreleaser-action@v2 46 | with: 47 | version: latest 48 | args: release -f .goreleaser/linux.yml --rm-dist 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | 52 | build-windows: 53 | runs-on: windows-latest 54 | steps: 55 | - name: Code checkout 56 | uses: actions/checkout@v2 57 | with: 58 | fetch-depth: 0 59 | - name: Set up Go 60 | uses: actions/setup-go@v2 61 | with: 62 | go-version: 1.17 63 | - name: Run GoReleaser 64 | uses: goreleaser/goreleaser-action@v2 65 | with: 66 | version: latest 67 | args: release -f .goreleaser/windows.yml --rm-dist 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 70 | -------------------------------------------------------------------------------- /cmd/collab/collab.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | 9 | "github.com/projectdiscovery/collaborator/internal/runner" 10 | "github.com/projectdiscovery/collaborator/pkg/types" 11 | "github.com/projectdiscovery/goflags" 12 | "github.com/projectdiscovery/gologger" 13 | ) 14 | 15 | var ( 16 | cfgFile string 17 | options = &types.Options{} 18 | ) 19 | 20 | func main() { 21 | readConfig() 22 | 23 | runner.ParseOptions(options) 24 | 25 | collabRunner, err := runner.NewRunner(options) 26 | if err != nil { 27 | gologger.Fatal().Msgf("Could not create runner: %s\n", err) 28 | } 29 | 30 | // Setup close handler 31 | go func() { 32 | c := make(chan os.Signal, 1) 33 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) 34 | go func() { 35 | <-c 36 | fmt.Println("\r- Ctrl+C pressed in Terminal") 37 | collabRunner.Close() 38 | os.Exit(0) 39 | }() 40 | }() 41 | 42 | err = collabRunner.Run() 43 | if err != nil { 44 | gologger.Fatal().Msgf("Could not run collab: %s\n", err) 45 | } 46 | } 47 | 48 | func readConfig() { 49 | set := goflags.NewFlagSet() 50 | set.Marshal = true 51 | set.SetDescription(`Collaborator is a tool to fetch and print the interactions from burp collaborator`) 52 | set.StringVar(&cfgFile, "config", "", "Collaborator configuration file") 53 | set.StringVar(&options.BIID, "biid", "", "burp collaborator unique id") 54 | set.BoolVar(&options.Silent, "silent", false, "Don't print the banner") 55 | set.BoolVar(&options.Version, "version", false, "Show version of collaborator") 56 | set.BoolVar(&options.Verbose, "v", false, "Show Verbose output") 57 | set.IntVar(&options.Interval, "interval", 2, "Polling interval in seconds") 58 | set.StringVar(&options.HTTPMessage, "message-http", types.DefaultHTTPMessage, "HTTP Message") 59 | set.StringVar(&options.DNSMessage, "message-dns", types.DefaultDNSMessage, "DNS Message") 60 | set.StringVar(&options.SMTPMessage, "message-smtp", types.DefaultSMTPMessage, "SMTP Message") 61 | set.StringVar(&options.CLIMessage, "message-cli", types.DefaultCLIMessage, "CLI Message") 62 | 63 | _ = set.Parse() 64 | 65 | if cfgFile != "" { 66 | if err := set.MergeConfigFile(cfgFile); err != nil { 67 | gologger.Fatal().Msgf("Could not read config: %s\n", err) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /biid/intercept_unix.go: -------------------------------------------------------------------------------- 1 | // +build darwin linux 2 | 3 | package biid 4 | 5 | import ( 6 | "fmt" 7 | "net" 8 | "strings" 9 | 10 | "github.com/google/gopacket" 11 | "github.com/google/gopacket/pcap" 12 | ) 13 | 14 | func dumpBIID(stop *bool) string { 15 | var biid string 16 | 17 | sourceIP, err := GetSourceIP(net.ParseIP(externalIpProbeTarget)) 18 | if err != nil { 19 | return "" 20 | } 21 | networkInterface, err := GetInterfaceFromIP(sourceIP) 22 | if err != nil { 23 | return "" 24 | } 25 | 26 | handle, err := pcap.OpenLive(networkInterface.Name, snaplen, true, pcap.BlockForever) 27 | if err != nil { 28 | return "" 29 | } 30 | defer handle.Close() 31 | 32 | err = handle.SetBPFFilter(ebpFilter) 33 | if err != nil { 34 | return "" 35 | } 36 | 37 | packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) 38 | packets := packetSource.Packets() 39 | for { 40 | if *stop { 41 | return biid 42 | } 43 | if biid != "" { 44 | return biid 45 | } 46 | select { 47 | case packet := <-packets: 48 | if !checkPacket(packet) { 49 | continue 50 | } 51 | 52 | applicationLayer := packet.ApplicationLayer() 53 | biid = extractbiid(applicationLayer.Payload()) 54 | } 55 | } 56 | } 57 | 58 | // Code from naabu 59 | func GetSourceIP(dstip net.IP) (net.IP, error) { 60 | serverAddr, err := net.ResolveUDPAddr("udp", dstip.String()+":12345") 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | con, dialUpErr := net.DialUDP("udp", nil, serverAddr) 66 | if dialUpErr != nil { 67 | return nil, dialUpErr 68 | } 69 | 70 | defer con.Close() 71 | if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok { 72 | return udpaddr.IP, nil 73 | } 74 | 75 | return nil, nil 76 | } 77 | 78 | func GetInterfaceFromIP(ip net.IP) (*net.Interface, error) { 79 | address := ip.String() 80 | 81 | interfaces, err := net.Interfaces() 82 | if err != nil { 83 | return nil, err 84 | } 85 | 86 | for _, i := range interfaces { 87 | byNameInterface, err := net.InterfaceByName(i.Name) 88 | if err != nil { 89 | return nil, err 90 | } 91 | 92 | addresses, err := byNameInterface.Addrs() 93 | if err != nil { 94 | return nil, err 95 | } 96 | 97 | for _, v := range addresses { 98 | if strings.HasPrefix(v.String(), address+"/") { 99 | return byNameInterface, nil 100 | } 101 | } 102 | } 103 | 104 | return nil, fmt.Errorf("no interface found for ip %s", address) 105 | } 106 | -------------------------------------------------------------------------------- /internal/runner/runner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | "time" 8 | 9 | "github.com/projectdiscovery/collaborator" 10 | "github.com/projectdiscovery/collaborator/pkg/types" 11 | "github.com/projectdiscovery/gologger" 12 | ) 13 | 14 | // Runner contains the internal logic of the program 15 | type Runner struct { 16 | options *types.Options 17 | burpcollab *collaborator.BurpCollaborator 18 | } 19 | 20 | // NewRunner instance 21 | func NewRunner(options *types.Options) (*Runner, error) { 22 | burpcollab := collaborator.NewBurpCollaborator() 23 | 24 | return &Runner{options: options, burpcollab: burpcollab}, nil 25 | } 26 | 27 | // Run collab polling 28 | func (r *Runner) Run() error { 29 | 30 | // If BIID not passed via cli 31 | if r.options.BIID == "" { 32 | return fmt.Errorf("BIID not specified or not found") 33 | } 34 | 35 | gologger.Print().Msgf("Using BIID: %s", r.options.BIID) 36 | r.burpcollab.AddBIID(r.options.BIID) 37 | 38 | err := r.burpcollab.Poll() 39 | if err != nil { 40 | return err 41 | } 42 | 43 | pollTime := time.Duration(r.options.Interval) * time.Second 44 | for { 45 | time.Sleep(pollTime) 46 | //nolint:errcheck 47 | r.burpcollab.Poll() 48 | 49 | for _, httpresp := range r.burpcollab.RespBuffer { 50 | for i := range httpresp.Responses { 51 | resp := httpresp.Responses[i] 52 | var at int64 53 | var msg string 54 | at, _ = strconv.ParseInt(resp.Time, 10, 64) 55 | atTime := time.Unix(0, at*int64(time.Millisecond)) 56 | switch resp.Protocol { 57 | case "http", "https": 58 | 59 | rr := strings.NewReplacer( 60 | "{{protocol}}", strings.ToUpper(resp.Protocol), 61 | "{{from}}", resp.Client, 62 | "{{time}}", atTime.String(), 63 | "{{request}}", resp.Data.RequestDecoded, 64 | "{{response}}", resp.Data.ResponseDecoded, 65 | ) 66 | msg = rr.Replace(r.options.HTTPMessage) 67 | 68 | case "dns": 69 | rr := strings.NewReplacer( 70 | "{{type}}", resp.Data.RequestType, 71 | "{{domain}} ", resp.Data.SubDomain, 72 | "{{from}}", resp.Client, 73 | "{{time}}", atTime.String(), 74 | "{{request}}", resp.Data.RawRequestDecoded, 75 | ) 76 | msg = rr.Replace(r.options.DNSMessage) 77 | 78 | case "smtp": 79 | rr := strings.NewReplacer( 80 | "{{from}}", resp.Client, 81 | "{{time}}", atTime.String(), 82 | "{{sender}}", resp.Data.SenderDecoded, 83 | "{{recipients}}", strings.Join(resp.Data.RecipientsDecoded, ","), 84 | "{{message}}", resp.Data.MessageDecoded, 85 | "{{conversation}}", resp.Data.ConversationDecoded, 86 | ) 87 | msg = rr.Replace(r.options.SMTPMessage) 88 | } 89 | gologger.Print().Msgf(msg) 90 | } 91 | } 92 | r.burpcollab.Empty() 93 | } 94 | } 95 | 96 | // Close the runner instance 97 | func (r *Runner) Close() { 98 | r.burpcollab.Empty() 99 | } 100 | -------------------------------------------------------------------------------- /burp.go: -------------------------------------------------------------------------------- 1 | package collaborator 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "math/rand" 7 | "sync" 8 | "time" 9 | 10 | "github.com/miekg/dns" 11 | "github.com/projectdiscovery/retryablehttp-go" 12 | ) 13 | 14 | const BURP_URL = "https://polling.burpcollaborator.net/burpresults?biid=" 15 | 16 | type BurpCollaborator struct { 17 | sync.RWMutex 18 | BurpURl string 19 | MaxBufferLimit int 20 | RespBuffer []BurpHTTPResponse 21 | BIIDs map[string]struct{} 22 | Subdomains []string 23 | client *retryablehttp.Client 24 | } 25 | 26 | func NewBurpCollaborator() *BurpCollaborator { 27 | retryablehttp := retryablehttp.NewClient(retryablehttp.DefaultOptionsSingle) 28 | 29 | return &BurpCollaborator{ 30 | BIIDs: make(map[string]struct{}), 31 | client: retryablehttp, 32 | } 33 | } 34 | 35 | func (b *BurpCollaborator) AddSubdomain(subdomain string) { 36 | b.Lock() 37 | defer b.Unlock() 38 | 39 | b.Subdomains = append(b.Subdomains, subdomain) 40 | } 41 | 42 | func (b *BurpCollaborator) AddSubdomains(subdomains []string) { 43 | b.Lock() 44 | defer b.Unlock() 45 | 46 | b.Subdomains = append(b.Subdomains, subdomains...) 47 | } 48 | 49 | func (b *BurpCollaborator) AddBIID(biid string) { 50 | b.Lock() 51 | defer b.Unlock() 52 | 53 | b.BIIDs[biid] = struct{}{} 54 | } 55 | 56 | func (b *BurpCollaborator) AddBIIDs(biids []string) { 57 | for _, biid := range biids { 58 | b.AddBIID(biid) 59 | } 60 | } 61 | 62 | func (b *BurpCollaborator) One() string { 63 | b.RLock() 64 | defer b.RUnlock() 65 | 66 | return b.Subdomains[rand.Intn(len(b.Subdomains))] 67 | } 68 | 69 | func (b *BurpCollaborator) Poll() error { 70 | if b.BurpURl == "" { 71 | b.BurpURl = BURP_URL 72 | } 73 | for biid := range b.BIIDs { 74 | b.poll(biid) 75 | } 76 | 77 | return nil 78 | } 79 | 80 | func (b *BurpCollaborator) PollEach(t time.Duration) { 81 | for range time.Tick(t) { 82 | if len(b.BIIDs) == 0 { 83 | return 84 | } 85 | 86 | b.Poll() 87 | } 88 | } 89 | 90 | func (b *BurpCollaborator) PollById(id string) error { 91 | _, err := b.poll(id) 92 | if err != nil { 93 | return err 94 | } 95 | 96 | return nil 97 | } 98 | 99 | func (b *BurpCollaborator) poll(id string) (*BurpHTTPResponse, error) { 100 | resp, err := b.client.Get(b.BurpURl + id) 101 | if err != nil { 102 | return nil, err 103 | } 104 | 105 | data, err := ioutil.ReadAll(resp.Body) 106 | if err != nil { 107 | return nil, err 108 | } 109 | defer resp.Body.Close() 110 | 111 | var burpHttpResp BurpHTTPResponse 112 | err = json.Unmarshal(data, &burpHttpResp) 113 | if err != nil { 114 | return nil, err 115 | } 116 | 117 | var r *BurpResponse 118 | for i := range burpHttpResp.Responses { 119 | r = &burpHttpResp.Responses[i] 120 | r.Data.RawRequestDecoded, _ = Base64Decode(r.Data.RawRequest) 121 | r.Data.RequestDecoded, _ = Base64Decode(r.Data.Request) 122 | r.Data.ResponseDecoded, _ = Base64Decode(r.Data.Response) 123 | if r.Data.Type > 0 { 124 | r.Data.RequestType = dns.TypeToString[uint16(r.Data.Type)] 125 | } 126 | r.Data.SenderDecoded, _ = Base64Decode(r.Data.Sender) 127 | for _, recipient := range r.Data.Recipients { 128 | recipientbase64Decoded, _ := Base64Decode(recipient) 129 | r.Data.RecipientsDecoded = append(r.Data.RecipientsDecoded, recipientbase64Decoded) 130 | } 131 | r.Data.MessageDecoded, _ = Base64Decode(r.Data.Message) 132 | r.Data.ConversationDecoded, _ = Base64Decode(r.Data.Conversation) 133 | } 134 | 135 | b.Lock() 136 | if b.MaxBufferLimit > 0 && len(b.RespBuffer) >= b.MaxBufferLimit { 137 | // evict oldest response 138 | b.RespBuffer = b.RespBuffer[len(b.RespBuffer)-b.MaxBufferLimit:] 139 | } 140 | b.RespBuffer = append(b.RespBuffer, burpHttpResp) 141 | defer b.Unlock() 142 | 143 | return &burpHttpResp, nil 144 | } 145 | 146 | func (b *BurpCollaborator) Empty() { 147 | b.Lock() 148 | defer b.Unlock() 149 | 150 | b.RespBuffer = make([]BurpHTTPResponse, 0) 151 | } 152 | 153 | type BurpHTTPResponse struct { 154 | Responses []BurpResponse `json:"responses,omitempty"` 155 | } 156 | 157 | type BurpResponse struct { 158 | Protocol string `json:"protocol,omitempty"` 159 | OpCode string `json:"opCode,omitempty"` 160 | InteractionString string `json:"interactionString,omitempty"` 161 | ClientPart string `json:"clientPart,omitempty"` 162 | Data BurpResponseData `json:"data,omitempty"` 163 | Time string `json:"time,omitempty"` 164 | Client string `json:"client,omitempty"` 165 | } 166 | 167 | type BurpResponseData struct { 168 | SubDomain string `json:"subDomain,omitempty"` 169 | Type int `json:"type,omitempty"` 170 | RequestType string 171 | RawRequest string `json:"rawRequest,omitempty"` 172 | RawRequestDecoded string 173 | Request string `json:"request,omitempty"` 174 | RequestDecoded string 175 | Response string `json:"response,omitempty"` 176 | ResponseDecoded string 177 | Sender string `json:"sender,omitempty"` 178 | SenderDecoded string 179 | Recipients []string `json:"recipients,omitempty"` 180 | RecipientsDecoded []string 181 | Message string `json:"message,omitempty"` 182 | MessageDecoded string 183 | Conversation string `json:"conversation,omitempty"` 184 | ConversationDecoded string 185 | } 186 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= 2 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= 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/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= 9 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 10 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= 11 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 12 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 13 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 14 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 15 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 16 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 17 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 18 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 19 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 20 | github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= 21 | github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= 22 | github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= 23 | github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= 24 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 25 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 26 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 27 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 28 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 29 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 30 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 31 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 32 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 33 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 34 | github.com/projectdiscovery/goflags v0.0.5 h1:jI6HD9Z7vkg4C4Cz16BfZKICnIf94W3KFU5M3DcUgUk= 35 | github.com/projectdiscovery/goflags v0.0.5/go.mod h1:Ae1mJ5MIIqjys0lFe3GiMZ10Z8VLaxkYJ1ySA4Zv8HA= 36 | github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI= 37 | github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY= 38 | github.com/projectdiscovery/retryablehttp-go v1.0.1 h1:V7wUvsZNq1Rcz7+IlcyoyQlNwshuwptuBVYWw9lx8RE= 39 | github.com/projectdiscovery/retryablehttp-go v1.0.1/go.mod h1:SrN6iLZilNG1X4neq1D+SBxoqfAF4nyzvmevkTkWsek= 40 | github.com/projectdiscovery/retryablehttp-go v1.0.2 h1:LV1/KAQU+yeWhNVlvveaYFsjBYRwXlNEq0PvrezMV0U= 41 | github.com/projectdiscovery/retryablehttp-go v1.0.2/go.mod h1:dx//aY9V247qHdsRf0vdWHTBZuBQ2vm6Dq5dagxrDYI= 42 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 43 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 44 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 45 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 46 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 47 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 48 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 49 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 50 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 51 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 52 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 53 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= 54 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 55 | golang.org/x/net v0.0.0-20210521195947-fe42d452be8f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 56 | golang.org/x/net v0.0.0-20211008194852-3b03d305991f h1:1scJEYZBaF48BaG6tYbtxmLcXqwYGSfGcMoStTqkkIw= 57 | golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 58 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 59 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= 60 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 61 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 62 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 63 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 64 | golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 65 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 66 | golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= 67 | golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 68 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw= 69 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 70 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 71 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 72 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 73 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 74 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 75 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 76 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 77 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 78 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 79 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 80 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 81 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 82 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 83 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 84 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 85 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 86 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 87 | --------------------------------------------------------------------------------