perf: 优化Check.go的代码,添加注释,规范输出

This commit is contained in:
ZacharyZcR 2024-12-19 14:49:58 +08:00
parent 9296ad0846
commit 7f62d4a835

View File

@ -15,182 +15,227 @@ import (
"time" "time"
) )
var ( // API配置常量
ceyeApi = "a78a1cb49d91fe09e01876078d1868b2" const (
ceyeDomain = "7wtusr.ceye.io" ceyeApi = "a78a1cb49d91fe09e01876078d1868b2" // Ceye平台的API密钥
ceyeDomain = "7wtusr.ceye.io" // Ceye平台的域名
) )
// Task 定义单个POC检测任务的结构体
type Task struct { type Task struct {
Req *http.Request Req *http.Request // HTTP请求对象
Poc *Poc Poc *Poc // POC检测脚本
} }
// CheckMultiPoc 并发执行多个POC检测
// 参数说明:
// - req: HTTP请求对象
// - pocs: POC检测脚本列表
// - workers: 并发工作协程数量
func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) { func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
tasks := make(chan Task) if workers <= 0 {
workers = 1 // 确保至少有一个工作协程
}
tasks := make(chan Task, len(pocs)) // 使用带缓冲的通道,避免阻塞
var wg sync.WaitGroup var wg sync.WaitGroup
// 启动工作协程池
for i := 0; i < workers; i++ { for i := 0; i < workers; i++ {
go func() { go func() {
for task := range tasks { for task := range tasks {
isVul, _, name := executePoc(task.Req, task.Poc) // 执行POC检测
if isVul { isVulnerable, details, vulName := executePoc(task.Req, task.Poc)
result := fmt.Sprintf("[+] PocScan %s %s %s", task.Req.URL, task.Poc.Name, name)
if isVulnerable {
// 格式化输出结果
result := fmt.Sprintf("[+] [发现漏洞] 目标: %s\n"+
" 漏洞类型: %s\n"+
" 漏洞名称: %s\n"+
" 详细信息: %s",
task.Req.URL,
task.Poc.Name,
vulName,
details)
Common.LogSuccess(result) Common.LogSuccess(result)
} }
wg.Done() wg.Done()
} }
}() }()
} }
// 分发任务
for _, poc := range pocs { for _, poc := range pocs {
task := Task{ wg.Add(1)
tasks <- Task{
Req: req, Req: req,
Poc: poc, Poc: poc,
} }
wg.Add(1)
tasks <- task
} }
// 等待所有任务完成
wg.Wait() wg.Wait()
close(tasks) close(tasks)
} }
// executePoc 执行单个POC检测
func executePoc(oReq *http.Request, p *Poc) (bool, error, string) { func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
c := NewEnvOption() // 初始化环境配置
c.UpdateCompileOptions(p.Set) config := NewEnvOption()
config.UpdateCompileOptions(p.Set)
// 处理额外的设置项
if len(p.Sets) > 0 { if len(p.Sets) > 0 {
var setMap StrMap var setMap StrMap
for _, item := range p.Sets { for _, item := range p.Sets {
value := ""
if len(item.Value) > 0 { if len(item.Value) > 0 {
setMap = append(setMap, StrItem{item.Key, item.Value[0]}) value = item.Value[0]
} else {
setMap = append(setMap, StrItem{item.Key, ""})
} }
setMap = append(setMap, StrItem{item.Key, value})
} }
c.UpdateCompileOptions(setMap) config.UpdateCompileOptions(setMap)
} }
env, err := NewEnv(&c)
// 创建执行环境
env, err := NewEnv(&config)
if err != nil { if err != nil {
fmt.Printf("[-] %s environment creation error: %s\n", p.Name, err) return false, fmt.Errorf("[-] 创建%s的执行环境失败: %v", p.Name, err), ""
return false, err, ""
} }
// 解析请求
req, err := ParseRequest(oReq) req, err := ParseRequest(oReq)
if err != nil { if err != nil {
fmt.Printf("[-] %s ParseRequest error: %s\n", p.Name, err) return false, fmt.Errorf("[-] 解析%s的请求失败: %v", p.Name, err), ""
return false, err, ""
} }
// 初始化变量映射
variableMap := make(map[string]interface{}) variableMap := make(map[string]interface{})
defer func() { variableMap = nil }() defer func() { variableMap = nil }()
variableMap["request"] = req variableMap["request"] = req
// 处理设置项
for _, item := range p.Set { for _, item := range p.Set {
k, expression := item.Key, item.Value key, expression := item.Key, item.Value
if expression == "newReverse()" { if expression == "newReverse()" {
if !Common.DnsLog { if !Common.DnsLog {
return false, nil, "" return false, nil, ""
} }
variableMap[k] = newReverse() variableMap[key] = newReverse()
continue continue
} }
err, _ = evalset(env, variableMap, k, expression) if err, _ = evalset(env, variableMap, key, expression); err != nil {
if err != nil { Common.LogError(fmt.Sprintf("[-] 执行%s的设置项失败: %v", p.Name, err))
fmt.Printf("[-] %s evalset error: %v\n", p.Name, err)
} }
} }
success := false
//爆破模式,比如tomcat弱口令 // 处理爆破模式
if len(p.Sets) > 0 { if len(p.Sets) > 0 {
success, err = clusterpoc(oReq, p, variableMap, req, env) success, err := clusterpoc(oReq, p, variableMap, req, env)
return success, nil, "" return success, err, ""
} }
// 处理单个规则的函数
DealWithRule := func(rule Rules) (bool, error) { DealWithRule := func(rule Rules) (bool, error) {
Headers := cloneMap(rule.Headers) Headers := cloneMap(rule.Headers)
var (
flag, ok bool // 替换变量
) for varName, varValue := range variableMap {
for k1, v1 := range variableMap { if _, isMap := varValue.(map[string]string); isMap {
_, isMap := v1.(map[string]string)
if isMap {
continue continue
} }
value := fmt.Sprintf("%v", v1) strValue := fmt.Sprintf("%v", varValue)
for k2, v2 := range Headers {
if !strings.Contains(v2, "{{"+k1+"}}") { // 替换Header中的变量
continue for headerKey, headerValue := range Headers {
if strings.Contains(headerValue, "{{"+varName+"}}") {
Headers[headerKey] = strings.ReplaceAll(headerValue, "{{"+varName+"}}", strValue)
} }
Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value)
} }
rule.Path = strings.ReplaceAll(rule.Path, "{{"+k1+"}}", value)
rule.Body = strings.ReplaceAll(rule.Body, "{{"+k1+"}}", value) // 替换Path和Body中的变量
rule.Path = strings.ReplaceAll(rule.Path, "{{"+varName+"}}", strValue)
rule.Body = strings.ReplaceAll(rule.Body, "{{"+varName+"}}", strValue)
} }
// 构建请求路径
if oReq.URL.Path != "" && oReq.URL.Path != "/" { if oReq.URL.Path != "" && oReq.URL.Path != "/" {
req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path) req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path)
} else { } else {
req.Url.Path = rule.Path req.Url.Path = rule.Path
} }
// 某些poc没有区分path和query需要处理
req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20") req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20")
//req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20")
newRequest, err := http.NewRequest(rule.Method, fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, string([]rune(req.Url.Path))), strings.NewReader(rule.Body)) // 创建新的请求
newRequest, err := http.NewRequest(
rule.Method,
fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, string([]rune(req.Url.Path))),
strings.NewReader(rule.Body),
)
if err != nil { if err != nil {
//fmt.Println("[-] newRequest error: ",err) return false, fmt.Errorf("创建新请求失败: %v", err)
return false, err
} }
// 设置请求头
newRequest.Header = oReq.Header.Clone() newRequest.Header = oReq.Header.Clone()
for k, v := range Headers { for k, v := range Headers {
newRequest.Header.Set(k, v) newRequest.Header.Set(k, v)
} }
Headers = nil Headers = nil
// 发送请求
resp, err := DoRequest(newRequest, rule.FollowRedirects) resp, err := DoRequest(newRequest, rule.FollowRedirects)
newRequest = nil newRequest = nil
if err != nil { if err != nil {
return false, err return false, err
} }
variableMap["response"] = resp variableMap["response"] = resp
// 先判断响应页面是否匹配search规则
// 执行搜索规则
if rule.Search != "" { if rule.Search != "" {
result := doSearch(rule.Search, GetHeader(resp.Headers)+string(resp.Body)) result := doSearch(rule.Search, GetHeader(resp.Headers)+string(resp.Body))
if len(result) > 0 { // 正则匹配成功 if len(result) == 0 {
for k, v := range result {
variableMap[k] = v
}
} else {
return false, nil return false, nil
} }
for k, v := range result {
variableMap[k] = v
}
} }
// 执行表达式
out, err := Evaluate(env, rule.Expression, variableMap) out, err := Evaluate(env, rule.Expression, variableMap)
if err != nil { if err != nil {
return false, err return false, err
} }
//如果false不继续执行后续rule
// 如果最后一步执行失败,就算前面成功了最终依旧是失败 if flag, ok := out.Value().(bool); ok {
flag, ok = out.Value().(bool) return flag, nil
if !ok {
flag = false
} }
return flag, nil return false, nil
} }
// 处理规则组的函数
DealWithRules := func(rules []Rules) bool { DealWithRules := func(rules []Rules) bool {
successFlag := false
for _, rule := range rules { for _, rule := range rules {
flag, err := DealWithRule(rule) flag, err := DealWithRule(rule)
if err != nil || !flag { //如果false不继续执行后续rule if err != nil || !flag {
successFlag = false // 如果其中一步为flag则直接break return false
break
} }
successFlag = true
} }
return successFlag return true
} }
// 执行检测规则
success := false
if len(p.Rules) > 0 { if len(p.Rules) > 0 {
success = DealWithRules(p.Rules) success = DealWithRules(p.Rules)
} else { } else {
for _, item := range p.Groups { for _, item := range p.Groups {
name, rules := item.Key, item.Value name, rules := item.Key, item.Value
success = DealWithRules(rules) if success = DealWithRules(rules); success {
if success { return true, nil, name
return success, nil, name
} }
} }
} }
@ -198,18 +243,25 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
return success, nil, "" return success, nil, ""
} }
// doSearch 在响应体中执行正则匹配并提取命名捕获组
func doSearch(re string, body string) map[string]string { func doSearch(re string, body string) map[string]string {
// 编译正则表达式
r, err := regexp.Compile(re) r, err := regexp.Compile(re)
if err != nil { if err != nil {
fmt.Println("[-] regexp.Compile error: ", err) Common.LogError(fmt.Sprintf("正则表达式编译失败: %v", err))
return nil return nil
} }
// 执行正则匹配
result := r.FindStringSubmatch(body) result := r.FindStringSubmatch(body)
names := r.SubexpNames() names := r.SubexpNames()
// 处理匹配结果
if len(result) > 1 && len(names) > 1 { if len(result) > 1 && len(names) > 1 {
paramsMap := make(map[string]string) paramsMap := make(map[string]string)
for i, name := range names { for i, name := range names {
if i > 0 && i <= len(result) { if i > 0 && i <= len(result) {
// 特殊处理Cookie头
if strings.HasPrefix(re, "Set-Cookie:") && strings.Contains(name, "cookie") { if strings.HasPrefix(re, "Set-Cookie:") && strings.Contains(name, "cookie") {
paramsMap[name] = optimizeCookies(result[i]) paramsMap[name] = optimizeCookies(result[i])
} else { } else {
@ -222,36 +274,61 @@ func doSearch(re string, body string) map[string]string {
return nil return nil
} }
func optimizeCookies(rawCookie string) (output string) { // optimizeCookies 优化Cookie字符串移除不必要的属性
// Parse the cookies func optimizeCookies(rawCookie string) string {
parsedCookie := strings.Split(rawCookie, "; ") var output strings.Builder
for _, c := range parsedCookie {
nameVal := strings.Split(c, "=") // 解析Cookie键值对
if len(nameVal) >= 2 { pairs := strings.Split(rawCookie, "; ")
switch strings.ToLower(nameVal[0]) { for _, pair := range pairs {
case "expires", "max-age", "path", "domain", "version", "comment", "secure", "samesite", "httponly": nameVal := strings.SplitN(pair, "=", 2)
continue if len(nameVal) < 2 {
} continue
output += fmt.Sprintf("%s=%s; ", nameVal[0], strings.Join(nameVal[1:], "="))
} }
// 跳过Cookie属性
switch strings.ToLower(nameVal[0]) {
case "expires", "max-age", "path", "domain",
"version", "comment", "secure", "samesite", "httponly":
continue
}
// 构建Cookie键值对
if output.Len() > 0 {
output.WriteString("; ")
}
output.WriteString(nameVal[0])
output.WriteString("=")
output.WriteString(strings.Join(nameVal[1:], "="))
} }
return return output.String()
} }
// newReverse 创建新的反连检测对象
func newReverse() *Reverse { func newReverse() *Reverse {
// 检查DNS日志功能是否启用
if !Common.DnsLog { if !Common.DnsLog {
return &Reverse{} return &Reverse{}
} }
letters := "1234567890abcdefghijklmnopqrstuvwxyz"
// 生成随机子域名
const (
letters = "1234567890abcdefghijklmnopqrstuvwxyz"
subdomainLength = 8
)
randSource := rand.New(rand.NewSource(time.Now().UnixNano())) randSource := rand.New(rand.NewSource(time.Now().UnixNano()))
sub := RandomStr(randSource, letters, 8) subdomain := RandomStr(randSource, letters, subdomainLength)
//if true {
// //默认不开启dns解析 // 构建URL
// return &Reverse{} urlStr := fmt.Sprintf("http://%s.%s", subdomain, ceyeDomain)
//} u, err := url.Parse(urlStr)
urlStr := fmt.Sprintf("http://%s.%s", sub, ceyeDomain) if err != nil {
u, _ := url.Parse(urlStr) Common.LogError(fmt.Sprintf("解析反连URL失败: %v", err))
return &Reverse{}
}
// 返回反连检测配置
return &Reverse{ return &Reverse{
Url: urlStr, Url: urlStr,
Domain: u.Hostname(), Domain: u.Hostname(),
@ -260,270 +337,368 @@ func newReverse() *Reverse {
} }
} }
// clusterpoc 执行集群POC检测支持批量参数组合测试
func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env) (success bool, err error) { func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env) (success bool, err error) {
var strMap StrMap var strMap StrMap // 存储成功的参数组合
var tmpnum int var shiroKeyCount int // shiro key测试计数
for i, rule := range p.Rules {
// 遍历POC规则
for ruleIndex, rule := range p.Rules {
// 检查是否需要进行参数Fuzz测试
if !isFuzz(rule, p.Sets) { if !isFuzz(rule, p.Sets) {
// 不需要Fuzz,直接发送请求
success, err = clustersend(oReq, variableMap, req, env, rule) success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil { if err != nil {
return false, err return false, err
} }
if success { if !success {
continue
} else {
return false, err return false, err
} }
continue
} }
// 生成参数组合
setsMap := Combo(p.Sets) setsMap := Combo(p.Sets)
ruleHash := make(map[string]struct{}) ruleHash := make(map[string]struct{}) // 用于去重的规则哈希表
look:
for j, item := range setsMap { // 遍历参数组合
//shiro默认只跑10key paramLoop:
if p.Name == "poc-yaml-shiro-key" && !Common.PocFull && j >= 10 { for comboIndex, paramCombo := range setsMap {
if item[1] == "cbc" { // Shiro Key测试特殊处理:默认只测试10个key
if p.Name == "poc-yaml-shiro-key" && !Common.PocFull && comboIndex >= 10 {
if paramCombo[1] == "cbc" {
continue continue
} else { } else {
if tmpnum == 0 { if shiroKeyCount == 0 {
tmpnum = j shiroKeyCount = comboIndex
} }
if j-tmpnum >= 10 { if comboIndex-shiroKeyCount >= 10 {
break break
} }
} }
} }
rule1 := cloneRules(rule)
var flag1 bool // 克隆规则以避免相互影响
var tmpMap StrMap currentRule := cloneRules(rule)
var payloads = make(map[string]interface{}) var hasReplacement bool
var tmpexpression string var currentParams StrMap
for i, one := range p.Sets { payloads := make(map[string]interface{})
key, expression := one.Key, item[i] var payloadExpr string
// 计算所有参数的实际值
for i, set := range p.Sets {
key, expr := set.Key, paramCombo[i]
if key == "payload" { if key == "payload" {
tmpexpression = expression payloadExpr = expr
} }
_, output := evalset1(env, variableMap, key, expression) _, output := evalset1(env, variableMap, key, expr)
payloads[key] = output payloads[key] = output
} }
for _, one := range p.Sets {
flag := false // 替换规则中的参数
key := one.Key for _, set := range p.Sets {
paramReplaced := false
key := set.Key
value := fmt.Sprintf("%v", payloads[key]) value := fmt.Sprintf("%v", payloads[key])
for k2, v2 := range rule1.Headers {
if strings.Contains(v2, "{{"+key+"}}") { // 替换Header中的参数
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+key+"}}", value) for headerKey, headerVal := range currentRule.Headers {
flag = true if strings.Contains(headerVal, "{{"+key+"}}") {
currentRule.Headers[headerKey] = strings.ReplaceAll(headerVal, "{{"+key+"}}", value)
paramReplaced = true
} }
} }
if strings.Contains(rule1.Path, "{{"+key+"}}") {
rule1.Path = strings.ReplaceAll(rule1.Path, "{{"+key+"}}", value) // 替换Path中的参数
flag = true if strings.Contains(currentRule.Path, "{{"+key+"}}") {
currentRule.Path = strings.ReplaceAll(currentRule.Path, "{{"+key+"}}", value)
paramReplaced = true
} }
if strings.Contains(rule1.Body, "{{"+key+"}}") {
rule1.Body = strings.ReplaceAll(rule1.Body, "{{"+key+"}}", value) // 替换Body中的参数
flag = true if strings.Contains(currentRule.Body, "{{"+key+"}}") {
currentRule.Body = strings.ReplaceAll(currentRule.Body, "{{"+key+"}}", value)
paramReplaced = true
} }
if flag {
flag1 = true // 记录替换的参数
if paramReplaced {
hasReplacement = true
if key == "payload" { if key == "payload" {
var flag2 bool // 处理payload的特殊情况
for k, v := range variableMap { hasVarInPayload := false
if strings.Contains(tmpexpression, k) { for varKey, varVal := range variableMap {
flag2 = true if strings.Contains(payloadExpr, varKey) {
tmpMap = append(tmpMap, StrItem{k, fmt.Sprintf("%v", v)}) hasVarInPayload = true
currentParams = append(currentParams, StrItem{varKey, fmt.Sprintf("%v", varVal)})
} }
} }
if flag2 { if hasVarInPayload {
continue continue
} }
} }
tmpMap = append(tmpMap, StrItem{key, value}) currentParams = append(currentParams, StrItem{key, value})
} }
} }
if !flag1 {
// 如果没有参数被替换,跳过当前组合
if !hasReplacement {
continue continue
} }
has := md5.Sum([]byte(fmt.Sprintf("%v", rule1)))
md5str := fmt.Sprintf("%x", has) // 规则去重
if _, ok := ruleHash[md5str]; ok { ruleDigest := md5.Sum([]byte(fmt.Sprintf("%v", currentRule)))
ruleMD5 := fmt.Sprintf("%x", ruleDigest)
if _, exists := ruleHash[ruleMD5]; exists {
continue continue
} }
ruleHash[md5str] = struct{}{} ruleHash[ruleMD5] = struct{}{}
success, err = clustersend(oReq, variableMap, req, env, rule1)
// 发送请求并处理结果
success, err = clustersend(oReq, variableMap, req, env, currentRule)
if err != nil { if err != nil {
return false, err return false, err
} }
if success { if success {
if rule.Continue { // 处理成功情况
if currentRule.Continue {
// 特殊POC的输出处理
if p.Name == "poc-yaml-backup-file" || p.Name == "poc-yaml-sql-file" { if p.Name == "poc-yaml-backup-file" || p.Name == "poc-yaml-sql-file" {
Common.LogSuccess(fmt.Sprintf("[+] PocScan %s://%s%s %s", req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name)) Common.LogSuccess(fmt.Sprintf("[+] 检测到漏洞 %s://%s%s %s",
req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name))
} else { } else {
Common.LogSuccess(fmt.Sprintf("[+] PocScan %s://%s%s %s %v", req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, tmpMap)) Common.LogSuccess(fmt.Sprintf("[+] 检测到漏洞 %s://%s%s %s 参数:%v",
req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, currentParams))
} }
continue continue
} }
strMap = append(strMap, tmpMap...)
if i == len(p.Rules)-1 { // 记录成功的参数组合
Common.LogSuccess(fmt.Sprintf("[+] PocScan %s://%s%s %s %v", req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, strMap)) strMap = append(strMap, currentParams...)
//防止后续继续打印poc成功信息 if ruleIndex == len(p.Rules)-1 {
Common.LogSuccess(fmt.Sprintf("[+] 检测到漏洞 %s://%s%s %s 参数:%v",
req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, strMap))
return false, nil return false, nil
} }
break look break paramLoop
} }
} }
if !success { if !success {
break break
} }
if rule.Continue { if rule.Continue {
//防止后续继续打印poc成功信息
return false, nil return false, nil
} }
} }
return success, nil return success, nil
} }
// isFuzz 检查规则是否包含需要Fuzz测试的参数
func isFuzz(rule Rules, Sets ListMap) bool { func isFuzz(rule Rules, Sets ListMap) bool {
for _, one := range Sets { // 遍历所有参数
key := one.Key for _, param := range Sets {
for _, v := range rule.Headers { key := param.Key
if strings.Contains(v, "{{"+key+"}}") { paramPattern := "{{" + key + "}}"
// 检查Headers中是否包含参数
for _, headerValue := range rule.Headers {
if strings.Contains(headerValue, paramPattern) {
return true return true
} }
} }
if strings.Contains(rule.Path, "{{"+key+"}}") {
// 检查Path中是否包含参数
if strings.Contains(rule.Path, paramPattern) {
return true return true
} }
if strings.Contains(rule.Body, "{{"+key+"}}") {
// 检查Body中是否包含参数
if strings.Contains(rule.Body, paramPattern) {
return true return true
} }
} }
return false return false
} }
func Combo(input ListMap) (output [][]string) { // Combo 生成参数组合
if len(input) > 1 { func Combo(input ListMap) [][]string {
output = Combo(input[1:]) if len(input) == 0 {
output = MakeData(output, input[0].Value) return nil
} else {
for _, i := range input[0].Value {
output = append(output, []string{i})
}
} }
return
// 处理只有一个参数的情况
if len(input) == 1 {
output := make([][]string, 0, len(input[0].Value))
for _, value := range input[0].Value {
output = append(output, []string{value})
}
return output
}
// 递归处理多个参数的情况
subCombos := Combo(input[1:])
return MakeData(subCombos, input[0].Value)
} }
func MakeData(base [][]string, nextData []string) (output [][]string) { // MakeData 将新的参数值与已有的组合进行组合
for i := range base { func MakeData(base [][]string, nextData []string) [][]string {
for _, j := range nextData { // 预分配足够的空间
output = append(output, append([]string{j}, base[i]...)) output := make([][]string, 0, len(base)*len(nextData))
// 遍历已有组合和新参数值
for _, existingCombo := range base {
for _, newValue := range nextData {
// 创建新组合
newCombo := make([]string, 0, len(existingCombo)+1)
newCombo = append(newCombo, newValue)
newCombo = append(newCombo, existingCombo...)
output = append(output, newCombo)
} }
} }
return
return output
} }
// clustersend 执行单个规则的HTTP请求和响应检测
func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Request, env *cel.Env, rule Rules) (bool, error) { func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Request, env *cel.Env, rule Rules) (bool, error) {
for k1, v1 := range variableMap { // 替换请求中的变量
_, isMap := v1.(map[string]string) for varName, varValue := range variableMap {
if isMap { // 跳过map类型的变量
if _, isMap := varValue.(map[string]string); isMap {
continue continue
} }
value := fmt.Sprintf("%v", v1)
for k2, v2 := range rule.Headers { strValue := fmt.Sprintf("%v", varValue)
if strings.Contains(v2, "{{"+k1+"}}") { varPattern := "{{" + varName + "}}"
rule.Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value)
// 替换Headers中的变量
for headerKey, headerValue := range rule.Headers {
if strings.Contains(headerValue, varPattern) {
rule.Headers[headerKey] = strings.ReplaceAll(headerValue, varPattern, strValue)
} }
} }
rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), "{{"+k1+"}}", value)
rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), "{{"+k1+"}}", value) // 替换Path和Body中的变量
rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), varPattern, strValue)
rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), varPattern, strValue)
} }
// 构建完整请求路径
if oReq.URL.Path != "" && oReq.URL.Path != "/" { if oReq.URL.Path != "" && oReq.URL.Path != "/" {
req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path) req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path)
} else { } else {
req.Url.Path = rule.Path req.Url.Path = rule.Path
} }
// 某些poc没有区分path和query需要处理
// URL编码处理
req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20") req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20")
//req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20")
// // 创建新的HTTP请求
newRequest, err := http.NewRequest(rule.Method, fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path), strings.NewReader(rule.Body)) reqURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path)
newRequest, err := http.NewRequest(rule.Method, reqURL, strings.NewReader(rule.Body))
if err != nil { if err != nil {
//fmt.Println("[-] newRequest error:",err) return false, fmt.Errorf("[-] 创建HTTP请求失败: %v", err)
return false, err
} }
defer func() { newRequest = nil }() // 及时释放资源
// 设置请求头
newRequest.Header = oReq.Header.Clone() newRequest.Header = oReq.Header.Clone()
for k, v := range rule.Headers { for key, value := range rule.Headers {
newRequest.Header.Set(k, v) newRequest.Header.Set(key, value)
} }
// 发送请求
resp, err := DoRequest(newRequest, rule.FollowRedirects) resp, err := DoRequest(newRequest, rule.FollowRedirects)
newRequest = nil
if err != nil { if err != nil {
return false, err return false, fmt.Errorf("[-] 发送请求失败: %v", err)
} }
// 更新响应到变量映射
variableMap["response"] = resp variableMap["response"] = resp
// 先判断响应页面是否匹配search规则
// 执行搜索规则
if rule.Search != "" { if rule.Search != "" {
result := doSearch(rule.Search, GetHeader(resp.Headers)+string(resp.Body)) searchContent := GetHeader(resp.Headers) + string(resp.Body)
if result != nil && len(result) > 0 { // 正则匹配成功 result := doSearch(rule.Search, searchContent)
for k, v := range result {
variableMap[k] = v if result != nil && len(result) > 0 {
// 将搜索结果添加到变量映射
for key, value := range result {
variableMap[key] = value
} }
//return false, nil
} else { } else {
return false, nil return false, nil
} }
} }
// 执行CEL表达式
out, err := Evaluate(env, rule.Expression, variableMap) out, err := Evaluate(env, rule.Expression, variableMap)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "Syntax error") { if strings.Contains(err.Error(), "Syntax error") {
fmt.Println(rule.Expression, err) Common.LogError(fmt.Sprintf("[-] CEL表达式语法错误 [%s]: %v", rule.Expression, err))
} }
return false, err return false, err
} }
//fmt.Println(fmt.Sprintf("%v, %s", out, out.Type().TypeName()))
if fmt.Sprintf("%v", out) == "false" { //如果false不继续执行后续rule // 检查表达式执行结果
return false, err // 如果最后一步执行失败,就算前面成功了最终依旧是失败 if fmt.Sprintf("%v", out) == "false" {
return false, nil
} }
return true, err
return true, nil
} }
// cloneRules 深度复制Rules结构体
// 参数:
// - tags: 原始Rules结构体
// 返回: 复制后的新Rules结构体
func cloneRules(tags Rules) Rules { func cloneRules(tags Rules) Rules {
cloneTags := Rules{} return Rules{
cloneTags.Method = tags.Method Method: tags.Method,
cloneTags.Path = tags.Path Path: tags.Path,
cloneTags.Body = tags.Body Body: tags.Body,
cloneTags.Search = tags.Search Search: tags.Search,
cloneTags.FollowRedirects = tags.FollowRedirects FollowRedirects: tags.FollowRedirects,
cloneTags.Expression = tags.Expression Expression: tags.Expression,
cloneTags.Headers = cloneMap(tags.Headers) Headers: cloneMap(tags.Headers),
return cloneTags }
} }
// cloneMap 深度复制字符串映射
func cloneMap(tags map[string]string) map[string]string { func cloneMap(tags map[string]string) map[string]string {
cloneTags := make(map[string]string) cloneTags := make(map[string]string, len(tags))
for k, v := range tags { for key, value := range tags {
cloneTags[k] = v cloneTags[key] = value
} }
return cloneTags return cloneTags
} }
func evalset(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (err error, output string) { // evalset 执行CEL表达式并处理特殊类型结果
func evalset(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (error, string) {
out, err := Evaluate(env, expression, variableMap) out, err := Evaluate(env, expression, variableMap)
if err != nil { if err != nil {
variableMap[k] = expression variableMap[k] = expression
} else { return err, expression
switch value := out.Value().(type) {
case *UrlType:
variableMap[k] = UrlTypeToString(value)
case int64:
variableMap[k] = int(value)
default:
variableMap[k] = fmt.Sprintf("%v", out)
}
} }
return err, fmt.Sprintf("%v", variableMap[k])
// 根据不同类型处理输出
switch value := out.Value().(type) {
case *UrlType:
variableMap[k] = UrlTypeToString(value)
case int64:
variableMap[k] = int(value)
default:
variableMap[k] = fmt.Sprintf("%v", out)
}
return nil, fmt.Sprintf("%v", variableMap[k])
} }
func evalset1(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (err error, output string) { // evalset1 执行CEL表达式的简化版本
func evalset1(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (error, string) {
out, err := Evaluate(env, expression, variableMap) out, err := Evaluate(env, expression, variableMap)
if err != nil { if err != nil {
variableMap[k] = expression variableMap[k] = expression
@ -533,6 +708,7 @@ func evalset1(env *cel.Env, variableMap map[string]interface{}, k string, expres
return err, fmt.Sprintf("%v", variableMap[k]) return err, fmt.Sprintf("%v", variableMap[k])
} }
// CheckInfoPoc 检查POC信息并返回别名
func CheckInfoPoc(infostr string) string { func CheckInfoPoc(infostr string) string {
for _, poc := range info.PocDatas { for _, poc := range info.PocDatas {
if strings.Contains(infostr, poc.Name) { if strings.Contains(infostr, poc.Name) {
@ -542,11 +718,12 @@ func CheckInfoPoc(infostr string) string {
return "" return ""
} }
func GetHeader(header map[string]string) (output string) { // GetHeader 将HTTP头转换为字符串格式
func GetHeader(header map[string]string) string {
var builder strings.Builder
for name, values := range header { for name, values := range header {
line := fmt.Sprintf("%s: %s\n", name, values) builder.WriteString(fmt.Sprintf("%s: %s\n", name, values))
output = output + line
} }
output = output + "\r\n" builder.WriteString("\r\n")
return return builder.String()
} }