├── .github └── workflows │ └── releases.yml ├── .gitignore ├── .gitmodules ├── .goreleaser.yml ├── .version.toml ├── CHANGELOG ├── LICENSE ├── README.md ├── cmd └── pocV │ ├── pocV.go │ ├── tag.go │ └── update.go ├── go.mod ├── go.sum ├── internal └── common │ ├── check │ ├── check.go │ ├── nuclei.go │ └── xray.go │ ├── errors │ └── errors.go │ ├── load │ └── load.go │ ├── output │ └── outut.go │ └── tag │ └── tag.go ├── pkg ├── common │ └── structs │ │ ├── output.go │ │ ├── result.go │ │ └── reverse.go ├── nuclei │ ├── parse │ │ └── parse.go │ └── structs │ │ ├── faketype.go │ │ ├── poc.go │ │ └── task.go └── xray │ ├── cel │ ├── cel.go │ ├── definition.go │ └── implementation.go │ ├── parse │ └── parse.go │ ├── requests │ ├── cache.go │ └── requests.go │ └── structs │ ├── cache.go │ ├── poc.go │ ├── requests.pb.go │ ├── requests.proto │ └── tasks.go ├── pocs └── test │ ├── nuclei │ ├── tag_test.yml │ └── test.yml │ └── xray │ ├── v2_cache_test.yml │ ├── v2_payload_test.yml │ ├── v2_reverse_test.yml │ ├── v2_tcp_cache_test.yml │ ├── v2_tcp_test.yml │ ├── v2_test.yml │ └── v2_udp_test.yml └── utils ├── banner.go ├── colorprint.go ├── exit.go ├── file.go ├── iconhash.go ├── log.go ├── slice.go └── string.go /.github/workflows/releases.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | create: 4 | tags: 5 | - "*" 6 | 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - 12 | name: "Check out code" 13 | uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | - 17 | name: "Set up Go" 18 | uses: actions/setup-go@v2 19 | with: 20 | go-version: 1.17 21 | - 22 | env: 23 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 24 | name: "Create release on GitHub" 25 | uses: goreleaser/goreleaser-action@v2 26 | with: 27 | args: "release --rm-dist" 28 | version: latest -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | *.old 8 | *.bat 9 | 10 | # Test binary, built with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | # Dependency directories (remove the comment below to include it) 17 | # vendor/ 18 | 19 | # vscode configuration 20 | .vscode/ 21 | 22 | # publish 23 | publish.py -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pocs/nuclei"] 2 | path = pocs/nuclei 3 | url = https://github.com/projectdiscovery/nuclei-templates 4 | [submodule "pocs/xray"] 5 | path = pocs/xray 6 | url = https://github.com/chaitin/xray 7 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | - binary: pocV 3 | main: ./cmd/pocV/ 4 | goos: 5 | - linux 6 | - windows 7 | - darwin 8 | goarch: 9 | - amd64 10 | - 386 11 | 12 | archives: 13 | - id: tgz 14 | format: tar.gz 15 | replacements: 16 | darwin: macOS 17 | format_overrides: 18 | - goos: windows 19 | format: zip -------------------------------------------------------------------------------- /.version.toml: -------------------------------------------------------------------------------- 1 | [main] 2 | extraCommands = ["git push", "git push --tags"] 3 | serialize = "{version}-{banner}" 4 | tag = true 5 | version = "3.7.5" 6 | 7 | [[operate]] 8 | location = "cmd/pocV/pocV.go" 9 | replace = "__version__ = \"{}\"" 10 | search = "__version__ = \"{}\"" -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WAY29/pocV/2dc89d32b006409690e6fb7511f11bf0b242f84c/CHANGELOG -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Longlone 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pocV 2 | 一个兼容xray V2 poc和nuclei的poc扫描框架,某知识星球作业(A compatible with xray and nuclei poc framework) 3 | 4 | ## Feature 5 | - 支持请求缓存,加快请求速度 (Support request caching to speed up requests) 6 | - 支持ceye.io和dnslog.cn作为反连平台 (Support ceye.io and dnslog.cn as dns platform) 7 | - 支持tag子命令为xray/nuclei的poc添加/删除tag,tag可用于筛选poc (supports tag subcommand to add/remove tags for the xray/nucleis poc, and tag can be used to filter poc) 8 | - 支持update子命令实现自我更新 (Support update subcommand to self-update) 9 | 10 | ## Short 11 | - 代码未经过大量测试,仅供学习 (The code is not heavily tested, just for learning) 12 | ## TODO 13 | - [x] xrayV2 http poc 14 | - [x] xrayV2 tcp/udp poc 15 | - [x] nuclei 16 | - [x] 使用tag筛选poc (Filter the poc through tags) 17 | ## Reference 18 | - [jjf012/gopoc](https://github.com/jjf012/gopoc) 19 | - [jweny/pocassist](https://github.com/jweny/pocassist) 20 | - [boyhack/w14scan](https://github.com/boy-hack) 21 | - [projectdiscovery/nuclei](https://github.com/projectdiscovery/nuclei) 22 | 23 | ## Install 24 | ### github 25 | ```bash 26 | # install pocV 27 | git clone --recurse-submodules https://github.com/WAY29/pocV 28 | go build -ldflags "-w -s" ./cmd/pocV/ 29 | # update all pocs 30 | git submodule update --remote --recursive 31 | # self-update 32 | pocV update 33 | ``` 34 | ### release 35 | ```bash 36 | # download releases from https://github.com/WAY29/pocV/releases 37 | # ... 38 | # clone pocs 39 | git clone https://github.com/projectdiscovery/nuclei-templates && git clone https://github.com/chaitin/xray 40 | # update pocs 41 | cd ./nuclei-templates && git pull && cd ../xray && git pull 42 | # self-update 43 | pocV update 44 | ``` 45 | 46 | ## Usage / Quickstart 47 | run 48 | ```bash 49 | # run single poc 50 | pocV run -t http://example.com -p ./pocs/test/xray/rule_test.yml 51 | # run multiple pocs 52 | pocV run -t http://example.com -P "./pocs/test/nuclei/*" 53 | pocV run -t http://example.com -P "./pocs/nuclei/*" 54 | pocV run -t http://example.com -P "./pocs/xray/pocs/*" 55 | # Specify multiple targets 56 | pocV run -T target.txt -p ./pocs/test/xray/rule_test.yml 57 | # Filter the poc through tags 58 | pocV run -T target.txt --tag test -p "./pocs/test/xray/*" 59 | ``` 60 | tag 61 | ```bash 62 | # add tag 63 | pocV tag -p ./pocs/test/nuclei/tag_test.yml newtag 64 | # remove tag 65 | pocV tag -p ./pocs/test/nuclei/tag_test.yml -r newtag 66 | ``` -------------------------------------------------------------------------------- /cmd/pocV/pocV.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "github.com/WAY29/errors" 8 | cli "github.com/jawher/mow.cli" 9 | 10 | "github.com/WAY29/pocV/internal/common/check" 11 | . "github.com/WAY29/pocV/internal/common/load" 12 | "github.com/WAY29/pocV/internal/common/output" 13 | "github.com/WAY29/pocV/utils" 14 | 15 | common_structs "github.com/WAY29/pocV/pkg/common/structs" 16 | nuclei_parse "github.com/WAY29/pocV/pkg/nuclei/parse" 17 | xray_requests "github.com/WAY29/pocV/pkg/xray/requests" 18 | xray_structs "github.com/WAY29/pocV/pkg/xray/structs" 19 | ) 20 | 21 | const ( 22 | __version__ = "3.7.5" 23 | ) 24 | 25 | var ( 26 | app *cli.Cli 27 | ) 28 | 29 | func cmdRun(cmd *cli.Cmd) { 30 | 31 | // 定义选项 32 | var ( 33 | target = cmd.StringsOpt("t target", make([]string, 0), "Target url(s)") 34 | targetFiles = cmd.StringsOpt("T targetfile", make([]string, 0), "Target url file(s)") 35 | poc = cmd.StringsOpt("p poc", make([]string, 0), "Poc file(s)") 36 | pocPath = cmd.StringsOpt("P pocpath", make([]string, 0), "Load poc from Path, support Glob grammer") 37 | apiKey = cmd.StringOpt("k key", "", "ceye.io api key") 38 | domain = cmd.StringOpt("d domain", "", "ceye.io subdomain") 39 | tags = cmd.StringsOpt("tag", make([]string, 0), "filter poc by tag") 40 | file = cmd.StringOpt("file", "", "Result file to write") 41 | json = cmd.BoolOpt("json", false, "Whether output is in JSON format or not, more information will be output") 42 | success = cmd.BoolOpt("success", false, "Only output success result") 43 | proxy = cmd.StringOpt("proxy", "", "Http proxy") 44 | threads = cmd.IntOpt("threads", 10, "Thread number") 45 | timeout = cmd.IntOpt("timeout", 20, "Request timeout") 46 | rate = cmd.IntOpt("rate", 100, "Request rate(per second)") 47 | debug = cmd.BoolOpt("debug", false, "Debug this program") 48 | verbose = cmd.BoolOpt("v verbose", false, "Print verbose messages") 49 | ) 50 | // 定义用法 51 | cmd.Spec = "(-t= | -T=)... (-p= | -P=)... [--tag=]... [--file= [--json]] [--success] [--proxy=] [--threads=] [--timeout=] [-k= | --key=] [-d= | --domain=] [--debug] [-v | --verbose]" 52 | 53 | cmd.Action = func() { 54 | // 设置变量 55 | timeoutSecond := time.Duration(*timeout) * time.Second 56 | 57 | if *debug { 58 | *verbose = true 59 | } 60 | // 初始化日志 61 | utils.InitLog(*debug, *verbose) 62 | 63 | // 初始化dnslog平台 64 | common_structs.InitReversePlatform(*apiKey, *domain, timeoutSecond) 65 | if common_structs.ReversePlatformType != xray_structs.ReverseType_Ceye { 66 | utils.WarningF("No Ceye api, use dnslog.cn") 67 | } 68 | 69 | // 初始化http客户端 70 | xray_requests.InitHttpClient(*threads, *proxy, timeoutSecond) 71 | 72 | // 初始化nuclei options 73 | nuclei_parse.InitExecuterOptions(*rate, *timeout) 74 | 75 | // 加载目标 76 | targets := LoadTargets(target, targetFiles) 77 | 78 | // 加载poc 79 | xrayPocs, nucleiPocs := LoadPocs(poc, pocPath) 80 | // 过滤poc 81 | xrayPocs, nucleiPocs = FilterPocs(*tags, xrayPocs, nucleiPocs) 82 | 83 | // 计算xray的总发包量,初始化缓存 84 | xrayTotalReqeusts := 0 85 | totalTargets := len(targets) 86 | for _, poc := range xrayPocs { 87 | ruleLens := len(poc.Rules) 88 | // 额外需要缓存connectionID 89 | if poc.Transport == "tcp" || poc.Transport == "udp" { 90 | ruleLens += 1 91 | } 92 | xrayTotalReqeusts += totalTargets * ruleLens 93 | } 94 | if xrayTotalReqeusts == 0 { 95 | xrayTotalReqeusts = 1 96 | } 97 | xray_requests.InitCache(xrayTotalReqeusts) 98 | 99 | // 初始化输出 100 | outputChannel, outputWg := output.InitOutput(*file, *json, *success) 101 | 102 | // 初始化check 103 | check.InitCheck(*threads, *rate, *verbose) 104 | 105 | // check开始 106 | check.Start(targets, xrayPocs, nucleiPocs, outputChannel) 107 | check.Wait() 108 | 109 | // check结束 110 | close(outputChannel) 111 | check.End() 112 | outputWg.Wait() 113 | 114 | } 115 | } 116 | 117 | func init() { 118 | errors.SetCurrentAbsPath() 119 | errors.SetSkipFrameNum(4) 120 | } 121 | 122 | func main() { 123 | // 输出banner 124 | utils.Banner() 125 | 126 | // 解析参数 127 | app = cli.App("pocV", "Powerful poc framework, adapted to Xray and Nuclei POC") 128 | app.Command("tag", "Add tag(s) for poc(s)", cmdTag) 129 | app.Command("run", "Run to test poc", cmdRun) 130 | app.Command("update", "Self-update pocV", cmdUpdate) 131 | 132 | app.Version("V version", "pocV "+__version__) 133 | app.Spec = "[-V]" 134 | 135 | app.Run(os.Args) 136 | } 137 | -------------------------------------------------------------------------------- /cmd/pocV/tag.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | . "github.com/WAY29/pocV/internal/common/load" 5 | "github.com/WAY29/pocV/internal/common/tag" 6 | nuclei_parse "github.com/WAY29/pocV/pkg/nuclei/parse" 7 | "github.com/WAY29/pocV/utils" 8 | 9 | cli "github.com/jawher/mow.cli" 10 | ) 11 | 12 | func cmdTag(cmd *cli.Cmd) { 13 | var ( 14 | poc = cmd.StringsOpt("p poc", make([]string, 0), "Poc file(s)") 15 | pocPath = cmd.StringsOpt("P pocpath", make([]string, 0), "Load poc from Path") 16 | tags = cmd.StringsArg("TAG", make([]string, 0), "poc tag") 17 | remove = cmd.BoolOpt("r rm", false, "Remove tag(s) instead of add") 18 | debug = cmd.BoolOpt("debug", false, "debug this program") 19 | verbose = cmd.BoolOpt("v verbose", false, "print verbose messages") 20 | ) 21 | 22 | cmd.Spec = "[--debug] [-v | --verbose] [-r] (-p= | -P=)... TAG..." 23 | 24 | cmd.Action = func() { 25 | // 初始化日志 26 | utils.InitLog(*debug, *verbose) 27 | 28 | // 初始化nuclei options 29 | nuclei_parse.InitExecuterOptions(100, 10) 30 | 31 | xrayPocMap, nucleiPocMap := LoadPocs(poc, pocPath) 32 | 33 | if *remove { 34 | tag.RemoveTags(*tags, xrayPocMap, nucleiPocMap) 35 | } else { 36 | tag.AddTags(*tags, xrayPocMap, nucleiPocMap) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /cmd/pocV/update.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "os" 6 | "strings" 7 | 8 | "github.com/WAY29/pocV/internal/common/errors" 9 | 10 | "github.com/WAY29/pocV/utils" 11 | "github.com/blang/semver" 12 | cli "github.com/jawher/mow.cli" 13 | "github.com/rhysd/go-github-selfupdate/selfupdate" 14 | ) 15 | 16 | func cmdUpdate(cmd *cli.Cmd) { 17 | var ( 18 | assumeYes = cmd.BoolOpt("y yes", false, "Automatic yes to prompts, this means automatically updating the latest version") 19 | debug = cmd.BoolOpt("debug", false, "Debug this program") 20 | verbose = cmd.BoolOpt("v verbose", false, "Print verbose messages") 21 | ) 22 | 23 | cmd.Spec = "[-y | --yes] [--debug] [-v | --verbose]" 24 | 25 | cmd.Action = func() { 26 | var ( 27 | input string = "y" 28 | ) 29 | 30 | // 初始化日志 31 | utils.InitLog(*debug, *verbose) 32 | latest, found, err := selfupdate.DetectLatest("WAY29/pocV") 33 | if err != nil { 34 | wrappedErr := errors.Wrap(err, "Error occurred while detecting version") 35 | utils.ErrorP(wrappedErr) 36 | return 37 | } 38 | 39 | v := semver.MustParse(__version__) 40 | if !found || latest.Version.LTE(v) { 41 | utils.MessageF("Current pocV[%s] is the latest", __version__) 42 | return 43 | } 44 | 45 | if !*assumeYes { 46 | utils.QuestionF("Do you want to update pocV[%s -> %s] ? (Y/n): ", __version__, latest.Version) 47 | input, err := bufio.NewReader(os.Stdin).ReadString('\n') 48 | input = strings.ToLower(strings.TrimSpace(input)) 49 | if err != nil || (input != "y" && input != "n" && input != "") { 50 | utils.Error("Invalid input") 51 | return 52 | } 53 | } 54 | 55 | if input == "n" { 56 | return 57 | } 58 | 59 | exe, err := os.Executable() 60 | if err != nil { 61 | wrappedErr := errors.Wrap(err, "Could not locate executable path") 62 | utils.ErrorP(wrappedErr) 63 | return 64 | } 65 | if err := selfupdate.UpdateTo(latest.AssetURL, exe); err != nil { 66 | wrappedErr := errors.Wrap(err, "Error occurred while updating binary") 67 | utils.ErrorP(wrappedErr) 68 | return 69 | } 70 | utils.SuccessF("Successfully updated to pocV[%s]", latest.Version) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/WAY29/pocV 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/WAY29/errors v1.6.0 7 | github.com/blang/semver v3.5.1+incompatible 8 | github.com/bluele/gcache v0.0.2 9 | github.com/dlclark/regexp2 v1.4.0 10 | github.com/google/cel-go v0.9.0 11 | github.com/jawher/mow.cli v1.2.0 12 | github.com/logrusorgru/aurora v2.0.3+incompatible 13 | github.com/panjf2000/ants v1.3.0 14 | github.com/projectdiscovery/nuclei/v2 v2.6.0 15 | github.com/remeh/sizedwaitgroup v1.0.0 16 | github.com/rhysd/go-github-selfupdate v1.2.3 17 | github.com/sirupsen/logrus v1.8.1 18 | github.com/spaolacci/murmur3 v1.1.0 19 | github.com/x-cray/logrus-prefixed-formatter v0.5.2 20 | go.uber.org/ratelimit v0.2.0 21 | google.golang.org/genproto v0.0.0-20220217155828-d576998c0009 22 | google.golang.org/protobuf v1.27.1 23 | gopkg.in/yaml.v2 v2.4.0 24 | ) 25 | -------------------------------------------------------------------------------- /internal/common/check/check.go: -------------------------------------------------------------------------------- 1 | package check 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | "sync" 8 | "time" 9 | 10 | "github.com/WAY29/pocV/internal/common/errors" 11 | common_structs "github.com/WAY29/pocV/pkg/common/structs" 12 | nuclei_structs "github.com/WAY29/pocV/pkg/nuclei/structs" 13 | xray_structs "github.com/WAY29/pocV/pkg/xray/structs" 14 | "github.com/WAY29/pocV/utils" 15 | 16 | "github.com/panjf2000/ants" 17 | ) 18 | 19 | var ( 20 | EmptyLinks = []string{} 21 | 22 | Ticker *time.Ticker 23 | Pool *ants.PoolWithFunc 24 | Verbose bool 25 | 26 | WaitGroup sync.WaitGroup 27 | 28 | OutputChannel chan common_structs.Result 29 | 30 | ResultPool = sync.Pool{ 31 | New: func() interface{} { 32 | return new(common_structs.PocResult) 33 | }, 34 | } 35 | ) 36 | 37 | // 初始化协程池 38 | func InitCheck(threads, rate int, verbose bool) { 39 | var err error 40 | 41 | rateLimit := time.Second / time.Duration(rate) 42 | Ticker = time.NewTicker(rateLimit) 43 | Pool, err = ants.NewPoolWithFunc(threads, check) 44 | if err != nil { 45 | utils.CliError("Initialize goroutine pool error: "+err.Error(), 2) 46 | } 47 | 48 | Verbose = verbose 49 | } 50 | 51 | // 将任务放入协程池 52 | func Start(targets []string, xrayPocMap map[string]xray_structs.Poc, nucleiPocMap map[string]nuclei_structs.Poc, outputChannel chan common_structs.Result) { 53 | // 设置outputChannel 54 | OutputChannel = outputChannel 55 | 56 | for _, target := range targets { 57 | for _, poc := range xrayPocMap { 58 | WaitGroup.Add(1) 59 | Pool.Invoke(&xray_structs.Task{ 60 | Target: target, 61 | Poc: poc, 62 | }) 63 | } 64 | for _, poc := range nucleiPocMap { 65 | WaitGroup.Add(1) 66 | Pool.Invoke(&nuclei_structs.Task{ 67 | Target: target, 68 | Poc: poc, 69 | }) 70 | } 71 | } 72 | } 73 | 74 | // 等待协程池 75 | func Wait() { 76 | WaitGroup.Wait() 77 | } 78 | 79 | // 释放协程池 80 | func End() { 81 | Pool.Release() 82 | } 83 | 84 | // 核心代码,poc检测 85 | func check(taskInterface interface{}) { 86 | var ( 87 | oRequest *http.Request = nil 88 | 89 | err error 90 | pocName string 91 | ) 92 | 93 | defer WaitGroup.Done() 94 | <-Ticker.C 95 | 96 | switch taskInterface.(type) { 97 | case *xray_structs.Task: 98 | task, ok := taskInterface.(*xray_structs.Task) 99 | if !ok { 100 | wrappedErr := errors.Newf(errors.ConvertInterfaceError, "Can't convert task interface: %#v", err) 101 | utils.ErrorP(wrappedErr) 102 | return 103 | } 104 | target, poc := task.Target, task.Poc 105 | 106 | pocName = poc.Name 107 | if poc.Transport != "tcp" && poc.Transport != "udp" { 108 | oRequest, _ = http.NewRequest("GET", target, nil) 109 | } 110 | 111 | isVul, err := executeXrayPoc(oRequest, target, &poc) 112 | if err != nil { 113 | utils.ErrorP(err) 114 | return 115 | } 116 | 117 | pocResult := ResultPool.Get().(*common_structs.PocResult) 118 | pocResult.Str = fmt.Sprintf("%s (%s)", target, pocName) 119 | pocResult.Success = isVul 120 | pocResult.URL = target 121 | pocResult.PocName = poc.Name 122 | pocResult.PocLink = poc.Detail.Links 123 | pocResult.PocAuthor = poc.Detail.Author 124 | pocResult.PocDescription = poc.Detail.Description 125 | 126 | OutputChannel <- pocResult 127 | 128 | case *nuclei_structs.Task: 129 | var ( 130 | desc string 131 | author string 132 | authors []string 133 | ) 134 | 135 | task, ok := taskInterface.(*nuclei_structs.Task) 136 | if !ok { 137 | wrappedErr := errors.Newf(errors.ConvertInterfaceError, "Can't convert task interface: %#v", err) 138 | utils.ErrorP(wrappedErr) 139 | return 140 | } 141 | target, poc := task.Target, task.Poc 142 | authors, ok = poc.Info.Authors.Value.([]string) 143 | if !ok { 144 | author = "Unknown" 145 | } else { 146 | author = strings.Join(authors, ", ") 147 | } 148 | 149 | results, isVul, err := executeNucleiPoc(target, &poc) 150 | if err != nil { 151 | utils.ErrorP(err) 152 | return 153 | } 154 | 155 | for _, r := range results { 156 | if r.ExtractorName != "" { 157 | desc = r.TemplateID + ":" + r.ExtractorName 158 | } else if r.MatcherName != "" { 159 | desc = r.TemplateID + ":" + r.MatcherName 160 | } 161 | 162 | pocResult := ResultPool.Get().(*common_structs.PocResult) 163 | pocResult.Str = fmt.Sprintf("%s (%s) ", r.Matched, r.TemplateID) 164 | pocResult.Success = isVul 165 | pocResult.URL = r.Matched 166 | pocResult.PocName = r.TemplateID 167 | pocResult.PocLink = EmptyLinks 168 | pocResult.PocAuthor = author 169 | pocResult.PocDescription = desc 170 | 171 | OutputChannel <- pocResult 172 | } 173 | } 174 | 175 | } 176 | 177 | func PutPocResult(result *common_structs.PocResult) { 178 | result.Str = "" 179 | result.Success = false 180 | result.URL = "" 181 | result.PocName = "" 182 | result.PocLink = nil 183 | result.PocDescription = "" 184 | result.PocAuthor = "" 185 | 186 | ResultPool.Put(result) 187 | } 188 | -------------------------------------------------------------------------------- /internal/common/check/nuclei.go: -------------------------------------------------------------------------------- 1 | package check 2 | 3 | import ( 4 | "github.com/WAY29/pocV/internal/common/errors" 5 | nuclei_structs "github.com/WAY29/pocV/pkg/nuclei/structs" 6 | "github.com/WAY29/pocV/utils" 7 | "github.com/projectdiscovery/nuclei/v2/pkg/output" 8 | ) 9 | 10 | func executeNucleiPoc(target string, poc *nuclei_structs.Poc) (results []*output.ResultEvent, isVul bool, err error) { 11 | isVul = false 12 | 13 | defer func() { 14 | if r := recover(); r != nil { 15 | err = errors.Wrapf(r.(error), "Run Nuclei Poc[%s] error", poc.ID) 16 | isVul = false 17 | } 18 | }() 19 | 20 | utils.DebugF("Run Nuclei Poc[%s] for %s", poc.Info.Name, target) 21 | 22 | e := poc.Executer 23 | results = make([]*output.ResultEvent, 0, e.Requests()) 24 | 25 | err = e.ExecuteWithResults(target, func(result *output.InternalWrappedEvent) { 26 | if len(result.Results) > 0 { 27 | isVul = true 28 | } 29 | results = append(results, result.Results...) 30 | }) 31 | 32 | if len(results) == 0 { 33 | results = append(results, &output.ResultEvent{TemplateID: poc.ID, Matched: target}) 34 | } 35 | return results, isVul, err 36 | } 37 | -------------------------------------------------------------------------------- /internal/common/check/xray.go: -------------------------------------------------------------------------------- 1 | package check 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "net/http" 8 | "net/http/httputil" 9 | "net/url" 10 | "strconv" 11 | "strings" 12 | "sync" 13 | "time" 14 | 15 | "github.com/WAY29/pocV/internal/common/errors" 16 | "github.com/WAY29/pocV/pkg/xray/cel" 17 | "github.com/WAY29/pocV/pkg/xray/requests" 18 | xray_structs "github.com/WAY29/pocV/pkg/xray/structs" 19 | "github.com/WAY29/pocV/utils" 20 | "github.com/google/cel-go/checker/decls" 21 | "gopkg.in/yaml.v2" 22 | ) 23 | 24 | var ( 25 | BodyBufPool = sync.Pool{ 26 | New: func() interface{} { 27 | return make([]byte, 1024) 28 | }, 29 | } 30 | BodyPool = sync.Pool{ 31 | New: func() interface{} { 32 | return make([]byte, 4096) 33 | }, 34 | } 35 | ) 36 | 37 | type RequestFuncType func(ruleName string, rule xray_structs.Rule) error 38 | 39 | func executeXrayPoc(oReq *http.Request, target string, poc *xray_structs.Poc) (isVul bool, err error) { 40 | isVul = false 41 | 42 | var ( 43 | milliseconds int64 44 | tcpudpType string = "" 45 | 46 | request *http.Request 47 | response *http.Response 48 | oProtoRequest *xray_structs.Request 49 | protoRequest *xray_structs.Request 50 | protoResponse *xray_structs.Response 51 | variableMap map[string]interface{} = make(map[string]interface{}) 52 | 53 | oReqUrlString string 54 | 55 | requestFunc cel.RequestFuncType 56 | ) 57 | 58 | // 异常处理 59 | defer func() { 60 | if r := recover(); r != nil { 61 | err = errors.Wrapf(r.(error), "Run Xray Poc[%s] error", poc.Name) 62 | isVul = false 63 | } 64 | }() 65 | // 回收 66 | defer func() { 67 | if protoRequest != nil { 68 | if protoRequest.Url != nil { 69 | requests.PutUrlType(protoRequest.Url) 70 | } 71 | requests.PutRequest(protoRequest) 72 | 73 | } 74 | if oProtoRequest != nil { 75 | if oProtoRequest.Url != nil { 76 | requests.PutUrlType(oProtoRequest.Url) 77 | } 78 | requests.PutRequest(oProtoRequest) 79 | 80 | } 81 | if protoResponse != nil { 82 | if protoResponse.Url != nil { 83 | requests.PutUrlType(protoResponse.Url) 84 | } 85 | if protoResponse.Conn != nil { 86 | requests.PutAddrType(protoResponse.Conn.Source) 87 | requests.PutAddrType(protoResponse.Conn.Destination) 88 | requests.PutConnectInfo(protoResponse.Conn) 89 | } 90 | requests.PutResponse(protoResponse) 91 | } 92 | 93 | for _, v := range variableMap { 94 | switch value := v.(type) { 95 | case *xray_structs.Reverse: 96 | cel.PutReverse(value) 97 | default: 98 | } 99 | } 100 | }() 101 | 102 | // 初始赋值 103 | if oReq != nil { 104 | oReqUrlString = oReq.URL.String() 105 | } 106 | utils.DebugF("Run Xray Poc[%s] for %s", poc.Name, target) 107 | 108 | // 设置原始请求变量 109 | oProtoRequest, _ = requests.ParseHttpRequest(oReq) 110 | variableMap["request"] = oProtoRequest 111 | 112 | // 判断transport,如果不合法则跳过 113 | transport := poc.Transport 114 | if transport == "tcp" || transport == "udp" { 115 | if strings.HasPrefix(target, "http://") || strings.HasPrefix(target, "https://") { 116 | utils.InfoF("Invalid target[%s], skip", target) 117 | return 118 | } 119 | } else { 120 | _, err = url.ParseRequestURI(target) 121 | if err != nil { 122 | utils.InfoF("Invalid target[%s], skip", target) 123 | return 124 | } 125 | } 126 | 127 | // 初始化cel-go环境,并在函数返回时回收 128 | c := cel.NewEnvOption() 129 | defer cel.PutCustomLib(c) 130 | 131 | globalEnv, err := cel.NewEnv(c) 132 | if err != nil { 133 | wrappedErr := errors.Wrap(err, "Environment creation error") 134 | utils.ErrorP(wrappedErr) 135 | return false, err 136 | } 137 | 138 | // 请求中的全局变量 139 | 140 | // 定义渲染函数 141 | render := func(v string) string { 142 | for k1, v1 := range variableMap { 143 | _, isMap := v1.(map[string]string) 144 | if isMap { 145 | continue 146 | } 147 | v1Value := fmt.Sprintf("%v", v1) 148 | t := "{{" + k1 + "}}" 149 | if !strings.Contains(v, t) { 150 | continue 151 | } 152 | v = strings.ReplaceAll(v, t, v1Value) 153 | } 154 | return v 155 | } 156 | // 刷新环境 157 | ReCreateEnv := func(c *cel.CustomLib) (*cel.Env, error) { 158 | env, err := cel.NewEnv(c) 159 | if err != nil { 160 | wrappedErr := errors.Newf(errors.EnvInitializationError, "Environment re-creation error: %v", err) 161 | return nil, wrappedErr 162 | } 163 | return env, nil 164 | } 165 | 166 | // 定义evaluateUpdateVariableMap 167 | evaluateUpdateVariableMap := func(set yaml.MapSlice) error { 168 | for _, item := range set { 169 | k, expression := item.Key.(string), item.Value.(string) 170 | 171 | out, err := cel.Evaluate(globalEnv, expression, variableMap) 172 | if err != nil { 173 | wrappedErr := errors.Wrapf(err, "Evalaute expression error: %s", expression) 174 | utils.ErrorP(wrappedErr) 175 | continue 176 | } 177 | 178 | // 设置variableMap并且更新CompileOption 179 | switch value := out.Value().(type) { 180 | case *xray_structs.UrlType: 181 | if _, ok := variableMap[k]; !ok { 182 | c.UpdateCompileOption(k, cel.UrlTypeType) 183 | } 184 | variableMap[k] = cel.UrlTypeToString(value) 185 | case *xray_structs.Reverse: 186 | if _, ok := variableMap[k]; !ok { 187 | c.UpdateCompileOption(k, cel.ReverseType) 188 | } 189 | variableMap[k] = value 190 | case int, int32, int64: 191 | if _, ok := variableMap[k]; !ok { 192 | c.UpdateCompileOption(k, decls.Int) 193 | } 194 | variableMap[k] = value 195 | case map[string]string: 196 | if _, ok := variableMap[k]; !ok { 197 | c.UpdateCompileOption(k, cel.StrStrMapType) 198 | } 199 | variableMap[k] = value 200 | case string: 201 | if _, ok := variableMap[k]; !ok { 202 | c.UpdateCompileOption(k, decls.String) 203 | } 204 | variableMap[k] = value 205 | default: 206 | if _, ok := variableMap[k]; !ok { 207 | c.UpdateCompileOption(k, decls.Any) 208 | } 209 | variableMap[k] = value 210 | } 211 | 212 | // ? 需要重新生成一遍环境,否则之前增加的变量定义不生效 213 | globalEnv, err = ReCreateEnv(c) 214 | if err != nil { 215 | return err 216 | } 217 | } 218 | return nil 219 | } 220 | 221 | // 处理set 222 | if err := evaluateUpdateVariableMap(poc.Set); err != nil { 223 | utils.ErrorP(err) 224 | return false, err 225 | } 226 | 227 | // 渲染detail 228 | detail := &poc.Detail 229 | detail.Author = render(detail.Author) 230 | for k, v := range poc.Detail.Links { 231 | detail.Links[k] = render(v) 232 | } 233 | fingerPrint := &detail.FingerPrint 234 | for _, info := range fingerPrint.Infos { 235 | info.ID = render(info.ID) 236 | info.Name = render(info.Name) 237 | info.Version = render(info.Version) 238 | info.Type = render(info.Type) 239 | } 240 | fingerPrint.HostInfo.Hostname = render(fingerPrint.HostInfo.Hostname) 241 | vulnerability := &detail.Vulnerability 242 | vulnerability.ID = render(vulnerability.ID) 243 | vulnerability.Match = render(vulnerability.Match) 244 | 245 | // transport=http: request处理 246 | HttpRequestInvoke := func(rule xray_structs.Rule) error { 247 | var ( 248 | ok bool 249 | err error 250 | ruleReq xray_structs.RuleRequest = rule.Request 251 | rawHeaderBuilder strings.Builder 252 | ) 253 | 254 | // 渲染请求头,请求路径和请求体 255 | for k, v := range ruleReq.Headers { 256 | ruleReq.Headers[k] = render(v) 257 | } 258 | ruleReq.Path = render(strings.TrimSpace(ruleReq.Path)) 259 | ruleReq.Body = render(strings.TrimSpace(ruleReq.Body)) 260 | 261 | // 尝试获取缓存 262 | if request, protoRequest, protoResponse, ok = requests.XrayGetHttpRequestCache(&ruleReq); !ok || !rule.Request.Cache { 263 | // 获取protoRequest 264 | protoRequest, err = requests.ParseHttpRequest(oReq) 265 | if err != nil { 266 | wrappedErr := errors.Wrapf(err, "Run poc[%v] parse request error", poc.Name) 267 | return wrappedErr 268 | } 269 | 270 | // 处理Path 271 | if strings.HasPrefix(ruleReq.Path, "/") { 272 | protoRequest.Url.Path = strings.Trim(oReq.URL.Path, "/") + "/" + ruleReq.Path[1:] 273 | } else if strings.HasPrefix(ruleReq.Path, "^") { 274 | protoRequest.Url.Path = "/" + ruleReq.Path[1:] 275 | } 276 | 277 | if !strings.HasPrefix(protoRequest.Url.Path, "/") { 278 | protoRequest.Url.Path = "/" + protoRequest.Url.Path 279 | } 280 | 281 | // 某些poc没有区分path和query,需要处理 282 | protoRequest.Url.Path = strings.ReplaceAll(protoRequest.Url.Path, " ", "%20") 283 | protoRequest.Url.Path = strings.ReplaceAll(protoRequest.Url.Path, "+", "%20") 284 | 285 | // 克隆请求对象 286 | request, err = http.NewRequest(ruleReq.Method, fmt.Sprintf("%s://%s%s", protoRequest.Url.Scheme, protoRequest.Url.Host, protoRequest.Url.Path), strings.NewReader(ruleReq.Body)) 287 | if err != nil { 288 | return err 289 | } 290 | 291 | // 处理请求头 292 | request.Header = oReq.Header.Clone() 293 | for k, v := range ruleReq.Headers { 294 | request.Header.Set(k, v) 295 | rawHeaderBuilder.WriteString(k) 296 | rawHeaderBuilder.WriteString(": ") 297 | rawHeaderBuilder.WriteString(v) 298 | rawHeaderBuilder.WriteString("\n") 299 | } 300 | 301 | protoRequest.RawHeader = []byte(strings.Trim(rawHeaderBuilder.String(), "\n")) 302 | 303 | // 额外处理protoRequest.Raw 304 | protoRequest.Raw, _ = httputil.DumpRequestOut(request, true) 305 | 306 | // 发起请求 307 | response, milliseconds, err = requests.DoRequest(request, ruleReq.FollowRedirects) 308 | if err != nil { 309 | return err 310 | } 311 | 312 | // 获取protoResponse 313 | protoResponse, err = requests.ParseHttpResponse(response, milliseconds) 314 | if err != nil { 315 | wrappedErr := errors.Wrapf(err, "Run poc[%s] parse response error", poc.Name) 316 | return wrappedErr 317 | } 318 | 319 | // 设置缓存 320 | requests.XraySetHttpRequestCache(&ruleReq, request, protoRequest, protoResponse) 321 | 322 | } else { 323 | utils.DebugF("Hit http request cache[%s%s]", oReqUrlString, ruleReq.Path) 324 | } 325 | 326 | return nil 327 | } 328 | 329 | // transport=tcp/udp: request处理 330 | TCPUDPRequestInvoke := func(rule xray_structs.Rule) error { 331 | var ( 332 | tcpudpTypeUpper = strings.ToUpper(tcpudpType) 333 | buffer = BodyBufPool.Get().([]byte) 334 | 335 | content = rule.Request.Content 336 | connectionID string = rule.Request.ConnectionID 337 | conn net.Conn 338 | connCache *net.Conn 339 | responseRaw []byte 340 | readTimeout int 341 | 342 | ok bool 343 | err error 344 | ) 345 | defer BodyBufPool.Put(buffer) 346 | 347 | // 获取response缓存 348 | if responseRaw, protoResponse, ok = requests.XrayGetTcpUdpResponseCache(rule.Request.Content); !ok || !rule.Request.Cache { 349 | responseRaw = BodyPool.Get().([]byte) 350 | defer BodyPool.Put(responseRaw) 351 | 352 | // 获取connectionID缓存 353 | if connCache, ok = requests.XrayGetTcpUdpConnectionCache(connectionID); !ok { 354 | // 处理timeout 355 | readTimeout, err = strconv.Atoi(rule.Request.ReadTimeout) 356 | if err != nil { 357 | wrappedErr := errors.Wrapf(err, "Parse read_timeout[%s] to int error", rule.Request.ReadTimeout) 358 | return wrappedErr 359 | } 360 | 361 | // 发起连接 362 | conn, err = net.Dial(tcpudpType, target) 363 | if err != nil { 364 | wrappedErr := errors.Wrapf(err, "%s connect to target[%s] error", tcpudpTypeUpper, target) 365 | return wrappedErr 366 | } 367 | 368 | // 设置读取超时 369 | err := conn.SetReadDeadline(time.Now().Add(time.Duration(readTimeout) * time.Second)) 370 | if err != nil { 371 | wrappedErr := errors.Wrapf(err, "Set read_timeout[%d] error", tcpudpTypeUpper, readTimeout) 372 | return wrappedErr 373 | } 374 | 375 | // 设置连接缓存 376 | requests.XraySetTcpUdpConnectionCache(connectionID, &conn) 377 | } else { 378 | conn = *connCache 379 | utils.DebugF("Hit connection_id cache[%s]", connectionID) 380 | } 381 | 382 | // 获取protoRequest 383 | protoRequest, _ = requests.ParseTCPUDPRequest([]byte(content)) 384 | 385 | // 发送数据 386 | _, err = conn.Write([]byte(content)) 387 | if err != nil { 388 | wrappedErr := errors.Wrapf(err, "%s[%s] write error", tcpudpTypeUpper, connectionID) 389 | return wrappedErr 390 | } 391 | 392 | // 接收数据 393 | for { 394 | n, err := conn.Read(buffer) 395 | if err != nil { 396 | if err == io.EOF { 397 | } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() { 398 | } else { 399 | wrappedErr := errors.Wrapf(err, "%s[%s] read error", tcpudpTypeUpper, connectionID) 400 | return wrappedErr 401 | } 402 | break 403 | } 404 | responseRaw = append(responseRaw, buffer[:n]...) 405 | } 406 | 407 | // 获取protoResponse 408 | protoResponse, _ = requests.ParseTCPUDPResponse(responseRaw, &conn, tcpudpType) 409 | 410 | // 设置响应缓存 411 | requests.XraySetTcpUdpResponseCache(content, responseRaw, protoResponse) 412 | 413 | } else { 414 | utils.DebugF("Hit tcp/udp request cache[%s]", responseRaw) 415 | } 416 | 417 | return nil 418 | } 419 | 420 | // reqeusts总处理 421 | RequestInvoke := func(requestFunc cel.RequestFuncType, ruleName string, rule xray_structs.Rule) (bool, error) { 422 | var ( 423 | flag bool 424 | ok bool 425 | err error 426 | ) 427 | err = requestFunc(rule) 428 | if err != nil { 429 | return false, err 430 | } 431 | 432 | variableMap["request"] = protoRequest 433 | variableMap["response"] = protoResponse 434 | 435 | utils.DebugF("raw requests: \n%#s", string(protoRequest.Raw)) 436 | utils.DebugF("raw response: \n%#s", string(protoResponse.Raw)) 437 | 438 | // 执行表达式 439 | out, err := cel.Evaluate(globalEnv, rule.Expression, variableMap) 440 | 441 | if err != nil { 442 | wrappedErr := errors.Wrapf(err, "Evalute rule[%s] expression error: %s", ruleName, rule.Expression) 443 | return false, wrappedErr 444 | } 445 | 446 | // 判断表达式结果 447 | flag, ok = out.Value().(bool) 448 | if !ok { 449 | flag = false 450 | } 451 | 452 | // 处理output 453 | if err := evaluateUpdateVariableMap(rule.Output); err != nil { 454 | return false, err 455 | } 456 | 457 | return flag, nil 458 | } 459 | 460 | // 判断transport类型,设置requestInvoke 461 | if poc.Transport == "tcp" { 462 | tcpudpType = "tcp" 463 | requestFunc = TCPUDPRequestInvoke 464 | } else if poc.Transport == "udp" { 465 | tcpudpType = "udp" 466 | requestFunc = TCPUDPRequestInvoke 467 | } else { 468 | requestFunc = HttpRequestInvoke 469 | } 470 | 471 | ruleSlice := poc.Rules 472 | // 提前定义名为ruleName的函数 473 | for _, ruleItem := range ruleSlice { 474 | c.DefineRuleFunction(requestFunc, ruleItem.Key, ruleItem.Value, RequestInvoke) 475 | if err != nil { 476 | wrappedErr := errors.Wrapf(err, "Define %s error", ruleItem.Key) 477 | return false, wrappedErr 478 | } 479 | } 480 | // ? 最后再生成一遍环境,否则之前增加的变量定义不生效 481 | globalEnv, err = ReCreateEnv(c) 482 | if err != nil { 483 | utils.ErrorP(err) 484 | return false, err 485 | } 486 | 487 | // 执行rule 并判断poc总体表达式结果 488 | run := func() (bool, error) { 489 | successVal, err := cel.Evaluate(globalEnv, poc.Expression, variableMap) 490 | if err != nil { 491 | wrappedErr := errors.Wrapf(err, "Evalute poc[%s] expression error: %s", poc.Name, poc.Expression) 492 | return false, wrappedErr 493 | } 494 | 495 | isVul, ok := successVal.Value().(bool) 496 | if !ok { 497 | isVul = false 498 | } 499 | 500 | return isVul, nil 501 | } 502 | 503 | // 如果没设置payload,则直接评估rules并返回 504 | if len(poc.Payloads.Payloads) == 0 { 505 | return run() 506 | } 507 | 508 | // 如果设置了payload,则遍历执行 509 | isVul = false 510 | 511 | for _, setMapVal := range poc.Payloads.Payloads { 512 | payloads := setMapVal.Value.(yaml.MapSlice) 513 | evaluateUpdateVariableMap(payloads) 514 | isVul, err = run() 515 | if err != nil { 516 | return false, err 517 | } 518 | 519 | if isVul && !poc.Payloads.Continue { 520 | return isVul, nil 521 | } 522 | } 523 | return isVul, nil 524 | } 525 | -------------------------------------------------------------------------------- /internal/common/errors/errors.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/WAY29/errors" 7 | ) 8 | 9 | type ErrorType uint16 10 | 11 | const ( 12 | Unknown ErrorType = iota 13 | ConvertInterfaceError 14 | EnvInitializationError 15 | CompileError 16 | ProgramCreationError 17 | EvaluationError 18 | ProxyError 19 | RequestError 20 | ResponseError 21 | FileError 22 | FileNotFoundError 23 | ) 24 | 25 | type CustomError struct { 26 | Type ErrorType 27 | Msg string 28 | } 29 | 30 | func (err CustomError) Error() string { 31 | return err.Msg 32 | } 33 | 34 | func New(Type ErrorType, msg string) error { 35 | return errors.Wrap(CustomError{Type: Type, Msg: msg}, "") 36 | } 37 | 38 | func Newf(Type ErrorType, format string, args ...interface{}) error { 39 | return errors.Wrap(CustomError{Type: Type, Msg: fmt.Sprintf(format, args...)}, "") 40 | } 41 | 42 | func Wrap(err error, msg string) error { 43 | return errors.Wrap(err, msg) 44 | } 45 | 46 | func Wrapf(err error, format string, args ...interface{}) error { 47 | return errors.Wrapf(err, format, args...) 48 | } 49 | -------------------------------------------------------------------------------- /internal/common/load/load.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "path/filepath" 5 | "strings" 6 | 7 | nuclei_parse "github.com/WAY29/pocV/pkg/nuclei/parse" 8 | nuclei_structs "github.com/WAY29/pocV/pkg/nuclei/structs" 9 | xray_parse "github.com/WAY29/pocV/pkg/xray/parse" 10 | xray_structs "github.com/WAY29/pocV/pkg/xray/structs" 11 | 12 | "github.com/WAY29/pocV/utils" 13 | ) 14 | 15 | // 读取目标 16 | func LoadTargets(target *[]string, targetFiles *[]string) []string { 17 | targetsSlice := make([]string, 0) 18 | if len(*target) != 0 { 19 | targetsSlice = append(targetsSlice, *target...) 20 | } 21 | 22 | for _, targetFile := range *targetFiles { 23 | if utils.Exists(targetFile) && utils.IsFile(targetFile) { 24 | utils.DebugF("Load target file: %v", targetFile) 25 | 26 | lineSlice, err := utils.ReadFileAsLine(targetFile) 27 | if err != nil { 28 | utils.CliError("Read target file error: "+err.Error(), 2) 29 | } 30 | targetsSlice = append(targetsSlice, lineSlice...) 31 | } else { 32 | utils.WarningF("Target file not found: %v", targetFile) 33 | } 34 | } 35 | 36 | utils.InfoF("Load [%d] target(s)", len(targetsSlice)) 37 | 38 | return targetsSlice 39 | } 40 | 41 | // 读取pocs 42 | func LoadPocs(pocs *[]string, pocPaths *[]string) (map[string]xray_structs.Poc, map[string]nuclei_structs.Poc) { 43 | xrayPocMap := make(map[string]xray_structs.Poc) 44 | nucleiPocMap := make(map[string]nuclei_structs.Poc) 45 | 46 | // 加载poc函数 47 | LoadPoc := func(pocFile string) { 48 | if utils.Exists(pocFile) && utils.IsFile(pocFile) { 49 | pocPath, err := filepath.Abs(pocFile) 50 | if err != nil { 51 | utils.CliError("Get poc filepath error: "+pocFile, 4) 52 | } 53 | utils.DebugF("Load poc file: %v", pocFile) 54 | 55 | xrayPoc, err := xray_parse.ParsePoc(pocPath) 56 | if err == nil { 57 | xrayPocMap[pocPath] = *xrayPoc 58 | return 59 | } 60 | nucleiPoc, err := nuclei_parse.ParsePoc(pocPath) 61 | 62 | if err == nil { 63 | nucleiPocMap[pocPath] = *nucleiPoc 64 | return 65 | } 66 | 67 | if err != nil { 68 | utils.WarningF("Poc[%s] Parse error", pocFile) 69 | } 70 | 71 | } else { 72 | utils.WarningF("Poc file not found: '%v'", pocFile) 73 | } 74 | } 75 | 76 | for _, pocFile := range *pocs { 77 | LoadPoc(pocFile) 78 | } 79 | for _, pocPath := range *pocPaths { 80 | utils.DebugF("Load from poc path: %v", pocPath) 81 | 82 | pocFiles, err := filepath.Glob(pocPath) 83 | if err != nil { 84 | utils.CliError("Path glob match error: "+err.Error(), 6) 85 | } 86 | for _, pocFile := range pocFiles { 87 | // 只解析yml或yaml文件 88 | if strings.HasSuffix(pocFile, ".yml") || strings.HasSuffix(pocFile, ".yaml") { 89 | LoadPoc(pocFile) 90 | } 91 | } 92 | 93 | } 94 | 95 | utils.InfoF("Load [%d] xray poc(s), [%d] nuclei poc(s)", len(xrayPocMap), len(nucleiPocMap)) 96 | 97 | return xrayPocMap, nucleiPocMap 98 | } 99 | 100 | func FilterPocs(tags []string, xrayPocMap map[string]xray_structs.Poc, nucleiPocMap map[string]nuclei_structs.Poc) (map[string]xray_structs.Poc, map[string]nuclei_structs.Poc) { 101 | 102 | for k, poc := range xrayPocMap { 103 | for _, tag := range tags { 104 | if !strings.Contains(poc.Detail.Tags, tag) { 105 | delete(xrayPocMap, k) 106 | break 107 | } 108 | } 109 | } 110 | 111 | // nuclei tag 不区分大小写 112 | for k, poc := range nucleiPocMap { 113 | for _, tag := range tags { 114 | if !strings.Contains(poc.Info.Tags.String(), strings.ToLower(tag)) { 115 | delete(nucleiPocMap, k) 116 | break 117 | } 118 | } 119 | } 120 | 121 | return xrayPocMap, nucleiPocMap 122 | } 123 | -------------------------------------------------------------------------------- /internal/common/output/outut.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/WAY29/pocV/internal/common/errors" 7 | "github.com/WAY29/pocV/pkg/common/structs" 8 | "github.com/WAY29/pocV/utils" 9 | 10 | "github.com/remeh/sizedwaitgroup" 11 | ) 12 | 13 | func InitOutput(file string, jsonFlag, successFlag bool) (chan structs.Result, *sizedwaitgroup.SizedWaitGroup) { 14 | 15 | outputChannel := make(chan structs.Result) 16 | outputs := make([]structs.Output, 0) 17 | outputWg := sizedwaitgroup.New(1) 18 | outputWg.Add() 19 | 20 | // inject StrandardOutput 21 | outputs = append(outputs, &structs.StandardOutput{}) 22 | 23 | // inject FileOutput 24 | if file != "" { 25 | var err error 26 | var f *os.File 27 | 28 | if file != "" { 29 | f, err = os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 30 | if err != nil { 31 | wrappedErr := errors.Newf(errors.FileError, "Can't create file '%s': %#v", file, err) 32 | utils.ErrorP(wrappedErr) 33 | } else { 34 | outputs = append(outputs, &structs.FileOutput{F: f, Json: jsonFlag}) 35 | 36 | } 37 | } 38 | 39 | } 40 | 41 | go func() { 42 | defer outputWg.Done() 43 | 44 | for result := range outputChannel { 45 | if successFlag && !result.SUCCESS() { 46 | continue 47 | } 48 | for _, output := range outputs { 49 | output.Write(result) 50 | } 51 | 52 | // pocResult, ok := result.(*structs.PocResult) 53 | // if ok { 54 | // check.PutPocResult(pocResult) 55 | // } 56 | } 57 | }() 58 | 59 | return outputChannel, &outputWg 60 | } 61 | -------------------------------------------------------------------------------- /internal/common/tag/tag.go: -------------------------------------------------------------------------------- 1 | package tag 2 | 3 | import ( 4 | "strings" 5 | 6 | nuclei_structs "github.com/WAY29/pocV/pkg/nuclei/structs" 7 | xray_structs "github.com/WAY29/pocV/pkg/xray/structs" 8 | "github.com/WAY29/pocV/utils" 9 | "gopkg.in/yaml.v2" 10 | 11 | "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice" 12 | ) 13 | 14 | func addTag(beforeTag string, tag string) string { 15 | if beforeTag == "" { 16 | return tag 17 | } 18 | return beforeTag + ", " + tag 19 | } 20 | 21 | func removeTag(beforeTag string, tag string) string { 22 | if beforeTag == tag { 23 | return "" 24 | } else { 25 | beforeTag = strings.TrimSpace(strings.ReplaceAll(beforeTag, ", "+tag, "")) 26 | beforeTag = strings.TrimSpace(strings.ReplaceAll(beforeTag, ","+tag, "")) 27 | beforeTag = strings.TrimSpace(strings.ReplaceAll(beforeTag, tag, "")) 28 | return beforeTag 29 | 30 | } 31 | } 32 | 33 | // 为poc添加标签 34 | func AddTags(tags []string, xrayPocMap map[string]xray_structs.Poc, nucleiPocMap map[string]nuclei_structs.Poc) { 35 | for _, tag := range tags { 36 | for pocPath, poc := range xrayPocMap { 37 | pocTags := poc.Detail.Tags 38 | if !strings.Contains(pocTags, tag) { 39 | poc.Detail.Tags = addTag(pocTags, tag) 40 | out, err := yaml.Marshal(poc) 41 | if err != nil { 42 | utils.CliError("Can't Marshal poc: "+poc.Name, 2) 43 | } 44 | err = utils.WriteFile(pocPath, out) 45 | if err != nil { 46 | utils.CliError("Can't write file: "+pocPath, 3) 47 | } 48 | utils.SuccessF("%s: Add [%s] Tag", poc.Name, tag) 49 | } 50 | } 51 | for pocPath, poc := range nucleiPocMap { 52 | pocTags := poc.Info.Tags.String() 53 | if !strings.Contains(pocTags, tag) { 54 | poc.Info.Tags = stringslice.StringSlice{ 55 | Value: addTag(pocTags, tag), 56 | } 57 | out, err := yaml.Marshal(poc) 58 | if err != nil { 59 | utils.CliError("Can't Marshal poc: "+poc.ID, 2) 60 | } 61 | err = utils.WriteFile(pocPath, out) 62 | if err != nil { 63 | utils.CliError("Can't write file: "+pocPath, 3) 64 | } 65 | utils.SuccessF("%s: Add [%s] Tag", poc.ID, tag) 66 | } 67 | } 68 | } 69 | 70 | } 71 | 72 | // 为poc移除标签 73 | func RemoveTags(tags []string, xrayPocMap map[string]xray_structs.Poc, nucleiPocMap map[string]nuclei_structs.Poc) { 74 | for _, tag := range tags { 75 | for pocPath, poc := range xrayPocMap { 76 | pocTags := poc.Detail.Tags 77 | if strings.Contains(pocTags, tag) { 78 | poc.Detail.Tags = removeTag(pocTags, tag) 79 | out, err := yaml.Marshal(poc) 80 | if err != nil { 81 | utils.CliError("Can't Marshal poc: "+poc.Name, 2) 82 | } 83 | err = utils.WriteFile(pocPath, out) 84 | if err != nil { 85 | utils.CliError("Can't write file: "+pocPath, 3) 86 | } 87 | utils.SuccessF("%s: Remove [%s] Tag", poc.Name, tag) 88 | } 89 | } 90 | // nuclei tag 不区分大小写 91 | for pocPath, poc := range nucleiPocMap { 92 | pocTags := poc.Info.Tags.String() 93 | tag = strings.ToLower(tag) 94 | if strings.Contains(pocTags, tag) { 95 | poc.Info.Tags = stringslice.StringSlice{ 96 | Value: removeTag(pocTags, tag), 97 | } 98 | out, err := yaml.Marshal(poc) 99 | if err != nil { 100 | utils.CliError("Can't Marshal poc: "+poc.ID, 2) 101 | } 102 | err = utils.WriteFile(pocPath, out) 103 | if err != nil { 104 | utils.CliError("Can't write file: "+pocPath, 3) 105 | } 106 | utils.SuccessF("%s: Remove [%s] Tag", poc.ID, tag) 107 | } 108 | } 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /pkg/common/structs/output.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/WAY29/pocV/internal/common/errors" 7 | "github.com/WAY29/pocV/utils" 8 | ) 9 | 10 | type Output interface { 11 | Write(result Result) 12 | } 13 | 14 | // StandardOutput 15 | type StandardOutput struct{} 16 | 17 | func (o *StandardOutput) Write(result Result) { 18 | if result.SUCCESS() { 19 | utils.Success(result.STR()) 20 | } else { 21 | utils.Failure(result.STR()) 22 | } 23 | } 24 | 25 | // FileOutput 26 | type FileOutput struct { 27 | F *os.File 28 | Json bool 29 | } 30 | 31 | func (o *FileOutput) Write(result Result) { 32 | var row string 33 | if o.Json { 34 | row = result.JSON() 35 | } else { 36 | row = result.STR() 37 | if result.SUCCESS() { 38 | row = "[+] " + row 39 | } else { 40 | row = "[-] " + row 41 | } 42 | } 43 | 44 | _, err := o.F.WriteString(row + "\n") 45 | if err != nil { 46 | wrappedErr := errors.Newf(errors.ConvertInterfaceError, "Can't write file '%s': %#v", o.F.Name(), err) 47 | utils.ErrorP(wrappedErr) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /pkg/common/structs/result.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import "encoding/json" 4 | 5 | type Result interface { 6 | STR() string 7 | JSON() string 8 | SUCCESS() bool 9 | } 10 | 11 | type PocResult struct { 12 | Str string 13 | Success bool 14 | URL string `json:"url"` 15 | PocName string `json:"poc_name"` 16 | PocLink []string `json:"poc_link"` 17 | PocAuthor string `json:"poc_author"` 18 | PocDescription string `json:"poc_description"` 19 | } 20 | 21 | func (r *PocResult) JSON() string { 22 | if js, err := json.Marshal(r); err == nil { 23 | return string(js) 24 | } 25 | return "" 26 | } 27 | 28 | func (r *PocResult) STR() string { 29 | return r.Str 30 | } 31 | 32 | func (r *PocResult) SUCCESS() bool { 33 | return r.Success 34 | } 35 | -------------------------------------------------------------------------------- /pkg/common/structs/reverse.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import ( 4 | "net/http" 5 | "strings" 6 | "time" 7 | 8 | xray_structs "github.com/WAY29/pocV/pkg/xray/structs" 9 | ) 10 | 11 | var ( 12 | CeyeApi string 13 | CeyeDomain string 14 | ReversePlatformType xray_structs.ReverseType 15 | DnslogCNGetDomainRequest *http.Request 16 | DnslogCNGetRecordRequest *http.Request 17 | ) 18 | 19 | func InitReversePlatform(api, domain string, timeout time.Duration) { 20 | if api != "" && domain != "" && strings.HasSuffix(domain, ".ceye.io") { 21 | CeyeApi = api 22 | CeyeDomain = domain 23 | ReversePlatformType = xray_structs.ReverseType_Ceye 24 | } else { 25 | ReversePlatformType = xray_structs.ReverseType_DnslogCN 26 | 27 | // 设置请求相关参数 28 | DnslogCNGetDomainRequest, _ = http.NewRequest("GET", "http://dnslog.cn/getdomain.php", nil) 29 | DnslogCNGetRecordRequest, _ = http.NewRequest("GET", "http://dnslog.cn/getrecords.php", nil) 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pkg/nuclei/parse/parse.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "github.com/WAY29/errors" 5 | "github.com/WAY29/pocV/pkg/nuclei/structs" 6 | "github.com/WAY29/pocV/utils" 7 | "github.com/projectdiscovery/nuclei/v2/pkg/catalog" 8 | "github.com/projectdiscovery/nuclei/v2/pkg/protocols" 9 | "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit" 10 | "github.com/projectdiscovery/nuclei/v2/pkg/templates" 11 | "github.com/projectdiscovery/nuclei/v2/pkg/types" 12 | 13 | "go.uber.org/ratelimit" 14 | ) 15 | 16 | var ( 17 | ExecuterOptions protocols.ExecuterOptions 18 | ) 19 | 20 | func InitExecuterOptions(rate int, timeout int) { 21 | fakeWriter := structs.FakeWrite{} 22 | progress := &structs.FakeProgress{} 23 | o := types.Options{ 24 | RateLimit: rate, 25 | BulkSize: 25, 26 | TemplateThreads: 25, 27 | HeadlessBulkSize: 10, 28 | HeadlessTemplateThreads: 10, 29 | Timeout: timeout, 30 | Retries: 1, 31 | MaxHostError: 30, 32 | } 33 | err := protocolinit.Init(&o) 34 | if err != nil { 35 | utils.CliError("Nuclei InitExecuterOptions error", 2) 36 | return 37 | } 38 | 39 | catalog2 := catalog.New("") 40 | ExecuterOptions = protocols.ExecuterOptions{ 41 | Output: &fakeWriter, 42 | Options: &o, 43 | Progress: progress, 44 | Catalog: catalog2, 45 | RateLimiter: ratelimit.New(rate), 46 | } 47 | 48 | } 49 | 50 | func ParsePoc(filename string) (*structs.Poc, error) { 51 | var err error 52 | poc, err := templates.Parse(filename, nil, ExecuterOptions) 53 | if err != nil { 54 | return nil, err 55 | } 56 | if poc == nil { 57 | return nil, nil 58 | } 59 | if poc.ID == "" { 60 | return nil, errors.New("Nuclei poc id can't be nil") 61 | } 62 | return poc, nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/nuclei/structs/faketype.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import ( 4 | "github.com/logrusorgru/aurora" 5 | "github.com/projectdiscovery/nuclei/v2/pkg/output" 6 | ) 7 | 8 | type FakeWrite struct{} 9 | 10 | func (r *FakeWrite) Close() {} 11 | func (r *FakeWrite) Colorizer() aurora.Aurora { 12 | return nil 13 | } 14 | func (r *FakeWrite) WriteFailure(event output.InternalEvent) error { return nil } 15 | func (r *FakeWrite) Write(w *output.ResultEvent) error { return nil } 16 | func (r *FakeWrite) Request(templateID, url, requestType string, err error) {} 17 | 18 | type FakeProgress struct{} 19 | 20 | func (p *FakeProgress) Stop() {} 21 | func (p *FakeProgress) Init(hostCount int64, rulesCount int, requestCount int64) {} 22 | func (p *FakeProgress) AddToTotal(delta int64) {} 23 | func (p *FakeProgress) IncrementRequests() {} 24 | func (p *FakeProgress) IncrementMatched() {} 25 | func (p *FakeProgress) IncrementErrorsBy(count int64) {} 26 | func (p *FakeProgress) IncrementFailedRequestsBy(count int64) {} 27 | -------------------------------------------------------------------------------- /pkg/nuclei/structs/poc.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import "github.com/projectdiscovery/nuclei/v2/pkg/templates" 4 | 5 | type Poc = templates.Template 6 | -------------------------------------------------------------------------------- /pkg/nuclei/structs/task.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | type Task struct { 4 | Poc Poc 5 | Target string 6 | } 7 | -------------------------------------------------------------------------------- /pkg/xray/cel/cel.go: -------------------------------------------------------------------------------- 1 | package cel 2 | 3 | import ( 4 | "strings" 5 | "sync" 6 | 7 | "github.com/WAY29/pocV/internal/common/errors" 8 | 9 | "github.com/WAY29/pocV/pkg/xray/structs" 10 | "github.com/WAY29/pocV/utils" 11 | "github.com/google/cel-go/cel" 12 | "github.com/google/cel-go/checker/decls" 13 | "github.com/google/cel-go/common/types" 14 | "github.com/google/cel-go/common/types/ref" 15 | "github.com/google/cel-go/interpreter/functions" 16 | exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" 17 | ) 18 | 19 | type RequestFuncType func(rule structs.Rule) error 20 | 21 | var ( 22 | CustomLibPool = sync.Pool{ 23 | New: func() interface{} { 24 | return new(CustomLib) 25 | }, 26 | } 27 | ) 28 | 29 | // 自定义Lib库,包含变量和函数 30 | 31 | type Env = cel.Env 32 | type CustomLib struct { 33 | envOptions []cel.EnvOption 34 | programOptions []cel.ProgramOption 35 | } 36 | 37 | // 执行表达式 38 | func Evaluate(env *cel.Env, expression string, params map[string]interface{}) (ref.Val, error) { 39 | utils.DebugF("Evaluate expression: %s", strings.TrimSpace(expression)) 40 | 41 | ast, iss := env.Compile(expression) 42 | err := iss.Err() 43 | if err != nil { 44 | wrappedErr := errors.Newf(errors.CompileError, "Compile error: %v", err) 45 | return nil, wrappedErr 46 | } 47 | 48 | prg, err := env.Program(ast) 49 | if err != nil { 50 | wrappedErr := errors.Newf(errors.ProgramCreationError, "Program creation error: %v", err) 51 | return nil, wrappedErr 52 | } 53 | 54 | out, _, err := prg.Eval(params) 55 | if err != nil { 56 | wrappedErr := errors.Newf(errors.EvaluationError, "Evaluation error: %v", err) 57 | return nil, wrappedErr 58 | } 59 | return out, nil 60 | } 61 | 62 | func UrlTypeToString(u *structs.UrlType) string { 63 | var buf strings.Builder 64 | 65 | if u.Scheme != "" { 66 | buf.WriteString(u.Scheme) 67 | buf.WriteByte(':') 68 | } 69 | if u.Scheme != "" || u.Host != "" { 70 | if u.Host != "" || u.Path != "" { 71 | buf.WriteString("//") 72 | } 73 | if h := u.Host; h != "" { 74 | buf.WriteString(u.Host) 75 | } 76 | } 77 | path := u.Path 78 | if path != "" && path[0] != '/' && u.Host != "" { 79 | buf.WriteString("/") 80 | } 81 | if buf.Len() == 0 { 82 | if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 { 83 | buf.WriteString("./") 84 | } 85 | } 86 | buf.WriteString(path) 87 | 88 | if u.Query != "" { 89 | buf.WriteByte('?') 90 | buf.WriteString(u.Query) 91 | } 92 | if u.Fragment != "" { 93 | buf.WriteByte('#') 94 | buf.WriteString(u.Fragment) 95 | } 96 | return buf.String() 97 | } 98 | 99 | func NewEnv(c *CustomLib) (*cel.Env, error) { 100 | return cel.NewEnv(cel.Lib(c)) 101 | } 102 | 103 | func NewEnvOption() *CustomLib { 104 | c := CustomLibPool.Get().(*CustomLib) 105 | reg := types.NewEmptyRegistry() 106 | c.envOptions = NewFunctionDefineOptions(reg) 107 | c.programOptions = NewFunctionImplOptions(reg) 108 | return c 109 | } 110 | 111 | func NewExtraFunctionEnvOption(declOpt cel.EnvOption, progOpt cel.ProgramOption) *CustomLib { 112 | c := CustomLibPool.Get().(*CustomLib) 113 | c.envOptions = []cel.EnvOption{declOpt} 114 | c.programOptions = []cel.ProgramOption{progOpt} 115 | return c 116 | } 117 | 118 | func PutCustomLib(c *CustomLib) { 119 | c.envOptions = nil 120 | c.programOptions = nil 121 | 122 | CustomLibPool.Put(c) 123 | } 124 | 125 | func NewCompileOption(k string, t *exprpb.Type) cel.EnvOption { 126 | return cel.Declarations(decls.NewVar(k, t)) 127 | } 128 | 129 | // 声明环境中的变量类型和函数 130 | func (c *CustomLib) CompileOptions() []cel.EnvOption { 131 | return c.envOptions 132 | } 133 | 134 | func (c *CustomLib) ProgramOptions() []cel.ProgramOption { 135 | return c.programOptions 136 | } 137 | 138 | func (c *CustomLib) UpdateCompileOption(k string, t *exprpb.Type) { 139 | c.envOptions = append(c.envOptions, cel.Declarations(decls.NewVar(k, t))) 140 | } 141 | func (c *CustomLib) DefineRuleFunction(requestFunc RequestFuncType, ruleName string, rule structs.Rule, function func(requestFunc RequestFuncType, ruleName string, rule structs.Rule) (bool, error)) { 142 | c.envOptions = append(c.envOptions, cel.Declarations( 143 | decls.NewFunction(ruleName, 144 | decls.NewOverload(ruleName, 145 | []*exprpb.Type{}, 146 | decls.Bool)), 147 | )) 148 | 149 | c.programOptions = append(c.programOptions, cel.Functions( 150 | &functions.Overload{ 151 | Operator: ruleName, 152 | Function: func(values ...ref.Val) ref.Val { 153 | r, err := function(requestFunc, ruleName, rule) 154 | if err != nil { 155 | r = false 156 | utils.ErrorP(err) 157 | } 158 | return types.Bool(r) 159 | }, 160 | })) 161 | } 162 | -------------------------------------------------------------------------------- /pkg/xray/cel/definition.go: -------------------------------------------------------------------------------- 1 | package cel 2 | 3 | import ( 4 | "github.com/WAY29/pocV/pkg/xray/structs" 5 | "github.com/google/cel-go/cel" 6 | "github.com/google/cel-go/checker/decls" 7 | "github.com/google/cel-go/common/types/ref" 8 | exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" 9 | ) 10 | 11 | var ( 12 | StrStrMapType = decls.NewMapType(decls.String, decls.String) 13 | RequestType = decls.NewObjectType("structs.Request") 14 | ResponseType = decls.NewObjectType("structs.Response") 15 | ReverseType = decls.NewObjectType("structs.Reverse") 16 | UrlTypeType = decls.NewObjectType("structs.UrlType") 17 | 18 | StandradEnvOptions = []cel.EnvOption{ 19 | cel.Container("structs"), 20 | cel.Types( 21 | &structs.UrlType{}, 22 | &structs.Request{}, 23 | &structs.Response{}, 24 | &structs.Reverse{}, 25 | StrStrMapType, 26 | ), 27 | cel.Declarations( 28 | decls.NewVar("request", RequestType), 29 | decls.NewVar("response", ResponseType), 30 | ), 31 | cel.Declarations( 32 | // functions 33 | decls.NewFunction("bcontains", 34 | decls.NewInstanceOverload("bytes_bcontains_bytes", 35 | []*exprpb.Type{decls.Bytes, decls.Bytes}, 36 | decls.Bool)), 37 | decls.NewFunction("ibcontains", 38 | decls.NewInstanceOverload("bytes_ibcontains_bytes", 39 | []*exprpb.Type{decls.Bytes, decls.Bytes}, 40 | decls.Bool)), 41 | decls.NewFunction("icontains", 42 | decls.NewInstanceOverload("icontains_string", 43 | []*exprpb.Type{decls.String, decls.String}, 44 | decls.Bool)), 45 | decls.NewFunction("bstartsWith", 46 | decls.NewInstanceOverload("bytes_bstartsWith_bytes", 47 | []*exprpb.Type{decls.Bytes, decls.Bytes}, 48 | decls.Bool)), 49 | decls.NewFunction("submatch", 50 | decls.NewInstanceOverload("string_submatch_string", 51 | []*exprpb.Type{decls.String, decls.String}, 52 | StrStrMapType, 53 | )), 54 | decls.NewFunction("bmatches", 55 | decls.NewInstanceOverload("string_bmatches_bytes", 56 | []*exprpb.Type{decls.String, decls.Bytes}, 57 | decls.Bool)), 58 | decls.NewFunction("bsubmatch", 59 | decls.NewInstanceOverload("string_bsubmatch_bytes", 60 | []*exprpb.Type{decls.String, decls.Bytes}, 61 | StrStrMapType, 62 | )), 63 | decls.NewFunction("wait", 64 | decls.NewInstanceOverload("reverse_wait_int", 65 | []*exprpb.Type{decls.Any, decls.Int}, 66 | decls.Bool)), 67 | decls.NewFunction("newReverse", 68 | decls.NewOverload("newReverse", 69 | []*exprpb.Type{}, 70 | ReverseType)), 71 | decls.NewFunction("md5", 72 | decls.NewOverload("md5_string", 73 | []*exprpb.Type{decls.String}, 74 | decls.String)), 75 | decls.NewFunction("randomInt", 76 | decls.NewOverload("randomInt_int_int", 77 | []*exprpb.Type{decls.Int, decls.Int}, 78 | decls.Int)), 79 | decls.NewFunction("randomLowercase", 80 | decls.NewOverload("randomLowercase_int", 81 | []*exprpb.Type{decls.Int}, 82 | decls.String)), 83 | decls.NewFunction("base64", 84 | decls.NewOverload("base64_string", 85 | []*exprpb.Type{decls.String}, 86 | decls.String)), 87 | decls.NewFunction("base64", 88 | decls.NewOverload("base64_bytes", 89 | []*exprpb.Type{decls.Bytes}, 90 | decls.String)), 91 | decls.NewFunction("base64Decode", 92 | decls.NewOverload("base64Decode_string", 93 | []*exprpb.Type{decls.String}, 94 | decls.String)), 95 | decls.NewFunction("base64Decode", 96 | decls.NewOverload("base64Decode_bytes", 97 | []*exprpb.Type{decls.Bytes}, 98 | decls.String)), 99 | decls.NewFunction("urlencode", 100 | decls.NewOverload("urlencode_string", 101 | []*exprpb.Type{decls.String}, 102 | decls.String)), 103 | decls.NewFunction("urlencode", 104 | decls.NewOverload("urlencode_bytes", 105 | []*exprpb.Type{decls.Bytes}, 106 | decls.String)), 107 | decls.NewFunction("urldecode", 108 | decls.NewOverload("urldecode_string", 109 | []*exprpb.Type{decls.String}, 110 | decls.String)), 111 | decls.NewFunction("urldecode", 112 | decls.NewOverload("urldecode_bytes", 113 | []*exprpb.Type{decls.Bytes}, 114 | decls.String)), 115 | decls.NewFunction("substr", 116 | decls.NewOverload("substr_string_int_int", 117 | []*exprpb.Type{decls.String, decls.Int, decls.Int}, 118 | decls.String)), 119 | decls.NewFunction("replaceAll", 120 | decls.NewOverload("replaceAll_string_string_string", 121 | []*exprpb.Type{decls.String, decls.String, decls.String}, 122 | decls.String)), 123 | decls.NewFunction("printable", 124 | decls.NewOverload("printable_string", 125 | []*exprpb.Type{decls.String}, 126 | decls.String)), 127 | decls.NewFunction("sleep", 128 | decls.NewOverload("sleep_int", 129 | []*exprpb.Type{decls.Int}, 130 | decls.Bool)), 131 | decls.NewFunction("faviconHash", 132 | decls.NewOverload("faviconHash_stringOrBytes", 133 | []*exprpb.Type{decls.Any}, 134 | decls.Int)), 135 | decls.NewFunction("toUintString", 136 | decls.NewOverload("toUintString_string_string", 137 | []*exprpb.Type{decls.String, decls.String}, 138 | decls.String)), 139 | ), 140 | } 141 | ) 142 | 143 | func NewFunctionDefineOptions(reg ref.TypeRegistry) []cel.EnvOption { 144 | 145 | newOptions := []cel.EnvOption{ 146 | cel.CustomTypeAdapter(reg), 147 | cel.CustomTypeProvider(reg), 148 | } 149 | newOptions = append(newOptions, StandradEnvOptions...) 150 | 151 | return newOptions 152 | } 153 | -------------------------------------------------------------------------------- /pkg/xray/cel/implementation.go: -------------------------------------------------------------------------------- 1 | package cel 2 | 3 | import ( 4 | "bytes" 5 | "crypto/md5" 6 | "encoding/base64" 7 | "fmt" 8 | "math/rand" 9 | "net/http" 10 | "net/url" 11 | "strconv" 12 | "strings" 13 | "sync" 14 | "time" 15 | "unicode" 16 | 17 | "github.com/WAY29/pocV/internal/common/errors" 18 | common_structs "github.com/WAY29/pocV/pkg/common/structs" 19 | "github.com/WAY29/pocV/pkg/xray/requests" 20 | "github.com/WAY29/pocV/pkg/xray/structs" 21 | "github.com/WAY29/pocV/utils" 22 | "github.com/dlclark/regexp2" 23 | "github.com/google/cel-go/cel" 24 | "github.com/google/cel-go/common/types" 25 | "github.com/google/cel-go/common/types/ref" 26 | "github.com/google/cel-go/interpreter/functions" 27 | ) 28 | 29 | var ( 30 | ReversePool = sync.Pool{ 31 | New: func() interface{} { 32 | return new(structs.Reverse) 33 | }, 34 | } 35 | 36 | StandradProgramOption = []cel.ProgramOption{ 37 | cel.Functions( 38 | &functions.Overload{ 39 | Operator: "bytes_bcontains_bytes", 40 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 41 | v1, ok := lhs.(types.Bytes) 42 | if !ok { 43 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type()) 44 | } 45 | v2, ok := rhs.(types.Bytes) 46 | if !ok { 47 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type()) 48 | } 49 | return types.Bool(bytes.Contains(v1, v2)) 50 | }, 51 | }, 52 | &functions.Overload{ 53 | Operator: "bytes_ibcontains_bytes", 54 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 55 | v1, ok := lhs.(types.Bytes) 56 | if !ok { 57 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type()) 58 | } 59 | v2, ok := rhs.(types.Bytes) 60 | if !ok { 61 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type()) 62 | } 63 | return types.Bool(bytes.Contains(bytes.ToLower(v1), bytes.ToLower(v2))) 64 | }, 65 | }, 66 | &functions.Overload{ 67 | Operator: "icontains_string", 68 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 69 | v1, ok := lhs.(types.String) 70 | if !ok { 71 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type()) 72 | } 73 | v2, ok := rhs.(types.String) 74 | if !ok { 75 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type()) 76 | } 77 | // 不区分大小写包含 78 | return types.Bool(strings.Contains(strings.ToLower(string(v1)), strings.ToLower(string(v2)))) 79 | }, 80 | }, 81 | &functions.Overload{ 82 | Operator: "bytes_bstartsWith_bytes", 83 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 84 | v1, ok := lhs.(types.Bytes) 85 | if !ok { 86 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bstartsWith", lhs.Type()) 87 | } 88 | v2, ok := rhs.(types.Bytes) 89 | if !ok { 90 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bstartsWith", rhs.Type()) 91 | } 92 | return types.Bool(bytes.HasPrefix(v1, v2)) 93 | }, 94 | }, 95 | &functions.Overload{ 96 | Operator: "string_bmatches_bytes", 97 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 98 | var isMatch = false 99 | var err error 100 | 101 | v1, ok := lhs.(types.String) 102 | if !ok { 103 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bmatches", lhs.Type()) 104 | } 105 | v2, ok := rhs.(types.Bytes) 106 | if !ok { 107 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bmatches", rhs.Type()) 108 | } 109 | re := regexp2.MustCompile(string(v1), 0) 110 | if isMatch, err = re.MatchString(string([]byte(v2))); err != nil { 111 | return types.NewErr("%v", err) 112 | } 113 | return types.Bool(isMatch) 114 | }, 115 | }, 116 | &functions.Overload{ 117 | Operator: "matches_string", 118 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 119 | var ( 120 | isMatch = false 121 | err error 122 | ) 123 | 124 | v1, ok := lhs.(types.String) 125 | if !ok { 126 | return types.ValOrErr(lhs, "unexpected type '%v' passed to matches", lhs.Type()) 127 | } 128 | v2, ok := rhs.(types.String) 129 | if !ok { 130 | return types.ValOrErr(rhs, "unexpected type '%v' passed to matches", rhs.Type()) 131 | } 132 | 133 | re := regexp2.MustCompile(string(v1), 0) 134 | if isMatch, err = re.MatchString(string(v2)); err != nil { 135 | return types.NewErr("%v", err) 136 | } 137 | return types.Bool(isMatch) 138 | }, 139 | }, 140 | 141 | &functions.Overload{ 142 | Operator: "md5_string", 143 | Unary: func(value ref.Val) ref.Val { 144 | v, ok := value.(types.String) 145 | if !ok { 146 | return types.ValOrErr(value, "unexpected type '%v' passed to md5_string", value.Type()) 147 | } 148 | return types.String(fmt.Sprintf("%x", md5.Sum([]byte(v)))) 149 | }, 150 | }, 151 | &functions.Overload{ 152 | Operator: "randomInt_int_int", 153 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 154 | from, ok := lhs.(types.Int) 155 | if !ok { 156 | return types.ValOrErr(lhs, "unexpected type '%v' passed to randomInt", lhs.Type()) 157 | } 158 | to, ok := rhs.(types.Int) 159 | if !ok { 160 | return types.ValOrErr(rhs, "unexpected type '%v' passed to randomInt", rhs.Type()) 161 | } 162 | min, max := int(from), int(to) 163 | return types.Int(rand.Intn(max-min) + min) 164 | }, 165 | }, 166 | &functions.Overload{ 167 | Operator: "randomLowercase_int", 168 | Unary: func(value ref.Val) ref.Val { 169 | n, ok := value.(types.Int) 170 | if !ok { 171 | return types.ValOrErr(value, "unexpected type '%v' passed to randomLowercase", value.Type()) 172 | } 173 | return types.String(utils.RandomStr(utils.AsciiLowercase, int(n))) 174 | }, 175 | }, 176 | &functions.Overload{ 177 | Operator: "base64_string", 178 | Unary: func(value ref.Val) ref.Val { 179 | v, ok := value.(types.String) 180 | if !ok { 181 | return types.ValOrErr(value, "unexpected type '%v' passed to base64_string", value.Type()) 182 | } 183 | return types.String(base64.StdEncoding.EncodeToString([]byte(v))) 184 | }, 185 | }, 186 | &functions.Overload{ 187 | Operator: "base64_bytes", 188 | Unary: func(value ref.Val) ref.Val { 189 | v, ok := value.(types.Bytes) 190 | if !ok { 191 | return types.ValOrErr(value, "unexpected type '%v' passed to base64_bytes", value.Type()) 192 | } 193 | return types.String(base64.StdEncoding.EncodeToString(v)) 194 | }, 195 | }, 196 | &functions.Overload{ 197 | Operator: "base64Decode_string", 198 | Unary: func(value ref.Val) ref.Val { 199 | v, ok := value.(types.String) 200 | if !ok { 201 | return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_string", value.Type()) 202 | } 203 | decodeBytes, err := base64.StdEncoding.DecodeString(string(v)) 204 | if err != nil { 205 | return types.NewErr("%v", err) 206 | } 207 | return types.String(decodeBytes) 208 | }, 209 | }, 210 | &functions.Overload{ 211 | Operator: "base64Decode_bytes", 212 | Unary: func(value ref.Val) ref.Val { 213 | v, ok := value.(types.Bytes) 214 | if !ok { 215 | return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_bytes", value.Type()) 216 | } 217 | decodeBytes, err := base64.StdEncoding.DecodeString(string(v)) 218 | if err != nil { 219 | return types.NewErr("%v", err) 220 | } 221 | return types.String(decodeBytes) 222 | }, 223 | }, 224 | &functions.Overload{ 225 | Operator: "urlencode_string", 226 | Unary: func(value ref.Val) ref.Val { 227 | v, ok := value.(types.String) 228 | if !ok { 229 | return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_string", value.Type()) 230 | } 231 | return types.String(url.QueryEscape(string(v))) 232 | }, 233 | }, 234 | &functions.Overload{ 235 | Operator: "urlencode_bytes", 236 | Unary: func(value ref.Val) ref.Val { 237 | v, ok := value.(types.Bytes) 238 | if !ok { 239 | return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_bytes", value.Type()) 240 | } 241 | return types.String(url.QueryEscape(string(v))) 242 | }, 243 | }, 244 | &functions.Overload{ 245 | Operator: "urldecode_string", 246 | Unary: func(value ref.Val) ref.Val { 247 | v, ok := value.(types.String) 248 | if !ok { 249 | return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_string", value.Type()) 250 | } 251 | decodeString, err := url.QueryUnescape(string(v)) 252 | if err != nil { 253 | return types.NewErr("%v", err) 254 | } 255 | return types.String(decodeString) 256 | }, 257 | }, 258 | &functions.Overload{ 259 | Operator: "urldecode_bytes", 260 | Unary: func(value ref.Val) ref.Val { 261 | v, ok := value.(types.Bytes) 262 | if !ok { 263 | return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_bytes", value.Type()) 264 | } 265 | decodeString, err := url.QueryUnescape(string(v)) 266 | if err != nil { 267 | return types.NewErr("%v", err) 268 | } 269 | return types.String(decodeString) 270 | }, 271 | }, 272 | &functions.Overload{ 273 | Operator: "substr_string_int_int", 274 | Function: func(values ...ref.Val) ref.Val { 275 | if len(values) == 3 { 276 | str, ok := values[0].(types.String) 277 | if !ok { 278 | return types.NewErr("invalid string to 'substr'") 279 | } 280 | start, ok := values[1].(types.Int) 281 | if !ok { 282 | return types.NewErr("invalid start to 'substr'") 283 | } 284 | length, ok := values[2].(types.Int) 285 | if !ok { 286 | return types.NewErr("invalid length to 'substr'") 287 | } 288 | runes := []rune(str) 289 | if start < 0 || length < 0 || int(start+length) > len(runes) { 290 | return types.NewErr("invalid start or length to 'substr'") 291 | } 292 | return types.String(runes[start : start+length]) 293 | } else { 294 | return types.NewErr("too many arguments to 'substr'") 295 | } 296 | }, 297 | }, 298 | &functions.Overload{ 299 | Operator: "reverse_wait_int", 300 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 301 | reverse, ok := lhs.Value().(*structs.Reverse) 302 | if !ok { 303 | return types.ValOrErr(lhs, "unexpected type '%v' passed to 'wait'", lhs.Type()) 304 | } 305 | timeout, ok := rhs.Value().(int64) 306 | if !ok { 307 | return types.ValOrErr(rhs, "unexpected type '%v' passed to 'wait'", rhs.Type()) 308 | } 309 | 310 | return types.Bool(reverseCheck(reverse, timeout)) 311 | }, 312 | }, 313 | &functions.Overload{ 314 | Operator: "replaceAll_string_string_string", 315 | Function: func(values ...ref.Val) ref.Val { 316 | s, ok := values[0].(types.String) 317 | if !ok { 318 | return types.ValOrErr(s, "unexpected type '%v' passed to replaceAll", s.Type()) 319 | } 320 | old, ok := values[1].(types.String) 321 | if !ok { 322 | return types.ValOrErr(old, "unexpected type '%v' passed to replaceAll", old.Type()) 323 | } 324 | new, ok := values[2].(types.String) 325 | if !ok { 326 | return types.ValOrErr(new, "unexpected type '%v' passed to replaceAll", new.Type()) 327 | } 328 | 329 | return types.String(strings.ReplaceAll(string(s), string(old), string(new))) 330 | }, 331 | }, 332 | &functions.Overload{ 333 | Operator: "printable_string", 334 | Unary: func(value ref.Val) ref.Val { 335 | s, ok := value.(types.String) 336 | if !ok { 337 | return types.ValOrErr(s, "unexpected type '%v' passed to printable", s.Type()) 338 | } 339 | 340 | clean := strings.Map(func(r rune) rune { 341 | if unicode.IsPrint(r) { 342 | return r 343 | } 344 | return -1 345 | }, string(s)) 346 | 347 | return types.String(clean) 348 | }, 349 | }, 350 | &functions.Overload{ 351 | Operator: "sleep_int", 352 | Unary: func(value ref.Val) ref.Val { 353 | i, ok := value.(types.Int) 354 | if !ok { 355 | return types.ValOrErr(i, "unexpected type '%v' passed to sleep", i.Type()) 356 | } 357 | time.Sleep(time.Duration(int64(i)) * time.Second) 358 | return types.Bool(true) 359 | }, 360 | }, 361 | &functions.Overload{ 362 | Operator: "faviconHash_stringOrBytes", 363 | Unary: func(value ref.Val) ref.Val { 364 | b, ok := value.(types.Bytes) 365 | if !ok { 366 | bStr, ok := value.(types.String) 367 | b = []byte(bStr) 368 | if !ok { 369 | return types.ValOrErr(bStr, "unexpected type '%v' passed to faviconHash", bStr.Type()) 370 | } 371 | } 372 | 373 | return types.Int(utils.Mmh3Hash32(utils.Base64Encode(b))) 374 | }, 375 | }, 376 | &functions.Overload{ 377 | Operator: "toUintString_string_string", 378 | Function: func(values ...ref.Val) ref.Val { 379 | s1, ok := values[0].(types.String) 380 | s := string(s1) 381 | if !ok { 382 | return types.ValOrErr(s1, "unexpected type '%v' passed to toUintString", s1.Type()) 383 | } 384 | direction, ok := values[1].(types.String) 385 | if !ok { 386 | return types.ValOrErr(direction, "unexpected type '%v' passed to toUintString", direction.Type()) 387 | } 388 | if direction == "<" { 389 | s = utils.ReverseString(s) 390 | } 391 | if _, err := strconv.Atoi(s); err == nil { 392 | return types.String(s) 393 | } else { 394 | return types.NewErr("%v", err) 395 | } 396 | }, 397 | }, 398 | ), 399 | } 400 | ) 401 | 402 | func NewFunctionImplOptions(reg ref.TypeRegistry) []cel.ProgramOption { 403 | newOptions := []cel.ProgramOption{ 404 | cel.Functions( 405 | &functions.Overload{ 406 | Operator: "string_submatch_string", 407 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 408 | var ( 409 | resultMap = make(map[string]string) 410 | ) 411 | 412 | v1, ok := lhs.(types.String) 413 | if !ok { 414 | return types.ValOrErr(lhs, "unexpected type '%v' passed to submatch", lhs.Type()) 415 | } 416 | v2, ok := rhs.(types.String) 417 | if !ok { 418 | return types.ValOrErr(rhs, "unexpected type '%v' passed to submatch", rhs.Type()) 419 | } 420 | 421 | re := regexp2.MustCompile(string(v1), regexp2.RE2) 422 | if m, _ := re.FindStringMatch(string(v2)); m != nil { 423 | gps := m.Groups() 424 | for n, gp := range gps { 425 | if n == 0 { 426 | continue 427 | } 428 | resultMap[gp.Name] = gp.String() 429 | } 430 | } 431 | return types.NewStringStringMap(reg, resultMap) 432 | }, 433 | }, 434 | &functions.Overload{ 435 | Operator: "string_bsubmatch_bytes", 436 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 437 | var ( 438 | resultMap = make(map[string]string) 439 | ) 440 | 441 | v1, ok := lhs.(types.String) 442 | if !ok { 443 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bsubmatch", lhs.Type()) 444 | } 445 | v2, ok := rhs.(types.Bytes) 446 | if !ok { 447 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bsubmatch", rhs.Type()) 448 | } 449 | 450 | re := regexp2.MustCompile(string(v1), regexp2.RE2) 451 | if m, _ := re.FindStringMatch(string([]byte(v2))); m != nil { 452 | gps := m.Groups() 453 | for n, gp := range gps { 454 | if n == 0 { 455 | continue 456 | } 457 | resultMap[gp.Name] = gp.String() 458 | } 459 | } 460 | 461 | return types.NewStringStringMap(reg, resultMap) 462 | }, 463 | }, 464 | &functions.Overload{ 465 | Operator: "newReverse", 466 | Function: func(values ...ref.Val) ref.Val { 467 | return reg.NativeToValue(xrayNewReverse()) 468 | }, 469 | }, 470 | ), 471 | } 472 | 473 | newOptions = append(newOptions, StandradProgramOption...) 474 | 475 | return newOptions 476 | } 477 | 478 | // xray dns反连平台 目前只支持dnslog.cn和ceye.io 479 | func xrayNewReverse() (reverse *structs.Reverse) { 480 | var ( 481 | urlStr string 482 | ) 483 | reverse = ReversePool.Get().(*structs.Reverse) 484 | reverse.IsDomainNameServer = false 485 | reverse.ReverseType = common_structs.ReversePlatformType 486 | 487 | switch common_structs.ReversePlatformType { 488 | case structs.ReverseType_Ceye: 489 | sub := utils.RandomStr(utils.AsciiLowercaseAndDigits, 8) 490 | urlStr = fmt.Sprintf("http://%s.%s/", sub, common_structs.CeyeDomain) 491 | case structs.ReverseType_DnslogCN: 492 | dnslogCnRequest := common_structs.DnslogCNGetDomainRequest 493 | resp, _, err := requests.DoRequest(dnslogCnRequest, false) 494 | if err != nil { 495 | wrappedErr := errors.Wrap(err, "Get reverse domain error: Can't get domain from dnslog.cn") 496 | utils.ErrorP(wrappedErr) 497 | return 498 | } 499 | content, _ := requests.GetRespBody(resp) 500 | urlStr = "http://" + string(content) + "/" 501 | default: 502 | panic("Reverse platform type error") 503 | } 504 | 505 | u, _ := url.Parse(urlStr) 506 | utils.DebugF("Get reverse domain: %s", u.Hostname()) 507 | 508 | reverse.Url = requests.ParseUrl(u) 509 | reverse.Domain = u.Hostname() 510 | reverse.Ip = u.Host 511 | 512 | return 513 | } 514 | 515 | func reverseCheck(r *structs.Reverse, timeout int64) bool { 516 | sub := strings.Split(r.Domain, ".")[0] 517 | if r.Domain == "" || sub == "" { 518 | return false 519 | } 520 | 521 | switch r.ReverseType { 522 | case structs.ReverseType_Ceye: 523 | time.Sleep(time.Second * time.Duration(timeout)) 524 | urlStr := fmt.Sprintf("http://api.ceye.io/v1/records?token=%s&type=dns&filter=%s", common_structs.CeyeApi, sub) 525 | req, _ := http.NewRequest("GET", urlStr, nil) 526 | resp, _, err := requests.DoRequest(req, false) 527 | if err != nil { 528 | wrappedErr := errors.Wrap(err, "Reverse check error") 529 | utils.ErrorP(wrappedErr) 530 | return false 531 | } 532 | content, _ := requests.GetRespBody(resp) 533 | 534 | if resp.StatusCode == 200 && len(content) > 0 && bytes.Contains(content, []byte(sub)) { // api返回结果不为空 535 | utils.DebugF("Got reverse dnslog from %s", r.Domain) 536 | return true 537 | } 538 | return false 539 | case structs.ReverseType_DnslogCN: 540 | time.Sleep(time.Second * time.Duration(timeout)) 541 | resp, _, err := requests.DoRequest(common_structs.DnslogCNGetRecordRequest, false) 542 | if err != nil { 543 | wrappedErr := errors.Wrap(err, "Reverse check error") 544 | utils.ErrorP(wrappedErr) 545 | return false 546 | } 547 | content, _ := requests.GetRespBody(resp) 548 | 549 | if bytes.Contains(content, []byte(sub)) { // api返回结果存在域名 550 | utils.DebugF("Got reverse dnslog from %s", r.Domain) 551 | return true 552 | } 553 | return false 554 | default: 555 | return false 556 | } 557 | 558 | } 559 | 560 | func PutReverse(reverse *structs.Reverse) { 561 | reverse.Url = nil 562 | reverse.Domain = "" 563 | reverse.Ip = "" 564 | reverse.ReverseType = structs.ReverseType_DnslogCN 565 | reverse.IsDomainNameServer = false 566 | 567 | ReversePool.Put(reverse) 568 | } 569 | -------------------------------------------------------------------------------- /pkg/xray/parse/parse.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "os" 5 | "sync" 6 | 7 | "github.com/WAY29/errors" 8 | "github.com/WAY29/pocV/pkg/xray/structs" 9 | "gopkg.in/yaml.v2" 10 | ) 11 | 12 | var PocPool = sync.Pool{ 13 | New: func() interface{} { 14 | return new(structs.Poc) 15 | }, 16 | } 17 | 18 | func ParsePoc(filename string) (*structs.Poc, error) { 19 | poc := PocPool.Get().(*structs.Poc) 20 | 21 | f, err := os.Open(filename) 22 | if err != nil { 23 | return nil, err 24 | } 25 | defer f.Close() 26 | 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | err = yaml.NewDecoder(f).Decode(poc) 32 | 33 | if err != nil { 34 | return nil, err 35 | } 36 | if poc.Name == "" { 37 | return nil, errors.Newf("Xray poc[%s] name can't be nil", filename) 38 | } 39 | 40 | if poc.Transport == "" { 41 | poc.Transport = "http" 42 | } 43 | return poc, nil 44 | } 45 | -------------------------------------------------------------------------------- /pkg/xray/requests/cache.go: -------------------------------------------------------------------------------- 1 | package requests 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "net/http" 7 | "sort" 8 | 9 | "github.com/WAY29/pocV/pkg/xray/structs" 10 | "github.com/WAY29/pocV/utils" 11 | "github.com/bluele/gcache" 12 | ) 13 | 14 | var ( 15 | GC gcache.Cache 16 | ) 17 | 18 | func InitCache(size int) { 19 | GC = gcache.New(size).ARC().Build() 20 | } 21 | 22 | func getHttpRuleHash(req *structs.RuleRequest) string { 23 | headers := req.Headers 24 | keys := make([]string, len(headers)) 25 | headerStirng := "" 26 | i := 0 27 | for k := range headers { 28 | keys[i] = k 29 | i++ 30 | } 31 | sort.Strings(keys) 32 | for _, k := range keys { 33 | headerStirng += fmt.Sprintf("%s%s", k, headers[k]) 34 | } 35 | 36 | return "rule_" + utils.MD5(fmt.Sprintf("%s%s%s%s%v", req.Method, req.Path, headerStirng, req.Body, req.FollowRedirects)) 37 | } 38 | 39 | func XraySetHttpRequestCache(ruleReq *structs.RuleRequest, request *http.Request, protoRequest *structs.Request, protoResponse *structs.Response) bool { 40 | 41 | ruleHash := getHttpRuleHash(ruleReq) 42 | 43 | if cache, err := GC.Get(ruleHash); err != nil { 44 | if _, ok := cache.(*structs.HttpRequestCache); ok { 45 | return true 46 | } 47 | } 48 | 49 | if err := GC.Set(ruleHash, &structs.HttpRequestCache{ 50 | Request: request, 51 | ProtoRequest: protoRequest, 52 | ProtoResponse: protoResponse, 53 | }); err == nil { 54 | return true 55 | } 56 | 57 | return false 58 | } 59 | 60 | func XrayGetHttpRequestCache(ruleReq *structs.RuleRequest) (*http.Request, *structs.Request, *structs.Response, bool) { 61 | ruleHash := getHttpRuleHash(ruleReq) 62 | 63 | if cache, err := GC.Get(ruleHash); err == nil { 64 | if requestCache, ok := cache.(*structs.HttpRequestCache); ok { 65 | return requestCache.Request, requestCache.ProtoRequest, requestCache.ProtoResponse, true 66 | } else { 67 | } 68 | } 69 | 70 | return nil, nil, nil, false 71 | } 72 | 73 | func getConnectionIdHash(connectionId string) string { 74 | return "connetionID_" + connectionId 75 | } 76 | 77 | func XraySetTcpUdpConnectionCache(connectionId string, conn *net.Conn) bool { 78 | connectionIdHash := getConnectionIdHash(connectionId) 79 | if err := GC.Set(connectionIdHash, conn); err == nil { 80 | return true 81 | } 82 | 83 | return false 84 | } 85 | 86 | func XrayGetTcpUdpConnectionCache(connectionId string) (*net.Conn, bool) { 87 | connectionIdHash := getConnectionIdHash(connectionId) 88 | 89 | if cache, err := GC.Get(connectionIdHash); err == nil { 90 | if connectionCache, ok := cache.(*net.Conn); ok { 91 | return connectionCache, true 92 | } else { 93 | } 94 | } 95 | 96 | return nil, false 97 | } 98 | 99 | func getTCPUDPResponseHash(content string) string { 100 | return "tcpudpResponse_" + content 101 | } 102 | 103 | func XraySetTcpUdpResponseCache(content string, response []byte, protoResponse *structs.Response) bool { 104 | responseHash := getTCPUDPResponseHash(content) 105 | 106 | if cache, err := GC.Get(responseHash); err != nil { 107 | if _, ok := cache.(*structs.TCPUDPRequestCache); ok { 108 | return true 109 | } 110 | } 111 | 112 | if err := GC.Set(responseHash, &structs.TCPUDPRequestCache{ 113 | Response: response, 114 | ProtoResponse: protoResponse, 115 | }); err == nil { 116 | return true 117 | } 118 | 119 | return false 120 | } 121 | 122 | func XrayGetTcpUdpResponseCache(content string) ([]byte, *structs.Response, bool) { 123 | responseHash := getTCPUDPResponseHash(content) 124 | if cache, err := GC.Get(responseHash); err == nil { 125 | if requestCache, ok := cache.(*structs.TCPUDPRequestCache); ok { 126 | return requestCache.Response, requestCache.ProtoResponse, true 127 | } else { 128 | } 129 | } 130 | 131 | return nil, nil, false 132 | } 133 | -------------------------------------------------------------------------------- /pkg/xray/requests/requests.go: -------------------------------------------------------------------------------- 1 | package requests 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | "crypto/tls" 7 | "io" 8 | "io/ioutil" 9 | "net" 10 | "net/http" 11 | "net/http/cookiejar" 12 | "net/http/httptrace" 13 | "net/http/httputil" 14 | "net/url" 15 | "strconv" 16 | "strings" 17 | "sync" 18 | "time" 19 | 20 | "github.com/WAY29/pocV/internal/common/errors" 21 | "github.com/WAY29/pocV/pkg/xray/structs" 22 | ) 23 | 24 | var ( 25 | Client *http.Client 26 | ClientNoRedirect *http.Client 27 | DialTimout = 5 * time.Second 28 | KeepAlive = 15 * time.Second 29 | 30 | urlTypePool = sync.Pool{ 31 | New: func() interface{} { 32 | return new(structs.UrlType) 33 | }, 34 | } 35 | connectInfoTypePool = sync.Pool{ 36 | New: func() interface{} { 37 | return new(structs.ConnInfoType) 38 | }, 39 | } 40 | addrTypePool = sync.Pool{ 41 | New: func() interface{} { 42 | return new(structs.AddrType) 43 | }, 44 | } 45 | tracePool = sync.Pool{ 46 | New: func() interface{} { 47 | return new(httptrace.ClientTrace) 48 | }, 49 | } 50 | 51 | requestPool = sync.Pool{ 52 | New: func() interface{} { 53 | return new(structs.Request) 54 | }, 55 | } 56 | responsePool = sync.Pool{ 57 | New: func() interface{} { 58 | return new(structs.Response) 59 | }, 60 | } 61 | httpBodyBufPool = sync.Pool{ 62 | New: func() interface{} { 63 | return make([]byte, 1024) 64 | }, 65 | } 66 | httpBodyPool = sync.Pool{ 67 | New: func() interface{} { 68 | return make([]byte, 4096) 69 | }, 70 | } 71 | ) 72 | 73 | func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) error { 74 | dialer := &net.Dialer{ 75 | Timeout: DialTimout, 76 | KeepAlive: KeepAlive, 77 | } 78 | 79 | tr := &http.Transport{ 80 | DialContext: dialer.DialContext, 81 | MaxIdleConns: 1000, 82 | MaxIdleConnsPerHost: ThreadsNum * 2, 83 | IdleConnTimeout: KeepAlive, 84 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 85 | TLSHandshakeTimeout: 5 * time.Second, 86 | } 87 | 88 | if DownProxy != "" { 89 | u, err := url.Parse(DownProxy) 90 | if err != nil { 91 | wrappedErr := errors.Newf(errors.ProxyError, "Parse Proxy error: %v", err) 92 | return wrappedErr 93 | } 94 | tr.Proxy = http.ProxyURL(u) 95 | } 96 | 97 | clientCookieJar, _ := cookiejar.New(nil) 98 | clientNoRedirectCookieJar, _ := cookiejar.New(nil) 99 | 100 | Client = &http.Client{ 101 | Transport: tr, 102 | Timeout: Timeout, 103 | Jar: clientCookieJar, 104 | } 105 | ClientNoRedirect = &http.Client{ 106 | Transport: tr, 107 | Timeout: Timeout, 108 | Jar: clientNoRedirectCookieJar, 109 | } 110 | ClientNoRedirect.CheckRedirect = func(req *http.Request, via []*http.Request) error { 111 | return http.ErrUseLastResponse 112 | } 113 | 114 | return nil 115 | } 116 | 117 | func ParseUrl(u *url.URL) *structs.UrlType { 118 | urlType := urlTypePool.Get().(*structs.UrlType) 119 | 120 | urlType.Scheme = u.Scheme 121 | urlType.Domain = u.Hostname() 122 | urlType.Host = u.Host 123 | urlType.Port = u.Port() 124 | urlType.Path = u.Path 125 | urlType.Query = u.RawQuery 126 | urlType.Fragment = u.Fragment 127 | 128 | return urlType 129 | } 130 | 131 | func DoRequest(req *http.Request, redirect bool) (*http.Response, int64, error) { 132 | var ( 133 | milliseconds int64 134 | oResp *http.Response 135 | err error 136 | ) 137 | if req.Body == nil || req.Body == http.NoBody { 138 | } else { 139 | req.Header.Set("Content-Length", strconv.Itoa(int(req.ContentLength))) 140 | if req.Header.Get("Content-Type") == "" { 141 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 142 | } 143 | } 144 | start := time.Now() 145 | trace := tracePool.Get().(*httptrace.ClientTrace) 146 | trace.GotFirstResponseByte = func() { 147 | milliseconds = time.Since(start).Nanoseconds() / 1e6 148 | } 149 | 150 | req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) 151 | 152 | if redirect { 153 | oResp, err = Client.Do(req) 154 | } else { 155 | oResp, err = ClientNoRedirect.Do(req) 156 | } 157 | 158 | if err != nil { 159 | wrappedErr := errors.Newf(errors.RequestError, "Request error: %v", err) 160 | return nil, 0, wrappedErr 161 | } 162 | 163 | return oResp, milliseconds, nil 164 | } 165 | 166 | func ParseHttpRequest(oReq *http.Request) (*structs.Request, error) { 167 | var ( 168 | req = requestPool.Get().(*structs.Request) 169 | ) 170 | 171 | req.Method = oReq.Method 172 | req.Url = ParseUrl(oReq.URL) 173 | 174 | headers := make(map[string]string) 175 | for k := range oReq.Header { 176 | headers[k] = oReq.Header.Get(k) 177 | } 178 | req.Headers = headers 179 | 180 | req.ContentType = oReq.Header.Get("Content-Type") 181 | if oReq.Body != nil && oReq.Body != http.NoBody { 182 | data, err := ioutil.ReadAll(oReq.Body) 183 | if err != nil { 184 | wrappedErr := errors.Newf(errors.RequestError, "Get request error: %v", err) 185 | return nil, wrappedErr 186 | } 187 | req.Body = data 188 | oReq.Body = ioutil.NopCloser(bytes.NewBuffer(data)) 189 | } 190 | 191 | return req, nil 192 | } 193 | 194 | func ParseHttpResponse(oResp *http.Response, milliseconds int64) (*structs.Response, error) { 195 | var ( 196 | resp *structs.Response = responsePool.Get().(*structs.Response) 197 | err error 198 | header string 199 | rawHeaderBuilder strings.Builder 200 | ) 201 | 202 | headers := make(map[string]string) 203 | resp.Status = int32(oResp.StatusCode) 204 | resp.Url = ParseUrl(oResp.Request.URL) 205 | 206 | for k := range oResp.Header { 207 | header = oResp.Header.Get(k) 208 | headers[k] = header 209 | 210 | rawHeaderBuilder.WriteString(k) 211 | rawHeaderBuilder.WriteString(": ") 212 | rawHeaderBuilder.WriteString(header) 213 | rawHeaderBuilder.WriteString("\n") 214 | } 215 | resp.Headers = headers 216 | resp.ContentType = oResp.Header.Get("Content-Type") 217 | // 原始请求头 218 | resp.RawHeader = []byte(strings.Trim(rawHeaderBuilder.String(), "\n")) 219 | 220 | // 原始http响应 221 | resp.Raw, err = httputil.DumpResponse(oResp, true) 222 | body, err := GetRespBody(oResp) 223 | if err != nil { 224 | return nil, err 225 | } 226 | 227 | if err != nil { 228 | resp.Raw = body 229 | } 230 | // http响应体 231 | resp.Body = body 232 | 233 | // 响应时间 234 | resp.Latency = milliseconds 235 | 236 | return resp, nil 237 | } 238 | 239 | func ParseTCPUDPRequest(content []byte) (*structs.Request, error) { 240 | var ( 241 | req = requestPool.Get().(*structs.Request) 242 | ) 243 | 244 | req.Raw = content 245 | 246 | return req, nil 247 | } 248 | 249 | func ParseTCPUDPResponse(content []byte, socket *net.Conn, transport string) (*structs.Response, error) { 250 | var ( 251 | resp *structs.Response = responsePool.Get().(*structs.Response) 252 | conn *structs.ConnInfoType = connectInfoTypePool.Get().(*structs.ConnInfoType) 253 | connection = *socket 254 | 255 | addr string 256 | addrType *structs.AddrType 257 | addrList []string 258 | port string 259 | ) 260 | 261 | resp.Raw = content 262 | 263 | // source 264 | addr = connection.LocalAddr().String() 265 | addrList = strings.SplitN(addr, ":", 2) 266 | if len(addrList) == 2 { 267 | port = addrList[1] 268 | } else { 269 | port = "" 270 | } 271 | 272 | addrType = addrTypePool.Get().(*structs.AddrType) 273 | addrType.Transport = transport 274 | addrType.Addr = addr 275 | addrType.Port = port 276 | conn.Source = addrType 277 | 278 | // destination 279 | addr = connection.RemoteAddr().String() 280 | addrList = strings.SplitN(addr, ":", 2) 281 | if len(addrList) == 2 { 282 | port = addrList[1] 283 | } else { 284 | port = "" 285 | } 286 | 287 | addrType = addrTypePool.Get().(*structs.AddrType) 288 | addrType.Transport = transport 289 | addrType.Addr = addr 290 | addrType.Port = port 291 | conn.Source = addrType 292 | conn.Destination = addrType 293 | 294 | resp.Conn = conn 295 | 296 | return resp, nil 297 | } 298 | 299 | func GetRespBody(oResp *http.Response) ([]byte, error) { 300 | body := httpBodyPool.Get().([]byte) 301 | defer httpBodyPool.Put(body) 302 | 303 | if oResp.Header.Get("Content-Encoding") == "gzip" { 304 | gr, _ := gzip.NewReader(oResp.Body) 305 | defer gr.Close() 306 | for { 307 | buf := httpBodyBufPool.Get().([]byte) 308 | n, err := gr.Read(buf) 309 | if err != nil && err != io.EOF { 310 | return nil, err 311 | } 312 | if n == 0 { 313 | break 314 | } 315 | body = append(body, buf...) 316 | httpBodyBufPool.Put(buf) 317 | } 318 | } else { 319 | raw, err := ioutil.ReadAll(oResp.Body) 320 | if err != nil { 321 | wrappedErr := errors.Newf(errors.ResponseError, "Get response body error: %v", err) 322 | return nil, wrappedErr 323 | } 324 | body = raw 325 | } 326 | return body, nil 327 | } 328 | 329 | func PutUrlType(urlType *structs.UrlType) { 330 | urlType.Scheme = "" 331 | urlType.Domain = "" 332 | urlType.Host = "" 333 | urlType.Port = "" 334 | urlType.Path = "" 335 | urlType.Query = "" 336 | urlType.Fragment = "" 337 | 338 | urlTypePool.Put(urlType) 339 | } 340 | 341 | func PutConnectInfo(connInfo *structs.ConnInfoType) { 342 | connInfo.Source = nil 343 | connInfo.Destination = nil 344 | 345 | connectInfoTypePool.Put(connInfo) 346 | } 347 | 348 | func PutAddrType(addrType *structs.AddrType) { 349 | addrType.Transport = "" 350 | addrType.Addr = "" 351 | 352 | addrTypePool.Put(addrType) 353 | } 354 | 355 | func PutRequest(request *structs.Request) { 356 | request.Url = nil 357 | request.Method = "" 358 | request.Headers = nil 359 | request.ContentType = "" 360 | request.Body = nil 361 | request.Raw = nil 362 | request.RawHeader = nil 363 | request.Content = "" 364 | request.ReadTimeout = "" 365 | request.ConnectionId = "" 366 | 367 | requestPool.Put(request) 368 | } 369 | func PutResponse(response *structs.Response) { 370 | response.Url = nil 371 | response.Status = 0 372 | response.Headers = nil 373 | response.ContentType = "" 374 | response.Body = nil 375 | response.Raw = nil 376 | response.RawHeader = nil 377 | response.Latency = 0 378 | response.Conn = nil 379 | 380 | responsePool.Put(response) 381 | } 382 | -------------------------------------------------------------------------------- /pkg/xray/structs/cache.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import "net/http" 4 | 5 | type HttpRequestCache struct { 6 | Request *http.Request 7 | ProtoRequest *Request 8 | ProtoResponse *Response 9 | } 10 | 11 | type TCPUDPRequestCache struct { 12 | Response []byte 13 | ProtoResponse *Response 14 | } 15 | -------------------------------------------------------------------------------- /pkg/xray/structs/poc.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import "gopkg.in/yaml.v2" 4 | 5 | var ORDER = 0 6 | 7 | // 参考 pocassist/blob/master/poc/rule/rule.go 8 | // 单个规则 9 | type Rule struct { 10 | Request RuleRequest `yaml:"request"` 11 | Expression string `yaml:"expression"` 12 | Output yaml.MapSlice `yaml:"output"` 13 | order int 14 | } 15 | 16 | type ruleAlias struct { 17 | Request RuleRequest `yaml:"request"` 18 | Expression string `yaml:"expression"` 19 | Output yaml.MapSlice `yaml:"output"` 20 | } 21 | 22 | // 用于帮助yaml解析,保证Rule有序 23 | type RuleMapItem struct { 24 | Key string 25 | Value Rule 26 | } 27 | 28 | // 用于帮助yaml解析,保证Rule有序 29 | type RuleMapSlice []RuleMapItem 30 | 31 | type RuleRequest struct { 32 | Cache bool `yaml:"cache"` 33 | Method string `yaml:"method"` 34 | Path string `yaml:"path"` 35 | Headers map[string]string `yaml:"headers"` 36 | Body string `yaml:"body"` 37 | FollowRedirects bool `yaml:"follow_redirects"` 38 | Content string `yaml:"content"` 39 | ReadTimeout string `yaml:"read_timeout"` 40 | ConnectionID string `yaml:"connection_id"` 41 | } 42 | 43 | type Infos struct { 44 | ID string `yaml:"id"` 45 | Name string `yaml:"name"` 46 | Version string `yaml:"version"` 47 | Type string `yaml:"type"` 48 | Confidence int `yaml:"confidence"` 49 | } 50 | 51 | type HostInfo struct { 52 | Hostname string `yaml:"hostname"` 53 | } 54 | 55 | type Vulnerability struct { 56 | ID string `yaml:"id"` 57 | Match string `yaml:"match"` 58 | } 59 | 60 | type FingerPrint struct { 61 | Infos []Infos `yaml:"infos"` 62 | HostInfo HostInfo `yaml:"host_info"` 63 | } 64 | type Detail struct { 65 | Author string `yaml:"author"` 66 | Links []string `yaml:"links"` 67 | FingerPrint FingerPrint `yaml:"fingerprint"` 68 | Vulnerability Vulnerability `yaml:"vulnerability"` 69 | Description string `yaml:"description"` 70 | Version string `yaml:"version"` 71 | Tags string `yaml:"tags"` 72 | } 73 | 74 | type SetMapSlice = yaml.MapSlice 75 | type PayloadsMapSlice = yaml.MapSlice 76 | 77 | type Payloads struct { 78 | Continue bool `yaml:"continue,omitempty"` 79 | Payloads PayloadsMapSlice `yaml:"payloads"` 80 | } 81 | 82 | type Poc struct { 83 | Name string `yaml:"name"` 84 | Transport string `yaml:"transport"` 85 | Set SetMapSlice `yaml:"set"` 86 | Payloads Payloads `yaml:"payloads"` 87 | Rules RuleMapSlice `yaml:"rules"` 88 | Expression string `yaml:"expression"` 89 | Detail Detail `yaml:"detail"` 90 | } 91 | 92 | func (r *Rule) UnmarshalYAML(unmarshal func(interface{}) error) error { 93 | 94 | var tmp ruleAlias 95 | if err := unmarshal(&tmp); err != nil { 96 | return err 97 | } 98 | 99 | r.Request = tmp.Request 100 | r.Expression = tmp.Expression 101 | r.Output = tmp.Output 102 | r.order = ORDER 103 | 104 | ORDER += 1 105 | 106 | return nil 107 | } 108 | 109 | func (m *RuleMapSlice) UnmarshalYAML(unmarshal func(interface{}) error) error { 110 | ORDER = 0 111 | 112 | tempMap := make(map[string]Rule, 1) 113 | err := unmarshal(&tempMap) 114 | if err != nil { 115 | return err 116 | } 117 | 118 | newRuleSlice := make([]RuleMapItem, len(tempMap)) 119 | 120 | for roleName, role := range tempMap { 121 | newRuleSlice[role.order] = RuleMapItem{ 122 | Key: roleName, 123 | Value: role, 124 | } 125 | } 126 | 127 | *m = RuleMapSlice(newRuleSlice) 128 | 129 | return nil 130 | } 131 | -------------------------------------------------------------------------------- /pkg/xray/structs/requests.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.26.0 4 | // protoc v3.18.0 5 | // source: requests.proto 6 | 7 | package structs 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type ReverseType int32 24 | 25 | const ( 26 | ReverseType_Ceye ReverseType = 0 27 | ReverseType_DnslogCN ReverseType = 1 28 | ) 29 | 30 | // Enum value maps for ReverseType. 31 | var ( 32 | ReverseType_name = map[int32]string{ 33 | 0: "Ceye", 34 | 1: "DnslogCN", 35 | } 36 | ReverseType_value = map[string]int32{ 37 | "Ceye": 0, 38 | "DnslogCN": 1, 39 | } 40 | ) 41 | 42 | func (x ReverseType) Enum() *ReverseType { 43 | p := new(ReverseType) 44 | *p = x 45 | return p 46 | } 47 | 48 | func (x ReverseType) String() string { 49 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 50 | } 51 | 52 | func (ReverseType) Descriptor() protoreflect.EnumDescriptor { 53 | return file_requests_proto_enumTypes[0].Descriptor() 54 | } 55 | 56 | func (ReverseType) Type() protoreflect.EnumType { 57 | return &file_requests_proto_enumTypes[0] 58 | } 59 | 60 | func (x ReverseType) Number() protoreflect.EnumNumber { 61 | return protoreflect.EnumNumber(x) 62 | } 63 | 64 | // Deprecated: Use ReverseType.Descriptor instead. 65 | func (ReverseType) EnumDescriptor() ([]byte, []int) { 66 | return file_requests_proto_rawDescGZIP(), []int{0} 67 | } 68 | 69 | type UrlType struct { 70 | state protoimpl.MessageState 71 | sizeCache protoimpl.SizeCache 72 | unknownFields protoimpl.UnknownFields 73 | 74 | Scheme string `protobuf:"bytes,1,opt,name=scheme,proto3" json:"scheme,omitempty"` 75 | Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` 76 | Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` 77 | Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"` 78 | Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` 79 | Query string `protobuf:"bytes,6,opt,name=query,proto3" json:"query,omitempty"` 80 | Fragment string `protobuf:"bytes,7,opt,name=fragment,proto3" json:"fragment,omitempty"` 81 | } 82 | 83 | func (x *UrlType) Reset() { 84 | *x = UrlType{} 85 | if protoimpl.UnsafeEnabled { 86 | mi := &file_requests_proto_msgTypes[0] 87 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 88 | ms.StoreMessageInfo(mi) 89 | } 90 | } 91 | 92 | func (x *UrlType) String() string { 93 | return protoimpl.X.MessageStringOf(x) 94 | } 95 | 96 | func (*UrlType) ProtoMessage() {} 97 | 98 | func (x *UrlType) ProtoReflect() protoreflect.Message { 99 | mi := &file_requests_proto_msgTypes[0] 100 | if protoimpl.UnsafeEnabled && x != nil { 101 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 102 | if ms.LoadMessageInfo() == nil { 103 | ms.StoreMessageInfo(mi) 104 | } 105 | return ms 106 | } 107 | return mi.MessageOf(x) 108 | } 109 | 110 | // Deprecated: Use UrlType.ProtoReflect.Descriptor instead. 111 | func (*UrlType) Descriptor() ([]byte, []int) { 112 | return file_requests_proto_rawDescGZIP(), []int{0} 113 | } 114 | 115 | func (x *UrlType) GetScheme() string { 116 | if x != nil { 117 | return x.Scheme 118 | } 119 | return "" 120 | } 121 | 122 | func (x *UrlType) GetDomain() string { 123 | if x != nil { 124 | return x.Domain 125 | } 126 | return "" 127 | } 128 | 129 | func (x *UrlType) GetHost() string { 130 | if x != nil { 131 | return x.Host 132 | } 133 | return "" 134 | } 135 | 136 | func (x *UrlType) GetPort() string { 137 | if x != nil { 138 | return x.Port 139 | } 140 | return "" 141 | } 142 | 143 | func (x *UrlType) GetPath() string { 144 | if x != nil { 145 | return x.Path 146 | } 147 | return "" 148 | } 149 | 150 | func (x *UrlType) GetQuery() string { 151 | if x != nil { 152 | return x.Query 153 | } 154 | return "" 155 | } 156 | 157 | func (x *UrlType) GetFragment() string { 158 | if x != nil { 159 | return x.Fragment 160 | } 161 | return "" 162 | } 163 | 164 | type AddrType struct { 165 | state protoimpl.MessageState 166 | sizeCache protoimpl.SizeCache 167 | unknownFields protoimpl.UnknownFields 168 | 169 | Transport string `protobuf:"bytes,1,opt,name=transport,proto3" json:"transport,omitempty"` 170 | Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` 171 | Port string `protobuf:"bytes,3,opt,name=port,proto3" json:"port,omitempty"` 172 | } 173 | 174 | func (x *AddrType) Reset() { 175 | *x = AddrType{} 176 | if protoimpl.UnsafeEnabled { 177 | mi := &file_requests_proto_msgTypes[1] 178 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 179 | ms.StoreMessageInfo(mi) 180 | } 181 | } 182 | 183 | func (x *AddrType) String() string { 184 | return protoimpl.X.MessageStringOf(x) 185 | } 186 | 187 | func (*AddrType) ProtoMessage() {} 188 | 189 | func (x *AddrType) ProtoReflect() protoreflect.Message { 190 | mi := &file_requests_proto_msgTypes[1] 191 | if protoimpl.UnsafeEnabled && x != nil { 192 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 193 | if ms.LoadMessageInfo() == nil { 194 | ms.StoreMessageInfo(mi) 195 | } 196 | return ms 197 | } 198 | return mi.MessageOf(x) 199 | } 200 | 201 | // Deprecated: Use AddrType.ProtoReflect.Descriptor instead. 202 | func (*AddrType) Descriptor() ([]byte, []int) { 203 | return file_requests_proto_rawDescGZIP(), []int{1} 204 | } 205 | 206 | func (x *AddrType) GetTransport() string { 207 | if x != nil { 208 | return x.Transport 209 | } 210 | return "" 211 | } 212 | 213 | func (x *AddrType) GetAddr() string { 214 | if x != nil { 215 | return x.Addr 216 | } 217 | return "" 218 | } 219 | 220 | func (x *AddrType) GetPort() string { 221 | if x != nil { 222 | return x.Port 223 | } 224 | return "" 225 | } 226 | 227 | type ConnInfoType struct { 228 | state protoimpl.MessageState 229 | sizeCache protoimpl.SizeCache 230 | unknownFields protoimpl.UnknownFields 231 | 232 | Source *AddrType `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` 233 | Destination *AddrType `protobuf:"bytes,2,opt,name=destination,proto3" json:"destination,omitempty"` 234 | } 235 | 236 | func (x *ConnInfoType) Reset() { 237 | *x = ConnInfoType{} 238 | if protoimpl.UnsafeEnabled { 239 | mi := &file_requests_proto_msgTypes[2] 240 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 241 | ms.StoreMessageInfo(mi) 242 | } 243 | } 244 | 245 | func (x *ConnInfoType) String() string { 246 | return protoimpl.X.MessageStringOf(x) 247 | } 248 | 249 | func (*ConnInfoType) ProtoMessage() {} 250 | 251 | func (x *ConnInfoType) ProtoReflect() protoreflect.Message { 252 | mi := &file_requests_proto_msgTypes[2] 253 | if protoimpl.UnsafeEnabled && x != nil { 254 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 255 | if ms.LoadMessageInfo() == nil { 256 | ms.StoreMessageInfo(mi) 257 | } 258 | return ms 259 | } 260 | return mi.MessageOf(x) 261 | } 262 | 263 | // Deprecated: Use ConnInfoType.ProtoReflect.Descriptor instead. 264 | func (*ConnInfoType) Descriptor() ([]byte, []int) { 265 | return file_requests_proto_rawDescGZIP(), []int{2} 266 | } 267 | 268 | func (x *ConnInfoType) GetSource() *AddrType { 269 | if x != nil { 270 | return x.Source 271 | } 272 | return nil 273 | } 274 | 275 | func (x *ConnInfoType) GetDestination() *AddrType { 276 | if x != nil { 277 | return x.Destination 278 | } 279 | return nil 280 | } 281 | 282 | type Request struct { 283 | state protoimpl.MessageState 284 | sizeCache protoimpl.SizeCache 285 | unknownFields protoimpl.UnknownFields 286 | 287 | Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` 288 | Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"` 289 | Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 290 | ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` 291 | Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` 292 | Raw []byte `protobuf:"bytes,6,opt,name=raw,proto3" json:"raw,omitempty"` 293 | RawHeader []byte `protobuf:"bytes,7,opt,name=raw_header,json=rawHeader,proto3" json:"raw_header,omitempty"` 294 | Content string `protobuf:"bytes,8,opt,name=content,proto3" json:"content,omitempty"` 295 | ReadTimeout string `protobuf:"bytes,9,opt,name=read_timeout,json=readTimeout,proto3" json:"read_timeout,omitempty"` 296 | ConnectionId string `protobuf:"bytes,10,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` 297 | } 298 | 299 | func (x *Request) Reset() { 300 | *x = Request{} 301 | if protoimpl.UnsafeEnabled { 302 | mi := &file_requests_proto_msgTypes[3] 303 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 304 | ms.StoreMessageInfo(mi) 305 | } 306 | } 307 | 308 | func (x *Request) String() string { 309 | return protoimpl.X.MessageStringOf(x) 310 | } 311 | 312 | func (*Request) ProtoMessage() {} 313 | 314 | func (x *Request) ProtoReflect() protoreflect.Message { 315 | mi := &file_requests_proto_msgTypes[3] 316 | if protoimpl.UnsafeEnabled && x != nil { 317 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 318 | if ms.LoadMessageInfo() == nil { 319 | ms.StoreMessageInfo(mi) 320 | } 321 | return ms 322 | } 323 | return mi.MessageOf(x) 324 | } 325 | 326 | // Deprecated: Use Request.ProtoReflect.Descriptor instead. 327 | func (*Request) Descriptor() ([]byte, []int) { 328 | return file_requests_proto_rawDescGZIP(), []int{3} 329 | } 330 | 331 | func (x *Request) GetUrl() *UrlType { 332 | if x != nil { 333 | return x.Url 334 | } 335 | return nil 336 | } 337 | 338 | func (x *Request) GetMethod() string { 339 | if x != nil { 340 | return x.Method 341 | } 342 | return "" 343 | } 344 | 345 | func (x *Request) GetHeaders() map[string]string { 346 | if x != nil { 347 | return x.Headers 348 | } 349 | return nil 350 | } 351 | 352 | func (x *Request) GetContentType() string { 353 | if x != nil { 354 | return x.ContentType 355 | } 356 | return "" 357 | } 358 | 359 | func (x *Request) GetBody() []byte { 360 | if x != nil { 361 | return x.Body 362 | } 363 | return nil 364 | } 365 | 366 | func (x *Request) GetRaw() []byte { 367 | if x != nil { 368 | return x.Raw 369 | } 370 | return nil 371 | } 372 | 373 | func (x *Request) GetRawHeader() []byte { 374 | if x != nil { 375 | return x.RawHeader 376 | } 377 | return nil 378 | } 379 | 380 | func (x *Request) GetContent() string { 381 | if x != nil { 382 | return x.Content 383 | } 384 | return "" 385 | } 386 | 387 | func (x *Request) GetReadTimeout() string { 388 | if x != nil { 389 | return x.ReadTimeout 390 | } 391 | return "" 392 | } 393 | 394 | func (x *Request) GetConnectionId() string { 395 | if x != nil { 396 | return x.ConnectionId 397 | } 398 | return "" 399 | } 400 | 401 | type Response struct { 402 | state protoimpl.MessageState 403 | sizeCache protoimpl.SizeCache 404 | unknownFields protoimpl.UnknownFields 405 | 406 | Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` 407 | Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` 408 | Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 409 | ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` 410 | Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` 411 | Raw []byte `protobuf:"bytes,6,opt,name=raw,proto3" json:"raw,omitempty"` 412 | RawHeader []byte `protobuf:"bytes,7,opt,name=raw_header,json=rawHeader,proto3" json:"raw_header,omitempty"` 413 | Latency int64 `protobuf:"varint,8,opt,name=latency,proto3" json:"latency,omitempty"` 414 | Conn *ConnInfoType `protobuf:"bytes,9,opt,name=conn,proto3" json:"conn,omitempty"` 415 | } 416 | 417 | func (x *Response) Reset() { 418 | *x = Response{} 419 | if protoimpl.UnsafeEnabled { 420 | mi := &file_requests_proto_msgTypes[4] 421 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 422 | ms.StoreMessageInfo(mi) 423 | } 424 | } 425 | 426 | func (x *Response) String() string { 427 | return protoimpl.X.MessageStringOf(x) 428 | } 429 | 430 | func (*Response) ProtoMessage() {} 431 | 432 | func (x *Response) ProtoReflect() protoreflect.Message { 433 | mi := &file_requests_proto_msgTypes[4] 434 | if protoimpl.UnsafeEnabled && x != nil { 435 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 436 | if ms.LoadMessageInfo() == nil { 437 | ms.StoreMessageInfo(mi) 438 | } 439 | return ms 440 | } 441 | return mi.MessageOf(x) 442 | } 443 | 444 | // Deprecated: Use Response.ProtoReflect.Descriptor instead. 445 | func (*Response) Descriptor() ([]byte, []int) { 446 | return file_requests_proto_rawDescGZIP(), []int{4} 447 | } 448 | 449 | func (x *Response) GetUrl() *UrlType { 450 | if x != nil { 451 | return x.Url 452 | } 453 | return nil 454 | } 455 | 456 | func (x *Response) GetStatus() int32 { 457 | if x != nil { 458 | return x.Status 459 | } 460 | return 0 461 | } 462 | 463 | func (x *Response) GetHeaders() map[string]string { 464 | if x != nil { 465 | return x.Headers 466 | } 467 | return nil 468 | } 469 | 470 | func (x *Response) GetContentType() string { 471 | if x != nil { 472 | return x.ContentType 473 | } 474 | return "" 475 | } 476 | 477 | func (x *Response) GetBody() []byte { 478 | if x != nil { 479 | return x.Body 480 | } 481 | return nil 482 | } 483 | 484 | func (x *Response) GetRaw() []byte { 485 | if x != nil { 486 | return x.Raw 487 | } 488 | return nil 489 | } 490 | 491 | func (x *Response) GetRawHeader() []byte { 492 | if x != nil { 493 | return x.RawHeader 494 | } 495 | return nil 496 | } 497 | 498 | func (x *Response) GetLatency() int64 { 499 | if x != nil { 500 | return x.Latency 501 | } 502 | return 0 503 | } 504 | 505 | func (x *Response) GetConn() *ConnInfoType { 506 | if x != nil { 507 | return x.Conn 508 | } 509 | return nil 510 | } 511 | 512 | type Reverse struct { 513 | state protoimpl.MessageState 514 | sizeCache protoimpl.SizeCache 515 | unknownFields protoimpl.UnknownFields 516 | 517 | Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` 518 | Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` 519 | Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip,omitempty"` 520 | IsDomainNameServer bool `protobuf:"varint,4,opt,name=is_domain_name_server,json=isDomainNameServer,proto3" json:"is_domain_name_server,omitempty"` 521 | ReverseType ReverseType `protobuf:"varint,5,opt,name=reverse_type,json=reverseType,proto3,enum=structs.ReverseType" json:"reverse_type,omitempty"` 522 | } 523 | 524 | func (x *Reverse) Reset() { 525 | *x = Reverse{} 526 | if protoimpl.UnsafeEnabled { 527 | mi := &file_requests_proto_msgTypes[5] 528 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 529 | ms.StoreMessageInfo(mi) 530 | } 531 | } 532 | 533 | func (x *Reverse) String() string { 534 | return protoimpl.X.MessageStringOf(x) 535 | } 536 | 537 | func (*Reverse) ProtoMessage() {} 538 | 539 | func (x *Reverse) ProtoReflect() protoreflect.Message { 540 | mi := &file_requests_proto_msgTypes[5] 541 | if protoimpl.UnsafeEnabled && x != nil { 542 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 543 | if ms.LoadMessageInfo() == nil { 544 | ms.StoreMessageInfo(mi) 545 | } 546 | return ms 547 | } 548 | return mi.MessageOf(x) 549 | } 550 | 551 | // Deprecated: Use Reverse.ProtoReflect.Descriptor instead. 552 | func (*Reverse) Descriptor() ([]byte, []int) { 553 | return file_requests_proto_rawDescGZIP(), []int{5} 554 | } 555 | 556 | func (x *Reverse) GetUrl() *UrlType { 557 | if x != nil { 558 | return x.Url 559 | } 560 | return nil 561 | } 562 | 563 | func (x *Reverse) GetDomain() string { 564 | if x != nil { 565 | return x.Domain 566 | } 567 | return "" 568 | } 569 | 570 | func (x *Reverse) GetIp() string { 571 | if x != nil { 572 | return x.Ip 573 | } 574 | return "" 575 | } 576 | 577 | func (x *Reverse) GetIsDomainNameServer() bool { 578 | if x != nil { 579 | return x.IsDomainNameServer 580 | } 581 | return false 582 | } 583 | 584 | func (x *Reverse) GetReverseType() ReverseType { 585 | if x != nil { 586 | return x.ReverseType 587 | } 588 | return ReverseType_Ceye 589 | } 590 | 591 | var File_requests_proto protoreflect.FileDescriptor 592 | 593 | var file_requests_proto_rawDesc = []byte{ 594 | 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 595 | 0x12, 0x07, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x07, 0x55, 0x72, 596 | 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 597 | 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x16, 0x0a, 598 | 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 599 | 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 600 | 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 601 | 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 602 | 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 603 | 0x68, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 604 | 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 605 | 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 606 | 0x65, 0x6e, 0x74, 0x22, 0x50, 0x0a, 0x08, 0x61, 0x64, 0x64, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 607 | 0x1c, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 608 | 0x28, 0x09, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 609 | 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 610 | 0x72, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 611 | 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x6e, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x49, 0x6e, 0x66, 612 | 0x6f, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 613 | 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x2e, 614 | 0x61, 0x64, 0x64, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 615 | 0x12, 0x33, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 616 | 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x2e, 617 | 0x61, 0x64, 0x64, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 618 | 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x84, 0x03, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 619 | 0x74, 0x12, 0x22, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 620 | 0x2e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x2e, 0x55, 0x72, 0x6c, 0x54, 0x79, 0x70, 0x65, 621 | 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 622 | 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x37, 0x0a, 623 | 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 624 | 0x2e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 625 | 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 626 | 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 627 | 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 628 | 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 629 | 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x10, 0x0a, 630 | 0x03, 0x72, 0x61, 0x77, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x61, 0x77, 0x12, 631 | 0x1d, 0x0a, 0x0a, 0x72, 0x61, 0x77, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 632 | 0x01, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x61, 0x77, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x18, 633 | 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 634 | 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 635 | 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 636 | 0x72, 0x65, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x63, 637 | 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 638 | 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 639 | 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 640 | 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 641 | 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 642 | 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe9, 0x02, 0x0a, 643 | 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x03, 0x75, 0x72, 0x6c, 644 | 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 645 | 0x2e, 0x55, 0x72, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 646 | 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 647 | 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x38, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 648 | 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 649 | 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 650 | 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 651 | 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 652 | 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 653 | 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 654 | 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x61, 0x77, 0x18, 0x06, 0x20, 655 | 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x61, 0x77, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x61, 0x77, 0x5f, 656 | 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x61, 657 | 0x77, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 658 | 0x63, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 659 | 0x79, 0x12, 0x29, 0x0a, 0x04, 0x63, 0x6f, 0x6e, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 660 | 0x15, 0x2e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x49, 0x6e, 661 | 0x66, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x6e, 0x6e, 0x1a, 0x3a, 0x0a, 0x0c, 662 | 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 663 | 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 664 | 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 665 | 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc1, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x76, 666 | 0x65, 0x72, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 667 | 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x2e, 0x55, 0x72, 0x6c, 0x54, 668 | 0x79, 0x70, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 669 | 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 670 | 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 671 | 0x12, 0x31, 0x0a, 0x15, 0x69, 0x73, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 672 | 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 673 | 0x12, 0x69, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 674 | 0x76, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x74, 675 | 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x73, 0x74, 0x72, 0x75, 676 | 0x63, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 677 | 0x0b, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2a, 0x25, 0x0a, 0x0b, 678 | 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x43, 679 | 0x65, 0x79, 0x65, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x6e, 0x73, 0x6c, 0x6f, 0x67, 0x43, 680 | 0x4e, 0x10, 0x01, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x3b, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 681 | 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 682 | } 683 | 684 | var ( 685 | file_requests_proto_rawDescOnce sync.Once 686 | file_requests_proto_rawDescData = file_requests_proto_rawDesc 687 | ) 688 | 689 | func file_requests_proto_rawDescGZIP() []byte { 690 | file_requests_proto_rawDescOnce.Do(func() { 691 | file_requests_proto_rawDescData = protoimpl.X.CompressGZIP(file_requests_proto_rawDescData) 692 | }) 693 | return file_requests_proto_rawDescData 694 | } 695 | 696 | var file_requests_proto_enumTypes = make([]protoimpl.EnumInfo, 1) 697 | var file_requests_proto_msgTypes = make([]protoimpl.MessageInfo, 8) 698 | var file_requests_proto_goTypes = []interface{}{ 699 | (ReverseType)(0), // 0: structs.ReverseType 700 | (*UrlType)(nil), // 1: structs.UrlType 701 | (*AddrType)(nil), // 2: structs.addrType 702 | (*ConnInfoType)(nil), // 3: structs.connInfoType 703 | (*Request)(nil), // 4: structs.Request 704 | (*Response)(nil), // 5: structs.Response 705 | (*Reverse)(nil), // 6: structs.Reverse 706 | nil, // 7: structs.Request.HeadersEntry 707 | nil, // 8: structs.Response.HeadersEntry 708 | } 709 | var file_requests_proto_depIdxs = []int32{ 710 | 2, // 0: structs.connInfoType.source:type_name -> structs.addrType 711 | 2, // 1: structs.connInfoType.destination:type_name -> structs.addrType 712 | 1, // 2: structs.Request.url:type_name -> structs.UrlType 713 | 7, // 3: structs.Request.headers:type_name -> structs.Request.HeadersEntry 714 | 1, // 4: structs.Response.url:type_name -> structs.UrlType 715 | 8, // 5: structs.Response.headers:type_name -> structs.Response.HeadersEntry 716 | 3, // 6: structs.Response.conn:type_name -> structs.connInfoType 717 | 1, // 7: structs.Reverse.url:type_name -> structs.UrlType 718 | 0, // 8: structs.Reverse.reverse_type:type_name -> structs.ReverseType 719 | 9, // [9:9] is the sub-list for method output_type 720 | 9, // [9:9] is the sub-list for method input_type 721 | 9, // [9:9] is the sub-list for extension type_name 722 | 9, // [9:9] is the sub-list for extension extendee 723 | 0, // [0:9] is the sub-list for field type_name 724 | } 725 | 726 | func init() { file_requests_proto_init() } 727 | func file_requests_proto_init() { 728 | if File_requests_proto != nil { 729 | return 730 | } 731 | if !protoimpl.UnsafeEnabled { 732 | file_requests_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 733 | switch v := v.(*UrlType); i { 734 | case 0: 735 | return &v.state 736 | case 1: 737 | return &v.sizeCache 738 | case 2: 739 | return &v.unknownFields 740 | default: 741 | return nil 742 | } 743 | } 744 | file_requests_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 745 | switch v := v.(*AddrType); i { 746 | case 0: 747 | return &v.state 748 | case 1: 749 | return &v.sizeCache 750 | case 2: 751 | return &v.unknownFields 752 | default: 753 | return nil 754 | } 755 | } 756 | file_requests_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 757 | switch v := v.(*ConnInfoType); i { 758 | case 0: 759 | return &v.state 760 | case 1: 761 | return &v.sizeCache 762 | case 2: 763 | return &v.unknownFields 764 | default: 765 | return nil 766 | } 767 | } 768 | file_requests_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 769 | switch v := v.(*Request); i { 770 | case 0: 771 | return &v.state 772 | case 1: 773 | return &v.sizeCache 774 | case 2: 775 | return &v.unknownFields 776 | default: 777 | return nil 778 | } 779 | } 780 | file_requests_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 781 | switch v := v.(*Response); i { 782 | case 0: 783 | return &v.state 784 | case 1: 785 | return &v.sizeCache 786 | case 2: 787 | return &v.unknownFields 788 | default: 789 | return nil 790 | } 791 | } 792 | file_requests_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { 793 | switch v := v.(*Reverse); i { 794 | case 0: 795 | return &v.state 796 | case 1: 797 | return &v.sizeCache 798 | case 2: 799 | return &v.unknownFields 800 | default: 801 | return nil 802 | } 803 | } 804 | } 805 | type x struct{} 806 | out := protoimpl.TypeBuilder{ 807 | File: protoimpl.DescBuilder{ 808 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 809 | RawDescriptor: file_requests_proto_rawDesc, 810 | NumEnums: 1, 811 | NumMessages: 8, 812 | NumExtensions: 0, 813 | NumServices: 0, 814 | }, 815 | GoTypes: file_requests_proto_goTypes, 816 | DependencyIndexes: file_requests_proto_depIdxs, 817 | EnumInfos: file_requests_proto_enumTypes, 818 | MessageInfos: file_requests_proto_msgTypes, 819 | }.Build() 820 | File_requests_proto = out.File 821 | file_requests_proto_rawDesc = nil 822 | file_requests_proto_goTypes = nil 823 | file_requests_proto_depIdxs = nil 824 | } 825 | -------------------------------------------------------------------------------- /pkg/xray/structs/requests.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "./;structs"; 4 | package structs; 5 | 6 | message UrlType { 7 | string scheme = 1; 8 | string domain = 2; 9 | string host = 3; 10 | string port = 4; 11 | string path = 5; 12 | string query = 6; 13 | string fragment = 7; 14 | } 15 | 16 | message addrType { 17 | string transport = 1; 18 | string addr = 2; 19 | string port = 3; 20 | } 21 | 22 | message connInfoType { 23 | addrType source = 1; 24 | addrType destination = 2; 25 | } 26 | 27 | message Request { 28 | UrlType url = 1; 29 | string method = 2; 30 | map headers = 3; 31 | string content_type = 4; 32 | bytes body = 5; 33 | bytes raw = 6; 34 | bytes raw_header = 7; 35 | string content = 8; 36 | string read_timeout = 9; 37 | string connection_id = 10; 38 | } 39 | 40 | message Response { 41 | UrlType url = 1; 42 | int32 status = 2 ; 43 | map headers = 3; 44 | string content_type = 4; 45 | bytes body = 5; 46 | bytes raw = 6; 47 | bytes raw_header = 7; 48 | int64 latency = 8; 49 | connInfoType conn = 9; 50 | } 51 | 52 | enum ReverseType { 53 | Ceye = 0; 54 | DnslogCN = 1; 55 | } 56 | 57 | message Reverse { 58 | UrlType url = 1; 59 | string domain = 2; 60 | string ip = 3; 61 | bool is_domain_name_server = 4; 62 | ReverseType reverse_type = 5; 63 | } -------------------------------------------------------------------------------- /pkg/xray/structs/tasks.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | type Task struct { 4 | Poc Poc 5 | Target string 6 | } 7 | -------------------------------------------------------------------------------- /pocs/test/nuclei/tag_test.yml: -------------------------------------------------------------------------------- 1 | id: poc-yaml-nuclei-test-example-com 2 | info: 3 | name: poc-yaml-nuclei-test-example-com 4 | author: 5 | - longlone 6 | tags: test 7 | description: None 8 | severity: info 9 | requests: 10 | - matchers: 11 | - type: status 12 | part: body 13 | status: 14 | - 200 15 | - type: word 16 | part: body 17 | words: 18 | - Example Domain 19 | matchers-condition: and 20 | path: 21 | - '{{BaseURL}}/index.html' 22 | method: GET 23 | -------------------------------------------------------------------------------- /pocs/test/nuclei/test.yml: -------------------------------------------------------------------------------- 1 | id: poc-yaml-nuclei-test-example-com 2 | 3 | info: 4 | name: poc-yaml-nuclei-test-example-com 5 | description: None 6 | author: Longlone 7 | severity: info 8 | tags: test 9 | 10 | requests: 11 | - method: GET 12 | path: 13 | - "{{BaseURL}}/index.html" 14 | 15 | matchers-condition: and 16 | matchers: 17 | - type: status 18 | status: 19 | - 200 20 | - type: word 21 | part: body 22 | words: 23 | - "Example Domain" -------------------------------------------------------------------------------- /pocs/test/xray/v2_cache_test.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-example-com 2 | transport: http 3 | rules: 4 | r1: 5 | request: 6 | cache: true 7 | method: GET 8 | path: /index.html 9 | headers: {} 10 | body: "" 11 | follow_redirects: false 12 | expression: | 13 | response.status==200 && response.body.bcontains(b'Example Domain') 14 | r2: 15 | request: 16 | cache: true 17 | method: GET 18 | path: /index.html 19 | headers: {} 20 | body: "" 21 | follow_redirects: false 22 | expression: | 23 | response.status==200 && response.body.bcontains(b'Example Domain') 24 | expression: r1() && r2() 25 | detail: 26 | author: name(link) 27 | links: 28 | - http://example.com 29 | fingerprint: 30 | infos: [] 31 | host_info: 32 | hostname: "" 33 | vulnerability: 34 | id: "" 35 | match: "" 36 | description: "" 37 | version: "" 38 | tags: test, test2 39 | -------------------------------------------------------------------------------- /pocs/test/xray/v2_payload_test.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-example-com 2 | transport: http 3 | set: 4 | PATH: r"index" 5 | payloads: 6 | continue: true 7 | payloads: 8 | s1: 9 | PATH2: PATH + r".html" 10 | s2: 11 | PATH2: r"" 12 | rules: 13 | r1: 14 | request: 15 | cache: false 16 | method: GET 17 | path: /{{PATH2}} 18 | headers: {} 19 | body: "" 20 | follow_redirects: false 21 | expression: | 22 | response.status==200 && response.body.bcontains(b'Example Domain') 23 | output: 24 | raw: request.raw 25 | expression: r1() 26 | detail: 27 | author: name(link) 28 | links: 29 | - http://example.com 30 | fingerprint: 31 | infos: [] 32 | host_info: 33 | hostname: "" 34 | vulnerability: 35 | id: "" 36 | match: "" 37 | description: "" 38 | version: "" 39 | tags: test, test2 40 | -------------------------------------------------------------------------------- /pocs/test/xray/v2_reverse_test.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-xray-revese-test 2 | transport: http 3 | set: 4 | reverse: newReverse() 5 | reverseURL: reverse.url 6 | rules: 7 | r1: 8 | request: 9 | method: GET 10 | path: "/ssrf.php?url={{reverseURL}}" 11 | expression: | 12 | response.status == 200 && reverse.wait(5) 13 | expression: 14 | r1() 15 | # 信息部分 16 | detail: 17 | author: name(link) 18 | links: 19 | - http://example.com 20 | tags: test 21 | -------------------------------------------------------------------------------- /pocs/test/xray/v2_tcp_cache_test.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tcp-example 2 | transport: tcp 3 | rules: 4 | r1: 5 | request: 6 | cache: true 7 | content: "hello world" 8 | read_timeout: "10" 9 | connection_id: c1 10 | expression: | 11 | response.raw.bcontains(b'hello world') 12 | r2: 13 | request: 14 | cache: true 15 | content: "hello world" 16 | read_timeout: "10" 17 | connection_id: c1 18 | expression: | 19 | response.raw.bcontains(b'hello world') 20 | 21 | expression: r1() && r2() 22 | detail: 23 | author: name(link) 24 | links: 25 | - http://example.com 26 | fingerprint: 27 | infos: [] 28 | host_info: 29 | hostname: "" 30 | vulnerability: 31 | id: "" 32 | match: "" 33 | description: "" 34 | version: "" 35 | tags: test 36 | -------------------------------------------------------------------------------- /pocs/test/xray/v2_tcp_test.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tcp-example 2 | transport: tcp 3 | rules: 4 | r1: 5 | request: 6 | cache: false 7 | content: "hello world" 8 | read_timeout: "10" 9 | connection_id: c1 10 | expression: | 11 | response.raw.bcontains(b'hello world') 12 | 13 | expression: r1() 14 | detail: 15 | author: name(link) 16 | links: 17 | - http://example.com 18 | fingerprint: 19 | infos: [] 20 | host_info: 21 | hostname: "" 22 | vulnerability: 23 | id: "" 24 | match: "" 25 | description: "" 26 | version: "" 27 | tags: test 28 | -------------------------------------------------------------------------------- /pocs/test/xray/v2_test.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-example-com 2 | transport: http 3 | set: 4 | PATH: r"index" 5 | PATH2: r".html" 6 | PATH3: PATH+PATH2 7 | rules: 8 | r1: 9 | request: 10 | cache: false 11 | method: GET 12 | path: /{{PATH3}} 13 | headers: {} 14 | body: "" 15 | follow_redirects: false 16 | expression: | 17 | response.status==200 && response.body.bcontains(b'Example Domain') 18 | output: 19 | raw: request.raw 20 | expression: r1() 21 | detail: 22 | author: name(link) 23 | links: 24 | - http://example.com 25 | fingerprint: 26 | infos: [] 27 | host_info: 28 | hostname: "" 29 | vulnerability: 30 | id: "" 31 | match: "" 32 | description: "" 33 | version: "" 34 | tags: test, test2 35 | -------------------------------------------------------------------------------- /pocs/test/xray/v2_udp_test.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tcp-example 2 | transport: udp 3 | rules: 4 | r1: 5 | request: 6 | cache: false 7 | content: "hello world" 8 | read_timeout: "10" 9 | connection_id: c1 10 | expression: | 11 | response.raw.bcontains(b'hello world') 12 | 13 | expression: r1() 14 | detail: 15 | author: name(link) 16 | links: 17 | - http://example.com 18 | fingerprint: 19 | infos: [] 20 | host_info: 21 | hostname: "" 22 | vulnerability: 23 | id: "" 24 | match: "" 25 | description: "" 26 | version: "" 27 | tags: test 28 | -------------------------------------------------------------------------------- /utils/banner.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func Banner() { 4 | println(` 5 | _ __ 6 | ____ ____ ____| | / / 7 | / __ \/ __ \/ ___/ | / / 8 | / /_/ / /_/ / /__ | |/ / 9 | / .___/\____/\___/ |___/ 10 | /_/ 11 | 12 | `) 13 | } 14 | -------------------------------------------------------------------------------- /utils/colorprint.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | 6 | . "github.com/logrusorgru/aurora" 7 | ) 8 | 9 | func Success(message string) { 10 | fmt.Println(Cyan("[+]"), message) 11 | } 12 | func SuccessF(message string, args ...interface{}) { 13 | fmt.Println(Cyan("[+]"), fmt.Sprintf(message, args...)) 14 | } 15 | 16 | func Message(message string) { 17 | fmt.Println(Gray(8, "[#]"), message) 18 | } 19 | func MessageF(message string, args ...interface{}) { 20 | fmt.Println(Gray(8, "[#]"), fmt.Sprintf(message, args...)) 21 | } 22 | 23 | func Question(message string) { 24 | fmt.Print(Yellow("[?]"), message) 25 | } 26 | func QuestionF(message string, args ...interface{}) { 27 | fmt.Print(Yellow("[?]"), fmt.Sprintf(message, args...)) 28 | } 29 | 30 | func Failure(message string) { 31 | fmt.Println(Red("[-]"), message) 32 | } 33 | func FailureF(message string, args ...interface{}) { 34 | fmt.Println(Red("[-]"), fmt.Sprintf(message, args...)) 35 | } 36 | 37 | func Exit(message string) { 38 | fmt.Println(Red("[-]"), message) 39 | } 40 | func ExitF(message string, args ...interface{}) { 41 | fmt.Println(Red("[-]"), fmt.Sprintf(message, args...)) 42 | } 43 | -------------------------------------------------------------------------------- /utils/exit.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | cli "github.com/jawher/mow.cli" 5 | ) 6 | 7 | // 输出错误并退出 8 | func CliError(message string, exitCode int) { 9 | Exit(message) 10 | cli.Exit(exitCode) 11 | } 12 | -------------------------------------------------------------------------------- /utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "io/ioutil" 7 | "os" 8 | "strings" 9 | 10 | "github.com/WAY29/pocV/internal/common/errors" 11 | ) 12 | 13 | // 判断所给路径文件/文件夹是否存在 14 | func Exists(path string) bool { 15 | _, err := os.Stat(path) //os.Stat获取文件信息 16 | if err != nil { 17 | if os.IsExist(err) { 18 | return true 19 | } 20 | return false 21 | } 22 | return true 23 | } 24 | 25 | // 判断所给路径是否为文件夹 26 | func IsDir(path string) bool { 27 | s, err := os.Stat(path) 28 | if err != nil { 29 | return false 30 | } 31 | return s.IsDir() 32 | } 33 | 34 | // 判断所给路径是否为文件 35 | func IsFile(path string) bool { 36 | return !IsDir(path) 37 | } 38 | 39 | // 读取文件并返回一个字符串切片 40 | func ReadFileAsLine(path string) ([]string, error) { 41 | lineSlice := make([]string, 0) 42 | 43 | if !IsFile(path) { 44 | return nil, os.ErrNotExist 45 | } 46 | file, err := os.OpenFile(path, os.O_RDWR, 0666) 47 | if err != nil { 48 | wrappedErr := errors.Newf(errors.FileError, "Open file %s error", path) 49 | return nil, wrappedErr 50 | } 51 | 52 | buf := bufio.NewReader(file) 53 | for { 54 | line, err := buf.ReadString('\n') 55 | line = strings.TrimSpace(line) 56 | lineSlice = append(lineSlice, line) 57 | if err != nil { 58 | if err == io.EOF { 59 | break 60 | } else { 61 | wrappedErr := errors.Newf(errors.FileError, "Read file %s error", path) 62 | return nil, wrappedErr 63 | } 64 | } 65 | } 66 | 67 | return lineSlice, nil 68 | } 69 | 70 | // 读取文件的前n个字节 71 | func ReadFileN(path string, n int) ([]byte, error) { 72 | data := make([]byte, n) 73 | 74 | if !IsFile(path) { 75 | wrappedErr := errors.Newf(errors.FileNotFoundError, "File %s not found", path) 76 | return nil, wrappedErr 77 | } 78 | file, err := os.OpenFile(path, os.O_RDWR, 0666) 79 | if err != nil { 80 | wrappedErr := errors.Newf(errors.FileError, "Open file %s error", path) 81 | return nil, wrappedErr 82 | } 83 | 84 | file.Read(data) 85 | 86 | return data, nil 87 | } 88 | 89 | func WriteFile(path string, data []byte) error { 90 | return ioutil.WriteFile(path, data, 0) 91 | } 92 | -------------------------------------------------------------------------------- /utils/iconhash.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "hash" 7 | 8 | "github.com/spaolacci/murmur3" 9 | ) 10 | 11 | // Reference: https://github.com/Becivells/iconhash 12 | 13 | // Mmh3Hash32 计算 mmh3 hash 14 | func Mmh3Hash32(raw []byte) int32 { 15 | var h32 hash.Hash32 = murmur3.New32() 16 | h32.Write(raw) 17 | return int32(h32.Sum32()) 18 | } 19 | 20 | // base64 encode 21 | func Base64Encode(braw []byte) []byte { 22 | bckd := base64.StdEncoding.EncodeToString(braw) 23 | var buffer bytes.Buffer 24 | for i := 0; i < len(bckd); i++ { 25 | ch := bckd[i] 26 | buffer.WriteByte(ch) 27 | if (i+1)%76 == 0 { 28 | buffer.WriteByte('\n') 29 | } 30 | } 31 | buffer.WriteByte('\n') 32 | return buffer.Bytes() 33 | } 34 | -------------------------------------------------------------------------------- /utils/log.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/WAY29/errors" 8 | myerrors "github.com/WAY29/pocV/internal/common/errors" 9 | "github.com/sirupsen/logrus" 10 | prefixed "github.com/x-cray/logrus-prefixed-formatter" 11 | ) 12 | 13 | var ( 14 | logger *logrus.Logger 15 | DebugFlag, VerboseFlag bool 16 | ) 17 | 18 | func InitLog(debug, verbose bool) { 19 | logger = &logrus.Logger{ 20 | Out: os.Stdout, 21 | Level: logrus.ErrorLevel, 22 | Formatter: &prefixed.TextFormatter{ 23 | ForceColors: true, 24 | ForceFormatting: true, 25 | FullTimestamp: true, 26 | TimestampFormat: "15:04", 27 | }, 28 | } 29 | if debug == true { 30 | logger.SetLevel(logrus.DebugLevel) 31 | } else if verbose == true { 32 | logger.SetOutput(os.Stdout) 33 | logger.SetLevel(logrus.InfoLevel) 34 | } 35 | DebugFlag = debug 36 | VerboseFlag = verbose 37 | } 38 | 39 | // Info 40 | func InfoF(format string, args ...interface{}) { 41 | logger.Info(fmt.Sprintf(format, args...)) 42 | } 43 | 44 | func Info(args ...interface{}) { 45 | logger.Infoln(args) 46 | } 47 | 48 | // Error 49 | func ErrorF(format string, args ...interface{}) { 50 | logger.Error(fmt.Sprintf(format, args...)) 51 | } 52 | 53 | func Error(args ...interface{}) { 54 | logger.Errorln(args) 55 | } 56 | 57 | // PrintError 58 | func ErrorP(err error) { 59 | // print stack trace if debug 60 | if DebugFlag { 61 | switch customErr := errors.Cause(err).(type) { 62 | case myerrors.CustomError: 63 | switch customErr.Type { 64 | // case myerrors.ConvertInterfaceError: 65 | // case myerrors.CompileError: 66 | default: 67 | logger.Error(fmt.Sprintf("%s: %+v", "PocV Error", err)) 68 | } 69 | default: 70 | // raw error 71 | logger.Error(fmt.Sprintf("%s: %+v", "Raw Error", err)) 72 | } 73 | 74 | } else { 75 | logger.Error(fmt.Sprintf("%v", err)) 76 | } 77 | } 78 | 79 | // Warning 80 | func WarningF(format string, args ...interface{}) { 81 | logger.Warningf(fmt.Sprintf(format, args...)) 82 | } 83 | 84 | func Warning(args ...interface{}) { 85 | logger.Warningln(args) 86 | } 87 | 88 | // Debug 89 | func DebugF(format string, args ...interface{}) { 90 | logger.Debug(fmt.Sprintf(format, args...)) 91 | } 92 | 93 | func Debug(args ...interface{}) { 94 | logger.Debugln(args) 95 | } 96 | -------------------------------------------------------------------------------- /utils/slice.go: -------------------------------------------------------------------------------- 1 | package utils 2 | -------------------------------------------------------------------------------- /utils/string.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/hex" 6 | "math/rand" 7 | "time" 8 | ) 9 | 10 | const ( 11 | AsciiLowercase = "abcdefghijklmnopqrstuvwxyz" 12 | AsciiUppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 13 | AsciiLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 14 | AsciiDigits = "0123456789" 15 | AsciiLowercaseAndDigits = AsciiLowercase + AsciiDigits 16 | AsciiUppercaseAndDigits = AsciiUppercase + AsciiDigits 17 | AsciiLettersAndDigits = AsciiLetters + AsciiDigits 18 | ) 19 | 20 | // 获取随机字符串 21 | func RandomStr(letterBytes string, n int) string { 22 | randSource := rand.New(rand.NewSource(time.Now().Unix())) 23 | const ( 24 | letterIdxBits = 6 // 6 bits to represent a letter index 25 | letterIdxMask = 1<= 0; { 31 | if remain == 0 { 32 | cache, remain = randSource.Int63(), letterIdxMax 33 | } 34 | if idx := int(cache & letterIdxMask); idx < len(letterBytes) { 35 | randBytes[i] = letterBytes[idx] 36 | i-- 37 | } 38 | cache >>= letterIdxBits 39 | remain-- 40 | } 41 | return string(randBytes) 42 | } 43 | 44 | // 获取字符串md5 45 | func MD5(str string) string { 46 | c := md5.New() 47 | c.Write([]byte(str)) 48 | bytes := c.Sum(nil) 49 | return hex.EncodeToString(bytes) 50 | } 51 | 52 | //反向string 53 | 54 | func ReverseString(s string) string { 55 | runes := []rune(s) 56 | for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { 57 | runes[i], runes[j] = runes[j], runes[i] 58 | } 59 | return string(runes) 60 | } 61 | --------------------------------------------------------------------------------