diff --git a/CHANGELOG.MD b/CHANGELOG.MD index cd5d906..6678213 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -3,6 +3,7 @@ 更新日志: - [BUG] 修复某些情况 `path` 开头包含多个 `/` 问题 +- [优化] 使用 `interactsh` 反连随机选择可用的服务器 - [优化] 开启 `debug` 时请求响应限制打印长度 感谢以下用户的贡献: diff --git a/reverse/interact.go b/reverse/interact.go index 67db368..7ae3f61 100644 --- a/reverse/interact.go +++ b/reverse/interact.go @@ -22,12 +22,15 @@ import ( "crypto/rand" "crypto/rsa" "encoding/json" + "errors" "fmt" "strings" + "sync" "time" "github.com/4ra1n/poc-runner/client" "github.com/4ra1n/poc-runner/log" + "github.com/4ra1n/poc-runner/util" "github.com/4ra1n/poc-runner/xerr" ) @@ -75,7 +78,55 @@ type Interact struct { func NewInteract(c *client.HttpClient, server string) (*Interact, error) { if server == "" { - server = randomPick(defaultServers) + // 随机选取一个 default server + picker := util.NewPicker(defaultServers) + + var ( + ok bool + tryTimes int + ) + + for { + tryTimes++ + + if tryTimes > 5 { + return nil, xerr.Wrap(errors.New("cannot connect to interact.sh server")) + } + + server, ok = picker.RandomPick() + if !ok { + // 只有所有的 server 被选完没得选才会返回 false + return nil, xerr.Wrap(errors.New("all default server is invalid")) + } + + var ( + httpErr error + httpsErr error + ) + + // 并发测试 http/https 只要有一个可用即可 + wg := new(sync.WaitGroup) + + wg.Add(2) + + go func() { + defer wg.Done() + _, httpErr = c.Get("http://" + server) + }() + + go func() { + defer wg.Done() + _, httpsErr = c.Get("https://" + server) + }() + + wg.Wait() + + // 任何一个不报错就使用它 + if httpErr == nil || httpsErr == nil { + log.Infof("use reverse server: %s", server) + break + } + } } correlationID := randLower(20) secretKey := randomUUID() diff --git a/reverse/util.go b/reverse/util.go index 70ee92c..7e82b2e 100644 --- a/reverse/util.go +++ b/reverse/util.go @@ -49,11 +49,6 @@ func randomUUID() string { return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]) } -func randomPick(choices []string) string { - randomIndex := rand.Intn(len(choices)) - return choices[randomIndex] -} - func randUpper(n int) string { letterRunes := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ") b := make([]rune, n) diff --git a/util/picker.go b/util/picker.go new file mode 100644 index 0000000..77f1022 --- /dev/null +++ b/util/picker.go @@ -0,0 +1,55 @@ +/* + * poc-runner project + * Copyright (C) 2024 4ra1n + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package util + +import ( + "math/rand" + "time" +) + +func init() { + rand.New(rand.NewSource(time.Now().UnixNano())) +} + +type Picker struct { + choices []string + used map[int]bool +} + +func NewPicker(choices []string) *Picker { + return &Picker{ + choices: choices, + used: make(map[int]bool), + } +} + +func (p *Picker) RandomPick() (string, bool) { + if len(p.used) == len(p.choices) { + return "", false + } + var index int + for { + index = rand.Intn(len(p.choices)) + if !p.used[index] { + break + } + } + p.used[index] = true + return p.choices[index], true +}