diff --git a/.github/workflows/release-binary.yml b/.github/workflows/release-binary.yml
new file mode 100644
index 0000000..e507504
--- /dev/null
+++ b/.github/workflows/release-binary.yml
@@ -0,0 +1,24 @@
+name: 🎉 Release Binary
+
+on:
+ push:
+ tags:
+ - '*'
+ workflow_dispatch:
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up Go
+ uses: projectdiscovery/actions/setup/go@v1
+
+ - uses: projectdiscovery/actions/goreleaser@v1
+ with:
+ release: true
+ env:
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
\ No newline at end of file
diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml
new file mode 100644
index 0000000..1fee128
--- /dev/null
+++ b/.github/workflows/release-test.yml
@@ -0,0 +1,23 @@
+name: 🔨 Release Test
+
+on:
+ pull_request:
+ paths:
+ - '**.go'
+ - '**.mod'
+ workflow_dispatch:
+
+jobs:
+ release-test:
+ runs-on: ubuntu-latest-16-cores
+ steps:
+ - name: "Check out code"
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up Go
+ uses: projectdiscovery/actions/setup/go@v1
+
+ - name: Release snapshot
+ uses: projectdiscovery/actions/goreleaser@v1
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8ad0c4a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+.idea
+dist
+text
+*.exe
+*.pprof
+*.csv
+*.txt
\ No newline at end of file
diff --git a/.goreleaser.yml b/.goreleaser.yml
new file mode 100644
index 0000000..d297832
--- /dev/null
+++ b/.goreleaser.yml
@@ -0,0 +1,42 @@
+before:
+ hooks:
+ - go mod tidy
+
+builds:
+ - main: cmd/riverPass/riverPass.go
+ binary: riverPass
+ env:
+ - CGO_ENABLED=0
+
+ goos: [windows,linux,darwin]
+ goarch: [amd64,386,arm,arm64]
+ ignore:
+ - goos: darwin
+ goarch: 386
+ - goos: windows
+ goarch: arm
+ - goos: windows
+ goarch: arm64
+ ldflags:
+ - "-s"
+ - "-w"
+ flags:
+ - -trimpath
+
+#- main: cmd/tmc/main.go
+# binary: tmc
+# id: annotate
+#
+# env:
+# - CGO_ENABLED=0
+#
+# goos: [linux]
+# goarch: [amd64]
+
+archives:
+ - format: zip
+ name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}'
+
+checksum:
+ name_template: "{{ .ProjectName }}-linux-checksums.txt"
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..dea3200
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,14 @@
+# Build
+FROM golang:1.23.0-alpine AS builder
+RUN apk add build-base
+WORKDIR /app
+COPY . /app
+RUN go mod download
+RUN go build cmd/riverPass/riverPass.go
+
+FROM alpine:3.18.3
+RUN apk add bind-tools ca-certificates
+COPY --from=builder /app/riverPass /usr/local/bin/riverPass
+RUN riverPass
+
+ENTRYPOINT ["riverPass"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e2e36d9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 wjlin0
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..061bc4d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,118 @@
+
riverPass 是一个用Go编写的瑞数WAF绕过工具。它利用了WebSocket协议,将请求发送的自身浏览器中,从而绕过了瑞数WAF的检测。
+
+
+
+
+
+
+
+
+
+
+# 特征
+
+- 无需安装任意其他工具,只需导入`mitmproxy`证书即可使用
+- 可自定义设置下游代理
+- 支持联动Burp进行重放
+
+
+# 安装riverPass
+## 自行编译
+riverPass自行编译,则需要**go1.23**才能安装成功。执行一下命令
+
+```sh
+go install -v github.com/wjlin0/riverPass/cmd/riverPass@latest
+```
+## 二进制
+下载准备运行的[二进制文件](https://github.com/wjlin0/riverPass/releases/latest)
+
+- [macOS-arm64](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_macOS_arm64.zip)
+
+- [macOS-amd64](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_macOS_amd64.zip)
+
+- [linux-amd64](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_linux_amd64.zip)
+
+- [windows-amd64](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_windows_amd64.zip)
+
+- [windows-386](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_windows_386.zip)
+
+
+# 用法
+
+```shell
+riverPass -h
+```
+```yaml
+riverPass 1.0.0 数瑞WAF绕过工具
+
+Usage:
+ ./riverPass [flags]
+
+Flags:
+输入:
+ -pp, -proxy-port int 代理监听端口 (default 8001)
+ -wp, -websocket-port int websocket监听端口 (default 10001)
+ -wt, -websocket-token string websocket通信密钥 (default "123456")
+
+代理:
+ -p, -proxy string[] 下游代理
+
+版本:
+ -v, -version 输出版本
+ -update 更新版本
+ -duc, -disable-update-check 跳过自动检查更新
+
+
+EXAMPLES:
+
+运行 riverPass 并监听 8081端口:
+ $ riverPass -pp 8081
+运行 riverPass 设置下游代理:
+ $ riverPass -proxy http://127.0.0.1:7890
+
+
+
+```
+
+**注意**:在此之前你必须导入`mitmproxy`的证书(若没有 可随意运行一次 `riverPass`,它位于你主机的 `$HOME/.mitmproxy` 目录下)
+
+![img.png](./img/README/img.png)
+
+首先 运行 `riverPass`
+```shell
+$ riverPass -pp 8081
+```
+![img2.png](./img/README/img2.png)
+
+使用浏览器设置`Burp`代理
+
+![image-20241017202645518](./img/README/image-20241017202645518.png)
+
+同时在`Burp` 设置目标
+
+![image-20241017202734525](./img/README/image-20241017202734525.png)
+
+完成后,访问目标一次`https://www.189.cn/sc/`
+
+![image-20241017202921338](./img/README/image-20241017202921338.png)
+
+其中你会在请求记录中,得到以下结果,则表明此时已经完成代理
+
+![image-20241017203033463](./img/README/image-20241017203033463.png)
+
+对某一个包进行重复攻击,加入以下请求头
+
+```text
+Req-Flag: 1
+```
+
+
+
+![image-20241017204535406](./img/README/image-20241017204535406.png)
+
+其中,你可以在`Burp` 日志中,发现你刚刚重复的请求包
+
+![image-20241017204644634](./img/README/image-20241017204644634.png)
+
+# 借鉴
+- https://github.com/R0A1NG/Botgate_bypass
diff --git a/cmd/riverPass/riverPass.go b/cmd/riverPass/riverPass.go
new file mode 100644
index 0000000..0284017
--- /dev/null
+++ b/cmd/riverPass/riverPass.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+ "fmt"
+ "github.com/projectdiscovery/gologger"
+ "github.com/wjlin0/riverPass/pkg/runner"
+ "os"
+ "os/signal"
+)
+
+func main() {
+ run, err := runner.NewRunner(runner.ParserOptions())
+ if err != nil || run == nil {
+ if err != nil {
+ gologger.Print().Msg(fmt.Sprintf("unable to create Runner:%s", err.Error()))
+ os.Exit(-1)
+ }
+ return
+ }
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt)
+ go func() {
+ for range c {
+ gologger.Info().Msg("ctrl+c press: exiting")
+ os.Exit(-1)
+ }
+ }()
+ if err := run.RunEnumeration(); err != nil {
+ gologger.Fatal().Msgf("unable to run enumeration: %s", err.Error())
+ }
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..2dd9ef2
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,88 @@
+module github.com/wjlin0/riverPass
+
+go 1.23
+
+require (
+ github.com/google/uuid v1.6.0
+ github.com/gorilla/websocket v1.5.3
+ github.com/lqqyt2423/go-mitmproxy v1.8.5
+ github.com/projectdiscovery/goflags v0.1.64
+ github.com/projectdiscovery/gologger v1.1.27
+ github.com/projectdiscovery/utils v0.2.14
+ github.com/wjlin0/utils v0.0.36
+)
+
+require (
+ aead.dev/minisign v0.2.0 // indirect
+ github.com/Masterminds/semver/v3 v3.2.1 // indirect
+ github.com/VividCortex/ewma v1.2.0 // indirect
+ github.com/alecthomas/chroma/v2 v2.14.0 // indirect
+ github.com/andybalholm/brotli v1.0.6 // indirect
+ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+ github.com/aymerick/douceur v0.2.0 // indirect
+ github.com/charmbracelet/glamour v0.8.0 // indirect
+ github.com/charmbracelet/lipgloss v0.13.0 // indirect
+ github.com/charmbracelet/x/ansi v0.3.2 // indirect
+ github.com/cheggaaa/pb/v3 v3.1.4 // indirect
+ github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect
+ github.com/denisbrodbeck/machineid v1.0.1 // indirect
+ github.com/dlclark/regexp2 v1.11.4 // indirect
+ github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
+ github.com/fatih/color v1.15.0 // indirect
+ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+ github.com/golang/protobuf v1.5.3 // indirect
+ github.com/golang/snappy v0.0.4 // indirect
+ github.com/google/go-github/v30 v30.1.0 // indirect
+ github.com/google/go-querystring v1.1.0 // indirect
+ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+ github.com/gorilla/css v1.0.1 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.17.8 // indirect
+ github.com/klauspost/pgzip v1.2.5 // indirect
+ github.com/kr/pretty v0.3.1 // indirect
+ github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
+ github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
+ github.com/mholt/archiver/v3 v3.5.1 // indirect
+ github.com/microcosm-cc/bluemonday v1.0.27 // indirect
+ github.com/miekg/dns v1.1.56 // indirect
+ github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/muesli/reflow v0.3.0 // indirect
+ github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
+ github.com/nwaples/rardecode v1.1.3 // indirect
+ github.com/pierrec/lz4/v4 v4.1.2 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/projectdiscovery/blackrock v0.0.1 // indirect
+ github.com/remeh/sizedwaitgroup v1.0.0 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
+ github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
+ github.com/satori/go.uuid v1.2.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/tidwall/gjson v1.14.4 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.1 // indirect
+ github.com/ulikunitz/xz v0.5.11 // indirect
+ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
+ github.com/yuin/goldmark v1.7.4 // indirect
+ github.com/yuin/goldmark-emoji v1.0.3 // indirect
+ go.uber.org/atomic v1.11.0 // indirect
+ golang.org/x/crypto v0.27.0 // indirect
+ golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/net v0.29.0 // indirect
+ golang.org/x/oauth2 v0.11.0 // indirect
+ golang.org/x/sync v0.8.0 // indirect
+ golang.org/x/sys v0.25.0 // indirect
+ golang.org/x/term v0.24.0 // indirect
+ golang.org/x/text v0.18.0 // indirect
+ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+ google.golang.org/appengine v1.6.7 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
+ gopkg.in/djherbis/times.v1 v1.3.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..a79e012
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,241 @@
+aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
+aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
+github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
+github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
+github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
+github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
+github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
+github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
+github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
+github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
+github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
+github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
+github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
+github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
+github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
+github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
+github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
+github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs=
+github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw=
+github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
+github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
+github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY=
+github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
+github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30=
+github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
+github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo=
+github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA=
+github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
+github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
+github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
+github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
+github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
+github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
+github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
+github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
+github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
+github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
+github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
+github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
+github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
+github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
+github.com/lqqyt2423/go-mitmproxy v1.8.5 h1:F/Jt+Z5+LkJVMvjbRNtovCt6EuPArnumSOcRK9ImU7Q=
+github.com/lqqyt2423/go-mitmproxy v1.8.5/go.mod h1:dSGnI17tVZ8dtYu9vnaIz7kxVwJNFH0CoNQwEQlTpxE=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
+github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
+github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
+github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
+github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
+github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
+github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc=
+github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
+github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
+github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
+github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
+github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
+github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
+github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
+github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ=
+github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss=
+github.com/projectdiscovery/goflags v0.1.64 h1:FDfwdt9N97Hi8OuhbkDlKtVttpc/CRMIWQVa08VsHsI=
+github.com/projectdiscovery/goflags v0.1.64/go.mod h1:3FyHIVQtnycNOc1LE3O1jj/XR5XuMdF9QfHd0ujhnX4=
+github.com/projectdiscovery/gologger v1.1.27 h1:et/adsKS0jAkPZNUuZTJ+J4U/Ofadxu6Bj3NlUYs1e8=
+github.com/projectdiscovery/gologger v1.1.27/go.mod h1:TXLvCbofuDyQlweDkSBanN083w51QKT4EmyKAVMQ+Ts=
+github.com/projectdiscovery/utils v0.2.14 h1:n4zc6n1Z9EPZWu1T2CbhBwib81pShvTcCXtcBrmSny0=
+github.com/projectdiscovery/utils v0.2.14/go.mod h1:V8t4qhy4MBOvNwZv7WNWT8P3WaU+ahprtGCMnHboLtI=
+github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
+github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
+github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
+github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
+github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
+github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/wjlin0/utils v0.0.36 h1:LjPPSbAr/q/ptOyBTtKNBex/3Ac7WpE4kBYrPuOlD+E=
+github.com/wjlin0/utils v0.0.36/go.mod h1:q5UFofjWzM8RrKpejgF83mor0YAttpOO12XZYp86X7Q=
+github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
+github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
+github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
+github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
+github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
+github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4=
+github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo=
+golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
+golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
+golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
+golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o=
+gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/img/README/image-20241017202645518.png b/img/README/image-20241017202645518.png
new file mode 100644
index 0000000..eda139b
Binary files /dev/null and b/img/README/image-20241017202645518.png differ
diff --git a/img/README/image-20241017202734525.png b/img/README/image-20241017202734525.png
new file mode 100644
index 0000000..b18461b
Binary files /dev/null and b/img/README/image-20241017202734525.png differ
diff --git a/img/README/image-20241017202921338.png b/img/README/image-20241017202921338.png
new file mode 100644
index 0000000..8b504de
Binary files /dev/null and b/img/README/image-20241017202921338.png differ
diff --git a/img/README/image-20241017203033463.png b/img/README/image-20241017203033463.png
new file mode 100644
index 0000000..d9bf47a
Binary files /dev/null and b/img/README/image-20241017203033463.png differ
diff --git a/img/README/image-20241017204535406.png b/img/README/image-20241017204535406.png
new file mode 100644
index 0000000..4ee2cc5
Binary files /dev/null and b/img/README/image-20241017204535406.png differ
diff --git a/img/README/image-20241017204644634.png b/img/README/image-20241017204644634.png
new file mode 100644
index 0000000..48cebef
Binary files /dev/null and b/img/README/image-20241017204644634.png differ
diff --git a/img/README/img.png b/img/README/img.png
new file mode 100644
index 0000000..a72803b
Binary files /dev/null and b/img/README/img.png differ
diff --git a/img/README/img2.png b/img/README/img2.png
new file mode 100644
index 0000000..7122d3e
Binary files /dev/null and b/img/README/img2.png differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..96c472f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,82 @@
+
\ No newline at end of file
diff --git a/pkg/runner/banner.go b/pkg/runner/banner.go
new file mode 100644
index 0000000..ff97890
--- /dev/null
+++ b/pkg/runner/banner.go
@@ -0,0 +1,42 @@
+package runner
+
+import (
+ "github.com/projectdiscovery/gologger"
+ folderutil "github.com/projectdiscovery/utils/folder"
+ "os"
+ "path/filepath"
+)
+
+const (
+ banner = `
+ _
+ _____(_) _____ _____ ____ ____ ___________
+ / ___/ / | / / _ \/ ___/_____/ __ \/ __ / ___/ ___/
+ / / / /| |/ / __/ / /_____/ /_/ / /_/ (__ |__ )
+/_/ /_/ |___/\___/_/ / .___/\__,_/____/____/
+/_/
+`
+ Version = "1.0.0"
+ repoName = "riverByPass"
+ user = "wjlin0"
+)
+
+var (
+ DefaultRiverPassDir = filepath.Join(folderutil.HomeDirOrDefault("."), ".config", "riverPass")
+ DefaultConfig = filepath.Join(DefaultRiverPassDir, "config.yaml")
+)
+
+func showBanner() {
+ gologger.Print().Msgf("%s\n", banner)
+ gologger.Print().Msgf("\t\t\twjlin0.com\n\n")
+ gologger.Print().Msgf("慎用。你要为自己的行为负责\n")
+ gologger.Print().Msgf("开发者不承担任何责任,也不对任何误用或损坏负责.\n")
+}
+func getVersionFromCallback() func() {
+ return func() {
+ showBanner()
+ gologger.Info().Msgf("RiverPass Engine Version: v%s", Version)
+ gologger.Info().Msgf("RiverPass Config Directory: %s", DefaultConfig)
+ os.Exit(0)
+ }
+}
diff --git a/pkg/runner/options.go b/pkg/runner/options.go
new file mode 100644
index 0000000..92c2448
--- /dev/null
+++ b/pkg/runner/options.go
@@ -0,0 +1,108 @@
+package runner
+
+import (
+ "bufio"
+ "fmt"
+ "github.com/projectdiscovery/goflags"
+ "github.com/projectdiscovery/gologger"
+ errorutil "github.com/projectdiscovery/utils/errors"
+ fileutil "github.com/projectdiscovery/utils/file"
+ proxyutils "github.com/projectdiscovery/utils/proxy"
+ "github.com/wjlin0/riverPass/pkg/types"
+ updateutils "github.com/wjlin0/utils/update"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+func ParserOptions() *types.Options {
+ options := &types.Options{}
+ set := goflags.NewFlagSet()
+ set.SetDescription(fmt.Sprintf("riverPass %s 数瑞WAF绕过工具 ", Version))
+ set.CreateGroup("Input", "输入",
+ set.IntVarP(&options.ProxyPort, "proxy-port", "pp", 8001, "代理监听端口"),
+ set.IntVarP(&options.WebSocketPort, "websocket-port", "wp", 10001, "websocket监听端口"),
+ set.StringVarP(&options.WebSocketToken, "websocket-token", "wt", "123456", "websocket通信密钥"),
+ )
+ set.CreateGroup("Proxy", "代理",
+ set.StringSliceVarP(&options.Proxy, "proxy", "p", nil, "下游代理", goflags.FileCommaSeparatedStringSliceOptions),
+ )
+ set.CreateGroup("Version", "版本",
+ set.CallbackVarP(getVersionFromCallback(), "version", "v", "输出版本"),
+ set.CallbackVar(updateutils.GetUpdateToolCallback(repoName, Version), "update", "更新版本"),
+ set.BoolVarP(&options.DisableUpdateCheck, "disable-update-check", "duc", false, "跳过自动检查更新"),
+ )
+ set.SetCustomHelpText(`EXAMPLES:
+
+运行 riverPass 并监听 8081端口:
+ $ riverPass -pp 8081
+运行 riverPass 设置下游代理:
+ $ riverPass -proxy http://127.0.0.1:7890
+`)
+ set.SetConfigFilePath(filepath.Join(DefaultConfig))
+
+ _ = set.Parse()
+ // show banner
+ showBanner()
+
+ err := ValidateRunEnumeration(options)
+ if err != nil {
+ gologger.Fatal().Msgf("options validation error: %s", err.Error())
+ }
+
+ return options
+}
+func ValidateRunEnumeration(options *types.Options) error {
+ var (
+ err error
+ )
+
+ // loading the proxy server list from file or cli and test the connectivity
+ if err = loadProxyServers(options); err != nil {
+ return err
+ }
+ return nil
+}
+func loadProxyServers(options *types.Options) error {
+ var (
+ file *os.File
+ err error
+ aliveProxy string
+ proxyURL *url.URL
+ )
+
+ if len(options.Proxy) == 0 {
+ return nil
+ }
+ proxyList := []string{}
+ for _, p := range options.Proxy {
+ if fileutil.FileExists(p) {
+ if file, err = os.Open(p); err != nil {
+ return fmt.Errorf("could not open proxy file: %w", err)
+ }
+ defer file.Close()
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ if proxy := scanner.Text(); strings.TrimSpace(proxy) == "" {
+ continue
+ } else {
+ proxyList = append(proxyList, proxy)
+ }
+
+ }
+ } else {
+ proxyList = append(proxyList, p)
+ }
+ }
+ aliveProxy, err = proxyutils.GetAnyAliveProxy(30, proxyList...)
+ if err != nil {
+ return err
+ }
+ proxyURL, err = url.Parse(aliveProxy)
+ if err != nil {
+ return errorutil.WrapfWithNil(err, "failed to parse proxy got %v", err)
+ }
+ types.ProxyURL = proxyURL.String()
+ return nil
+}
diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go
new file mode 100644
index 0000000..8cc86f6
--- /dev/null
+++ b/pkg/runner/runner.go
@@ -0,0 +1,177 @@
+package runner
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "github.com/lqqyt2423/go-mitmproxy/proxy"
+ "github.com/projectdiscovery/gologger"
+ "github.com/wjlin0/riverPass/pkg/types"
+ "github.com/wjlin0/riverPass/pkg/websocketbody"
+ "github.com/wjlin0/riverPass/pkg/websocketserver"
+ "net/http"
+ "strconv"
+ "strings"
+)
+
+var jstext = " function socket_start() {\n // 避免重复连接\n if (typeof window.globalSocket121 !== 'undefined' && window.globalSocket121.readyState !== WebSocket.CLOSED) {\n return;\n }\n window.globalSocket121 = new WebSocket(\"ws://127.0.0.1:{{websocketPort}}\"),\n window.globalSocket121.onopen = function (t) {\n window.globalSocket121.send(\"{{websocketToken}}\");\n },\n window.globalSocket121.onmessage = function (t) {\n // 解析接收到的数据\n const data = JSON.parse(t.data); // 假设这里接收的是 JSON 格式的数据\n // 从 data 中提取 uuid\n const uuid = data.uuid; // 从数据中提取 UUID\n var method = data.method;\n var url = data.url;\n var body = atob(data.body);\n var headers = JSON.parse(atob(data.headers)) || {};\n // alert(headers);\n // 将 headers 设置为请求头\n const fetchOptions = {\n method: method,\n headers: new Headers(headers),\n };\n\n if (body !== \"\") {\n fetchOptions.body = body;\n }\n\n fetch(url, fetchOptions)\n .then(response => {\n const statusCode = response.status;\n\n // 将 Headers 对象转换为字典格式\n const responseHeaders = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value; // 将 headers 转换为键值对的形式存储在对象中\n });\n\n return response.text().then(body => ({\n statusCode: statusCode,\n headers: responseHeaders, // 使用字典格式的 headers\n body: body,\n }));\n })\n .then(({ statusCode, headers, body }) => {\n const textEncoder = new TextEncoder();\n const bodyAsBytes = textEncoder.encode(body);\n const bodyAsBase64 = btoa(String.fromCharCode(...bodyAsBytes));\n\n\n // 发送响应回去,包括 uuid\n const responseMessage = JSON.stringify({\n uuid: uuid, // 传递回去的 UUID\n statusCode: statusCode,\n headers: btoa(JSON.stringify(headers)), // 保持 headers 为字典格式\n body:bodyAsBase64,\n });\n console.log(btoa(JSON.stringify(headers)))\n window.globalSocket121.send(responseMessage);\n })\n .catch((e) => {\n // 处理错误,发送失败信息\n const errorMessage = JSON.stringify({\n uuid: uuid,\n statusCode: 500,\n headers: \"\",\n body: e.toString(),\n });\n window.globalSocket121.send(errorMessage);\n });\n };\n }\n\n // 确保只有在 WebSocket 没有连接的情况下启动\n if (typeof window.globalSocket121 === 'undefined' || window.globalSocket121.readyState === WebSocket.CLOSED) {\n socket_start();\n }"
+
+type Runner struct {
+ Websocket *websocketserver.WebSocketServer
+ Proxy *proxy.Proxy
+ Options *types.Options
+ proxy.BaseAddon
+}
+
+func (r *Runner) Request(flow *proxy.Flow) {
+ // 得到所有的请求头
+ headers := flow.Request.Header
+ flag := headers.Get("Req-Flag")
+ if flag == "1" {
+ //gologger.Info().Msgf("Request: %s", flow.Request.URL.String())
+ // 修改请求头
+ r.HandleDelayedRequest(flow)
+ }
+}
+func (r *Runner) HandleDelayedRequest(flow *proxy.Flow) {
+ w := websocketbody.NewWebsocketBody()
+ headers := make(map[string]string)
+ for k, _ := range flow.Request.Header {
+ if k == "Req-Flag" {
+ headers["Res-Flag"] = "1"
+ continue
+ }
+ headers[k] = flow.Request.Header.Get(k)
+ }
+ marshal, _ := json.Marshal(headers)
+
+ w.Headers = base64.StdEncoding.EncodeToString(marshal)
+
+ w.Method = flow.Request.Method
+ w.URL = flow.Request.URL.String()
+ w.Body = base64.StdEncoding.EncodeToString(flow.Request.Body)
+
+ // TODO: 传递 WebsocketReflectorBody 给 服务器
+ body, _ := w.Marshal()
+ //gologger.Info().Msgf("发送数据: %s", string(body))
+
+ c2, err := r.Websocket.SendMessageToClient(w.GetURL(), string(body))
+ headers = make(map[string]string)
+
+ if err != nil {
+ flow.Response = &proxy.Response{
+ StatusCode: 500,
+ Body: []byte(err.Error()),
+ Header: make(http.Header),
+ }
+
+ } else {
+ // 获取 c2 通道数据
+ msg := <-c2
+ err = w.UnMarshal([]byte(msg))
+ if err != nil {
+ flow.Response = &proxy.Response{
+ StatusCode: 500,
+ Body: []byte(err.Error()),
+ Header: make(http.Header),
+ }
+ return
+ }
+ code := w.StatusCode
+ if code == 500 {
+ gologger.Error().Msgf("Error: %s", string(w.Body))
+ flow.Response = &proxy.Response{
+ StatusCode: 500,
+ Body: []byte(fmt.Sprintf("Error: %s", string(w.Body))),
+ Header: make(http.Header),
+ }
+ return
+ }
+
+ hs := make(map[string]string)
+
+ h, _ := base64.StdEncoding.DecodeString(w.Headers)
+
+ err := json.Unmarshal(h, &hs)
+ if err != nil {
+ flow.Response = &proxy.Response{
+ StatusCode: 500,
+ Body: []byte(err.Error()),
+ Header: make(http.Header),
+ }
+ return
+ }
+ //gologger.Info().Msgf("接收到数据: %s", string(w.Body))
+ bs, _ := base64.StdEncoding.DecodeString(w.Body)
+
+ flow.Response = &proxy.Response{
+ StatusCode: code,
+ Body: bs,
+ Header: make(http.Header),
+ }
+ for k, _ := range hs {
+ flow.Response.Header.Set(k, hs[k])
+ }
+ return
+ }
+
+}
+
+func (r *Runner) Response(flow *proxy.Flow) {
+ flow.Response.ReplaceToDecodedBody()
+ // 得到所有的响应头
+ headers := flow.Request.Header
+ flag := headers.Get("Req-Flag")
+ ResFlag := headers.Get("Res-Flag")
+ if flag == "" && ResFlag == "" {
+ // 修改响应头
+ contentType := flow.Response.Header.Get("Content-Type")
+ switch {
+ // 判断是否是 text/html 开头
+ case strings.HasPrefix(contentType, "text/html"):
+ flow.Response.Body = append(flow.Response.Body, []byte("")...)
+ case strings.HasPrefix(contentType, "application/javascript"):
+ flow.Response.Body = append(flow.Response.Body, []byte(jstext)...)
+ }
+
+ if flow.Response.Header.Get("Content-Security-Policy") != "" {
+ // 删除 Content-Security-Policy
+ flow.Response.Header.Del("Content-Security-Policy")
+ }
+
+ flow.Response.Header.Set("Content-Length", strconv.Itoa(len(flow.Response.Body)))
+ }
+ if ResFlag == "1" {
+ gologger.Info().Msgf("%s Method: %s Content-Length: %d Status: %d", flow.Request.URL.String(), flow.Request.Method, len(flow.Response.Body), flow.Response.StatusCode)
+ }
+}
+
+func NewRunner(opts *types.Options) (*Runner, error) {
+ ws := websocketserver.NewWebSocketServer(opts.WebSocketToken)
+ jstext = strings.ReplaceAll(jstext, "{{websocketPort}}", fmt.Sprintf("%d", opts.WebSocketPort))
+ jstext = strings.ReplaceAll(jstext, "{{websocketToken}}", opts.WebSocketToken)
+ proxyOpts := &proxy.Options{
+ Addr: fmt.Sprintf(":%d", opts.ProxyPort),
+ StreamLargeBodies: 1024 * 1024 * 5,
+ Upstream: types.ProxyURL,
+ SslInsecure: true,
+ }
+ ps, err := proxy.NewProxy(proxyOpts)
+ if err != nil {
+ return nil, err
+ }
+ run := &Runner{
+ Websocket: ws,
+ Proxy: ps,
+ Options: opts,
+ }
+ ps.AddAddon(run)
+ return run, nil
+
+}
+
+func (r *Runner) RunEnumeration() error {
+ go r.Websocket.Start(fmt.Sprintf(":%d", r.Options.WebSocketPort))
+ panic(r.Proxy.Start())
+ return nil
+}
diff --git a/pkg/types/Proxy.go b/pkg/types/Proxy.go
new file mode 100644
index 0000000..562804a
--- /dev/null
+++ b/pkg/types/Proxy.go
@@ -0,0 +1,4 @@
+package types
+
+// ProxyURL is the proxy url
+var ProxyURL string
diff --git a/pkg/types/options.go b/pkg/types/options.go
new file mode 100644
index 0000000..14e9a2a
--- /dev/null
+++ b/pkg/types/options.go
@@ -0,0 +1,11 @@
+package types
+
+import "github.com/projectdiscovery/goflags"
+
+type Options struct {
+ WebSocketPort int `json:"webSocketPort"`
+ WebSocketToken string `json:"webSocketToken"`
+ ProxyPort int `json:"proxyPort"`
+ Proxy goflags.StringSlice `json:"proxy"`
+ DisableUpdateCheck bool `json:"disableUpdateCheck"`
+}
diff --git a/pkg/websocketbody/websocketbody.go b/pkg/websocketbody/websocketbody.go
new file mode 100644
index 0000000..f686388
--- /dev/null
+++ b/pkg/websocketbody/websocketbody.go
@@ -0,0 +1,36 @@
+package websocketbody
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/google/uuid"
+ "net/url"
+)
+
+type WebsocketBody struct {
+ Headers string `json:"headers"`
+ Method string `json:"method"`
+ URL string `json:"url"`
+ Body string `json:"body"`
+ StatusCode int `json:"statusCode"`
+ UUID string `json:"uuid"`
+}
+
+func NewWebsocketBody() *WebsocketBody {
+ return &WebsocketBody{
+ UUID: uuid.New().String(),
+ }
+}
+
+func (w *WebsocketBody) GetURL() string {
+ parse, _ := url.Parse(w.URL)
+ return fmt.Sprintf("%s://%s", parse.Scheme, parse.Host)
+}
+
+func (w *WebsocketBody) Marshal() ([]byte, error) {
+ return json.Marshal(w)
+}
+func (w *WebsocketBody) UnMarshal(data []byte) error {
+
+ return json.Unmarshal(data, w)
+}
diff --git a/pkg/websocketserver/websocketserver.go b/pkg/websocketserver/websocketserver.go
new file mode 100644
index 0000000..154cec8
--- /dev/null
+++ b/pkg/websocketserver/websocketserver.go
@@ -0,0 +1,132 @@
+package websocketserver
+
+import (
+ "fmt"
+ "github.com/gorilla/websocket"
+ "github.com/projectdiscovery/gologger"
+ "net/http"
+ "sync"
+)
+
+type Client struct {
+ Conn *websocket.Conn
+ Messages chan string // 为每个客户端设置独立的消息通道
+}
+
+// WebSocketServer 处理结构体
+type WebSocketServer struct {
+ allClients map[string]*Client
+ mutex sync.Mutex
+ token string // 每次初始化时传入的 token
+}
+
+// NewWebSocketServer 创建一个新的 WebSocket 服务器实例
+func NewWebSocketServer(token string) *WebSocketServer {
+ return &WebSocketServer{
+ allClients: make(map[string]*Client),
+ token: token,
+ }
+}
+
+// HandleClient 处理 WebSocket 客户端连接
+func (wsServer *WebSocketServer) HandleClient(conn *websocket.Conn, r *http.Request) {
+ defer conn.Close()
+
+ // 接收 token
+ _, receivedToken, err := conn.ReadMessage()
+ if err != nil {
+ fmt.Println("Error reading token:", err)
+ return
+ }
+
+ // 校验 token
+ if string(receivedToken) != wsServer.token {
+ fmt.Println("Invalid token, closing connection")
+ conn.Close()
+ return
+ }
+
+ //clientAddress := conn.RemoteAddr().String()
+ var origin string
+ // 从 http 头中 获取origin
+ //gologger.Info().Msg(r.Header.Get("Origin"))
+ origin = r.Header.Get("Origin")
+ // gologger.Info().Msgf("get websocket: {%s}")
+
+ client := &Client{
+ Conn: conn,
+ Messages: make(chan string), // 初始化消息通道
+ }
+ // 将连接加入到 clients map
+ wsServer.mutex.Lock()
+ wsServer.allClients[origin] = client
+ wsServer.mutex.Unlock()
+
+ //gologger.Info().Msgf("WebSocket client connected: IP=%s, Origin=%s\n", clientAddress, origin)
+ // 发送欢迎消息
+ //successMessage := base64.StdEncoding.EncodeToString([]byte("success!"))
+ //if err := conn.WriteMessage(websocket.TextMessage, []byte(successMessage)); err != nil {
+ // gologger.Error().Msgf("Error sending welcome message: %s", err)
+ // return
+ //}
+
+ // 处理消息
+ for {
+ _, msg, err := conn.ReadMessage()
+ if err != nil {
+ //fmt.Printf("WebSocket client disconnected: Origin=%s\n", origin)
+ wsServer.mutex.Lock()
+ // 关闭通道
+ close(client.Messages)
+ // 删除
+ delete(wsServer.allClients, origin)
+ wsServer.mutex.Unlock()
+ break
+ }
+
+ decodedMessage := string(msg)
+ //gologger.Info().Msgf("Received message from client: %s", decodedMessage)
+ client.Messages <- decodedMessage
+
+ }
+}
+
+func (wsServer *WebSocketServer) SendMessageToClient(origin string, msg string) (chan string, error) {
+ wsServer.mutex.Lock()
+ defer wsServer.mutex.Unlock()
+
+ client, exists := wsServer.allClients[origin]
+ if !exists {
+ return nil, fmt.Errorf("client not found: %s", origin)
+ }
+
+ err := client.Conn.WriteMessage(websocket.TextMessage, []byte(msg))
+ if err != nil {
+ fmt.Println("Error sending message:", err)
+ client.Conn.Close()
+ close(client.Messages)
+ delete(wsServer.allClients, origin) // 移除失效的客户端
+ return nil, err
+ }
+ return client.Messages, nil
+}
+
+// ServeHTTP WebSocket 路由处理函数
+func (wsServer *WebSocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ upgrader := websocket.Upgrader{
+ CheckOrigin: func(r *http.Request) bool { return true },
+ }
+
+ conn, err := upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ gologger.Error().Msgf("WebSocket upgrade failed: %s", err)
+ return
+ }
+ wsServer.HandleClient(conn, r)
+}
+func (ws *WebSocketServer) Start(addr string) {
+ http.HandleFunc("/", ws.ServeHTTP)
+
+ gologger.Info().Msgf("WebSocket server started at %s", addr)
+ http.ListenAndServe(addr, nil)
+}