├── .all-contributorsrc ├── .github └── workflows │ ├── automatic-rebase.yml │ ├── check-large-files.yml │ ├── code_quality.yml │ ├── dependency-review.yml │ ├── go.yml │ ├── language.yml │ ├── markdown-lint.yml │ ├── misspell.yml │ ├── release.yml │ ├── reportcard.yml │ ├── runtest.yml │ ├── shellcheck.yml │ └── yaml-lint.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE.md ├── Makefile ├── README.md ├── assets └── banner.png ├── cmd └── sif │ └── main.go ├── flake.lock ├── flake.nix ├── go.mod ├── go.sum ├── gomod2nix.toml ├── internal ├── nuclei │ ├── format │ │ └── format.go │ └── templates │ │ └── templates.go └── styles │ └── styles.go ├── pkg ├── config │ └── config.go ├── logger │ └── logger.go ├── scan │ ├── cloudstorage.go │ ├── cms.go │ ├── dirlist.go │ ├── dnslist.go │ ├── dork.go │ ├── git.go │ ├── headers.go │ ├── js │ │ ├── frameworks │ │ │ └── next.go │ │ ├── scan.go │ │ └── supabase.go │ ├── nuclei.go │ ├── ports.go │ ├── scan.go │ ├── subdomaintakeover.go │ └── whois.go └── utils │ └── returnApiOutput.go ├── sif.code-workspace ├── sif.go └── template-example.toml /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "sif", 3 | "projectOwner": "lunchcat", 4 | "files": [ 5 | "README.md" 6 | ], 7 | "commitType": "docs", 8 | "commitConvention": "angular", 9 | "contributorsPerLine": 7, 10 | "contributors": [ 11 | { 12 | "login": "vmfunc", 13 | "name": "mel", 14 | "avatar_url": "https://avatars.githubusercontent.com/u/59031302?v=4", 15 | "profile": "https://vmfunc.re", 16 | "contributions": [ 17 | "maintenance", 18 | "mentoring", 19 | "projectManagement", 20 | "security", 21 | "test", 22 | "business", 23 | "code", 24 | "design", 25 | "financial", 26 | "ideas" 27 | ] 28 | }, 29 | { 30 | "login": "projectdiscovery", 31 | "name": "ProjectDiscovery", 32 | "avatar_url": "https://avatars.githubusercontent.com/u/50994705?v=4", 33 | "profile": "https://projectdiscovery.io", 34 | "contributions": [ 35 | "platform" 36 | ] 37 | }, 38 | { 39 | "login": "macdoos", 40 | "name": "macdoos", 41 | "avatar_url": "https://avatars.githubusercontent.com/u/127897805?v=4", 42 | "profile": "https://github.com/macdoos", 43 | "contributions": [ 44 | ] 45 | }, 46 | { 47 | "login": "D3adPlays", 48 | "name": "Matthieu Witrowiez", 49 | "avatar_url": "https://avatars.githubusercontent.com/u/75166283?v=4", 50 | "profile": "https://epitech.eu", 51 | "contributions": [ 52 | "ideas" 53 | ] 54 | }, 55 | { 56 | "login": "tessa-u-k", 57 | "name": "tessa ", 58 | "avatar_url": "https://avatars.githubusercontent.com/u/109355732?v=4", 59 | "profile": "https://github.com/tessa-u-k", 60 | "contributions": [ 61 | "infra", 62 | "question", 63 | "userTesting" 64 | ] 65 | }, 66 | { 67 | "login": "xyzeva", 68 | "name": "Eva", 69 | "avatar_url": "https://avatars.githubusercontent.com/u/133499694?v=4", 70 | "profile": "https://github.com/xyzeva", 71 | "contributions": [ 72 | "blog", 73 | "content", 74 | "research", 75 | "security", 76 | "test", 77 | "code" 78 | ] 79 | } 80 | ] 81 | } 82 | -------------------------------------------------------------------------------- /.github/workflows/automatic-rebase.yml: -------------------------------------------------------------------------------- 1 | name: Automatic Rebase 2 | on: 3 | issue_comment: 4 | types: [created] 5 | jobs: 6 | rebase: 7 | name: Rebase 8 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout the latest code 12 | uses: actions/checkout@v3 13 | with: 14 | fetch-depth: 0 15 | - name: Automatic Rebase 16 | uses: cirrus-actions/rebase@1.8 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | -------------------------------------------------------------------------------- /.github/workflows/check-large-files.yml: -------------------------------------------------------------------------------- 1 | name: Check Large Files 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | 8 | jobs: 9 | check-large-files: 10 | name: Check for large files 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Check for large files 15 | run: | 16 | find . -type f -size +5M | while read file; do 17 | echo "::error file=${file}::File ${file} is larger than 5MB" 18 | done 19 | -------------------------------------------------------------------------------- /.github/workflows/code_quality.yml: -------------------------------------------------------------------------------- 1 | name: Qodana 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | qodana: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write 14 | pull-requests: write 15 | checks: write 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | ref: ${{ github.event.pull_request.head.sha }} 20 | fetch-depth: 0 21 | - name: 'Qodana Scan' 22 | uses: JetBrains/qodana-action@v2023.3 23 | env: 24 | QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: "Dependency Review" 2 | on: 3 | pull_request: 4 | push: 5 | branches: [main] 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | dependency-review: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: "Checkout Repository" 15 | uses: actions/checkout@v3 16 | - name: "Dependency Review" 17 | uses: actions/dependency-review-action@v3 18 | continue-on-error: ${{ github.event_name == 'push' }} 19 | - name: "Check Dependency Review Outcome" 20 | if: github.event_name == 'push' && failure() 21 | run: | 22 | echo "::warning::Dependency review failed. Please check the dependencies for potential issues." 23 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: 3 | push: 4 | branches: ["main"] 5 | pull_request: 6 | branches: ["main"] 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Set up Go 13 | uses: actions/setup-go@v4 14 | with: 15 | go-version: "1.23" 16 | - name: Build 17 | run: make 18 | -------------------------------------------------------------------------------- /.github/workflows/language.yml: -------------------------------------------------------------------------------- 1 | name: Mind your language 2 | on: 3 | issues: 4 | types: 5 | - opened 6 | - edited 7 | issue_comment: 8 | types: 9 | - created 10 | - edited 11 | pull_request_review_comment: 12 | types: 13 | - created 14 | - edited 15 | jobs: 16 | echo_issue_comment: 17 | runs-on: ubuntu-latest 18 | name: profanity check 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | - name: Profanity check step 23 | uses: tailaiw/mind-your-language-action@v1.0.3 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/markdown-lint.yml: -------------------------------------------------------------------------------- 1 | name: Markdown Lint 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "**/*.md" 7 | 8 | jobs: 9 | markdownlint: 10 | name: runner / markdownlint 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: markdownlint 15 | uses: reviewdog/action-markdownlint@v0.10.0 16 | with: 17 | github_token: ${{ secrets.GITHUB_TOKEN }} 18 | reporter: github-pr-review 19 | -------------------------------------------------------------------------------- /.github/workflows/misspell.yml: -------------------------------------------------------------------------------- 1 | name: Misspell Check 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | 8 | jobs: 9 | misspell: 10 | name: runner / misspell 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: misspell 15 | uses: reviewdog/action-misspell@v1.13.0 16 | with: 17 | github_token: ${{ secrets.GITHUB_TOKEN }} 18 | reporter: github-pr-review 19 | level: warning 20 | locale: "US" 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | permissions: 8 | contents: write 9 | packages: write 10 | 11 | jobs: 12 | test: 13 | uses: ./.github/workflows/runtest.yml 14 | 15 | build-and-release: 16 | needs: test 17 | runs-on: ubuntu-latest 18 | permissions: 19 | contents: write 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Set up Go 23 | uses: actions/setup-go@v4 24 | with: 25 | go-version: "1.23" 26 | 27 | - name: Build for Windows 28 | run: | 29 | GOOS=windows GOARCH=amd64 go build -o sif-windows-amd64.exe ./cmd/sif 30 | GOOS=windows GOARCH=386 go build -o sif-windows-386.exe ./cmd/sif 31 | 32 | - name: Build for macOS 33 | run: | 34 | GOOS=darwin GOARCH=amd64 go build -o sif-macos-amd64 ./cmd/sif 35 | GOOS=darwin GOARCH=arm64 go build -o sif-macos-arm64 ./cmd/sif 36 | 37 | - name: Build for Linux 38 | run: | 39 | GOOS=linux GOARCH=amd64 go build -o sif-linux-amd64 ./cmd/sif 40 | GOOS=linux GOARCH=386 go build -o sif-linux-386 ./cmd/sif 41 | GOOS=linux GOARCH=arm64 go build -o sif-linux-arm64 ./cmd/sif 42 | 43 | - name: Set release version 44 | run: echo "RELEASE_VERSION=$(git rev-parse --short HEAD)" >> $GITHUB_ENV 45 | 46 | - name: Get commit info 47 | run: | 48 | echo "COMMIT_MESSAGE=$(git log -1 --pretty=%B)" >> $GITHUB_ENV 49 | echo "COMMIT_AUTHOR=$(git log -1 --pretty=%an)" >> $GITHUB_ENV 50 | echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_ENV 51 | 52 | - name: Create Release 53 | id: create_release 54 | uses: actions/create-release@v1 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | with: 58 | tag_name: automated-release-${{ env.RELEASE_VERSION }} 59 | release_name: Release ${{ env.RELEASE_VERSION }} 60 | body: | 61 | 🚀 sif automated release v${{ env.RELEASE_VERSION }} 62 | 63 | This is an automated release pushed by the release workflow. 64 | 65 | ## Commit Information 66 | - **Message:** ${{ env.COMMIT_MESSAGE }} 67 | - **Author:** ${{ env.COMMIT_AUTHOR }} 68 | - **SHA:** ${{ env.COMMIT_SHA }} 69 | 70 | ## Build Information 71 | - Built on: ${{ runner.os }} 72 | 73 | ## Assets 74 | - Windows (64-bit): `sif-windows-amd64.exe` 75 | - Windows (32-bit): `sif-windows-386.exe` 76 | - macOS (64-bit Intel): `sif-macos-amd64` 77 | - macOS (64-bit ARM): `sif-macos-arm64` 78 | - Linux (64-bit): `sif-linux-amd64` 79 | - Linux (32-bit): `sif-linux-386` 80 | - Linux (64-bit ARM): `sif-linux-arm64` 81 | 82 | For more details, please check the [commit history](https://github.com/${{ github.repository }}/commits/main). 83 | 84 | @${{ env.COMMIT_AUTHOR }}, your changes have been included in this release. 85 | draft: false 86 | prerelease: false 87 | 88 | - name: Upload Windows Release Asset 89 | uses: actions/upload-release-asset@v1 90 | env: 91 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 92 | with: 93 | upload_url: ${{ steps.create_release.outputs.upload_url }} 94 | asset_path: ./sif-windows-amd64.exe 95 | asset_name: sif-windows-amd64.exe 96 | asset_content_type: application/octet-stream 97 | 98 | - name: Upload Windows (32-bit) Release Asset 99 | uses: actions/upload-release-asset@v1 100 | env: 101 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 102 | with: 103 | upload_url: ${{ steps.create_release.outputs.upload_url }} 104 | asset_path: ./sif-windows-386.exe 105 | asset_name: sif-windows-386.exe 106 | asset_content_type: application/octet-stream 107 | 108 | - name: Upload macOS Release Asset 109 | uses: actions/upload-release-asset@v1 110 | env: 111 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 112 | with: 113 | upload_url: ${{ steps.create_release.outputs.upload_url }} 114 | asset_path: ./sif-macos-amd64 115 | asset_name: sif-macos-amd64 116 | asset_content_type: application/octet-stream 117 | 118 | - name: Upload macOS (ARM64) Release Asset 119 | uses: actions/upload-release-asset@v1 120 | env: 121 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 122 | with: 123 | upload_url: ${{ steps.create_release.outputs.upload_url }} 124 | asset_path: ./sif-macos-arm64 125 | asset_name: sif-macos-arm64 126 | asset_content_type: application/octet-stream 127 | 128 | - name: Upload Linux Release Asset 129 | uses: actions/upload-release-asset@v1 130 | env: 131 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 132 | with: 133 | upload_url: ${{ steps.create_release.outputs.upload_url }} 134 | asset_path: ./sif-linux-amd64 135 | asset_name: sif-linux-amd64 136 | asset_content_type: application/octet-stream 137 | 138 | - name: Upload Linux (32-bit) Release Asset 139 | uses: actions/upload-release-asset@v1 140 | env: 141 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 142 | with: 143 | upload_url: ${{ steps.create_release.outputs.upload_url }} 144 | asset_path: ./sif-linux-386 145 | asset_name: sif-linux-386 146 | asset_content_type: application/octet-stream 147 | 148 | - name: Upload Linux (ARM64) Release Asset 149 | uses: actions/upload-release-asset@v1 150 | env: 151 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 152 | with: 153 | upload_url: ${{ steps.create_release.outputs.upload_url }} 154 | asset_path: ./sif-linux-arm64 155 | asset_name: sif-linux-arm64 156 | asset_content_type: application/octet-stream 157 | -------------------------------------------------------------------------------- /.github/workflows/reportcard.yml: -------------------------------------------------------------------------------- 1 | name: Update Report Card 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | workflow_call: 9 | 10 | jobs: 11 | update-report-card: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Update Go Report Card 16 | uses: creekorful/goreportcard-action@v1.0 17 | -------------------------------------------------------------------------------- /.github/workflows/runtest.yml: -------------------------------------------------------------------------------- 1 | name: Functional Test 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | workflow_call: 9 | 10 | jobs: 11 | build-and-test: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Set up Go 16 | uses: actions/setup-go@v4 17 | with: 18 | go-version: "1.23" 19 | - name: Build Sif 20 | run: make 21 | - name: Run Sif with features 22 | run: | 23 | ./sif -u https://google.com -dnslist small -dirlist small -dork -git -whois -cms 24 | if [ $? -eq 0 ]; then 25 | echo "Sif ran successfully" 26 | else 27 | echo "Sif exited with an error" 28 | exit 1 29 | fi 30 | -------------------------------------------------------------------------------- /.github/workflows/shellcheck.yml: -------------------------------------------------------------------------------- 1 | name: Shell Check 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "**/*.sh" 7 | 8 | jobs: 9 | shellcheck: 10 | name: runner / shellcheck 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: shellcheck 15 | uses: reviewdog/action-shellcheck@v1.18.0 16 | with: 17 | github_token: ${{ secrets.GITHUB_TOKEN }} 18 | reporter: github-pr-review 19 | -------------------------------------------------------------------------------- /.github/workflows/yaml-lint.yml: -------------------------------------------------------------------------------- 1 | name: YAML Lint 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "**/*.yml" 7 | - "**/*.yaml" 8 | 9 | jobs: 10 | yamllint: 11 | name: runner / yamllint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: yamllint 16 | uses: reviewdog/action-yamllint@v1.8.0 17 | with: 18 | github_token: ${{ secrets.GITHUB_TOKEN }} 19 | reporter: github-pr-review 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) meow 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | 23 | # sif binary 24 | /sif 25 | 26 | # logs for testing 27 | logs 28 | 29 | # nix build output 30 | result 31 | 32 | # nuclei templates 33 | nuclei-templates 34 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # sif Code of Conduct 2 | 3 | The sif project aims to be **enjoyable** for anyone to participate in, regardless of their identity or level of expertise. To achieve this, the community must create an environment which is **safe** and **equitable**; the following guidelines have been created with these goals in mind. 4 | 5 | 1. **This is not a professional space.** Individuality is not only welcome, but encouraged. Professionalism asks marginalized individuals to censor themselves, and perform their identity in an inauthentic, unchallenging manner, which caters solely to those in power (namely rich, white, cisgender, heterosexual men). Seeking professionalism is *antithetical* to the goal of equity, and thus, these guidelines reject it. 6 | - Attempting to suppress self-expression or non-harmful speech is not acceptable for any reason. 7 | - There will be queers, punks, femboys, drag queens, furries, hackers, kinksters, and all sorts of other people here. And the project will reflect that. If you don't like this, consider looking for Free Software projects [elsewhere](https://loose-files.keithhacks.cyou/img/trashcan.jpg). 8 | 9 | 2. **Treat individuals with respect.** Differing experiences and viewpoints deserve to be respected, and bigotry and harassment are not tolerated under any circumstances. 10 | - Individuals should never be made to feel unsafe or unvalued due to their age, gender, sexuality, race, ethnicity, disability, religion, appearance, education, level of expertise, or other factors. 11 | - Behaviour that is harmful in nature should be addressed and corrected *regardless of intent*. 12 | - Respect personal boundaries and ask for clarification whenever they are unclear. 13 | - (Obviously, hate does not count as merely a "differing viewpoint", because it is harmful in nature.) 14 | 15 | 3. **Be understanding of differences in communication.** Not everyone is aware of unspoken social cues, and speech that is not intended to be offensive should not be treated as such simply due to an atypical manner of communication. 16 | - Somebody who speaks bluntly is not necessarily rude, and somebody who swears a lot is not necessarily volatile. 17 | - Try to confirm your interpretation of their intent rather than assuming bad faith. 18 | 19 | 4. **"Uncomfortable" does not mean "unsafe".** In an ideal world, the community would be safe, equitable, enjoyable, *and* comfortable for all members at all times. Unfortunately, this is not always possible in reality. 20 | - Safety and equity will be prioritized over comfort whenever it is necessary to do so. 21 | - Weaponizing one's own discomfort to deflect accountability or censor an individual (e.g. "white fragility") is a form of discriminatory conduct. 22 | 23 | 5. **Let people grow from their mistakes.** Nobody is perfect; even the most well-meaning individual can do something hurtful. Everyone should be given a fair opportunity to explain themselves and correct their behaviour. Portraying someone as inherently malicious prevents improvement and shifts focus away from the *action* that was problematic. 24 | - Avoid bringing up past events that do not accurately reflect an individual's current actions or beliefs. (This is, of course, different from providing evidence of a recurring pattern of behaviour.) 25 | 26 | --- 27 | This document was created by ~keith as part of punks default repository template, and is licensed under CC-BY-SA 4.0. The original template is here: 28 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for taking the time to contribute to sif! All contributions are valued, and no contribution is too small or insignificant. 4 | If you want to contribute but don't know where to start, worry not; there is no shortage of things to do. 5 | Even if you don't know any Go, don't let that stop you from trying to contribute! We're here to help. 6 | 7 | *By contributing to this repository, you agree to adhere to the sif [Code of Conduct](https://github.com/dropalldatabases/sif/blob/main/CODE_OF_CONDUCT.md). Not doing so may result in a ban.* 8 | 9 | ## How can I help? 10 | 11 | Here are some ways to get started: 12 | - Have a look at our [issue tracker](https://github.com/dropalldatabases/sif/issues). 13 | - If you've encountered a bug, discuss it with us, [report it](#reporting-issues). 14 | - Once you've found a bug you believe you can fix, open a [pull request](#contributing-code) for it. 15 | - Alternatively, consider [packaging sif for your distribution](#packaging). 16 | 17 | If you like the project, but don't have time to contribute, that's okay too! Here are other ways to show your appreciation for the project: 18 | - Use sif (seriously, that's enough) 19 | - Star the repository 20 | - Share sif with your friends 21 | - Support us on Liberapay (thank you!) 22 | 23 | ## Reporting issues 24 | 25 | If you believe you've found a bug, or you have a new feature to request, please hop on the [Discord server](https://discord.gg/dropalldatabases) first to discuss it. 26 | This way, if it's an easy fix, we could help you solve it more quickly, and if it's a feature request we could workshop it together into something more mature. 27 | 28 | When opening an issue, please use the search tool and make sure that the issue has not been discussed before. In the case of a bug report, run sif with the `-d/-debug` flag for full debug logs. 29 | 30 | ## Contributing code 31 | 32 | ### Development 33 | 34 | To develop sif, you'll need version 1.20 or later of the Go toolchain. After making your changes, run the program using `go run ./cmd/sif` to make sure it compiles and runs properly. 35 | 36 | *Nix users:* the repository provides a flake that can be used to develop and run sif. Use `nix run`, `nix develop`, `nix build`, etc. Make sure to run `gomod2nix` if `go.mod` is changed. 37 | 38 | ### Submitting a pull request 39 | 40 | When making a pull request, please adhere to the following conventions: 41 | 42 | - sif adheres to the Go style guidelines. Always format your gode with `gofmt`. 43 | - When adding/removing imports, make sure to use `go mod tidy`, and then run `gomod2nix` to generate the Nix-readable module list. 44 | - Set `git config pull.rebase true` to rebase commits on pull instead of creating ugly merge commits. 45 | - Title your commits in present tense, in the imperative style. 46 | - You may use prefixes like `feat`, `fix`, `chore`, `deps`, etc. 47 | **Example:** `deps: update gopkg.in/yaml.v3 to v3.0.1` 48 | - You may use prefixes to denote the part of the code changed in the commit. 49 | **Example:** `pkg/scan: ignore 3xx redirects` 50 | - If not using a prefix, make sure to use sentence case. 51 | **Example:** `Add nuclei template parsing support` 52 | - If applicable, provide a helpful commit description, listing usage notes, implementation details, and tasks that still need to be done. 53 | 54 | If you have any questions, feel free to ask around on the IRC channel. 55 | 56 | ## Packaging 57 | 58 | We'd love it if you helped us bring sif to your distribution. 59 | The repository provides a Makefile for building and packaging sif for any distro; consult your distribution's documentation for details. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 - 2024 lunchcat, inc. ALL RIGHTS RESERVED. 2 | 3 | Use of this tool is restricted to research and educational purposes only. Usage in a production environment outside of these categories is strictly prohibited. Any person or entity wishing to use this tool outside of research or school purposes must purchase a license from https://lunchcat.dev. 4 | 5 | For Businesses: 6 | 1. Licensing Requirement: Businesses intending to use this tool for any commercial, operational, or production purposes must obtain a commercial license from [lunchcat.dev](https://lunchcat.dev). 7 | 2. Compliance: Businesses must ensure compliance with all applicable laws and regulations when using this tool. 8 | 3. Liability: lunchcat assumes no liability for any damages or losses incurred by businesses using this tool without an appropriate license. 9 | 4. Support: Licensed business users are eligible for dedicated support and updates as per the terms of their license agreement. 10 | 5. Audits: lunchcat reserves the right to audit business usage of this tool to ensure compliance with the licensing terms. 11 | 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **Copyright 2023 - 2024 lunchcat. ALL RIGHTS RESERVED.** 4 | 5 | Use of this tool is restricted to research and educational purposes only. Usage in a production environment outside of these categories is strictly prohibited. Any person or entity wishing to use this tool outside of research or school purposes must purchase a license from [lunchcat.dev](https://lunchcat.dev). 6 | 7 | **For Businesses:** 8 | 1. **Licensing Requirement:** Businesses intending to use this tool for any commercial, operational, or production purposes must obtain a commercial license from [lunchcat.dev](https://lunchcat.dev). 9 | 2. **Compliance:** Businesses must ensure compliance with all applicable laws and regulations when using this tool. 10 | 3. **Liability:** lunchcat assumes no liability for any damages or losses incurred by businesses using this tool without an appropriate license. 11 | 4. **Support:** Licensed business users are eligible for dedicated support and updates as per the terms of their license agreement. 12 | 5. **Audits:** lunchcat reserves the right to audit business usage of this tool to ensure compliance with the licensing terms. 13 | 14 | --- 15 | 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024 vmfunc, xyzeva, lunchcat, and contributors 2 | # SPDX-License-Identifier: MIT 3 | 4 | .POSIX: 5 | .SUFFIXES: 6 | 7 | GO ?= go 8 | RM ?= rm 9 | GOFLAGS ?= 10 | PREFIX ?= /usr/local 11 | BINDIR ?= bin 12 | 13 | define COPYRIGHT_ASCII 14 | ╭────────────────────────────────────────────────────────────╮ 15 | │ _____________ │ 16 | │ __________(_)__ __/ │ 17 | │ __ ___/_ /__ /_ │ 18 | │ _(__ )_ / _ __/ │ 19 | │ /____/ /_/ /_/ │ 20 | │ │ 21 | ╰────────────────────────────────────────────────────────────╯ 22 | Copyright (c) 2024 vmfunc, xyzeva, lunchcat, and contributors 23 | 24 | 25 | endef 26 | export COPYRIGHT_ASCII 27 | 28 | define SUPPORT_MESSAGE 29 | 30 | 31 | ╭────────────────────────────────────────────────────────────╮ 32 | │ │ 33 | │ 🌟 Enjoying sif? Please consider: │ 34 | │ │ 35 | │ • Starring our repo: https://github.com/lunchcat/sif │ 36 | │ • Supporting the devs: https://lunchcat.dev │ 37 | │ │ 38 | │ Your support helps us continue improving sif! │ 39 | │ │ 40 | ╰────────────────────────────────────────────────────────────╯ 41 | endef 42 | export SUPPORT_MESSAGE 43 | 44 | all: check_go_version sif 45 | @echo "✅ All tasks completed successfully! 🎉" 46 | @echo "$$SUPPORT_MESSAGE" 47 | 48 | check_go_version: 49 | @echo "$$COPYRIGHT_ASCII" 50 | @echo "🔍 Checking Go version..." 51 | @$(GO) version | grep -q "go1\.23\." || (echo "❌ Error: Please install the latest version of Go" && exit 1) 52 | @echo "✅ Go version check passed!" 53 | 54 | sif: check_go_version 55 | @echo "🛠️ Building sif..." 56 | @echo "📁 Current directory: $$(pwd)" 57 | @echo "🔧 Go flags: $(GOFLAGS)" 58 | @echo "📦 Building package: ./cmd/sif" 59 | $(GO) build -v $(GOFLAGS) ./cmd/sif 60 | @echo "📊 Build info:" 61 | @$(GO) version -m sif 62 | @echo "✅ sif built successfully! 🚀" 63 | 64 | clean: 65 | @echo "$$COPYRIGHT_ASCII" 66 | @echo "🧹 Cleaning up..." 67 | @$(RM) -rf sif 68 | @echo "✨ Cleanup complete!" 69 | 70 | install: check_go_version 71 | @echo "$$COPYRIGHT_ASCII" 72 | @echo "📦 Installing sif..." 73 | @if [ "$$(uname)" != "Linux" ] && [ "$$(uname)" != "Darwin" ]; then \ 74 | echo "❌ Error: This installation script is for UNIX systems only."; \ 75 | exit 1; \ 76 | fi 77 | @mkdir -p $(DESTDIR)$(PREFIX)/$(BINDIR) || (echo "🔒 Permission denied. Trying with sudo..." && sudo mkdir -p $(DESTDIR)$(PREFIX)/$(BINDIR)) 78 | @cp -f sif $(DESTDIR)$(PREFIX)/$(BINDIR) || (echo "🔒 Permission denied. Trying with sudo..." && sudo cp -f sif $(DESTDIR)$(PREFIX)/$(BINDIR)) 79 | @echo "✅ sif installed successfully! 🎊" 80 | 81 | uninstall: 82 | @echo "$$COPYRIGHT_ASCII" 83 | @echo "🗑️ Uninstalling sif..." 84 | @if [ "$$(uname)" != "Linux" ] && [ "$$(uname)" != "Darwin" ]; then \ 85 | echo "❌ Error: This uninstallation script is for UNIX systems only."; \ 86 | exit 1; \ 87 | fi 88 | @$(RM) $(DESTDIR)$(PREFIX)/$(BINDIR)/sif || (echo "🔒 Permission denied. Trying with sudo..." && sudo $(RM) $(DESTDIR)$(PREFIX)/$(BINDIR)/sif) 89 | @echo "✅ sif uninstalled successfully!" 90 | 91 | .PHONY: all check_go_version sif clean install uninstall -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ![Go version](https://img.shields.io/github/go-mod/go-version/dropalldatabases/sif?style=flat-square) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/dropalldatabases/sif?style=flat-square)](https://goreportcard.com/report/github.com/dropalldatabases/sif) 5 | [![Version](https://img.shields.io/github/v/tag/dropalldatabases/sif?style=flat-square)](https://github.com/dropalldatabases/sif/tags) 6 | 7 |
8 | 9 | ## 📖 Table of Contents 10 | 11 | - [Modules](#-modules) 12 | - [Installation](#-installation) 13 | - [Quick Start](#-quick-start) 14 | - [Usage](#-usage) 15 | - [Performance](#-performance) 16 | - [Contributing](#-contributing) 17 | - [Contributors](#-contributors) 18 | - [Acknowledgements](#-acknowledgements) 19 | 20 | ## 🧩 Modules 21 | 22 | sif is built with a modular architecture, allowing for easy extension and customization. Some of our key modules include: 23 | 24 | - 📂 Directory/file fuzzing/scanning 25 | - 📡 DNS subdomain enumeration 26 | - 🐾 Common Web scanning 27 | - 🖥️ Port/service scanning 28 | - 🦠 Vulnerability scanning 29 | - Support for pre-existing nuclei templates 30 | - Metasploit emulation for execution 31 | - 🔎 Automated Google dorking 32 | - 💘 Shodan integration 33 | - 📦 CMS detection 34 | - 🔍 HTTP Header Analysis 35 | - ☁️ C3 Misconfiguration Scanner 36 | - 🔍 Subdomain Takeover Checks 37 | 38 | ## 📦 Installation 39 | 40 | ### Using pre-built binaries 41 | 42 | Visit our [Releases](https://github.com/dropalldatabases/sif/releases) page to download the latest pre-built binary for your operating system. 43 | 44 | ### Building from source 45 | 46 | 1. Ensure you have Go 1.23+ installed on your system. 47 | 2. Clone the repository: 48 | ``` 49 | git clone https://github.com/lunchcat/sif.git 50 | cd sif 51 | ``` 52 | 3. Build using the Makefile: 53 | ``` 54 | make 55 | ``` 56 | 4. The binary will be available in the root directory. 57 | 58 | ## 🚀 Quick Start 59 | 60 | 1. Run a basic scan: 61 | ``` 62 | ./sif -u example.com 63 | ``` 64 | 2. For more options and advanced usage, refer to the help command: 65 | ``` 66 | ./sif -h 67 | ``` 68 | 69 | ## 🛠 Usage 70 | 71 | sif offers a wide range of commands and options to customize your pentesting workflow. Here are some common usage examples: 72 | 73 | - Directory fuzzing 74 | 75 | ``` 76 | ./sif -u http://example.com -dirlist medium 77 | ``` 78 | 79 | - Subdomain enumeration 80 | 81 | ``` 82 | ./sif -u http://example.com -dnslist medium 83 | ``` 84 | 85 | - Supabase/Firebase and C3 Vulnerability scanning 86 | 87 | ``` 88 | ./sif -u https://example.com -js -c3 89 | ``` 90 | 91 | - Port scanning 92 | 93 | ``` 94 | ./sif -u https://example.com -ports common 95 | ``` 96 | 97 | For a complete list of commands and options, run `./sif -h`. 98 | 99 | ## ⚡ Performance 100 | 101 | sif is designed for high performance and efficiency: 102 | 103 | - Written in Go for excellent concurrency and speed 104 | - Optimized algorithms for minimal resource usage 105 | - Supports multi-threading for faster scans 106 | - Efficient caching mechanisms to reduce redundant operations 107 | 108 | ## 🤝 Contributing 109 | 110 | We welcome contributions from the community! Please read our [Contributing Guidelines](CONTRIBUTING.md) before submitting a pull request. 111 | 112 | Areas we're particularly interested in: 113 | 114 | - New scanning modules 115 | - Performance improvements 116 | - Documentation enhancements 117 | - Bug fixes and error handling improvements 118 | 119 | ## 🌟 Contributors 120 | 121 | Thanks to these wonderful people who have contributed to sif: 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 |
mel
mel

🚧 🧑‍🏫 📆 🛡️ ⚠️ 💼 💻 🎨 💵 🤔
ProjectDiscovery
ProjectDiscovery

📦
macdoos
macdoos

💻
Matthieu Witrowiez
Matthieu Witrowiez

🤔
tessa
tessa

🚇 💬 📓
Eva
Eva

📝 🖋 🔬 🛡️ ⚠️ 💻
138 | 139 | 140 | 141 | 142 | 143 | 144 | ## 🙏 Acknowledgements 145 | 146 | We'd like to thank the following projects and communities for their inspiration and support: 147 | 148 | - [ProjectDiscovery](https://projectdiscovery.io/) for their amazing open-source security tools 149 | - [Shodan](https://www.shodan.io/) 150 | - [Malcore](https://www.malcore.io/), for providing us direct API support at Lunchcat. 151 | 152 | --- 153 | 154 |
155 | Happy Hunting! 🐾 156 |

157 | Built with ❤️ by the lunchcat team and contributors worldwide 158 |

159 |
160 | -------------------------------------------------------------------------------- /assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmfunc/sif/bef84ce9e7bc6e2086ae8eb3282e6fbe40479ba3/assets/banner.png -------------------------------------------------------------------------------- /cmd/sif/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package main 26 | 27 | import ( 28 | "github.com/charmbracelet/log" 29 | "github.com/dropalldatabases/sif" 30 | "github.com/dropalldatabases/sif/pkg/config" 31 | ) 32 | 33 | func main() { 34 | settings := config.Parse() 35 | 36 | app, err := sif.New(settings) 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | 41 | err = app.Run() 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "gomod2nix": { 4 | "inputs": { 5 | "nixpkgs": [ 6 | "nixpkgs" 7 | ], 8 | "utils": [ 9 | "utils" 10 | ] 11 | }, 12 | "locked": { 13 | "lastModified": 1677459247, 14 | "narHash": "sha256-JbakfAiPYmCCV224yAMq/XO0udN5coWv/oazblMKdoY=", 15 | "owner": "tweag", 16 | "repo": "gomod2nix", 17 | "rev": "3cbf3a51fe32e2f57af4c52744e7228bab22983d", 18 | "type": "github" 19 | }, 20 | "original": { 21 | "owner": "tweag", 22 | "repo": "gomod2nix", 23 | "type": "github" 24 | } 25 | }, 26 | "nixpkgs": { 27 | "locked": { 28 | "lastModified": 1693844670, 29 | "narHash": "sha256-t69F2nBB8DNQUWHD809oJZJVE+23XBrth4QZuVd6IE0=", 30 | "owner": "NixOS", 31 | "repo": "nixpkgs", 32 | "rev": "3c15feef7770eb5500a4b8792623e2d6f598c9c1", 33 | "type": "github" 34 | }, 35 | "original": { 36 | "owner": "NixOS", 37 | "ref": "nixpkgs-unstable", 38 | "repo": "nixpkgs", 39 | "type": "github" 40 | } 41 | }, 42 | "root": { 43 | "inputs": { 44 | "gomod2nix": "gomod2nix", 45 | "nixpkgs": "nixpkgs", 46 | "utils": "utils" 47 | } 48 | }, 49 | "systems": { 50 | "locked": { 51 | "lastModified": 1681028828, 52 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 56 | "type": "github" 57 | }, 58 | "original": { 59 | "owner": "nix-systems", 60 | "repo": "default", 61 | "type": "github" 62 | } 63 | }, 64 | "utils": { 65 | "inputs": { 66 | "systems": "systems" 67 | }, 68 | "locked": { 69 | "lastModified": 1692799911, 70 | "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", 71 | "owner": "numtide", 72 | "repo": "flake-utils", 73 | "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", 74 | "type": "github" 75 | }, 76 | "original": { 77 | "owner": "numtide", 78 | "repo": "flake-utils", 79 | "type": "github" 80 | } 81 | } 82 | }, 83 | "root": "root", 84 | "version": 7 85 | } 86 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "a blazing-fast pentesting (recon/exploitation) suite"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 | utils.url = "github:numtide/flake-utils"; 7 | 8 | gomod2nix = { 9 | url = "github:tweag/gomod2nix"; 10 | inputs.nixpkgs.follows = "nixpkgs"; 11 | inputs.utils.follows = "utils"; 12 | }; 13 | }; 14 | 15 | outputs = { self, nixpkgs, utils, gomod2nix }: 16 | utils.lib.eachDefaultSystem (system: 17 | let pkgs = import nixpkgs { 18 | inherit system; 19 | overlays = [ gomod2nix.overlays.default ]; 20 | }; 21 | in 22 | { 23 | packages.default = pkgs.buildGoApplication { 24 | pname = "sif"; 25 | version = "0.1.0"; 26 | src = ./.; 27 | modules = ./gomod2nix.toml; 28 | }; 29 | devShells.default = pkgs.mkShell { 30 | buildInputs = with pkgs; [ 31 | go 32 | gomod2nix.packages.${system}.default 33 | ]; 34 | }; 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/dropalldatabases/sif 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/antchfx/htmlquery v1.3.0 7 | github.com/charmbracelet/lipgloss v0.8.0 8 | github.com/charmbracelet/log v0.2.4 9 | github.com/likexian/whois v1.15.1 10 | github.com/projectdiscovery/goflags v0.1.54 11 | github.com/projectdiscovery/nuclei/v2 v2.9.14 12 | github.com/projectdiscovery/ratelimit v0.0.9 13 | github.com/projectdiscovery/utils v0.1.1 14 | github.com/rocketlaunchr/google-search v1.1.6 15 | ) 16 | 17 | require ( 18 | aead.dev/minisign v0.2.0 // indirect 19 | git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a // indirect 20 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect 21 | github.com/Masterminds/semver/v3 v3.2.1 // indirect 22 | github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect 23 | github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 // indirect 24 | github.com/PuerkitoBio/goquery v1.8.1 // indirect 25 | github.com/VividCortex/ewma v1.2.0 // indirect 26 | github.com/akrylysov/pogreb v0.10.1 // indirect 27 | github.com/alecthomas/chroma v0.10.0 // indirect 28 | github.com/alecthomas/jsonschema v0.0.0-20211022214203-8b29eab41725 // indirect 29 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect 30 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect 31 | github.com/andybalholm/brotli v1.0.6 // indirect 32 | github.com/andybalholm/cascadia v1.3.2 // indirect 33 | github.com/andygrunwald/go-jira v1.16.0 // indirect 34 | github.com/antchfx/xmlquery v1.3.15 // indirect 35 | github.com/antchfx/xpath v1.2.4 // indirect 36 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect 37 | github.com/aws/aws-sdk-go-v2 v1.19.0 // indirect 38 | github.com/aws/aws-sdk-go-v2/config v1.18.28 // indirect 39 | github.com/aws/aws-sdk-go-v2/credentials v1.13.27 // indirect 40 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect 41 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect 42 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect 43 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 // indirect 44 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 // indirect 45 | github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 // indirect 46 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect 47 | github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 // indirect 48 | github.com/aws/smithy-go v1.13.5 // indirect 49 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 50 | github.com/aymerick/douceur v0.2.0 // indirect 51 | github.com/bluele/gcache v0.0.2 // indirect 52 | github.com/caddyserver/certmagic v0.19.2 // indirect 53 | github.com/charmbracelet/glamour v0.6.0 // indirect 54 | github.com/cheggaaa/pb/v3 v3.1.4 // indirect 55 | github.com/cloudflare/cfssl v1.6.4 // indirect 56 | github.com/cloudflare/circl v1.3.7 // indirect 57 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect 58 | github.com/corpix/uarand v0.2.0 // indirect 59 | github.com/dimchansky/utfbom v1.1.1 // indirect 60 | github.com/dlclark/regexp2 v1.8.1 // indirect 61 | github.com/docker/go-units v0.5.0 // indirect 62 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect 63 | github.com/fatih/color v1.16.0 // indirect 64 | github.com/fatih/structs v1.1.0 // indirect 65 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 66 | github.com/gaukas/godicttls v0.0.4 // indirect 67 | github.com/go-logfmt/logfmt v0.6.0 // indirect 68 | github.com/go-ole/go-ole v1.2.6 // indirect 69 | github.com/go-playground/locales v0.14.1 // indirect 70 | github.com/go-playground/universal-translator v0.18.1 // indirect 71 | github.com/go-playground/validator/v10 v10.14.1 // indirect 72 | github.com/go-rod/rod v0.114.0 // indirect 73 | github.com/goburrow/cache v0.1.4 // indirect 74 | github.com/gobwas/glob v0.2.3 // indirect 75 | github.com/gobwas/httphead v0.1.0 // indirect 76 | github.com/gobwas/pool v0.2.1 // indirect 77 | github.com/gobwas/ws v1.2.1 // indirect 78 | github.com/gocolly/colly/v2 v2.1.0 // indirect 79 | github.com/golang-jwt/jwt/v4 v4.5.1 // indirect 80 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 81 | github.com/golang/protobuf v1.5.3 // indirect 82 | github.com/golang/snappy v0.0.4 // indirect 83 | github.com/google/certificate-transparency-go v1.1.4 // indirect 84 | github.com/google/go-github v17.0.0+incompatible // indirect 85 | github.com/google/go-github/v30 v30.1.0 // indirect 86 | github.com/google/go-querystring v1.1.0 // indirect 87 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect 88 | github.com/google/uuid v1.3.1 // indirect 89 | github.com/gorilla/css v1.0.0 // indirect 90 | github.com/h2non/filetype v1.1.3 // indirect 91 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 92 | github.com/hashicorp/go-retryablehttp v0.7.7 // indirect 93 | github.com/hashicorp/go-version v1.6.0 // indirect 94 | github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf // indirect 95 | github.com/hdm/jarm-go v0.0.7 // indirect 96 | github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect 97 | github.com/itchyny/gojq v0.12.13 // indirect 98 | github.com/itchyny/timefmt-go v0.1.5 // indirect 99 | github.com/json-iterator/go v1.1.12 // indirect 100 | github.com/julienschmidt/httprouter v1.3.0 // indirect 101 | github.com/kataras/jwt v0.1.8 // indirect 102 | github.com/kennygrant/sanitize v1.2.4 // indirect 103 | github.com/klauspost/compress v1.16.7 // indirect 104 | github.com/klauspost/cpuid/v2 v2.2.5 // indirect 105 | github.com/klauspost/pgzip v1.2.5 // indirect 106 | github.com/leodido/go-urn v1.2.4 // indirect 107 | github.com/libdns/libdns v0.2.1 // indirect 108 | github.com/logrusorgru/aurora v2.0.3+incompatible // indirect 109 | github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect 110 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 111 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect 112 | github.com/mackerelio/go-osstat v0.2.4 // indirect 113 | github.com/mattn/go-colorable v0.1.13 // indirect 114 | github.com/mattn/go-isatty v0.0.20 // indirect 115 | github.com/mattn/go-runewidth v0.0.14 // indirect 116 | github.com/mholt/acmez v1.2.0 // indirect 117 | github.com/mholt/archiver v3.1.1+incompatible // indirect 118 | github.com/mholt/archiver/v3 v3.5.1 // indirect 119 | github.com/microcosm-cc/bluemonday v1.0.25 // indirect 120 | github.com/miekg/dns v1.1.56 // indirect 121 | github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect 122 | github.com/mitchellh/go-homedir v1.1.0 // indirect 123 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 124 | github.com/modern-go/reflect2 v1.0.2 // indirect 125 | github.com/muesli/reflow v0.3.0 // indirect 126 | github.com/muesli/termenv v0.15.2 // indirect 127 | github.com/nwaples/rardecode v1.1.3 // indirect 128 | github.com/olekukonko/tablewriter v0.0.5 // indirect 129 | github.com/pierrec/lz4 v2.6.1+incompatible // indirect 130 | github.com/pierrec/lz4/v4 v4.1.2 // indirect 131 | github.com/pkg/errors v0.9.1 // indirect 132 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect 133 | github.com/projectdiscovery/asnmap v1.1.0 // indirect 134 | github.com/projectdiscovery/blackrock v0.0.1 // indirect 135 | github.com/projectdiscovery/cdncheck v1.0.9 // indirect 136 | github.com/projectdiscovery/clistats v0.0.19 // indirect 137 | github.com/projectdiscovery/dsl v0.0.20 // indirect 138 | github.com/projectdiscovery/fastdialer v0.1.1 // indirect 139 | github.com/projectdiscovery/fasttemplate v0.0.2 // indirect 140 | github.com/projectdiscovery/freeport v0.0.5 // indirect 141 | github.com/projectdiscovery/gologger v1.1.12 // indirect 142 | github.com/projectdiscovery/gostruct v0.0.1 // indirect 143 | github.com/projectdiscovery/hmap v0.0.45 // indirect 144 | github.com/projectdiscovery/httpx v1.3.4 // indirect 145 | github.com/projectdiscovery/interactsh v1.2.0 // indirect 146 | github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb // indirect 147 | github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect 148 | github.com/projectdiscovery/mapcidr v1.1.34 // indirect 149 | github.com/projectdiscovery/networkpolicy v0.0.8 // indirect 150 | github.com/projectdiscovery/rawhttp v0.1.18 // indirect 151 | github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 // indirect 152 | github.com/projectdiscovery/retryabledns v1.0.62 // indirect 153 | github.com/projectdiscovery/retryablehttp-go v1.0.63 // indirect 154 | github.com/projectdiscovery/sarif v0.0.1 // indirect 155 | github.com/projectdiscovery/tlsx v1.1.4 // indirect 156 | github.com/projectdiscovery/yamldoc-go v1.0.4 // indirect 157 | github.com/quic-go/quic-go v0.42.0 // indirect 158 | github.com/refraction-networking/utls v1.5.4 // indirect 159 | github.com/remeh/sizedwaitgroup v1.0.0 // indirect 160 | github.com/rivo/uniseg v0.4.4 // indirect 161 | github.com/rs/xid v1.5.0 // indirect 162 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect 163 | github.com/sashabaranov/go-openai v1.14.2 // indirect 164 | github.com/segmentio/ksuid v1.0.4 // indirect 165 | github.com/shirou/gopsutil/v3 v3.23.7 // indirect 166 | github.com/shoenig/go-m1cpu v0.1.6 // indirect 167 | github.com/spaolacci/murmur3 v1.1.0 // indirect 168 | github.com/spf13/cast v1.5.1 // indirect 169 | github.com/syndtr/goleveldb v1.0.0 // indirect 170 | github.com/temoto/robotstxt v1.1.2 // indirect 171 | github.com/tidwall/btree v1.6.0 // indirect 172 | github.com/tidwall/buntdb v1.3.0 // indirect 173 | github.com/tidwall/gjson v1.14.4 // indirect 174 | github.com/tidwall/grect v0.1.4 // indirect 175 | github.com/tidwall/match v1.1.1 // indirect 176 | github.com/tidwall/pretty v1.2.1 // indirect 177 | github.com/tidwall/rtred v0.1.2 // indirect 178 | github.com/tidwall/tinyqueue v0.1.1 // indirect 179 | github.com/tklauser/go-sysconf v0.3.12 // indirect 180 | github.com/tklauser/numcpus v0.6.1 // indirect 181 | github.com/trivago/tgo v1.0.7 // indirect 182 | github.com/ulikunitz/xz v0.5.11 // indirect 183 | github.com/valyala/bytebufferpool v1.0.0 // indirect 184 | github.com/valyala/fasttemplate v1.2.2 // indirect 185 | github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db // indirect 186 | github.com/xanzy/go-gitlab v0.84.0 // indirect 187 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect 188 | github.com/yl2chen/cidranger v1.0.2 // indirect 189 | github.com/ysmood/fetchup v0.2.3 // indirect 190 | github.com/ysmood/goob v0.4.0 // indirect 191 | github.com/ysmood/got v0.34.1 // indirect 192 | github.com/ysmood/gson v0.7.3 // indirect 193 | github.com/ysmood/leakless v0.8.0 // indirect 194 | github.com/yuin/goldmark v1.5.4 // indirect 195 | github.com/yuin/goldmark-emoji v1.0.1 // indirect 196 | github.com/yusufpapurcu/wmi v1.2.4 // indirect 197 | github.com/zcalusic/sysinfo v1.0.2 // indirect 198 | github.com/zeebo/blake3 v0.2.3 // indirect 199 | github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect 200 | github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 // indirect 201 | go.etcd.io/bbolt v1.3.7 // indirect 202 | go.uber.org/multierr v1.11.0 // indirect 203 | go.uber.org/zap v1.25.0 // indirect 204 | goftp.io/server/v2 v2.0.1 // indirect 205 | golang.org/x/crypto v0.21.0 // indirect 206 | golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect 207 | golang.org/x/mod v0.12.0 // indirect 208 | golang.org/x/net v0.23.0 // indirect 209 | golang.org/x/oauth2 v0.11.0 // indirect 210 | golang.org/x/sync v0.6.0 // indirect 211 | golang.org/x/sys v0.20.0 // indirect 212 | golang.org/x/term v0.18.0 // indirect 213 | golang.org/x/text v0.14.0 // indirect 214 | golang.org/x/time v0.5.0 // indirect 215 | golang.org/x/tools v0.13.0 // indirect 216 | google.golang.org/appengine v1.6.7 // indirect 217 | google.golang.org/protobuf v1.33.0 // indirect 218 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect 219 | gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect 220 | gopkg.in/djherbis/times.v1 v1.3.0 // indirect 221 | gopkg.in/yaml.v2 v2.4.0 // indirect 222 | gopkg.in/yaml.v3 v3.0.1 // indirect 223 | moul.io/http2curl v1.0.0 // indirect 224 | ) 225 | -------------------------------------------------------------------------------- /gomod2nix.toml: -------------------------------------------------------------------------------- 1 | schema = 3 2 | 3 | [mod] 4 | [mod."aead.dev/minisign"] 5 | version = "v0.2.0" 6 | hash = "sha256-2a05wSk811IdX9WSfMsrAvjPe6XVXEd4cvojrV+zqJ4=" 7 | [mod."git.mills.io/prologic/smtpd"] 8 | version = "v0.0.0-20210710122116-a525b76c287a" 9 | hash = "sha256-tbfKCLDJKAoZE3BvimQQLPn1cou2eA2wyMB0y1zPJEc=" 10 | [mod."github.com/Knetic/govaluate"] 11 | version = "v3.0.1-0.20171022003610-9aa49832a739+incompatible" 12 | hash = "sha256-Qs7qeK+Mrlm4ToAEYvN+OY6X7SRFV808frvKNr6gNhE=" 13 | [mod."github.com/Masterminds/semver/v3"] 14 | version = "v3.2.1" 15 | hash = "sha256-VKHIquwriyOL8A0qgtmap/3cGEOpDokOLtPg1w4xjMA=" 16 | [mod."github.com/Mzack9999/gcache"] 17 | version = "v0.0.0-20230410081825-519e28eab057" 18 | hash = "sha256-ofR592gukVdlEqA5ny9BPRDL4q2DrDTZeh4x1lrEmnQ=" 19 | [mod."github.com/Mzack9999/go-http-digest-auth-client"] 20 | version = "v0.6.1-0.20220414142836-eb8883508809" 21 | hash = "sha256-N4W589FOd0Oej0hpWsH0FaOBFxrYmAyX+L6eFW5sXDA=" 22 | [mod."github.com/Mzack9999/ldapserver"] 23 | version = "v1.0.2-0.20211229000134-b44a0d6ad0dd" 24 | hash = "sha256-s7X5Zd9Py8mKjJ/xWfgtrmYXl6ynpETwf0KXlnj3rRc=" 25 | [mod."github.com/PuerkitoBio/goquery"] 26 | version = "v1.8.1" 27 | hash = "sha256-z2RaB8PVPEzSJdMUfkfNjT616yXWTjW2gkhNOh989ZU=" 28 | [mod."github.com/VividCortex/ewma"] 29 | version = "v1.2.0" 30 | hash = "sha256-mHprIVRUOgs1qyYpiMO3bh6fCzDrqasDsaTaRE0oHXI=" 31 | [mod."github.com/akrylysov/pogreb"] 32 | version = "v0.10.1" 33 | hash = "sha256-f1BoPiR4KghX68eDPYQVuv1AVj97X1a+biip4vCrQ/s=" 34 | [mod."github.com/alecthomas/chroma"] 35 | version = "v0.10.0" 36 | hash = "sha256-p721vddVTv4iv1O0/dqpdk5xF6x9iLIHcrfh8JEVnqQ=" 37 | [mod."github.com/alecthomas/jsonschema"] 38 | version = "v0.0.0-20211022214203-8b29eab41725" 39 | hash = "sha256-l0OFXpa2E/t839tJGLY6jJUCuQC0SLCseYKsfM5o2vI=" 40 | [mod."github.com/alecthomas/template"] 41 | version = "v0.0.0-20190718012654-fb15b899a751" 42 | hash = "sha256-RsS4qxdRQ3q+GejA8D9Iu31A/mZNms4LbJ7518jWiu4=" 43 | [mod."github.com/alecthomas/units"] 44 | version = "v0.0.0-20211218093645-b94a6e3cc137" 45 | hash = "sha256-uriYmwxT69xbmWKO/5OAyeMa2lFBOJDrU2KtQh/+ZjY=" 46 | [mod."github.com/andybalholm/brotli"] 47 | version = "v1.0.5" 48 | hash = "sha256-/qS8wU8yZQJ+uTOg66rEl9s7spxq9VIXF5L1BcaEClc=" 49 | [mod."github.com/andybalholm/cascadia"] 50 | version = "v1.3.2" 51 | hash = "sha256-Nc9SkqJO/ecincVcUBFITy24TMmMGj5o0Q8EgdNhrEk=" 52 | [mod."github.com/andygrunwald/go-jira"] 53 | version = "v1.16.0" 54 | hash = "sha256-veyWp65T9uYYmw9o0g4w6tqn5Svq5++WFXNfy4vI+HA=" 55 | [mod."github.com/antchfx/htmlquery"] 56 | version = "v1.3.0" 57 | hash = "sha256-tldRSQPTmUodUepZkOnISWjfWPY37MzNN2Pd2/zmvoo=" 58 | [mod."github.com/antchfx/xmlquery"] 59 | version = "v1.3.15" 60 | hash = "sha256-uenaH5HiVcIswTjfwm2qqOA0ljY5la0BI4NiH4LjFD4=" 61 | [mod."github.com/antchfx/xpath"] 62 | version = "v1.2.4" 63 | hash = "sha256-rT5AtOv49/iGdR6X42Ho+ZEw6+YGQqfNUcYkSp1CU/g=" 64 | [mod."github.com/asaskevich/govalidator"] 65 | version = "v0.0.0-20230301143203-a9d515a09cc2" 66 | hash = "sha256-UCENzt1c1tFgsAzK2TNq5s2g0tQMQ5PxFaQKe8hTL/A=" 67 | [mod."github.com/aws/aws-sdk-go-v2"] 68 | version = "v1.19.0" 69 | hash = "sha256-z4UJRyk3eLx0yQ3kTl3zKH6bEM7MK1sqPQKvbP8d2Ec=" 70 | [mod."github.com/aws/aws-sdk-go-v2/config"] 71 | version = "v1.18.28" 72 | hash = "sha256-zFNtrknzaJ0zQr8EOT/3Y1qqZ/YcRMizRUZHxt9QY0I=" 73 | [mod."github.com/aws/aws-sdk-go-v2/credentials"] 74 | version = "v1.13.27" 75 | hash = "sha256-so4NK+rlyZnBtxgUNLld/G7vQKP/wp1A6wRJtaZT2pU=" 76 | [mod."github.com/aws/aws-sdk-go-v2/feature/ec2/imds"] 77 | version = "v1.13.5" 78 | hash = "sha256-zseMGwUW3NjzhD5IixiTiwp7x9hRAvpMbADEaYIB6Ig=" 79 | [mod."github.com/aws/aws-sdk-go-v2/internal/configsources"] 80 | version = "v1.1.35" 81 | hash = "sha256-TuDsdVuVbqUQbV4Y2E9Exmlu2an0yrfMGgdTHhXY85E=" 82 | [mod."github.com/aws/aws-sdk-go-v2/internal/endpoints/v2"] 83 | version = "v2.4.29" 84 | hash = "sha256-P+9wAU5sbBn1tQqS1nFwisaoa3999czJilowwO2rO3Y=" 85 | [mod."github.com/aws/aws-sdk-go-v2/internal/ini"] 86 | version = "v1.3.36" 87 | hash = "sha256-9VmY8oidPMnAfpt2AyiCSSascqBZGGLtIizTydlK8k8=" 88 | [mod."github.com/aws/aws-sdk-go-v2/service/internal/presigned-url"] 89 | version = "v1.9.29" 90 | hash = "sha256-mXNOY17gXxhS2NV7azA0mxrARkROGrrpeN0Lgg7KQSw=" 91 | [mod."github.com/aws/aws-sdk-go-v2/service/sso"] 92 | version = "v1.12.13" 93 | hash = "sha256-F4tTYdgFvDImOQNuKQFFsLwd6bX1CO50Ab3KYqY32Lc=" 94 | [mod."github.com/aws/aws-sdk-go-v2/service/ssooidc"] 95 | version = "v1.14.13" 96 | hash = "sha256-XGj/ccaj00wNN32J3JTuuqthCbxrTfmxfSYJLf/hK8Y=" 97 | [mod."github.com/aws/aws-sdk-go-v2/service/sts"] 98 | version = "v1.19.3" 99 | hash = "sha256-Q8NFgFRjNUFldTmr/Ya9DyAUNfsC9AuWPkSFMrVF/jg=" 100 | [mod."github.com/aws/smithy-go"] 101 | version = "v1.13.5" 102 | hash = "sha256-lu1UnvPnLzXjDPBk2FJ4ZImKRQf7aj43mLbuolFdE64=" 103 | [mod."github.com/aymanbagabas/go-osc52/v2"] 104 | version = "v2.0.1" 105 | hash = "sha256-6Bp0jBZ6npvsYcKZGHHIUSVSTAMEyieweAX2YAKDjjg=" 106 | [mod."github.com/aymerick/douceur"] 107 | version = "v0.2.0" 108 | hash = "sha256-NiBX8EfOvLXNiK3pJaZX4N73YgfzdrzRXdiBFe3X3sE=" 109 | [mod."github.com/bluele/gcache"] 110 | version = "v0.0.2" 111 | hash = "sha256-gU44V3jqw6K3Mjgh6DG9f7DU+ft3wA9GDmH4AgMTjxE=" 112 | [mod."github.com/caddyserver/certmagic"] 113 | version = "v0.19.2" 114 | hash = "sha256-ruz2oG5E834tMjyL/HdFPaWlNuwBg/fxqVitZX3sQR0=" 115 | [mod."github.com/charmbracelet/glamour"] 116 | version = "v0.6.0" 117 | hash = "sha256-L5V2P/9EPP80703KJUSMDiAPgjW1B4i1IbJADPmUCoY=" 118 | [mod."github.com/charmbracelet/lipgloss"] 119 | version = "v0.8.0" 120 | hash = "sha256-m+cRJCCJjNyxJKxCk1ftu32OMesYDIUw/EVUzTZjo9I=" 121 | [mod."github.com/charmbracelet/log"] 122 | version = "v0.2.4" 123 | hash = "sha256-LQe3fQHf/v6q8pegS5E54eSfU0Y5tnKXM+Mk6uzeWvU=" 124 | [mod."github.com/cheggaaa/pb/v3"] 125 | version = "v3.1.4" 126 | hash = "sha256-Fl0bM8ag8sKr8C/hj5qaxN+VjmRA403xXcQoTdQ19LU=" 127 | [mod."github.com/cloudflare/cfssl"] 128 | version = "v1.6.4" 129 | hash = "sha256-dAUHPutZ+bpDgJ0mWrALLIbQqNF2d1OkgSAWzQkxXWY=" 130 | [mod."github.com/cloudflare/circl"] 131 | version = "v1.3.3" 132 | hash = "sha256-ItdVkU53Ep01553/tJ4MdAwoTpPljRxiBW9sAd7p0xI=" 133 | [mod."github.com/cnf/structhash"] 134 | version = "v0.0.0-20201127153200-e1b16c1ebc08" 135 | hash = "sha256-hvJSTpbaPHgWnJ16B9a4cFVblplAgCw5OkGSUFmJBvg=" 136 | [mod."github.com/corpix/uarand"] 137 | version = "v0.2.0" 138 | hash = "sha256-/2ZqTtYPEbfn5adf5tIU9p8jwHFRkBYzi4WE5h2AwkI=" 139 | [mod."github.com/dimchansky/utfbom"] 140 | version = "v1.1.1" 141 | hash = "sha256-w8KEprK54zJkMat78T6zldjDwvhbc/O8s6pVFzfmg1I=" 142 | [mod."github.com/dlclark/regexp2"] 143 | version = "v1.8.1" 144 | hash = "sha256-Xm4I+Qrpwn21QsWcUMden00zWapbloa6K1yJ83tTOVE=" 145 | [mod."github.com/docker/go-units"] 146 | version = "v0.5.0" 147 | hash = "sha256-iK/V/jJc+borzqMeqLY+38Qcts2KhywpsTk95++hImE=" 148 | [mod."github.com/dsnet/compress"] 149 | version = "v0.0.1" 150 | hash = "sha256-HCqu3cKayMvx1YIUPkJ+u4UM6WN8nrsNIhdvGJIJgwg=" 151 | [mod."github.com/fatih/color"] 152 | version = "v1.15.0" 153 | hash = "sha256-7b+scFVQeEUoXfeCDd8X2gS8GMoWA+HxjK8wfbypa5s=" 154 | [mod."github.com/fatih/structs"] 155 | version = "v1.1.0" 156 | hash = "sha256-OCmubTLF1anwNnkvFZDYHnF6hFlX0WDoe/9+dDlaMPM=" 157 | [mod."github.com/gabriel-vasile/mimetype"] 158 | version = "v1.4.2" 159 | hash = "sha256-laV+IkgbnEG07h1eFfPISqp0ctnLXfzchz/CLR1lftk=" 160 | [mod."github.com/gaukas/godicttls"] 161 | version = "v0.0.4" 162 | hash = "sha256-Tok6mN6P7rnqK+VCiI6LOV9DBnOTjGyGrgfzZdMCMVk=" 163 | [mod."github.com/go-logfmt/logfmt"] 164 | version = "v0.6.0" 165 | hash = "sha256-RtIG2qARd5sT10WQ7F3LR8YJhS8exs+KiuUiVf75bWg=" 166 | [mod."github.com/go-ole/go-ole"] 167 | version = "v1.2.6" 168 | hash = "sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs=" 169 | [mod."github.com/go-playground/locales"] 170 | version = "v0.14.1" 171 | hash = "sha256-BMJGAexq96waZn60DJXZfByRHb8zA/JP/i6f/YrW9oQ=" 172 | [mod."github.com/go-playground/universal-translator"] 173 | version = "v0.18.1" 174 | hash = "sha256-2/B2qP51zfiY+k8G0w0D03KXUc7XpWj6wKY7NjNP/9E=" 175 | [mod."github.com/go-playground/validator/v10"] 176 | version = "v10.14.1" 177 | hash = "sha256-13J8JqIuhI7lbBagaR7INykFRXqRbB7tjXtMZI3PNvA=" 178 | [mod."github.com/go-rod/rod"] 179 | version = "v0.114.0" 180 | hash = "sha256-YQwPbgeBPziMTmFg8kulEQkdTi3OTUutlX+8CmCdQ94=" 181 | [mod."github.com/goburrow/cache"] 182 | version = "v0.1.4" 183 | hash = "sha256-3imkv1DlePYg0aBswzxqOn1EzZFwMXW+D3Dq0u0GEEQ=" 184 | [mod."github.com/gobwas/glob"] 185 | version = "v0.2.3" 186 | hash = "sha256-hYHMUdwxVkMOjSKjR7UWO0D0juHdI4wL8JEy5plu/Jc=" 187 | [mod."github.com/gobwas/httphead"] 188 | version = "v0.1.0" 189 | hash = "sha256-6wFni/JkK2GqtVs3IW+GxHRNoSu4EJfzaBRGX2hF1IA=" 190 | [mod."github.com/gobwas/pool"] 191 | version = "v0.2.1" 192 | hash = "sha256-py8/+Wo5Q83EbYMUKK5U/4scRcyMo2MjOoxqi5y+sUY=" 193 | [mod."github.com/gobwas/ws"] 194 | version = "v1.2.1" 195 | hash = "sha256-5kWY244Vuyj01BzgTJuaJUJJwTXaKZ0UzPruKATByEg=" 196 | [mod."github.com/gocolly/colly/v2"] 197 | version = "v2.1.0" 198 | hash = "sha256-yWhPcNwGj31wWJrnHWOa3jBO1qZXfqOWuHDlmpSPuyg=" 199 | [mod."github.com/golang-jwt/jwt/v4"] 200 | version = "v4.5.0" 201 | hash = "sha256-dyKL8wQRApkdCkKxJ1knllvixsrBLw+BtRS0SjlN7NQ=" 202 | [mod."github.com/golang/groupcache"] 203 | version = "v0.0.0-20210331224755-41bb18bfe9da" 204 | hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0=" 205 | [mod."github.com/golang/protobuf"] 206 | version = "v1.5.3" 207 | hash = "sha256-svogITcP4orUIsJFjMtp+Uv1+fKJv2Q5Zwf2dMqnpOQ=" 208 | [mod."github.com/golang/snappy"] 209 | version = "v0.0.4" 210 | hash = "sha256-Umx+5xHAQCN/Gi4HbtMhnDCSPFAXSsjVbXd8n5LhjAA=" 211 | [mod."github.com/google/certificate-transparency-go"] 212 | version = "v1.1.4" 213 | hash = "sha256-/V18IcVehgvhkT+w7y8vpXaVAtdV3BAsxOnbRBromGw=" 214 | [mod."github.com/google/go-github"] 215 | version = "v17.0.0+incompatible" 216 | hash = "sha256-5EGZnkefwLCEODLICIgaq39UoOzBJqpeLraoc2hJfM8=" 217 | [mod."github.com/google/go-github/v30"] 218 | version = "v30.1.0" 219 | hash = "sha256-u6m+wWJl440UI64Q2tpX0qFF3LyEH3hPww82hIEf6/Q=" 220 | [mod."github.com/google/go-querystring"] 221 | version = "v1.1.0" 222 | hash = "sha256-itsKgKghuX26czU79cK6C2n+lc27jm5Dw1XbIRgwZJY=" 223 | [mod."github.com/google/uuid"] 224 | version = "v1.3.1" 225 | hash = "sha256-JxAEAB2bFlGPShFreyOWjUahjaGV3xYS5TpfUOikod0=" 226 | [mod."github.com/gorilla/css"] 227 | version = "v1.0.0" 228 | hash = "sha256-Mmt/IqHpgrtWpbr/AKcJyf/USQTqEuv1HVivY4eHzoQ=" 229 | [mod."github.com/h2non/filetype"] 230 | version = "v1.1.3" 231 | hash = "sha256-lSX/fSbT3MVlNK7d1U6Q/lBHtGXXAQ/HY4zW6Bppqhc=" 232 | [mod."github.com/hashicorp/go-cleanhttp"] 233 | version = "v0.5.2" 234 | hash = "sha256-N9GOKYo7tK6XQUFhvhImtL7PZW/mr4C4Manx/yPVvcQ=" 235 | [mod."github.com/hashicorp/go-retryablehttp"] 236 | version = "v0.7.2" 237 | hash = "sha256-PcLyolWF7G409rs7j3tnwgQK6xhgWYk9/iK2bO13TGQ=" 238 | [mod."github.com/hashicorp/go-version"] 239 | version = "v1.6.0" 240 | hash = "sha256-UV0equpmW6BiJnp4W3TZlSJ+PTHuTA+CdOs2JTeHhjs=" 241 | [mod."github.com/hbakhtiyor/strsim"] 242 | version = "v0.0.0-20190107154042-4d2bbb273edf" 243 | hash = "sha256-vK4ghGQy9IGvAq0/3roEDiE/ybNOePULr4s/V8ZHLj8=" 244 | [mod."github.com/hdm/jarm-go"] 245 | version = "v0.0.7" 246 | hash = "sha256-4SnBXV+O7iWPO0Yt9/D1BhaF7MEvNUrwBj116uMt5j0=" 247 | [mod."github.com/iancoleman/orderedmap"] 248 | version = "v0.0.0-20190318233801-ac98e3ecb4b0" 249 | hash = "sha256-IIm0P6GnYSBGHzOYc7ljp+5LPoWBmmqXt1Yi4vBRdsQ=" 250 | [mod."github.com/itchyny/gojq"] 251 | version = "v0.12.13" 252 | hash = "sha256-tlnj0CCsPZRQjIZCvNPjN0JD6oqRDvdWOCYR3tYMPUA=" 253 | [mod."github.com/itchyny/timefmt-go"] 254 | version = "v0.1.5" 255 | hash = "sha256-FvgqEW8fnZsfbHpV+X4FQvDzzneNOpdQtQLXovh1YmI=" 256 | [mod."github.com/json-iterator/go"] 257 | version = "v1.1.12" 258 | hash = "sha256-To8A0h+lbfZ/6zM+2PpRpY3+L6725OPC66lffq6fUoM=" 259 | [mod."github.com/julienschmidt/httprouter"] 260 | version = "v1.3.0" 261 | hash = "sha256-YVbnyFLVZX1mtqcwM1SStQdhcQsPHyi1ltpOrD3w2qg=" 262 | [mod."github.com/kataras/jwt"] 263 | version = "v0.1.8" 264 | hash = "sha256-3AKX8wmQ6RaRMAyhe1JirEl1P0ZiMNRJZ3D1yzBRuCU=" 265 | [mod."github.com/kennygrant/sanitize"] 266 | version = "v1.2.4" 267 | hash = "sha256-PRNblaLosaB7tvUVgAOZORMZGUo+7Wy7h1Z1mpJLd5c=" 268 | [mod."github.com/klauspost/compress"] 269 | version = "v1.16.7" 270 | hash = "sha256-8miX/lnXyNLPSqhhn5BesLauaIAxETpQpWtr1cu2f+0=" 271 | [mod."github.com/klauspost/cpuid/v2"] 272 | version = "v2.2.5" 273 | hash = "sha256-/M8CHNah2/EPr0va44r1Sx+3H6E+jN8bGFi5jQkLBrM=" 274 | [mod."github.com/leodido/go-urn"] 275 | version = "v1.2.4" 276 | hash = "sha256-N2HO7ChScxI79KGvXI9LxoIlr+lkBNdDZP9OPGwPRK0=" 277 | [mod."github.com/libdns/libdns"] 278 | version = "v0.2.1" 279 | hash = "sha256-bxEY0wYu4Um0t7sakLyMwMPDXfv2x07gjckKSyAypsc=" 280 | [mod."github.com/logrusorgru/aurora"] 281 | version = "v2.0.3+incompatible" 282 | hash = "sha256-7o5Fh4jscdYKgXfnNMbcD68Kjw8Z4LcPgHcr4ZyQYrI=" 283 | [mod."github.com/lor00x/goldap"] 284 | version = "v0.0.0-20180618054307-a546dffdd1a3" 285 | hash = "sha256-wE3bDMJqd+drbrYK0QPF3GMQOzgB8u9uN2T0uUX9xow=" 286 | [mod."github.com/lucasb-eyer/go-colorful"] 287 | version = "v1.2.0" 288 | hash = "sha256-Gg9dDJFCTaHrKHRR1SrJgZ8fWieJkybljybkI9x0gyE=" 289 | [mod."github.com/lufia/plan9stats"] 290 | version = "v0.0.0-20211012122336-39d0f177ccd0" 291 | hash = "sha256-thb+rkDx5IeWMgw5/5jgu5gZ+6RjJAUXeMgSkJHhRlA=" 292 | [mod."github.com/mackerelio/go-osstat"] 293 | version = "v0.2.4" 294 | hash = "sha256-WW5VbvDedsNRxclUjI/pvlf4vB4VyDKEGlpvcLqiAyo=" 295 | [mod."github.com/mattn/go-colorable"] 296 | version = "v0.1.13" 297 | hash = "sha256-qb3Qbo0CELGRIzvw7NVM1g/aayaz4Tguppk9MD2/OI8=" 298 | [mod."github.com/mattn/go-isatty"] 299 | version = "v0.0.19" 300 | hash = "sha256-wYQqGxeqV3Elkmn26Md8mKZ/viw598R4Ych3vtt72YE=" 301 | [mod."github.com/mattn/go-runewidth"] 302 | version = "v0.0.14" 303 | hash = "sha256-O3QdxqAcJgQ+HL1v8oBA4iKBwJ2AlDN+F464027hWMU=" 304 | [mod."github.com/mholt/acmez"] 305 | version = "v1.2.0" 306 | hash = "sha256-zfj14WFQr1/AO64gYsbFk4a4T0dsMEs+W3uIa9968/M=" 307 | [mod."github.com/mholt/archiver"] 308 | version = "v3.1.1+incompatible" 309 | hash = "sha256-+XCbzKmuqktmYveDdJCNWB8B6Ya8yJM8H7uugYxrhhA=" 310 | [mod."github.com/microcosm-cc/bluemonday"] 311 | version = "v1.0.25" 312 | hash = "sha256-/crG5s6cDrJ55nkDBwugLUpY7U+vQuHpCkKm7nnN8Zc=" 313 | [mod."github.com/miekg/dns"] 314 | version = "v1.1.55" 315 | hash = "sha256-Jbii9veDSpqF7yIkdrzb/bEUM3wZG41mNEAYV3VEAJo=" 316 | [mod."github.com/minio/selfupdate"] 317 | version = "v0.6.0" 318 | hash = "sha256-CupJKkF1MNaOEMBPjfCxF+k/k3yNWXfWShmJfezg3O4=" 319 | [mod."github.com/mitchellh/go-homedir"] 320 | version = "v1.1.0" 321 | hash = "sha256-oduBKXHAQG8X6aqLEpqZHs5DOKe84u6WkBwi4W6cv3k=" 322 | [mod."github.com/modern-go/concurrent"] 323 | version = "v0.0.0-20180306012644-bacd9c7ef1dd" 324 | hash = "sha256-OTySieAgPWR4oJnlohaFTeK1tRaVp/b0d1rYY8xKMzo=" 325 | [mod."github.com/modern-go/reflect2"] 326 | version = "v1.0.2" 327 | hash = "sha256-+W9EIW7okXIXjWEgOaMh58eLvBZ7OshW2EhaIpNLSBU=" 328 | [mod."github.com/muesli/reflow"] 329 | version = "v0.3.0" 330 | hash = "sha256-Pou2ybE9SFSZG6YfZLVV1Eyfm+X4FuVpDPLxhpn47Cc=" 331 | [mod."github.com/muesli/termenv"] 332 | version = "v0.15.2" 333 | hash = "sha256-Eum/SpyytcNIchANPkG4bYGBgcezLgej7j/+6IhqoMU=" 334 | [mod."github.com/nwaples/rardecode"] 335 | version = "v1.1.3" 336 | hash = "sha256-X7Cg0kEygyy6Xw6sxRF9HirgefkH9tn9UPPelxRaAGg=" 337 | [mod."github.com/olekukonko/tablewriter"] 338 | version = "v0.0.5" 339 | hash = "sha256-/5i70IkH/qSW5KjGzv8aQNKh9tHoz98tqtL0K2DMFn4=" 340 | [mod."github.com/pierrec/lz4"] 341 | version = "v2.6.1+incompatible" 342 | hash = "sha256-5+4i5SN97wG71knAF9eUgEEG5k03HW4wPnAdPd6JSfE=" 343 | [mod."github.com/pkg/errors"] 344 | version = "v0.9.1" 345 | hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw=" 346 | [mod."github.com/power-devops/perfstat"] 347 | version = "v0.0.0-20210106213030-5aafc221ea8c" 348 | hash = "sha256-ywykDYuqcMt0TvZOz1l9Z6Z2JMTYQw8cP2fT8AtpmX4=" 349 | [mod."github.com/projectdiscovery/asnmap"] 350 | version = "v1.0.4" 351 | hash = "sha256-J5Dn5eDzwj+ApwQ3ibTsMbwCobRAb1Cli+hbf74I9VQ=" 352 | [mod."github.com/projectdiscovery/blackrock"] 353 | version = "v0.0.1" 354 | hash = "sha256-E66IuBQ3meaGTVk26YzlUDwdUV4kP7VLhrhLnQShkHA=" 355 | [mod."github.com/projectdiscovery/cdncheck"] 356 | version = "v1.0.9" 357 | hash = "sha256-fJngwA9mAYB2awhEhS1gWXhOlmKeLrNV8WQj0r5y7Q0=" 358 | [mod."github.com/projectdiscovery/clistats"] 359 | version = "v0.0.19" 360 | hash = "sha256-vW7h0Eqm578jI/REU48rexVXGAeZt7JThRSeFm3gUt4=" 361 | [mod."github.com/projectdiscovery/dsl"] 362 | version = "v0.0.20" 363 | hash = "sha256-wkDZVgSU6EK5t6tH+g6EsEaTZ9bDNqIdix3I2MnQXOE=" 364 | [mod."github.com/projectdiscovery/fastdialer"] 365 | version = "v0.0.37" 366 | hash = "sha256-XxUFV6yfbH3Qw+Euogk/YFlHDxJtB4AIpOoFDK7poBY=" 367 | [mod."github.com/projectdiscovery/fasttemplate"] 368 | version = "v0.0.2" 369 | hash = "sha256-kl0lxr7Zhubs3b8Xgt5DRHVj6XxM/WtEAiVkecy62O4=" 370 | [mod."github.com/projectdiscovery/freeport"] 371 | version = "v0.0.5" 372 | hash = "sha256-14FrV/9ImnzdH8Pgl8VmgNhtEoqJtJGMO4QoYHdEZig=" 373 | [mod."github.com/projectdiscovery/goflags"] 374 | version = "v0.1.19" 375 | hash = "sha256-x72o/EiV2cTf9BW2XRwDGxW7rYFuXnmVc4MJyjoNvIg=" 376 | [mod."github.com/projectdiscovery/gologger"] 377 | version = "v1.1.11" 378 | hash = "sha256-ujoMwz77PRSqwE7Dr+MCm8144trX4le8z3l5yVNhMVs=" 379 | [mod."github.com/projectdiscovery/gostruct"] 380 | version = "v0.0.1" 381 | hash = "sha256-OhglrSmIVlNBWkY9WrIQB4SL4P47H/uqX9l+LjNZhSQ=" 382 | [mod."github.com/projectdiscovery/hmap"] 383 | version = "v0.0.16" 384 | hash = "sha256-mgnvUmgvTm7S71t5rK87eIxRHXZKsR7dUxAOuputtsE=" 385 | [mod."github.com/projectdiscovery/httpx"] 386 | version = "v1.3.4" 387 | hash = "sha256-Ye5xYjMaZamigmumgFzo8f3suXRJMOfJQa1S4OV2Gks=" 388 | [mod."github.com/projectdiscovery/interactsh"] 389 | version = "v1.1.6" 390 | hash = "sha256-kkUiuODfQwGesZi5w+t6f2BAIe9PLBDb24ltpbOqzp0=" 391 | [mod."github.com/projectdiscovery/mapcidr"] 392 | version = "v1.1.2" 393 | hash = "sha256-MXY4WRzRZ7OwuUxq5pCFgipHNakCB9U0UaNjYA5xnm8=" 394 | [mod."github.com/projectdiscovery/networkpolicy"] 395 | version = "v0.0.6" 396 | hash = "sha256-TEuxI6vJly0Sh1vkYhrr+EHZdFNZKOvNaU3q3cNyIlA=" 397 | [mod."github.com/projectdiscovery/nuclei/v2"] 398 | version = "v2.9.14" 399 | hash = "sha256-mTx6QCs0sTEHQX9/frJ6J1F+sJgmc4TqeoXR1esuTMY=" 400 | [mod."github.com/projectdiscovery/ratelimit"] 401 | version = "v0.0.9" 402 | hash = "sha256-/puvEIORXvDGDzotR0DhQnRXQramZYNtjaxjV0KgrN8=" 403 | [mod."github.com/projectdiscovery/rawhttp"] 404 | version = "v0.1.18" 405 | hash = "sha256-RkXxq/MAkPLTPzFvG90JgGtOeH/5oOPhCb42HCBweqs=" 406 | [mod."github.com/projectdiscovery/rdap"] 407 | version = "v0.9.1-0.20221108103045-9865884d1917" 408 | hash = "sha256-BEZDRPZPjhkNoyj/8Tk21UM98plLNitZ1W52GktJvMs=" 409 | [mod."github.com/projectdiscovery/retryabledns"] 410 | version = "v1.0.35" 411 | hash = "sha256-pGq+ZSETmt10PzBBY7ePnq+JW9YBJa9xq9+r1TmJY1E=" 412 | [mod."github.com/projectdiscovery/retryablehttp-go"] 413 | version = "v1.0.25" 414 | hash = "sha256-O2OksMSebG5fyiKlkTqC/draHa4g4ERYwuOmsZLPqec=" 415 | [mod."github.com/projectdiscovery/sarif"] 416 | version = "v0.0.1" 417 | hash = "sha256-m1s98hDVLAYbXgB0AEqHktZw2N89QeojqPZ7ConL4OE=" 418 | [mod."github.com/projectdiscovery/tlsx"] 419 | version = "v1.1.4" 420 | hash = "sha256-EMTNd5NOvaFbVxv31j3pBU//mWQQpThswCT8bMNx5Qw=" 421 | [mod."github.com/projectdiscovery/utils"] 422 | version = "v0.0.52" 423 | hash = "sha256-TOUCrtkO976RqBy6w4mQXJ8n/5klkg9tWuEMHdMooHg=" 424 | [mod."github.com/projectdiscovery/yamldoc-go"] 425 | version = "v1.0.4" 426 | hash = "sha256-ufjSaGHdRzyusbg5XKG6NVX/UyrUu2PBvGBl0Bour6I=" 427 | [mod."github.com/quic-go/quic-go"] 428 | version = "v0.37.4" 429 | hash = "sha256-EXsOITb0kh48+Wy2bIZyyNeGVuJmiL6xB0mtPOBUY/Y=" 430 | [mod."github.com/refraction-networking/utls"] 431 | version = "v1.5.2" 432 | hash = "sha256-QwYwEFkpo82NP4l6n6/+5HXzcFt6bEYqy4jFomushkw=" 433 | [mod."github.com/remeh/sizedwaitgroup"] 434 | version = "v1.0.0" 435 | hash = "sha256-CtjNoNeep0TnfkuRN/rc48diAo0jUog1fOz3I/z6jfc=" 436 | [mod."github.com/rivo/uniseg"] 437 | version = "v0.4.4" 438 | hash = "sha256-B8tbL9K6ICLdm0lEhs9+h4cpjAfvFtNiFMGvQZmw0bM=" 439 | [mod."github.com/rocketlaunchr/google-search"] 440 | version = "v1.1.6" 441 | hash = "sha256-2BMD4RXtrxMKC8AaxyeU/p1i92MvGIQjv4KOA4giXfk=" 442 | [mod."github.com/rs/xid"] 443 | version = "v1.5.0" 444 | hash = "sha256-u0QLm2YFMJqEjUhpWcLwfoS9lNHUxc2A79MObsqVbVU=" 445 | [mod."github.com/saintfish/chardet"] 446 | version = "v0.0.0-20230101081208-5e3ef4b5456d" 447 | hash = "sha256-JXlHMCbXB8iRQ9wQBGCeTjDSfgaBwUVOpvcjj0iVn5A=" 448 | [mod."github.com/sashabaranov/go-openai"] 449 | version = "v1.14.2" 450 | hash = "sha256-dc1SL5n3sOZPL018JDnqM6W/8pTwg7xUtxEnON4v+lM=" 451 | [mod."github.com/segmentio/ksuid"] 452 | version = "v1.0.4" 453 | hash = "sha256-50molk1vt8/n4Y+ruayW/EAn9NeeQ8ApmLJQVePhieE=" 454 | [mod."github.com/shirou/gopsutil/v3"] 455 | version = "v3.23.7" 456 | hash = "sha256-UppGryc5MO0sY3PuOC4H3hYsSomVTaXhgEprOsNFqe4=" 457 | [mod."github.com/shoenig/go-m1cpu"] 458 | version = "v0.1.6" 459 | hash = "sha256-hT+JP30BBllsXosK/lo89HV/uxxPLsUyO3dRaDiLnCg=" 460 | [mod."github.com/spaolacci/murmur3"] 461 | version = "v1.1.0" 462 | hash = "sha256-RWD4PPrlAsZZ8Xy356MBxpj+/NZI7w2XOU14Ob7/Y9M=" 463 | [mod."github.com/spf13/cast"] 464 | version = "v1.5.1" 465 | hash = "sha256-/tQNGGQv+Osp+2jepQaQe6GlncZbqdxzSR82FieiUBU=" 466 | [mod."github.com/syndtr/goleveldb"] 467 | version = "v1.0.0" 468 | hash = "sha256-rW7SW6nehede0oMZo4NBatM6Eizbnlb7xYoX/dcDUxA=" 469 | [mod."github.com/temoto/robotstxt"] 470 | version = "v1.1.2" 471 | hash = "sha256-/0zXEWCnvefGjU2RNxoyZu15KU6WYe9C4m58kyLU6zo=" 472 | [mod."github.com/tidwall/btree"] 473 | version = "v1.6.0" 474 | hash = "sha256-H4S46Yk3tVfOtrEhVWUrF4S1yWYmzU43W80HlzS9rcY=" 475 | [mod."github.com/tidwall/buntdb"] 476 | version = "v1.3.0" 477 | hash = "sha256-tXp+wcPYogh/Thubk4baFLpbwrCGVf0URvlBXwGg3eQ=" 478 | [mod."github.com/tidwall/gjson"] 479 | version = "v1.14.4" 480 | hash = "sha256-3DS2YNL95wG0qSajgRtIABD32J+oblaKVk8LIw+KSOc=" 481 | [mod."github.com/tidwall/grect"] 482 | version = "v0.1.4" 483 | hash = "sha256-iSS8YjTqtmlzK9T3PFXoLx5xF/vC8864yNzGw0KYwKs=" 484 | [mod."github.com/tidwall/match"] 485 | version = "v1.1.1" 486 | hash = "sha256-M2klhPId3Q3T3VGkSbOkYl/2nLHnsG+yMbXkPkyrRdg=" 487 | [mod."github.com/tidwall/pretty"] 488 | version = "v1.2.1" 489 | hash = "sha256-S0uTDDGD8qr415Ut7QinyXljCp0TkL4zOIrlJ+9OMl8=" 490 | [mod."github.com/tidwall/rtred"] 491 | version = "v0.1.2" 492 | hash = "sha256-C4p3rZWRLuNgbfVVPr83PZjbD8rZNN3a3YGQJQJlSQU=" 493 | [mod."github.com/tidwall/tinyqueue"] 494 | version = "v0.1.1" 495 | hash = "sha256-vsVVA0dAkYtX/C/pk0nDUiu6kURZrK+rxVBRB4wY78Q=" 496 | [mod."github.com/tklauser/go-sysconf"] 497 | version = "v0.3.11" 498 | hash = "sha256-io8s7PJi4OX+wXkCm+v5pKy4yiqA/RE/I4ksy6mKX30=" 499 | [mod."github.com/tklauser/numcpus"] 500 | version = "v0.6.0" 501 | hash = "sha256-6jssTsP5L6yVl43tXfqDdgeI+tEkBp3BpiWwKXLTHAM=" 502 | [mod."github.com/trivago/tgo"] 503 | version = "v1.0.7" 504 | hash = "sha256-VzCbopX6wKWVWmcr/qnKf4ruMicwyEeNfCEWc0UxoxI=" 505 | [mod."github.com/ulikunitz/xz"] 506 | version = "v0.5.11" 507 | hash = "sha256-SUyrjc2wyN3cTGKe5JdBEXjtZC1rJySRxJHVUZ59row=" 508 | [mod."github.com/ulule/deepcopier"] 509 | version = "v0.0.0-20200430083143-45decc6639b6" 510 | hash = "sha256-zyn5rHS5bU/4KajCVg+6pex42KVdXLZS8DFqRDUpn0E=" 511 | [mod."github.com/valyala/bytebufferpool"] 512 | version = "v1.0.0" 513 | hash = "sha256-I9FPZ3kCNRB+o0dpMwBnwZ35Fj9+ThvITn8a3Jr8mAY=" 514 | [mod."github.com/valyala/fasttemplate"] 515 | version = "v1.2.2" 516 | hash = "sha256-gp+lNXE8zjO+qJDM/YbS6V43HFsYP6PKn4ux1qa5lZ0=" 517 | [mod."github.com/weppos/publicsuffix-go"] 518 | version = "v0.30.1-0.20230422193905-8fecedd899db" 519 | hash = "sha256-Hw5S8ACINl+z/qZmLhcQcXjrXHzYM9HsqQF91RbDoB4=" 520 | [mod."github.com/xanzy/go-gitlab"] 521 | version = "v0.84.0" 522 | hash = "sha256-1Se9LHWGnmvAm0QHrb8Zw2jkyaKH2o3j0wvdMp289IQ=" 523 | [mod."github.com/xi2/xz"] 524 | version = "v0.0.0-20171230120015-48954b6210f8" 525 | hash = "sha256-2J4cb9KUnGHn1WZ2+g/S+yiHGLDt6KU0cP3fJpQDGZ0=" 526 | [mod."github.com/yl2chen/cidranger"] 527 | version = "v1.0.2" 528 | hash = "sha256-rPZApwakcZ1D3lmZnFds79+TFr9IlYkovTA7o52N9h0=" 529 | [mod."github.com/ysmood/fetchup"] 530 | version = "v0.2.3" 531 | hash = "sha256-sJ9PBMJ/PH3Es/ngAJkrxTPNAXr7AFjdsblF67mP2Hc=" 532 | [mod."github.com/ysmood/goob"] 533 | version = "v0.4.0" 534 | hash = "sha256-o0yVrxQRbN1dSjBH359VHADzPmkyrYOp7jn1GqIYhvw=" 535 | [mod."github.com/ysmood/got"] 536 | version = "v0.34.1" 537 | hash = "sha256-dCLb+1Yt/HAZhfQlVkEQoVG9Uv7iBGSqhxdunoakLTU=" 538 | [mod."github.com/ysmood/gson"] 539 | version = "v0.7.3" 540 | hash = "sha256-Dn5cTopPKtKCjQ7G6nlvPW2d7G4c5NfIdLVM9eLgR0E=" 541 | [mod."github.com/ysmood/leakless"] 542 | version = "v0.8.0" 543 | hash = "sha256-+D41mvLU29dPR4Lf9iWYq3oATgKHpRnUKahO0hTiCDc=" 544 | [mod."github.com/yuin/goldmark"] 545 | version = "v1.5.4" 546 | hash = "sha256-4he5sGi0uj1LogdqvgpvN8b7p6qlKMGuWXRFzh+FK8s=" 547 | [mod."github.com/yuin/goldmark-emoji"] 548 | version = "v1.0.1" 549 | hash = "sha256-liYCi6/EYG4obl51CzCaOmXf3fdzrU43J9VBZyHggEo=" 550 | [mod."github.com/yusufpapurcu/wmi"] 551 | version = "v1.2.3" 552 | hash = "sha256-HOLI8i58AMWeTotvYtdZessgrLwUG2aiS37eeHgsneY=" 553 | [mod."github.com/zeebo/blake3"] 554 | version = "v0.2.3" 555 | hash = "sha256-ZepnzkvOyicTGL078O1F84q0TzBAouJlB5AMmfsiOIg=" 556 | [mod."github.com/zmap/rc2"] 557 | version = "v0.0.0-20190804163417-abaa70531248" 558 | hash = "sha256-yMyZfFjcLynxiNXmUdfSfUlWekdtlXV3jGIoJMxMDz4=" 559 | [mod."github.com/zmap/zcrypto"] 560 | version = "v0.0.0-20230422215203-9a665e1e9968" 561 | hash = "sha256-nDBTEGDBv764XaC3KEwMtKGim0dEy4cjgo8XwnvyLh4=" 562 | [mod."go.etcd.io/bbolt"] 563 | version = "v1.3.7" 564 | hash = "sha256-poZk8tPLDWwW95oCOkTJcQtEvOJTD9UXAZ2TqGJutwk=" 565 | [mod."go.uber.org/multierr"] 566 | version = "v1.11.0" 567 | hash = "sha256-Lb6rHHfR62Ozg2j2JZy3MKOMKdsfzd1IYTR57r3Mhp0=" 568 | [mod."go.uber.org/zap"] 569 | version = "v1.25.0" 570 | hash = "sha256-aU270ds5r37xtfFFDVrvjOTTOv1aZNd7ffvHZJB6VIQ=" 571 | [mod."goftp.io/server/v2"] 572 | version = "v2.0.1" 573 | hash = "sha256-lI1UZVC9zQnyarOK6AR3Llw4exPqvNn3BZqwKlAOYbQ=" 574 | [mod."golang.org/x/crypto"] 575 | version = "v0.12.0" 576 | hash = "sha256-Wes72EA9ICTG8o0nEYWZk9xjpqlniorFeY6o26GExns=" 577 | [mod."golang.org/x/exp"] 578 | version = "v0.0.0-20230626212559-97b1e661b5df" 579 | hash = "sha256-aoesDZqls2sBtDmZ/ZSLzIudLuD8GDtGEEucyiqbCjY=" 580 | [mod."golang.org/x/mod"] 581 | version = "v0.12.0" 582 | hash = "sha256-M/oXnzm7odpJdQzEnG6W0pNYtl0uhOM/l7qgfGVpU2M=" 583 | [mod."golang.org/x/net"] 584 | version = "v0.14.0" 585 | hash = "sha256-QScKgO7lBWOsd0Y31wLRzFETv3tjqdB/eRQWW5q7aV4=" 586 | [mod."golang.org/x/oauth2"] 587 | version = "v0.11.0" 588 | hash = "sha256-ztz1lRVZXq6lTN/q4b4Y+P6L1EkP8ZJuhUbSJ0QvCw4=" 589 | [mod."golang.org/x/sys"] 590 | version = "v0.11.0" 591 | hash = "sha256-g/LjhABK2c/u6v7M2aAIrHvZjmx/ikGHkef86775N38=" 592 | [mod."golang.org/x/text"] 593 | version = "v0.12.0" 594 | hash = "sha256-aNQaW3EgCK9ehpnBzIAkZX6TmiUU1S175YlJUH7P5Qg=" 595 | [mod."golang.org/x/time"] 596 | version = "v0.3.0" 597 | hash = "sha256-/hmc9skIswMYbivxNS7R8A6vCTUF9k2/7tr/ACkcEaM=" 598 | [mod."golang.org/x/tools"] 599 | version = "v0.11.0" 600 | hash = "sha256-3fNsrCbUnbI5kwZRTx/olHLxR2DJhfvEQ3x0yeeZ8JY=" 601 | [mod."google.golang.org/appengine"] 602 | version = "v1.6.7" 603 | hash = "sha256-zIxGRHiq4QBvRqkrhMGMGCaVL4iM4TtlYpAi/hrivS4=" 604 | [mod."google.golang.org/protobuf"] 605 | version = "v1.31.0" 606 | hash = "sha256-UdIk+xRaMfdhVICvKRk1THe3R1VU+lWD8hqoW/y8jT0=" 607 | [mod."gopkg.in/alecthomas/kingpin.v2"] 608 | version = "v2.2.6" 609 | hash = "sha256-uViE2kPj7tMrGYVjjdLOl2jFDmmu+3P7GvnZBse2zVY=" 610 | [mod."gopkg.in/corvus-ch/zbase32.v1"] 611 | version = "v1.0.0" 612 | hash = "sha256-T6PzD4SJv6ipfCkr8CVHXjmKvYRGcLOypHTa238GGlw=" 613 | [mod."gopkg.in/djherbis/times.v1"] 614 | version = "v1.3.0" 615 | hash = "sha256-0ZIFWjtY4KyTPIRjUVIGKMXSXe++6vxBckckluhBYLY=" 616 | [mod."gopkg.in/yaml.v2"] 617 | version = "v2.4.0" 618 | hash = "sha256-uVEGglIedjOIGZzHW4YwN1VoRSTK8o0eGZqzd+TNdd0=" 619 | [mod."gopkg.in/yaml.v3"] 620 | version = "v3.0.1" 621 | hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU=" 622 | [mod."moul.io/http2curl"] 623 | version = "v1.0.0" 624 | hash = "sha256-1ZP4V71g1K3oTvz5nGWUBD5h84hXga/RUQwWTpSnphM=" 625 | -------------------------------------------------------------------------------- /internal/nuclei/format/format.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package format 26 | 27 | import ( 28 | "fmt" 29 | 30 | "github.com/dropalldatabases/sif/internal/styles" 31 | "github.com/projectdiscovery/nuclei/v2/pkg/output" 32 | ) 33 | 34 | func FormatLine(event *output.ResultEvent) string { 35 | output := event.TemplateID 36 | 37 | if event.MatcherName != "" { 38 | output += ":" + styles.Highlight.Render(event.MatcherName) 39 | } else if event.ExtractorName != "" { 40 | output += ":" + styles.Highlight.Render(event.ExtractorName) 41 | } 42 | 43 | output += " [" + event.Type + "]" 44 | output += " [" + formatSeverity(fmt.Sprintf("%s", event.Info.SeverityHolder.Severity)) + "]" 45 | 46 | return output 47 | } 48 | 49 | func formatSeverity(severity string) string { 50 | switch severity { 51 | case "low": 52 | return styles.SeverityLow.Render(severity) 53 | case "medium": 54 | return styles.SeverityMedium.Render(severity) 55 | case "high": 56 | return styles.SeverityHigh.Render(severity) 57 | case "critical": 58 | return styles.SeverityCritical.Render(severity) 59 | default: 60 | return severity 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /internal/nuclei/templates/templates.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package templates 26 | 27 | import ( 28 | "archive/tar" 29 | "compress/gzip" 30 | "errors" 31 | "fmt" 32 | "io" 33 | "net/http" 34 | "os" 35 | 36 | "github.com/charmbracelet/log" 37 | ) 38 | 39 | const ( 40 | archive = "https://github.com/projectdiscovery/nuclei-templates/archive/refs/tags/v%s.tar.gz" 41 | ref = "9.6.2" 42 | ) 43 | 44 | func Install(logger *log.Logger) error { 45 | // Check if already exists 46 | if _, err := os.Stat("nuclei-templates"); err == nil { 47 | return nil 48 | } 49 | 50 | logger.Infof("nuclei-templates directory not found. Installing...") 51 | 52 | resp, err := http.Get(fmt.Sprintf(archive, ref)) 53 | if err != nil { 54 | return err 55 | } 56 | defer resp.Body.Close() 57 | 58 | tarball, err := gzip.NewReader(resp.Body) 59 | if err != nil { 60 | return err 61 | } 62 | defer tarball.Close() 63 | 64 | data := tar.NewReader(tarball) 65 | 66 | for { 67 | header, err := data.Next() 68 | if errors.Is(io.EOF, err) { 69 | break 70 | } 71 | if err != nil { 72 | return err 73 | } 74 | 75 | switch header.Typeflag { 76 | case tar.TypeDir: 77 | if err := os.Mkdir(header.Name, 0755); err != nil { 78 | return err 79 | } 80 | case tar.TypeReg: 81 | file, err := os.Create(header.Name) 82 | if err != nil { 83 | return err 84 | } 85 | if _, err := io.Copy(file, data); err != nil { 86 | return err 87 | } 88 | file.Close() 89 | } 90 | } 91 | 92 | if err = os.Rename(fmt.Sprintf("nuclei-templates-%s", ref), "nuclei-templates"); err != nil { 93 | return err 94 | } 95 | 96 | return nil 97 | } 98 | -------------------------------------------------------------------------------- /internal/styles/styles.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | // Package styles provides custom styling options for the SIF tool's console output. 26 | // It uses the lipgloss library to create visually appealing and consistent text styles. 27 | 28 | package styles 29 | 30 | import "github.com/charmbracelet/lipgloss" 31 | 32 | var ( 33 | // Separator style for creating visual breaks in the output 34 | Separator = lipgloss.NewStyle(). 35 | Border(lipgloss.ThickBorder(), true, false). 36 | Bold(true) 37 | 38 | // Status style for highlighting important status messages 39 | Status = lipgloss.NewStyle(). 40 | Bold(true). 41 | Foreground(lipgloss.Color("#00ff1a")) 42 | 43 | // Highlight style for emphasizing specific text 44 | Highlight = lipgloss.NewStyle(). 45 | Bold(true). 46 | Underline(true) 47 | 48 | // Box style for creating bordered content boxes 49 | Box = lipgloss.NewStyle(). 50 | Bold(true). 51 | Foreground(lipgloss.Color("#fafafa")). 52 | BorderStyle(lipgloss.RoundedBorder()). 53 | Align(lipgloss.Center). 54 | PaddingRight(15). 55 | PaddingLeft(15). 56 | Width(60) 57 | 58 | // Subheading style for secondary titles or headers 59 | Subheading = lipgloss.NewStyle(). 60 | Bold(true). 61 | Align(lipgloss.Center). 62 | PaddingRight(15). 63 | PaddingLeft(15). 64 | Width(60) 65 | ) 66 | 67 | // Severity level styles for color-coding vulnerability severities 68 | var ( 69 | SeverityLow = lipgloss.NewStyle(). 70 | Foreground(lipgloss.Color("#00ff00")) 71 | 72 | SeverityMedium = lipgloss.NewStyle(). 73 | Foreground(lipgloss.Color("#ffff00")) 74 | 75 | SeverityHigh = lipgloss.NewStyle(). 76 | Foreground(lipgloss.Color("#ff8800")) 77 | 78 | SeverityCritical = lipgloss.NewStyle(). 79 | Foreground(lipgloss.Color("#ff0000")) 80 | ) 81 | -------------------------------------------------------------------------------- /pkg/config/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package config 26 | 27 | import ( 28 | "time" 29 | 30 | "github.com/charmbracelet/log" 31 | "github.com/projectdiscovery/goflags" 32 | ) 33 | 34 | type Settings struct { 35 | Dirlist string 36 | Dnslist string 37 | Debug bool 38 | LogDir string 39 | NoScan bool 40 | Ports string 41 | Dorking bool 42 | Git bool 43 | Whois bool 44 | Threads int 45 | Nuclei bool 46 | JavaScript bool 47 | Timeout time.Duration 48 | URLs goflags.StringSlice 49 | File string 50 | ApiMode bool 51 | Template string 52 | CMS bool 53 | Headers bool 54 | CloudStorage bool 55 | SubdomainTakeover bool 56 | } 57 | 58 | const ( 59 | Nil goflags.EnumVariable = iota 60 | 61 | // list sizes 62 | Small 63 | Medium 64 | Large 65 | 66 | // port scan scopes 67 | Common 68 | Full 69 | ) 70 | 71 | func Parse() *Settings { 72 | settings := &Settings{} 73 | 74 | flagSet := goflags.NewFlagSet() 75 | flagSet.SetDescription("a blazing-fast pentesting (recon/exploitation) suite") 76 | 77 | flagSet.CreateGroup("target", "Targets", 78 | flagSet.StringSliceVarP(&settings.URLs, "urls", "u", nil, "List of URLs to check (comma-separated)", goflags.FileCommaSeparatedStringSliceOptions), 79 | flagSet.StringVarP(&settings.File, "file", "f", "", "File that includes URLs to check"), 80 | ) 81 | 82 | listSizes := goflags.AllowdTypes{"small": Small, "medium": Medium, "large": Large, "none": Nil} 83 | portScopes := goflags.AllowdTypes{"common": Common, "full": Full, "none": Nil} 84 | flagSet.CreateGroup("scans", "Scans", 85 | flagSet.EnumVar(&settings.Dirlist, "dirlist", Nil, "Directory fuzzing scan size (small/medium/large)", listSizes), 86 | flagSet.EnumVar(&settings.Dnslist, "dnslist", Nil, "DNS fuzzing scan size (small/medium/large)", listSizes), 87 | flagSet.EnumVar(&settings.Ports, "ports", Nil, "Port scanning scope (common/full)", portScopes), 88 | flagSet.BoolVar(&settings.Dorking, "dork", false, "Enable Google dorking"), 89 | flagSet.BoolVar(&settings.Git, "git", false, "Enable git repository scanning"), 90 | flagSet.BoolVar(&settings.Nuclei, "nuclei", false, "Enable scanning using nuclei templates"), 91 | flagSet.BoolVar(&settings.NoScan, "noscan", false, "Do not perform base URL (robots.txt, etc) scanning"), 92 | flagSet.BoolVar(&settings.Whois, "whois", false, "Enable WHOIS lookup"), 93 | flagSet.BoolVar(&settings.JavaScript, "js", false, "Enable JavaScript scans"), 94 | flagSet.BoolVar(&settings.CMS, "cms", false, "Enable CMS detection"), 95 | flagSet.BoolVar(&settings.Headers, "headers", false, "Enable HTTP Header Analysis"), 96 | flagSet.BoolVar(&settings.CloudStorage, "c3", false, "Enable C3 Misconfiguration Scan"), 97 | flagSet.BoolVar(&settings.SubdomainTakeover, "st", false, "Enable Subdomain Takeover Check"), 98 | ) 99 | 100 | flagSet.CreateGroup("runtime", "Runtime", 101 | flagSet.BoolVarP(&settings.Debug, "debug", "d", false, "Enable debug logging"), 102 | flagSet.DurationVarP(&settings.Timeout, "timeout", "t", 10*time.Second, "HTTP request timeout"), 103 | flagSet.StringVarP(&settings.LogDir, "log", "l", "", "Directory to store logs in"), 104 | flagSet.IntVar(&settings.Threads, "threads", 10, "Number of threads to run scans on"), 105 | flagSet.StringVar(&settings.Template, "template", "", "Sif runtime template to use"), 106 | ) 107 | 108 | flagSet.CreateGroup("api", "API", 109 | flagSet.BoolVar(&settings.ApiMode, "api", false, "Enable API mode. Only useful for internal lunchcat usage"), 110 | ) 111 | 112 | if err := flagSet.Parse(); err != nil { 113 | log.Fatalf("Could not parse flags: %s", err) 114 | } 115 | 116 | return settings 117 | } 118 | -------------------------------------------------------------------------------- /pkg/logger/logger.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package logger 26 | 27 | import ( 28 | "fmt" 29 | "os" 30 | "strings" 31 | ) 32 | 33 | func Init(dir string) error { 34 | if _, err := os.Stat(dir); os.IsNotExist(err) { 35 | if err = os.Mkdir(dir, 0755); err != nil { 36 | return err 37 | } 38 | } 39 | 40 | return nil 41 | } 42 | 43 | func CreateFile(logFiles *[]string, url string, dir string) error { 44 | sanitizedURL := strings.Split(url, "://")[1] 45 | if _, err := os.Stat(dir + "/" + sanitizedURL + ".log"); os.IsNotExist(err) { 46 | f, err := os.OpenFile(dir+"/"+sanitizedURL+".log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | defer f.Close() 52 | } 53 | 54 | f, err := os.OpenFile(dir+"/"+sanitizedURL+".log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 55 | if err != nil { 56 | return err 57 | } 58 | defer f.Close() 59 | 60 | f.WriteString(fmt.Sprintf(" _____________\n__________(_)__ __/\n__ ___/_ /__ /_ \n_(__ )_ / _ __/ \n/____/ /_/ /_/ \n\nsif log file for %s\nhttps://sif.sh\n\n", url)) 61 | *logFiles = append(*logFiles, dir+"/"+sanitizedURL+".log") 62 | 63 | return nil 64 | } 65 | 66 | func Write(url string, dir string, text string) error { 67 | f, err := os.OpenFile(dir+"/"+url+".log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 68 | if err != nil { 69 | return err 70 | } 71 | defer f.Close() 72 | f.WriteString(text) 73 | 74 | return nil 75 | } 76 | 77 | func WriteHeader(url string, dir string, scan string) error { 78 | return Write(url, dir, fmt.Sprintf("\n\n--------------\nStarting %s\n--------------\n", scan)) 79 | } 80 | -------------------------------------------------------------------------------- /pkg/scan/cloudstorage.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package scan 26 | 27 | import ( 28 | "fmt" 29 | "net/http" 30 | "os" 31 | "strings" 32 | "time" 33 | 34 | "github.com/charmbracelet/log" 35 | "github.com/dropalldatabases/sif/internal/styles" 36 | "github.com/dropalldatabases/sif/pkg/logger" 37 | ) 38 | 39 | type CloudStorageResult struct { 40 | BucketName string `json:"bucket_name"` 41 | IsPublic bool `json:"is_public"` 42 | } 43 | 44 | func CloudStorage(url string, timeout time.Duration, logdir string) ([]CloudStorageResult, error) { 45 | fmt.Println(styles.Separator.Render("☁️ Starting " + styles.Status.Render("Cloud Storage Misconfiguration Scan") + "...")) 46 | 47 | sanitizedURL := strings.Split(url, "://")[1] 48 | 49 | if logdir != "" { 50 | if err := logger.WriteHeader(sanitizedURL, logdir, "Cloud Storage Misconfiguration Scan"); err != nil { 51 | log.Errorf("Error creating log file: %v", err) 52 | return nil, err 53 | } 54 | } 55 | 56 | cloudlog := log.NewWithOptions(os.Stderr, log.Options{ 57 | Prefix: "C3 ☁️", 58 | }).With("url", url) 59 | 60 | client := &http.Client{ 61 | Timeout: timeout, 62 | } 63 | 64 | potentialBuckets := extractPotentialBuckets(sanitizedURL) 65 | 66 | var results []CloudStorageResult 67 | 68 | for _, bucket := range potentialBuckets { 69 | isPublic, err := checkS3Bucket(bucket, client) 70 | if err != nil { 71 | cloudlog.Errorf("Error checking S3 bucket %s: %v", bucket, err) 72 | continue 73 | } 74 | 75 | result := CloudStorageResult{ 76 | BucketName: bucket, 77 | IsPublic: isPublic, 78 | } 79 | results = append(results, result) 80 | 81 | if isPublic { 82 | cloudlog.Warnf("Public S3 bucket found: %s", styles.Highlight.Render(bucket)) 83 | if logdir != "" { 84 | logger.Write(sanitizedURL, logdir, fmt.Sprintf("Public S3 bucket found: %s\n", bucket)) 85 | } 86 | } else { 87 | cloudlog.Infof("S3 bucket is not public/found: %s", bucket) 88 | } 89 | } 90 | 91 | return results, nil 92 | } 93 | 94 | func extractPotentialBuckets(url string) []string { 95 | // This is a simple implementation. 96 | // TODO: add more cases 97 | parts := strings.Split(url, ".") 98 | var buckets []string 99 | for i, part := range parts { 100 | buckets = append(buckets, part) 101 | buckets = append(buckets, part+"-s3") 102 | buckets = append(buckets, "s3-"+part) 103 | 104 | if i < len(parts)-1 { 105 | domainExtension := part + "-" + parts[i+1] 106 | buckets = append(buckets, domainExtension) 107 | buckets = append(buckets, parts[i+1]+"-"+part) 108 | } 109 | } 110 | return buckets 111 | } 112 | 113 | func checkS3Bucket(bucket string, client *http.Client) (bool, error) { 114 | url := fmt.Sprintf("https://%s.s3.amazonaws.com", bucket) 115 | resp, err := client.Get(url) 116 | if err != nil { 117 | return false, err 118 | } 119 | defer resp.Body.Close() 120 | 121 | // If we can access the bucket listing, it's public 122 | return resp.StatusCode == http.StatusOK, nil 123 | } 124 | -------------------------------------------------------------------------------- /pkg/scan/cms.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package scan 26 | 27 | import ( 28 | "fmt" 29 | "io" 30 | "net/http" 31 | "os" 32 | "strings" 33 | "time" 34 | 35 | "github.com/charmbracelet/log" 36 | "github.com/dropalldatabases/sif/internal/styles" 37 | "github.com/dropalldatabases/sif/pkg/logger" 38 | ) 39 | 40 | type CMSResult struct { 41 | Name string `json:"name"` 42 | Version string `json:"version"` 43 | } 44 | 45 | func CMS(url string, timeout time.Duration, logdir string) (*CMSResult, error) { 46 | fmt.Println(styles.Separator.Render("🔍 Starting " + styles.Status.Render("CMS detection") + "...")) 47 | 48 | sanitizedURL := strings.Split(url, "://")[1] 49 | 50 | if logdir != "" { 51 | if err := logger.WriteHeader(sanitizedURL, logdir, "CMS detection"); err != nil { 52 | log.Errorf("Error creating log file: %v", err) 53 | return nil, err 54 | } 55 | } 56 | 57 | cmslog := log.NewWithOptions(os.Stderr, log.Options{ 58 | Prefix: "CMS 🔍", 59 | }).With("url", url) 60 | 61 | client := &http.Client{ 62 | Timeout: timeout, 63 | } 64 | 65 | resp, err := client.Get(url) 66 | if err != nil { 67 | return nil, err 68 | } 69 | defer resp.Body.Close() 70 | 71 | body, err := io.ReadAll(resp.Body) 72 | if err != nil { 73 | return nil, err 74 | } 75 | bodyString := string(body) 76 | 77 | // WordPress 78 | if detectWordPress(url, client, bodyString) { 79 | result := &CMSResult{Name: "WordPress", Version: "Unknown"} 80 | cmslog.Infof("Detected CMS: %s", styles.Highlight.Render(result.Name)) 81 | return result, nil 82 | } 83 | 84 | // Drupal 85 | if strings.Contains(resp.Header.Get("X-Drupal-Cache"), "HIT") || strings.Contains(bodyString, "Drupal.settings") { 86 | result := &CMSResult{Name: "Drupal", Version: "Unknown"} 87 | cmslog.Infof("Detected CMS: %s", styles.Highlight.Render(result.Name)) 88 | return result, nil 89 | } 90 | 91 | // Joomla 92 | if strings.Contains(bodyString, "joomla") || strings.Contains(bodyString, "/media/system/js/core.js") { 93 | result := &CMSResult{Name: "Joomla", Version: "Unknown"} 94 | cmslog.Infof("Detected CMS: %s", styles.Highlight.Render(result.Name)) 95 | return result, nil 96 | } 97 | 98 | cmslog.Info("No CMS detected") 99 | return nil, nil 100 | } 101 | 102 | func detectWordPress(url string, client *http.Client, bodyString string) bool { 103 | // Check for common WordPress indicators in the HTML 104 | wpIndicators := []string{ 105 | "wp-content", 106 | "wp-includes", 107 | "wp-json", 108 | "wordpress", 109 | } 110 | 111 | for _, indicator := range wpIndicators { 112 | if strings.Contains(bodyString, indicator) { 113 | return true 114 | } 115 | } 116 | 117 | // Check for WordPress-specific files 118 | wpFiles := []string{ 119 | "/wp-login.php", 120 | "/wp-admin/", 121 | "/wp-config.php", 122 | } 123 | 124 | for _, file := range wpFiles { 125 | resp, err := client.Get(url + file) 126 | if err == nil { 127 | defer resp.Body.Close() 128 | if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusFound { 129 | return true 130 | } 131 | } 132 | } 133 | 134 | return false 135 | } 136 | -------------------------------------------------------------------------------- /pkg/scan/dirlist.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package scan 26 | 27 | import ( 28 | "bufio" 29 | "fmt" 30 | "net/http" 31 | "os" 32 | "strconv" 33 | "strings" 34 | "sync" 35 | "time" 36 | 37 | "github.com/charmbracelet/log" 38 | "github.com/dropalldatabases/sif/internal/styles" 39 | "github.com/dropalldatabases/sif/pkg/logger" 40 | ) 41 | 42 | const ( 43 | directoryURL = "https://raw.githubusercontent.com/dropalldatabases/sif-runtime/main/dirlist/" 44 | smallFile = "directory-list-2.3-small.txt" 45 | mediumFile = "directory-list-2.3-medium.txt" 46 | bigFile = "directory-list-2.3-big.txt" 47 | ) 48 | 49 | type DirectoryResult struct { 50 | Url string `json:"url"` 51 | StatusCode int `json:"status_code"` 52 | } 53 | 54 | // Dirlist performs directory fuzzing on the target URL. 55 | // 56 | // Parameters: 57 | // - size: determines the size of the directory list to use ("small", "medium", or "large") 58 | // - url: the target URL to scan 59 | // - timeout: maximum duration for each request 60 | // - threads: number of concurrent threads to use 61 | // - logdir: directory to store log files (empty string for no logging) 62 | // 63 | // Returns: 64 | // - []DirectoryResult: a slice of discovered directories and their status codes 65 | // - error: any error encountered during the scan 66 | func Dirlist(size string, url string, timeout time.Duration, threads int, logdir string) ([]DirectoryResult, error) { 67 | 68 | fmt.Println(styles.Separator.Render("📂 Starting " + styles.Status.Render("directory fuzzing") + "...")) 69 | 70 | sanitizedURL := strings.Split(url, "://")[1] 71 | 72 | if logdir != "" { 73 | if err := logger.WriteHeader(sanitizedURL, logdir, size+" directory fuzzing"); err != nil { 74 | log.Errorf("Error creating log file: %v", err) 75 | return nil, err 76 | } 77 | } 78 | 79 | dirlog := log.NewWithOptions(os.Stderr, log.Options{ 80 | Prefix: "Dirlist 📂", 81 | }).With("url", url) 82 | 83 | var list string 84 | 85 | switch size { 86 | case "small": 87 | list = directoryURL + smallFile 88 | case "medium": 89 | list = directoryURL + mediumFile 90 | case "large": 91 | list = directoryURL + bigFile 92 | } 93 | 94 | dirlog.Infof("Starting %s directory listing", size) 95 | 96 | resp, err := http.Get(list) 97 | if err != nil { 98 | log.Errorf("Error downloading directory list: %s", err) 99 | return nil, err 100 | } 101 | defer resp.Body.Close() 102 | var directories []string 103 | scanner := bufio.NewScanner(resp.Body) 104 | scanner.Split(bufio.ScanLines) 105 | for scanner.Scan() { 106 | directories = append(directories, scanner.Text()) 107 | } 108 | 109 | client := &http.Client{ 110 | Timeout: timeout, 111 | } 112 | 113 | var wg sync.WaitGroup 114 | wg.Add(threads) 115 | 116 | results := []DirectoryResult{} 117 | for thread := 0; thread < threads; thread++ { 118 | go func(thread int) { 119 | defer wg.Done() 120 | 121 | for i, directory := range directories { 122 | if i%threads != thread { 123 | continue 124 | } 125 | 126 | log.Debugf("%s", directory) 127 | resp, err := client.Get(url + "/" + directory) 128 | if err != nil { 129 | log.Debugf("Error %s: %s", directory, err) 130 | return 131 | } 132 | 133 | if resp.StatusCode != 404 && resp.StatusCode != 403 { 134 | // log url, directory, and status code 135 | dirlog.Infof("%s [%s]", styles.Status.Render(strconv.Itoa(resp.StatusCode)), styles.Highlight.Render(directory)) 136 | if logdir != "" { 137 | logger.Write(sanitizedURL, logdir, fmt.Sprintf("%s [%s]\n", strconv.Itoa(resp.StatusCode), directory)) 138 | } 139 | 140 | result := DirectoryResult{ 141 | Url: resp.Request.URL.String(), 142 | StatusCode: resp.StatusCode, 143 | } 144 | results = append(results, result) 145 | } 146 | } 147 | }(thread) 148 | } 149 | wg.Wait() 150 | 151 | return results, nil 152 | } 153 | -------------------------------------------------------------------------------- /pkg/scan/dnslist.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package scan 26 | 27 | import ( 28 | "bufio" 29 | "fmt" 30 | "net/http" 31 | "os" 32 | "strings" 33 | "sync" 34 | "time" 35 | 36 | "github.com/charmbracelet/log" 37 | "github.com/dropalldatabases/sif/internal/styles" 38 | "github.com/dropalldatabases/sif/pkg/logger" 39 | ) 40 | 41 | const ( 42 | dnsURL = "https://raw.githubusercontent.com/dropalldatabases/sif-runtime/main/dnslist/" 43 | dnsSmallFile = "subdomains-100.txt" 44 | dnsMediumFile = "subdomains-1000.txt" 45 | dnsBigFile = "subdomains-10000.txt" 46 | ) 47 | 48 | // Dnslist performs DNS subdomain enumeration on the target domain. 49 | // 50 | // Parameters: 51 | // - size: determines the size of the subdomain list to use ("small", "medium", or "large") 52 | // - url: the target URL to scan 53 | // - timeout: maximum duration for each DNS lookup 54 | // - threads: number of concurrent threads to use 55 | // - logdir: directory to store log files (empty string for no logging) 56 | // 57 | // Returns: 58 | // - []string: a slice of discovered subdomains 59 | // - error: any error encountered during the enumeration 60 | func Dnslist(size string, url string, timeout time.Duration, threads int, logdir string) ([]string, error) { 61 | 62 | fmt.Println(styles.Separator.Render("📡 Starting " + styles.Status.Render("DNS fuzzing") + "...")) 63 | 64 | dnslog := log.NewWithOptions(os.Stderr, log.Options{ 65 | Prefix: "Dnslist 📡", 66 | }).With("url", url) 67 | 68 | var list string 69 | 70 | switch size { 71 | case "small": 72 | list = dnsURL + dnsSmallFile 73 | case "medium": 74 | list = dnsURL + dnsMediumFile 75 | case "large": 76 | list = dnsURL + dnsBigFile 77 | } 78 | 79 | dnslog.Infof("Starting %s DNS listing", size) 80 | 81 | resp, err := http.Get(list) 82 | if err != nil { 83 | log.Errorf("Error downloading DNS list: %s", err) 84 | return nil, err 85 | } 86 | defer resp.Body.Close() 87 | var dns []string 88 | scanner := bufio.NewScanner(resp.Body) 89 | scanner.Split(bufio.ScanLines) 90 | for scanner.Scan() { 91 | dns = append(dns, scanner.Text()) 92 | } 93 | 94 | sanitizedURL := strings.Split(url, "://")[1] 95 | 96 | if logdir != "" { 97 | if err := logger.WriteHeader(sanitizedURL, logdir, size+" subdomain fuzzing"); err != nil { 98 | log.Errorf("Error creating log file: %v", err) 99 | return nil, err 100 | } 101 | } 102 | 103 | client := &http.Client{ 104 | Timeout: timeout, 105 | } 106 | 107 | var wg sync.WaitGroup 108 | wg.Add(threads) 109 | 110 | urls := []string{} 111 | for thread := 0; thread < threads; thread++ { 112 | go func(thread int) { 113 | defer wg.Done() 114 | 115 | for i, domain := range dns { 116 | if i%threads != thread { 117 | continue 118 | } 119 | 120 | log.Debugf("Looking up: %s", domain) 121 | resp, err := client.Get("http://" + domain + "." + sanitizedURL) 122 | if err != nil { 123 | log.Debugf("Error %s: %s", domain, err) 124 | } else { 125 | urls = append(urls, resp.Request.URL.String()) 126 | dnslog.Infof("%s %s.%s", styles.Status.Render("[http]"), styles.Highlight.Render(domain), sanitizedURL) 127 | 128 | if logdir != "" { 129 | f, err := os.OpenFile(logdir+"/"+sanitizedURL+".log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 130 | if err != nil { 131 | log.Errorf("Error creating log file: %s", err) 132 | return 133 | } 134 | defer f.Close() 135 | f.WriteString(fmt.Sprintf("[http] %s.%s\n", domain, sanitizedURL)) 136 | } 137 | } 138 | 139 | resp, err = client.Get("https://" + domain + "." + sanitizedURL) 140 | if err != nil { 141 | log.Debugf("Error %s: %s", domain, err) 142 | } else { 143 | urls = append(urls, resp.Request.URL.String()) 144 | dnslog.Infof("%s %s.%s", styles.Status.Render("[https]"), styles.Highlight.Render(domain), sanitizedURL) 145 | if logdir != "" { 146 | logger.Write(sanitizedURL, logdir, fmt.Sprintf("[https] %s.%s\n", domain, sanitizedURL)) 147 | } 148 | } 149 | } 150 | }(thread) 151 | } 152 | wg.Wait() 153 | 154 | return urls, nil 155 | } 156 | -------------------------------------------------------------------------------- /pkg/scan/dork.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | // Package scan provides various security scanning functionalities for web applications. 26 | // This file handles Google dorking operations. 27 | 28 | package scan 29 | 30 | import ( 31 | "bufio" 32 | "fmt" 33 | "net/http" 34 | "os" 35 | "strconv" 36 | "strings" 37 | "sync" 38 | "time" 39 | 40 | "github.com/charmbracelet/log" 41 | "github.com/dropalldatabases/sif/internal/styles" 42 | "github.com/dropalldatabases/sif/pkg/logger" 43 | googlesearch "github.com/rocketlaunchr/google-search" 44 | ) 45 | 46 | const ( 47 | dorkURL = "https://raw.githubusercontent.com/dropalldatabases/sif-runtime/main/dork/" 48 | dorkFile = "dork.txt" 49 | ) 50 | 51 | // DorkResult represents the result of a Google dork search. 52 | type DorkResult struct { 53 | Url string `json:"url"` // The URL found by the dork 54 | Count int `json:"count"` // The number of times this URL was found 55 | } 56 | 57 | // Dork performs Google dorking operations on the target URL. 58 | // It uses a predefined list of dorks to search for potentially sensitive information. 59 | // 60 | // Parameters: 61 | // - url: The target URL to dork 62 | // - timeout: Maximum duration for each dork search 63 | // - threads: Number of concurrent threads to use 64 | // - logdir: Directory to store log files (empty string for no logging) 65 | // 66 | // Returns: 67 | // - []DorkResult: A slice of results from the dorking operation 68 | // - error: Any error encountered during the dorking process 69 | func Dork(url string, timeout time.Duration, threads int, logdir string) ([]DorkResult, error) { 70 | 71 | fmt.Println(styles.Separator.Render("🤓 Starting " + styles.Status.Render("URL Dorking") + "...")) 72 | 73 | sanitizedURL := strings.Split(url, "://")[1] 74 | 75 | if logdir != "" { 76 | if err := logger.WriteHeader(sanitizedURL, logdir, "URL dorking"); err != nil { 77 | log.Errorf("Error creating log file: %v", err) 78 | return nil, err 79 | } 80 | } 81 | 82 | dorklog := log.NewWithOptions(os.Stderr, log.Options{ 83 | Prefix: "Dorking 🤓", 84 | }).With("url", url) 85 | 86 | dorklog.Infof("Starting URL dorking...") 87 | 88 | resp, err := http.Get(dorkURL + dorkFile) 89 | if err != nil { 90 | log.Errorf("Error downloading dork list: %s", err) 91 | return nil, err 92 | } 93 | defer resp.Body.Close() 94 | var dorks []string 95 | scanner := bufio.NewScanner(resp.Body) 96 | scanner.Split(bufio.ScanLines) 97 | for scanner.Scan() { 98 | dorks = append(dorks, scanner.Text()) 99 | } 100 | 101 | // util.InitProgressBar() 102 | var wg sync.WaitGroup 103 | wg.Add(threads) 104 | 105 | dorkResults := []DorkResult{} 106 | for thread := 0; thread < threads; thread++ { 107 | go func(thread int) { 108 | defer wg.Done() 109 | 110 | for i, dork := range dorks { 111 | 112 | 113 | if i%threads != thread { 114 | continue 115 | } 116 | 117 | results, _ := googlesearch.Search(nil, fmt.Sprintf("%s %s", dork, sanitizedURL)) 118 | if len(results) > 0 { 119 | dorklog.Infof("%s dork results found for dork [%s]", styles.Status.Render(strconv.Itoa(len(results))), styles.Highlight.Render(dork)) 120 | if logdir != "" { 121 | logger.Write(sanitizedURL, logdir, fmt.Sprintf("%s dork results found for dork [%s]\n", strconv.Itoa(len(results)), dork)) 122 | } 123 | 124 | result := DorkResult{ 125 | Url: dork, 126 | Count: len(results), 127 | } 128 | 129 | dorkResults = append(dorkResults, result) 130 | } 131 | } 132 | }(thread) 133 | } 134 | wg.Wait() 135 | 136 | return dorkResults, nil 137 | } 138 | -------------------------------------------------------------------------------- /pkg/scan/git.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package scan 26 | 27 | import ( 28 | "bufio" 29 | "fmt" 30 | "net/http" 31 | "os" 32 | "strconv" 33 | "strings" 34 | "sync" 35 | "time" 36 | 37 | "github.com/charmbracelet/log" 38 | "github.com/dropalldatabases/sif/internal/styles" 39 | "github.com/dropalldatabases/sif/pkg/logger" 40 | ) 41 | 42 | const ( 43 | gitURL = "https://raw.githubusercontent.com/dropalldatabases/sif-runtime/main/git/" 44 | gitFile = "git.txt" 45 | ) 46 | 47 | func Git(url string, timeout time.Duration, threads int, logdir string) ([]string, error) { 48 | 49 | fmt.Println(styles.Separator.Render("🌿 Starting " + styles.Status.Render("git repository scanning") + "...")) 50 | 51 | sanitizedURL := strings.Split(url, "://")[1] 52 | 53 | if logdir != "" { 54 | if err := logger.WriteHeader(sanitizedURL, logdir, "git directory fuzzing"); err != nil { 55 | log.Errorf("Error creating log file: %v", err) 56 | return nil, err 57 | } 58 | } 59 | 60 | gitlog := log.NewWithOptions(os.Stderr, log.Options{ 61 | Prefix: "Git 🌿", 62 | }).With("url", url) 63 | 64 | gitlog.Infof("Starting repository scanning") 65 | 66 | resp, err := http.Get(gitURL + gitFile) 67 | if err != nil { 68 | log.Errorf("Error downloading git list: %s", err) 69 | return nil, err 70 | } 71 | defer resp.Body.Close() 72 | var gitUrls []string 73 | scanner := bufio.NewScanner(resp.Body) 74 | scanner.Split(bufio.ScanLines) 75 | for scanner.Scan() { 76 | gitUrls = append(gitUrls, scanner.Text()) 77 | } 78 | 79 | // util.InitProgressBar() 80 | client := &http.Client{ 81 | Timeout: timeout, 82 | } 83 | 84 | var wg sync.WaitGroup 85 | wg.Add(threads) 86 | 87 | foundUrls := []string{} 88 | for thread := 0; thread < threads; thread++ { 89 | go func(thread int) { 90 | defer wg.Done() 91 | 92 | for i, repourl := range gitUrls { 93 | if i%threads != thread { 94 | continue 95 | } 96 | 97 | log.Debugf("%s", repourl) 98 | resp, err := client.Get(url + "/" + repourl) 99 | if err != nil { 100 | log.Debugf("Error %s: %s", repourl, err) 101 | } 102 | 103 | if resp.StatusCode == 200 && !strings.HasPrefix(resp.Header.Get("Content-Type"), "text/html") { 104 | // log url, directory, and status code 105 | gitlog.Infof("%s git found at [%s]", styles.Status.Render(strconv.Itoa(resp.StatusCode)), styles.Highlight.Render(repourl)) 106 | if logdir != "" { 107 | logger.Write(sanitizedURL, logdir, fmt.Sprintf("%s git found at [%s]\n", strconv.Itoa(resp.StatusCode), repourl)) 108 | } 109 | 110 | foundUrls = append(foundUrls, resp.Request.URL.String()) 111 | } 112 | } 113 | }(thread) 114 | } 115 | wg.Wait() 116 | 117 | return foundUrls, nil 118 | } 119 | -------------------------------------------------------------------------------- /pkg/scan/headers.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package scan 26 | 27 | import ( 28 | "fmt" 29 | "net/http" 30 | "os" 31 | "strings" 32 | "time" 33 | 34 | "github.com/charmbracelet/log" 35 | "github.com/dropalldatabases/sif/internal/styles" 36 | "github.com/dropalldatabases/sif/pkg/logger" 37 | ) 38 | 39 | type HeaderResult struct { 40 | Name string `json:"name"` 41 | Value string `json:"value"` 42 | } 43 | 44 | func Headers(url string, timeout time.Duration, logdir string) ([]HeaderResult, error) { 45 | fmt.Println(styles.Separator.Render("🔍 Starting " + styles.Status.Render("HTTP Header Analysis") + "...")) 46 | 47 | sanitizedURL := strings.Split(url, "://")[1] 48 | 49 | if logdir != "" { 50 | if err := logger.WriteHeader(sanitizedURL, logdir, "HTTP Header Analysis"); err != nil { 51 | log.Errorf("Error creating log file: %v", err) 52 | return nil, err 53 | } 54 | } 55 | 56 | headerlog := log.NewWithOptions(os.Stderr, log.Options{ 57 | Prefix: "Headers 🔍", 58 | }).With("url", url) 59 | 60 | client := &http.Client{ 61 | Timeout: timeout, 62 | } 63 | 64 | resp, err := client.Get(url) 65 | if err != nil { 66 | return nil, err 67 | } 68 | defer resp.Body.Close() 69 | 70 | var results []HeaderResult 71 | 72 | for name, values := range resp.Header { 73 | for _, value := range values { 74 | results = append(results, HeaderResult{Name: name, Value: value}) 75 | headerlog.Infof("%s: %s", styles.Highlight.Render(name), value) 76 | if logdir != "" { 77 | logger.Write(sanitizedURL, logdir, fmt.Sprintf("%s: %s\n", name, value)) 78 | } 79 | } 80 | } 81 | 82 | return results, nil 83 | } 84 | -------------------------------------------------------------------------------- /pkg/scan/js/frameworks/next.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | /* 26 | What we are doing is abusing a internal file in Next.js pages router called 27 | _buildManifest.js which lists all routes and script files ever referenced in 28 | the application within next.js, this allows us to optimise and not bruteforce 29 | directories for routes and instead get all of them at once. 30 | 31 | We are currently parsing this js file with regexes but that should ideally be 32 | replaced soon. 33 | */ 34 | 35 | package frameworks 36 | 37 | import ( 38 | "bufio" 39 | "fmt" 40 | "net/http" 41 | "regexp" 42 | "strings" 43 | 44 | urlutil "github.com/projectdiscovery/utils/url" 45 | ) 46 | 47 | func GetPagesRouterScripts(scriptUrl string) ([]string, error) { 48 | baseUrl, err := urlutil.Parse(scriptUrl) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | resp, err := http.Get(scriptUrl) 54 | if err != nil { 55 | fmt.Println(err) 56 | return nil, err 57 | } 58 | defer resp.Body.Close() 59 | 60 | var manifestText string 61 | scanner := bufio.NewScanner(resp.Body) 62 | scanner.Split(bufio.ScanLines) 63 | for scanner.Scan() { 64 | manifestText += scanner.Text() 65 | } 66 | 67 | regex, err := regexp.Compile("\\[(\"([^\"]+.js)\"(,?))") 68 | 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | list := regex.FindAllStringSubmatch(manifestText, -1) 74 | 75 | var scripts []string 76 | 77 | for _, el := range list { 78 | var script = strings.ReplaceAll(el[2], "\\u002F", "/") 79 | url, err := urlutil.Parse(script) 80 | if err != nil { 81 | continue 82 | } 83 | 84 | if url.IsRelative { 85 | url.Host = baseUrl.Host 86 | url.Scheme = baseUrl.Scheme 87 | url.Path = "/_next/" + url.Path 88 | } 89 | scripts = append(scripts, url.String()) 90 | } 91 | 92 | return scripts, nil 93 | } 94 | -------------------------------------------------------------------------------- /pkg/scan/js/scan.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package js 26 | 27 | import ( 28 | "bufio" 29 | "fmt" 30 | "io" 31 | "net/http" 32 | "os" 33 | "slices" 34 | "strings" 35 | "time" 36 | 37 | "github.com/antchfx/htmlquery" 38 | "github.com/charmbracelet/log" 39 | "github.com/dropalldatabases/sif/pkg/scan/js/frameworks" 40 | urlutil "github.com/projectdiscovery/utils/url" 41 | ) 42 | 43 | type JavascriptScanResult struct { 44 | SupabaseResults []supabaseScanResult `json:"supabase_results"` 45 | FoundEnvironmentVars map[string]string `json:"environment_variables"` 46 | } 47 | 48 | func JavascriptScan(url string, timeout time.Duration, threads int, logdir string) (*JavascriptScanResult, error) { 49 | jslog := log.NewWithOptions(os.Stderr, log.Options{ 50 | Prefix: "🚧 JavaScript", 51 | }).With("url", url) 52 | 53 | baseUrl, err := urlutil.Parse(url) 54 | if err != nil { 55 | return nil, err 56 | } 57 | resp, err := http.Get(url) 58 | if err != nil { 59 | fmt.Println(err) 60 | return nil, err 61 | } 62 | defer resp.Body.Close() 63 | 64 | var html string 65 | scanner := bufio.NewScanner(resp.Body) 66 | scanner.Split(bufio.ScanLines) 67 | for scanner.Scan() { 68 | html += scanner.Text() 69 | } 70 | 71 | doc, err := htmlquery.Parse(strings.NewReader(html)) 72 | if err != nil { 73 | return nil, err 74 | } 75 | 76 | var scripts []string 77 | nodes, err := htmlquery.QueryAll(doc, "//script/@src") 78 | if err != nil { 79 | return nil, err 80 | } 81 | for _, node := range nodes { 82 | var src = htmlquery.InnerText(node) 83 | url, err := urlutil.Parse(src) 84 | if err != nil { 85 | continue 86 | } 87 | 88 | if url.IsRelative { 89 | url.Host = baseUrl.Host 90 | url.Scheme = baseUrl.Scheme 91 | } 92 | scripts = append(scripts, url.String()) 93 | } 94 | 95 | for _, script := range scripts { 96 | if strings.Contains(script, "/_buildManifest.js") { 97 | jslog.Infof("Detected Next.JS pages router! Getting all scripts from %s", script) 98 | nextScripts, err := frameworks.GetPagesRouterScripts(script) 99 | if err != nil { 100 | return nil, err 101 | } 102 | 103 | for _, nextScript := range nextScripts { 104 | if slices.Contains(scripts, nextScript) { 105 | continue 106 | } 107 | scripts = append(scripts, nextScript) 108 | } 109 | } 110 | } 111 | 112 | jslog.Infof("Got %d scripts, now running scans on them", len(scripts)) 113 | 114 | var supabaseResults []supabaseScanResult 115 | for _, script := range scripts { 116 | jslog.Infof("Scanning %s", script) 117 | resp, err := http.Get(script) 118 | if err != nil { 119 | fmt.Println(err) 120 | continue 121 | } 122 | defer resp.Body.Close() 123 | 124 | bodyBytes, err := io.ReadAll(resp.Body) 125 | if err != nil { 126 | log.Fatal(err) 127 | } 128 | content := string(bodyBytes) 129 | 130 | jslog.Infof("Running supabase scanner on %s", script) 131 | scriptSupabaseResults, err := ScanSupabase(content, script) 132 | 133 | if err != nil { 134 | jslog.Errorf("Error while scanning supabase: %s", err) 135 | } 136 | 137 | if scriptSupabaseResults != nil { 138 | supabaseResults = append(supabaseResults, scriptSupabaseResults...) 139 | } 140 | } 141 | 142 | result := JavascriptScanResult{ 143 | SupabaseResults: supabaseResults, 144 | FoundEnvironmentVars: map[string]string{}, 145 | } 146 | 147 | return &result, nil 148 | } 149 | -------------------------------------------------------------------------------- /pkg/scan/js/supabase.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | // todo: scan for storage and auth vulns 26 | 27 | package js 28 | 29 | import ( 30 | "bytes" 31 | "encoding/base64" 32 | "encoding/json" 33 | "errors" 34 | "io" 35 | "math" 36 | "net/http" 37 | "os" 38 | "regexp" 39 | "slices" 40 | "strconv" 41 | "strings" 42 | "time" 43 | 44 | "github.com/charmbracelet/log" 45 | ) 46 | 47 | type supabaseJwtBody struct { 48 | ProjectId *string `json:"ref"` 49 | Role *string `json:"role"` 50 | } 51 | type supabaseScanResult struct { 52 | ProjectId string `json:"project_id"` 53 | ApiKey string `json:"api_key"` 54 | Role string `json:"role"` // note: if this isnt anon its bad 55 | Collections []supabaseCollection `json:"collections"` 56 | } 57 | type supabaseCollection struct { 58 | Name string `json:"name"` 59 | Sample []interface{} `json:"sample"` 60 | Count int `json:"count"` 61 | } 62 | 63 | func GetSupabaseJsonResponse(projectId string, path string, apikey string, auth *string) (map[string]interface{}, error) { 64 | client := http.Client{} 65 | 66 | req, err := http.NewRequest("GET", "https://"+projectId+".supabase.co"+path, nil) 67 | if err != nil { 68 | return nil, err 69 | } 70 | 71 | log.Debugf("Sending request to %s", req.URL.String()) 72 | req.Header.Set("apikey", apikey) 73 | req.Header.Set("Prefer", "count=exact") 74 | if auth != nil { 75 | req.Header.Set("Authorization", "Bearer "+*auth) 76 | } 77 | 78 | resp, err := client.Do(req) 79 | if err != nil { 80 | return nil, err 81 | } 82 | 83 | defer resp.Body.Close() 84 | 85 | if resp.StatusCode != 200 { 86 | return nil, errors.New("Request to " + resp.Request.URL.String() + " failed with status code " + strconv.Itoa(resp.StatusCode)) 87 | } 88 | body, err := io.ReadAll(resp.Body) 89 | if err != nil { 90 | return nil, err 91 | } 92 | content := string(body) 93 | 94 | var data interface{} 95 | 96 | err = json.Unmarshal([]byte(content), &data) 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | arr, ok := data.([]interface{}) 102 | if ok { 103 | wrappedData := map[string]interface{}{} 104 | 105 | contentRange := resp.Header.Get("Content-Range") 106 | count, err := strconv.Atoi(strings.Split(contentRange, "/")[1]) 107 | if err != nil { 108 | return nil, err 109 | } 110 | 111 | wrappedData["count"] = count 112 | wrappedData["array"] = arr 113 | 114 | return wrappedData, nil 115 | } 116 | 117 | return data.(map[string]interface{}), nil 118 | } 119 | 120 | func ScanSupabase(jsContent string, jsUrl string) ([]supabaseScanResult, error) { 121 | supabaselog := log.NewWithOptions(os.Stderr, log.Options{ 122 | Prefix: "🚧 JavaScript > Supabase ⚡️", 123 | }).With("url", jsUrl) 124 | 125 | jwtRegex, err := regexp.Compile("[\"|'|`](ey[A-Za-z0-9_-]{2,}(?:\\.[A-Za-z0-9_-]{2,}){2})[\"|'|`]") 126 | 127 | if err != nil { 128 | return nil, err 129 | } 130 | 131 | var results = []supabaseScanResult{} 132 | jwtGroups := jwtRegex.FindAllStringSubmatch(jsContent, -1) 133 | 134 | var jwts = []string{} 135 | 136 | for _, jwtGroup := range jwtGroups { 137 | jwts = append(jwts, jwtGroup[1]) 138 | } 139 | 140 | slices.Sort(jwts) 141 | jwts = slices.Compact(jwts) 142 | 143 | for _, jwt := range jwts { 144 | parts := strings.Split(jwt, ".") 145 | body := parts[1] 146 | 147 | decoded, err := base64.RawStdEncoding.DecodeString(body) 148 | if err != nil { 149 | supabaselog.Debugf("Failed to decode JWT %s: %s", body, err) 150 | continue 151 | } 152 | 153 | supabaselog.Debugf("JWT body: %s", decoded) 154 | var supabaseJwt *supabaseJwtBody 155 | err = json.Unmarshal([]byte(decoded), &supabaseJwt) 156 | if err != nil { 157 | supabaselog.Debugf("Failed to json parse JWT %s: %s", jwt, err) 158 | continue 159 | } 160 | 161 | if supabaseJwt.ProjectId == nil || supabaseJwt.Role == nil { 162 | continue 163 | } 164 | 165 | supabaselog.Infof("Found valid supabase project %s with role %s", *supabaseJwt.ProjectId, *supabaseJwt.Role) 166 | client := http.Client{} 167 | 168 | req, err := http.NewRequest("POST", "https://"+*supabaseJwt.ProjectId+".supabase.co/auth/v1/signup", bytes.NewBufferString(`{"email":"automated`+strconv.Itoa(int(time.Now().Unix()))+`@sif.sh","password":"automatedacct"}`)) 169 | if err != nil { 170 | supabaselog.Errorf("Error while creating HTTP req for creating user: %s", err) 171 | continue 172 | } 173 | req.Header.Set("apikey", jwt) 174 | 175 | resp, err := client.Do(req) 176 | if err != nil { 177 | supabaselog.Errorf("Error while sending request to create user: %s", err) 178 | continue 179 | } 180 | 181 | var auth string 182 | if resp.StatusCode == http.StatusOK { 183 | body, err := io.ReadAll(resp.Body) 184 | if err != nil { 185 | return nil, err 186 | } 187 | content := string(body) 188 | 189 | var data map[string]interface{} 190 | err = json.Unmarshal([]byte(content), &data) 191 | if err != nil { 192 | return nil, err 193 | } 194 | 195 | auth = data["access_token"].(string) 196 | supabaselog.Infof("Created account with JWT %s", auth) 197 | } 198 | 199 | var collections = []supabaseCollection{} 200 | 201 | res, err := GetSupabaseJsonResponse(*supabaseJwt.ProjectId, "/rest/v1/", jwt, &auth) 202 | if err != nil { 203 | return nil, err 204 | } 205 | 206 | index := res 207 | 208 | if index["paths"] == nil { 209 | return nil, errors.New("paths not found in supabase openapi") 210 | } 211 | 212 | var paths = index["paths"].(map[string]interface{}) 213 | 214 | for k := range paths { 215 | if k == "/" { 216 | continue 217 | } 218 | 219 | // todo: support for scanning rpc calls 220 | if strings.HasPrefix(k, "/rpc/") { 221 | continue 222 | } 223 | 224 | sampleObj, err := GetSupabaseJsonResponse(*supabaseJwt.ProjectId, "/rest/v1"+k, jwt, &auth) 225 | if err != nil { 226 | continue 227 | } 228 | 229 | samples := sampleObj["array"].([]interface{}) 230 | marshalled, err := json.Marshal(samples) 231 | if err != nil { 232 | supabaselog.Errorf("Failed to marshal sample data for %s: %s", k, err) 233 | } 234 | 235 | supabaselog.Infof("Got sample (1000 entries) for collection %s: %s", k, string(marshalled)) 236 | 237 | limitedSample := samples[0:int(math.Min(float64(len(samples)), 10))] 238 | 239 | collection := supabaseCollection{ 240 | Name: strings.TrimPrefix(k, "/"), 241 | Sample: limitedSample, // passed to local LLM for scope 242 | Count: sampleObj["count"].(int), 243 | } 244 | 245 | if collection.Count > 1 /* one entry may just be for the user */ { 246 | collections = append(collections, collection) 247 | } 248 | } 249 | 250 | result := supabaseScanResult{ 251 | ProjectId: *supabaseJwt.ProjectId, 252 | ApiKey: jwt, 253 | Role: *supabaseJwt.Role, 254 | Collections: collections, 255 | } 256 | results = append(results, result) 257 | } 258 | 259 | // todo(eva): implement supabase scanning 260 | return results, nil 261 | } 262 | -------------------------------------------------------------------------------- /pkg/scan/nuclei.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package scan 26 | 27 | import ( 28 | "context" 29 | "fmt" 30 | "os" 31 | "strings" 32 | "time" 33 | 34 | "github.com/charmbracelet/log" 35 | "github.com/dropalldatabases/sif/internal/nuclei/format" 36 | "github.com/dropalldatabases/sif/internal/nuclei/templates" 37 | "github.com/dropalldatabases/sif/internal/styles" 38 | "github.com/projectdiscovery/nuclei/v2/pkg/catalog/config" 39 | "github.com/projectdiscovery/nuclei/v2/pkg/catalog/disk" 40 | "github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader" 41 | "github.com/projectdiscovery/nuclei/v2/pkg/core" 42 | "github.com/projectdiscovery/nuclei/v2/pkg/core/inputs" 43 | "github.com/projectdiscovery/nuclei/v2/pkg/output" 44 | "github.com/projectdiscovery/nuclei/v2/pkg/parsers" 45 | "github.com/projectdiscovery/nuclei/v2/pkg/protocols" 46 | "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs" 47 | "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/hosterrorscache" 48 | "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh" 49 | "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit" 50 | "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate" 51 | "github.com/projectdiscovery/nuclei/v2/pkg/reporting" 52 | "github.com/projectdiscovery/nuclei/v2/pkg/testutils" 53 | "github.com/projectdiscovery/nuclei/v2/pkg/types" 54 | "github.com/projectdiscovery/ratelimit" 55 | ) 56 | 57 | func Nuclei(url string, timeout time.Duration, threads int, logdir string) ([]output.ResultEvent, error) { 58 | fmt.Println(styles.Separator.Render("⚛️ Starting " + styles.Status.Render("nuclei template scanning") + "...")) 59 | 60 | sanitizedURL := strings.Split(url, "://")[1] 61 | 62 | nucleilog := log.NewWithOptions(os.Stderr, log.Options{ 63 | Prefix: "nuclei ⚛️", 64 | }).With("url", url) 65 | 66 | // Apply threads, timeout, log settings 67 | options := types.DefaultOptions() 68 | options.TemplateThreads = threads 69 | options.Timeout = int(timeout.Seconds()) 70 | 71 | // Get templates 72 | templates.Install(nucleilog) 73 | pwd, _ := os.Getwd() 74 | config.DefaultConfig.SetTemplatesDir(pwd) 75 | catalog := disk.NewCatalog(pwd) 76 | 77 | results := []output.ResultEvent{} 78 | // Custom output 79 | outputWriter := testutils.NewMockOutputWriter() 80 | outputWriter.WriteCallback = func(event *output.ResultEvent) { 81 | if event.Matched != "" { 82 | nucleilog.Infof(format.FormatLine(event)) 83 | 84 | results = append(results, *event) 85 | // TODO: metasploit 86 | } 87 | } 88 | 89 | cache := hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount, nil) 90 | defer cache.Close() 91 | 92 | progressClient := &testutils.MockProgressClient{} 93 | reportingClient, _ := reporting.New(&reporting.Options{}, "") 94 | defer reportingClient.Close() 95 | 96 | interactOpts := interactsh.DefaultOptions(outputWriter, reportingClient, progressClient) 97 | interactClient, err := interactsh.New(interactOpts) 98 | if err != nil { 99 | return nil, err 100 | } 101 | defer interactClient.Close() 102 | 103 | protocolstate.Init(options) 104 | protocolinit.Init(options) 105 | 106 | executorOpts := protocols.ExecutorOptions{ 107 | Output: outputWriter, 108 | Progress: progressClient, 109 | Catalog: catalog, 110 | Options: options, 111 | IssuesClient: reportingClient, 112 | RateLimiter: ratelimit.New(context.Background(), 150, time.Second), 113 | Interactsh: interactClient, 114 | ResumeCfg: types.NewResumeCfg(), 115 | } 116 | engine := core.New(options) 117 | engine.SetExecuterOptions(executorOpts) 118 | 119 | workflowLoader, err := parsers.NewLoader(&executorOpts) 120 | if err != nil { 121 | return nil, err 122 | } 123 | executorOpts.WorkflowLoader = workflowLoader 124 | 125 | store, err := loader.New(loader.NewConfig(options, catalog, executorOpts)) 126 | if err != nil { 127 | return nil, err 128 | } 129 | store.Load() 130 | 131 | inputArgs := []*contextargs.MetaInput{{Input: sanitizedURL}} 132 | input := &inputs.SimpleInputProvider{Inputs: inputArgs} 133 | 134 | _ = engine.Execute(store.Templates(), input) 135 | engine.WorkPool().Wait() 136 | 137 | return results, nil 138 | } 139 | -------------------------------------------------------------------------------- /pkg/scan/ports.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | package scan 26 | 27 | import ( 28 | "bufio" 29 | "fmt" 30 | "net" 31 | "net/http" 32 | "os" 33 | "strconv" 34 | "strings" 35 | "sync" 36 | "time" 37 | 38 | "github.com/charmbracelet/log" 39 | "github.com/dropalldatabases/sif/internal/styles" 40 | "github.com/dropalldatabases/sif/pkg/logger" 41 | ) 42 | 43 | const commonPorts = "https://raw.githubusercontent.com/dropalldatabases/sif-runtime/main/ports/top-ports.txt" 44 | 45 | func Ports(scope string, url string, timeout time.Duration, threads int, logdir string) ([]string, error) { 46 | log.Printf(styles.Separator.Render("🚪 Starting " + styles.Status.Render("port scanning") + "...")) 47 | 48 | sanitizedURL := strings.Split(url, "://")[1] 49 | if logdir != "" { 50 | if err := logger.WriteHeader(sanitizedURL, logdir, scope+" port scanning"); err != nil { 51 | log.Errorf("Error creating log file: %v", err) 52 | return nil, err 53 | } 54 | } 55 | 56 | portlog := log.NewWithOptions(os.Stderr, log.Options{ 57 | Prefix: "Ports 🚪", 58 | }) 59 | 60 | portlog.Infof("Starting %s port scanning", scope) 61 | 62 | var ports []int 63 | switch scope { 64 | case "common": 65 | resp, err := http.Get(commonPorts) 66 | if err != nil { 67 | log.Errorf("Error downloading ports list: %s", err) 68 | return nil, err 69 | } 70 | defer resp.Body.Close() 71 | scanner := bufio.NewScanner(resp.Body) 72 | scanner.Split(bufio.ScanLines) 73 | for scanner.Scan() { 74 | if port, err := strconv.Atoi(scanner.Text()); err == nil { 75 | ports = append(ports, port) 76 | } 77 | } 78 | case "full": 79 | ports = make([]int, 65536) 80 | for i := range ports { 81 | ports[i] = i 82 | } 83 | } 84 | 85 | var openPorts []string 86 | var wg sync.WaitGroup 87 | wg.Add(threads) 88 | for thread := 0; thread < threads; thread++ { 89 | go func(thread int) { 90 | defer wg.Done() 91 | 92 | for i, port := range ports { 93 | if i%threads != thread { 94 | continue 95 | } 96 | 97 | log.Debugf("Looking up: %d", port) 98 | tcp, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", sanitizedURL, port), timeout) 99 | if err != nil { 100 | log.Debugf("Error %d: %v", port, err) 101 | } else { 102 | openPorts = append(openPorts, strconv.Itoa(port)) 103 | portlog.Infof("%s %s:%s", styles.Status.Render("[tcp]"), sanitizedURL, styles.Highlight.Render(strconv.Itoa(port))) 104 | tcp.Close() 105 | } 106 | } 107 | }(thread) 108 | } 109 | wg.Wait() 110 | 111 | if len(openPorts) > 0 { 112 | portlog.Infof("Found %d open ports: %s", len(openPorts), strings.Join(openPorts, ", ")) 113 | } else { 114 | portlog.Error("Found no open ports") 115 | } 116 | 117 | return openPorts, nil 118 | } 119 | -------------------------------------------------------------------------------- /pkg/scan/scan.go: -------------------------------------------------------------------------------- 1 | /* 2 | ╔══════════════════════════════════════════════════════════════════════════════╗ 3 | ║ ║ 4 | ║ SIF ║ 5 | ║ ║ 6 | ║ Blazing-fast pentesting suite written in Go ║ 7 | ║ ║ 8 | ║ Copyright (c) 2023-2024 vmfunc, xyzeva, lunchcat contributors ║ 9 | ║ and other sif contributors. ║ 10 | ║ ║ 11 | ║ ║ 12 | ║ Use of this tool is restricted to research and educational ║ 13 | ║ purposes only. Usage in a production environment outside ║ 14 | ║ of these categories is strictly prohibited. ║ 15 | ║ ║ 16 | ║ Any person or entity wishing to use this tool outside of ║ 17 | ║ research or educational purposes must purchase a license ║ 18 | ║ from https://lunchcat.dev ║ 19 | ║ ║ 20 | ║ For more information, visit: https://github.com/lunchcat/sif ║ 21 | ║ ║ 22 | ╚══════════════════════════════════════════════════════════════════════════════╝ 23 | */ 24 | 25 | // The scan package provides a collection of security scanning functions. 26 | // 27 | // Each scanning function typically returns a slice of custom result structures and an error. 28 | // The package utilizes concurrent operations to improve scanning performance and provides 29 | // options for logging and timeout management. 30 | package scan 31 | 32 | import ( 33 | "bufio" 34 | "fmt" 35 | "net/http" 36 | "os" 37 | "strconv" 38 | "strings" 39 | "sync" 40 | "time" 41 | 42 | "github.com/charmbracelet/log" 43 | "github.com/dropalldatabases/sif/internal/styles" 44 | "github.com/dropalldatabases/sif/pkg/logger" 45 | ) 46 | 47 | func fetchRobotsTXT(url string, client *http.Client) *http.Response { 48 | resp, err := client.Get(url) 49 | if err != nil { 50 | log.Debugf("Error fetching robots.txt: %s", err) 51 | return nil 52 | } 53 | 54 | if resp.StatusCode == http.StatusMovedPermanently { 55 | redirectURL := resp.Header.Get("Location") 56 | if redirectURL == "" { 57 | log.Debugf("Redirect location is empty for %s", url) 58 | return nil 59 | } 60 | resp.Body.Close() 61 | return fetchRobotsTXT(redirectURL, client) 62 | } 63 | 64 | return resp 65 | } 66 | 67 | // Scan performs a basic URL scan, including checks for robots.txt and other common endpoints. 68 | // It logs the results and doesn't return any values. 69 | // 70 | // Parameters: 71 | // - url: the target URL to scan 72 | // - timeout: maximum duration for the scan 73 | // - threads: number of concurrent threads to use 74 | // - logdir: directory to store log files (empty string for no logging) 75 | func Scan(url string, timeout time.Duration, threads int, logdir string) { 76 | fmt.Println(styles.Separator.Render("🐾 Starting " + styles.Status.Render("base url scanning") + "...")) 77 | 78 | sanitizedURL := strings.Split(url, "://")[1] 79 | 80 | if logdir != "" { 81 | if err := logger.WriteHeader(sanitizedURL, logdir, "URL scanning"); err != nil { 82 | log.Errorf("Error creating log file: %v", err) 83 | return 84 | } 85 | } 86 | 87 | scanlog := log.NewWithOptions(os.Stderr, log.Options{ 88 | Prefix: "Scan 👁️‍🗨️", 89 | }).With("url", url) 90 | 91 | client := &http.Client{ 92 | Timeout: timeout, 93 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 94 | return http.ErrUseLastResponse 95 | }, 96 | } 97 | 98 | resp := fetchRobotsTXT(url+"/robots.txt", client) 99 | if resp == nil { 100 | return 101 | } 102 | defer resp.Body.Close() 103 | 104 | if resp.StatusCode != 404 && resp.StatusCode != 301 && resp.StatusCode != 302 && resp.StatusCode != 307 { 105 | scanlog.Infof("file [%s] found", styles.Status.Render("robots.txt")) 106 | 107 | var robotsData []string 108 | scanner := bufio.NewScanner(resp.Body) 109 | scanner.Split(bufio.ScanLines) 110 | for scanner.Scan() { 111 | robotsData = append(robotsData, scanner.Text()) 112 | } 113 | 114 | var wg sync.WaitGroup 115 | wg.Add(threads) 116 | for thread := 0; thread < threads; thread++ { 117 | go func(thread int) { 118 | defer wg.Done() 119 | 120 | for i, robot := range robotsData { 121 | if i%threads != thread { 122 | continue 123 | } 124 | 125 | if robot == "" || strings.HasPrefix(robot, "#") || strings.HasPrefix(robot, "User-agent: ") || strings.HasPrefix(robot, "Sitemap: ") { 126 | continue 127 | } 128 | 129 | _, sanitizedRobot, _ := strings.Cut(robot, ": ") 130 | scanlog.Debugf("%s", robot) 131 | resp, err := client.Get(url + "/" + sanitizedRobot) 132 | if err != nil { 133 | scanlog.Debugf("Error %s: %s", sanitizedRobot, err) 134 | continue 135 | } 136 | defer resp.Body.Close() 137 | 138 | if resp.StatusCode != 404 { 139 | scanlog.Infof("%s from robots: [%s]", styles.Status.Render(strconv.Itoa(resp.StatusCode)), styles.Highlight.Render(sanitizedRobot)) 140 | if logdir != "" { 141 | logger.Write(sanitizedURL, logdir, fmt.Sprintf("%s from robots: [%s]\n", strconv.Itoa(resp.StatusCode), sanitizedRobot)) 142 | } 143 | } 144 | } 145 | 146 | }(thread) 147 | } 148 | wg.Wait() 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /pkg/scan/subdomaintakeover.go: -------------------------------------------------------------------------------- 1 | package scan 2 | 3 | import ( 4 | "fmt" 5 | "github.com/charmbracelet/log" 6 | "github.com/dropalldatabases/sif/internal/styles" 7 | "github.com/dropalldatabases/sif/pkg/logger" 8 | "io" 9 | "net" 10 | "net/http" 11 | "os" 12 | "strings" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | // SubdomainTakeoverResult represents the outcome of a subdomain takeover vulnerability check. 18 | // It includes the subdomain tested, whether it's vulnerable, and the potentially vulnerable service. 19 | type SubdomainTakeoverResult struct { 20 | Subdomain string `json:"subdomain"` 21 | Vulnerable bool `json:"vulnerable"` 22 | Service string `json:"service,omitempty"` 23 | } 24 | 25 | // SubdomainTakeover checks for potential subdomain takeover vulnerabilities. 26 | // 27 | // Parameters: 28 | // - url: the target URL to scan 29 | // - dnsResults: a slice of subdomains to check (typically from Dnslist function) 30 | // - timeout: maximum duration for each subdomain check 31 | // - threads: number of concurrent threads to use 32 | // - logdir: directory to store log files (empty string for no logging) 33 | // 34 | // Returns: 35 | // - []SubdomainTakeoverResult: a slice of results for each checked subdomain 36 | // - error: any error encountered during the scan 37 | func SubdomainTakeover(url string, dnsResults []string, timeout time.Duration, threads int, logdir string) ([]SubdomainTakeoverResult, error) { 38 | fmt.Println(styles.Separator.Render("🔍 Starting " + styles.Status.Render("Subdomain Takeover Vulnerability Check") + "...")) 39 | 40 | sanitizedURL := strings.Split(url, "://")[1] 41 | 42 | if logdir != "" { 43 | if err := logger.WriteHeader(sanitizedURL, logdir, "Subdomain Takeover Vulnerability Check"); err != nil { 44 | log.Errorf("Error creating log file: %v", err) 45 | return nil, err 46 | } 47 | } 48 | 49 | subdomainlog := log.NewWithOptions(os.Stderr, log.Options{ 50 | Prefix: "Subdomain Takeover 🔍", 51 | }) 52 | 53 | client := &http.Client{ 54 | Timeout: timeout, 55 | } 56 | 57 | var wg sync.WaitGroup 58 | wg.Add(threads) 59 | 60 | resultsChan := make(chan SubdomainTakeoverResult, len(dnsResults)) 61 | 62 | for thread := 0; thread < threads; thread++ { 63 | go func(thread int) { 64 | defer wg.Done() 65 | 66 | for i, subdomain := range dnsResults { 67 | if i%threads != thread { 68 | continue 69 | } 70 | 71 | vulnerable, service := checkSubdomainTakeover(subdomain, client) 72 | result := SubdomainTakeoverResult{ 73 | Subdomain: subdomain, 74 | Vulnerable: vulnerable, 75 | Service: service, 76 | } 77 | resultsChan <- result 78 | 79 | if vulnerable { 80 | subdomainlog.Warnf("Potential subdomain takeover: %s (%s)", styles.Highlight.Render(subdomain), service) 81 | if logdir != "" { 82 | logger.Write(sanitizedURL, logdir, fmt.Sprintf("Potential subdomain takeover: %s (%s)\n", subdomain, service)) 83 | } 84 | } else { 85 | subdomainlog.Infof("Subdomain not vulnerable: %s", subdomain) 86 | } 87 | } 88 | }(thread) 89 | } 90 | 91 | go func() { 92 | wg.Wait() 93 | close(resultsChan) 94 | }() 95 | 96 | var results []SubdomainTakeoverResult 97 | for result := range resultsChan { 98 | results = append(results, result) 99 | } 100 | 101 | return results, nil 102 | } 103 | 104 | func checkSubdomainTakeover(subdomain string, client *http.Client) (bool, string) { 105 | resp, err := client.Get("http://" + subdomain) 106 | if err != nil { 107 | if strings.Contains(err.Error(), "no such host") { 108 | // Check if CNAME exists 109 | cname, err := net.LookupCNAME(subdomain) 110 | if err == nil && cname != "" { 111 | return true, "Dangling CNAME" 112 | } 113 | } 114 | return false, "" 115 | } 116 | defer resp.Body.Close() 117 | 118 | body, _ := io.ReadAll(resp.Body) 119 | bodyString := string(body) 120 | 121 | // Check for common takeover signatures in the response 122 | signatures := map[string]string{ 123 | "GitHub Pages": "There isn't a GitHub Pages site here.", 124 | "Heroku": "No such app", 125 | "Shopify": "Sorry, this shop is currently unavailable.", 126 | "Tumblr": "There's nothing here.", 127 | "WordPress": "Do you want to register *.wordpress.com?", 128 | "Amazon S3": "The specified bucket does not exist", 129 | "Bitbucket": "Repository not found", 130 | "Ghost": "The thing you were looking for is no longer here, or never was", 131 | "Pantheon": "The gods are wise, but do not know of the site which you seek.", 132 | "Fastly": "Fastly error: unknown domain", 133 | "Zendesk": "Help Center Closed", 134 | "Teamwork": "Oops - We didn't find your site.", 135 | "Helpjuice": "We could not find what you're looking for.", 136 | "Helpscout": "No settings were found for this company:", 137 | "Cargo": "If you're moving your domain away from Cargo you must make this configuration through your registrar's DNS control panel.", 138 | "Uservoice": "This UserVoice subdomain is currently available!", 139 | "Surge": "project not found", 140 | "Intercom": "This page is reserved for artistic dogs.", 141 | "Webflow": "The page you are looking for doesn't exist or has been moved.", 142 | "Kajabi": "The page you were looking for doesn't exist.", 143 | "Thinkific": "You may have mistyped the address or the page may have moved.", 144 | "Tave": "Sorry, this page is no longer available.", 145 | "Wishpond": "https://www.wishpond.com/404?campaign=true", 146 | "Aftership": "Oops.

The page you're looking for doesn't exist.", 147 | "Aha": "There is no portal here ... sending you back to Aha!", 148 | "Brightcove": "

", 149 | "Bigcartel": "

Oops! We couldn’t find that page.

", 150 | "Activecompaign": "alt=\"LIGHTTPD - fly light.\"", 151 | "Compaignmonitor": "Double check the URL or 0 { 53 | app.targets = settings.URLs 54 | } else if settings.File != "" { 55 | if _, err := os.Stat(settings.File); err != nil { 56 | return app, err 57 | } 58 | 59 | data, err := os.Open(settings.File) 60 | if err != nil { 61 | return app, err 62 | } 63 | defer data.Close() 64 | 65 | scanner := bufio.NewScanner(data) 66 | scanner.Split(bufio.ScanLines) 67 | for scanner.Scan() { 68 | app.targets = append(app.targets, scanner.Text()) 69 | } 70 | } else { 71 | return app, errors.New("target(s) must be supplied with -u or -f\n\nSee 'sif -h' for more information") 72 | } 73 | 74 | return app, nil 75 | } 76 | 77 | // Run runs the pentesting suite, with the targets specified, according to the 78 | // settings specified. 79 | func (app *App) Run() error { 80 | if app.settings.Debug { 81 | log.SetLevel(log.DebugLevel) 82 | } 83 | 84 | if app.settings.ApiMode { 85 | log.SetLevel(5) 86 | } 87 | 88 | if app.settings.LogDir != "" { 89 | if err := logger.Init(app.settings.LogDir); err != nil { 90 | return err 91 | } 92 | } 93 | 94 | scansRun := []string{} 95 | 96 | for _, url := range app.targets { 97 | if !strings.Contains(url, "://") { 98 | return errors.New(fmt.Sprintf("URL %s must include leading protocol", url)) 99 | } 100 | 101 | log.Infof("📡Starting scan on %s...", url) 102 | 103 | moduleResults := []ModuleResult{} 104 | 105 | if app.settings.LogDir != "" { 106 | if err := logger.CreateFile(&app.logFiles, url, app.settings.LogDir); err != nil { 107 | return err 108 | } 109 | } 110 | 111 | if !app.settings.NoScan { 112 | scan.Scan(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 113 | scansRun = append(scansRun, "Basic Scan") 114 | } 115 | 116 | if app.settings.Dirlist != "none" { 117 | result, err := scan.Dirlist(app.settings.Dirlist, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 118 | if err != nil { 119 | log.Errorf("Error while running directory scan: %s", err) 120 | } else { 121 | moduleResults = append(moduleResults, ModuleResult{"dirlist", result}) 122 | scansRun = append(scansRun, "Directory Listing") 123 | } 124 | } 125 | 126 | var dnsResults []string 127 | 128 | if app.settings.Dnslist != "none" { 129 | result, err := scan.Dnslist(app.settings.Dnslist, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 130 | if err != nil { 131 | log.Errorf("Error while running dns scan: %s", err) 132 | } else { 133 | moduleResults = append(moduleResults, ModuleResult{"dnslist", result}) 134 | dnsResults = result // Store the DNS results 135 | scansRun = append(scansRun, "DNS Scan") 136 | } 137 | 138 | // Only run subdomain takeover check if DNS scan is enabled 139 | if app.settings.SubdomainTakeover { 140 | result, err := scan.SubdomainTakeover(url, dnsResults, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 141 | if err != nil { 142 | log.Errorf("Error while running Subdomain Takeover Vulnerability Check: %s", err) 143 | } else { 144 | moduleResults = append(moduleResults, ModuleResult{"subdomain_takeover", result}) 145 | scansRun = append(scansRun, "Subdomain Takeover") 146 | } 147 | } 148 | } else if app.settings.SubdomainTakeover { 149 | log.Warnf("Subdomain Takeover check is enabled but DNS scan is disabled. Skipping Subdomain Takeover check.") 150 | } 151 | 152 | if app.settings.Dorking { 153 | result, err := scan.Dork(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 154 | if err != nil { 155 | log.Errorf("Error while running Dork module: %s", err) 156 | } else { 157 | moduleResults = append(moduleResults, ModuleResult{"dork", result}) 158 | scansRun = append(scansRun, "Dork") 159 | } 160 | } 161 | 162 | if app.settings.Ports != "none" { 163 | result, err := scan.Ports(app.settings.Ports, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 164 | if err != nil { 165 | log.Errorf("Error while running port scan: %s", err) 166 | } else { 167 | moduleResults = append(moduleResults, ModuleResult{"portscan", result}) 168 | scansRun = append(scansRun, "Port Scan") 169 | } 170 | } 171 | 172 | if app.settings.Whois { 173 | scan.Whois(url, app.settings.LogDir) 174 | scansRun = append(scansRun, "Whois") 175 | } 176 | 177 | // func Git(url string, timeout time.Duration, threads int, logdir string) 178 | if app.settings.Git { 179 | result, err := scan.Git(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 180 | if err != nil { 181 | log.Errorf("Error while running Git module: %s", err) 182 | } else { 183 | moduleResults = append(moduleResults, ModuleResult{"git", result}) 184 | scansRun = append(scansRun, "Git") 185 | } 186 | } 187 | 188 | if app.settings.Nuclei { 189 | result, err := scan.Nuclei(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 190 | if err != nil { 191 | log.Errorf("Error while running Nuclei module: %s", err) 192 | } else { 193 | moduleResults = append(moduleResults, ModuleResult{"nuclei", result}) 194 | scansRun = append(scansRun, "Nuclei") 195 | } 196 | } 197 | 198 | if app.settings.JavaScript { 199 | result, err := jsscan.JavascriptScan(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 200 | if err != nil { 201 | log.Errorf("Error while running JS module: %s", err) 202 | } else { 203 | moduleResults = append(moduleResults, ModuleResult{"js", result}) 204 | scansRun = append(scansRun, "JS") 205 | } 206 | } 207 | 208 | if app.settings.CMS { 209 | result, err := scan.CMS(url, app.settings.Timeout, app.settings.LogDir) 210 | if err != nil { 211 | log.Errorf("Error while running CMS detection: %s", err) 212 | scansRun = append(scansRun, "CMS") 213 | } else if result != nil { 214 | moduleResults = append(moduleResults, ModuleResult{"cms", result}) 215 | } 216 | } 217 | 218 | if app.settings.Headers { 219 | result, err := scan.Headers(url, app.settings.Timeout, app.settings.LogDir) 220 | if err != nil { 221 | log.Errorf("Error while running HTTP Header Analysis: %s", err) 222 | } else { 223 | moduleResults = append(moduleResults, ModuleResult{"headers", result}) 224 | scansRun = append(scansRun, "HTTP Headers") 225 | } 226 | } 227 | 228 | if app.settings.CloudStorage { 229 | result, err := scan.CloudStorage(url, app.settings.Timeout, app.settings.LogDir) 230 | if err != nil { 231 | log.Errorf("Error while running C3 Scan: %s", err) 232 | } else { 233 | moduleResults = append(moduleResults, ModuleResult{"cloudstorage", result}) 234 | scansRun = append(scansRun, "Cloud Storage") 235 | } 236 | } 237 | 238 | if app.settings.SubdomainTakeover { 239 | // Pass the dnsResults to the SubdomainTakeover function 240 | result, err := scan.SubdomainTakeover(url, dnsResults, app.settings.Timeout, app.settings.Threads, app.settings.LogDir) 241 | if err != nil { 242 | log.Errorf("Error while running Subdomain Takeover Vulnerability Check: %s", err) 243 | } else { 244 | moduleResults = append(moduleResults, ModuleResult{"subdomain_takeover", result}) 245 | scansRun = append(scansRun, "Subdomain Takeover") 246 | } 247 | } 248 | 249 | if app.settings.ApiMode { 250 | result := UrlResult{ 251 | Url: url, 252 | Results: moduleResults, 253 | } 254 | 255 | marshalled, err := json.Marshal(result) 256 | if err != nil { 257 | log.Fatalf("failed to marshal result: %s", err) 258 | } 259 | fmt.Println(string(marshalled)) 260 | } 261 | } 262 | 263 | if !app.settings.ApiMode { 264 | scansRunList := " • " + strings.Join(scansRun, "\n • ") 265 | if app.settings.LogDir != "" { 266 | fmt.Println(styles.Box.Render(fmt.Sprintf("🌿 All scans completed!\n📂 Output saved to files: %s\n\n🔍 Ran scans:\n%s", 267 | strings.Join(app.logFiles, ", "), 268 | scansRunList))) 269 | } else { 270 | fmt.Println(styles.Box.Render(fmt.Sprintf("🌿 All scans completed!\n\n🔍 Ran scans:\n%s", 271 | scansRunList))) 272 | } 273 | } 274 | 275 | return nil 276 | } 277 | -------------------------------------------------------------------------------- /template-example.toml: -------------------------------------------------------------------------------- 1 | [scans] 2 | scans = [ 3 | "whois", 4 | "dork", 5 | "dirlist common" 6 | ] 7 | 8 | [config] 9 | logging = true 10 | threads = 10 --------------------------------------------------------------------------------