fix: 修复#431

This commit is contained in:
ZacharyZcR 2025-04-05 17:24:09 +08:00
parent 3e04e7801f
commit 87ceba4d8f

View File

@ -27,46 +27,69 @@ type Task struct {
Poc *Poc // POC检测脚本 Poc *Poc // POC检测脚本
} }
// VulnResult 漏洞结果结构体
type VulnResult struct {
Poc *Poc // POC脚本
VulName string // 漏洞名称
Target string // 目标URL
Details map[string]interface{} // 详细信息
}
// CheckMultiPoc 并发执行多个POC检测 // CheckMultiPoc 并发执行多个POC检测
// 参数说明: // 参数说明:
// - req: HTTP请求对象 // - req: HTTP请求对象
// - pocs: POC检测脚本列表 // - pocs: POC检测脚本列表
// - workers: 并发工作协程数量 // - workers: 并发工作协程数量
func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) { func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
// 确保至少有一个工作协程
if workers <= 0 { if workers <= 0 {
workers = 1 // 确保至少有一个工作协程 workers = 1
} }
// 创建任务通道缓冲区大小为POC列表长度
tasks := make(chan Task, len(pocs)) 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++ {
wg.Add(1)
go func() { go func() {
defer wg.Done()
// 从任务通道循环获取任务
for task := range tasks { for task := range tasks {
// 执行POC检测返回是否存在漏洞、错误信息和漏洞名称
isVulnerable, err, vulName := executePoc(task.Req, task.Poc) isVulnerable, err, vulName := executePoc(task.Req, task.Poc)
// 处理执行过程中的错误
if err != nil { if err != nil {
wg.Done() Common.LogError(fmt.Sprintf("执行POC错误 %s: %v", task.Poc.Name, err))
continue continue
} }
if isVulnerable { // 仅当通过普通POC规则(非clusterpoc)检测到漏洞时,才创建结果
// 构造详细信息 // 因为clusterpoc已在内部处理了漏洞输出
if isVulnerable && vulName != "" {
// 构造漏洞详细信息
details := make(map[string]interface{}) details := make(map[string]interface{})
details["vulnerability_type"] = task.Poc.Name details["vulnerability_type"] = task.Poc.Name
details["vulnerability_name"] = vulName details["vulnerability_name"] = vulName
// 添加作者信息(如果有)
if task.Poc.Detail.Author != "" { if task.Poc.Detail.Author != "" {
details["author"] = task.Poc.Detail.Author details["author"] = task.Poc.Detail.Author
} }
// 添加参考链接(如果有)
if len(task.Poc.Detail.Links) != 0 { if len(task.Poc.Detail.Links) != 0 {
details["references"] = task.Poc.Detail.Links details["references"] = task.Poc.Detail.Links
} }
// 添加漏洞描述(如果有)
if task.Poc.Detail.Description != "" { if task.Poc.Detail.Description != "" {
details["description"] = task.Poc.Detail.Description details["description"] = task.Poc.Detail.Description
} }
// 保存漏洞结果 // 创建并保存扫描结果
result := &Common.ScanResult{ result := &Common.ScanResult{
Time: time.Now(), Time: time.Now(),
Type: Common.VULN, Type: Common.VULN,
@ -76,41 +99,96 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
} }
Common.SaveResult(result) Common.SaveResult(result)
// 控制台输出 // 构造控制台输出的日志信息
logMsg := fmt.Sprintf("目标: %s\n 漏洞类型: %s\n 漏洞名称: %s\n 详细信息:", logMsg := fmt.Sprintf("目标: %s\n 漏洞类型: %s\n 漏洞名称: %s\n 详细信息:",
task.Req.URL, task.Req.URL,
task.Poc.Name, task.Poc.Name,
vulName) vulName)
// 添加作者信息到日志
if task.Poc.Detail.Author != "" { if task.Poc.Detail.Author != "" {
logMsg += "\n\tauthor:" + task.Poc.Detail.Author logMsg += "\n\t作者:" + task.Poc.Detail.Author
}
if len(task.Poc.Detail.Links) != 0 {
logMsg += "\n\tlinks:" + strings.Join(task.Poc.Detail.Links, "\n")
}
if task.Poc.Detail.Description != "" {
logMsg += "\n\tdescription:" + task.Poc.Detail.Description
} }
// 添加参考链接到日志
if len(task.Poc.Detail.Links) != 0 {
logMsg += "\n\t参考链接:" + strings.Join(task.Poc.Detail.Links, "\n")
}
// 添加描述信息到日志
if task.Poc.Detail.Description != "" {
logMsg += "\n\t描述:" + task.Poc.Detail.Description
}
// 输出成功日志
Common.LogSuccess(logMsg) Common.LogSuccess(logMsg)
} }
wg.Done()
} }
}() }()
} }
// 分发任务 // 分发所有POC任务到通道
for _, poc := range pocs { for _, poc := range pocs {
wg.Add(1)
tasks <- Task{ tasks <- Task{
Req: req, Req: req,
Poc: poc, Poc: poc,
} }
} }
// 等待所有任务完成 // 关闭任务通道
wg.Wait()
close(tasks) close(tasks)
// 等待所有POC检测任务完成
wg.Wait()
}
// createVulnDetails 创建漏洞详情信息
func createVulnDetails(poc *Poc, vulName string) map[string]interface{} {
details := make(map[string]interface{})
details["vulnerability_type"] = poc.Name
details["vulnerability_name"] = vulName
// 添加作者信息(如果有)
if poc.Detail.Author != "" {
details["author"] = poc.Detail.Author
}
// 添加参考链接(如果有)
if len(poc.Detail.Links) != 0 {
details["references"] = poc.Detail.Links
}
// 添加漏洞描述(如果有)
if poc.Detail.Description != "" {
details["description"] = poc.Detail.Description
}
return details
}
// buildLogMessage 构建漏洞日志消息
func buildLogMessage(result *VulnResult) string {
logMsg := fmt.Sprintf("目标: %s\n 漏洞类型: %s\n 漏洞名称: %s\n 详细信息:",
result.Target,
result.Poc.Name,
result.VulName)
// 添加作者信息到日志
if result.Poc.Detail.Author != "" {
logMsg += "\n\t作者:" + result.Poc.Detail.Author
}
// 添加参考链接到日志
if len(result.Poc.Detail.Links) != 0 {
logMsg += "\n\t参考链接:" + strings.Join(result.Poc.Detail.Links, "\n")
}
// 添加描述信息到日志
if result.Poc.Detail.Description != "" {
logMsg += "\n\t描述:" + result.Poc.Detail.Description
}
return logMsg
} }
// executePoc 执行单个POC检测 // executePoc 执行单个POC检测
@ -170,8 +248,13 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
return success, err, "" return success, err, ""
} }
return executeRules(oReq, p, variableMap, req, env)
}
// executeRules 执行POC规则并返回结果
func executeRules(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env) (bool, error, string) {
// 处理单个规则的函数 // 处理单个规则的函数
DealWithRule := func(rule Rules) (bool, error) { executeRule := func(rule Rules) (bool, error) {
Headers := cloneMap(rule.Headers) Headers := cloneMap(rule.Headers)
// 替换变量 // 替换变量
@ -251,9 +334,9 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
} }
// 处理规则组的函数 // 处理规则组的函数
DealWithRules := func(rules []Rules) bool { executeRuleSet := func(rules []Rules) bool {
for _, rule := range rules { for _, rule := range rules {
flag, err := DealWithRule(rule) flag, err := executeRule(rule)
if err != nil || !flag { if err != nil || !flag {
return false return false
} }
@ -264,17 +347,18 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
// 执行检测规则 // 执行检测规则
success := false success := false
if len(p.Rules) > 0 { if len(p.Rules) > 0 {
success = DealWithRules(p.Rules) success = executeRuleSet(p.Rules)
return success, nil, ""
} else { } else {
for _, item := range p.Groups { for _, item := range p.Groups {
name, rules := item.Key, item.Value name, rules := item.Key, item.Value
if success = DealWithRules(rules); success { if success = executeRuleSet(rules); success {
return true, nil, name return true, nil, name
} }
} }
} }
return success, nil, "" return false, nil, ""
} }
// doSearch 在响应体中执行正则匹配并提取命名捕获组 // doSearch 在响应体中执行正则匹配并提取命名捕获组
@ -378,6 +462,61 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{},
var strMap StrMap // 存储成功的参数组合 var strMap StrMap // 存储成功的参数组合
var shiroKeyCount int // shiro key测试计数 var shiroKeyCount int // shiro key测试计数
// 记录漏洞的辅助函数,统一保存结果和输出日志
recordVulnerability := func(targetURL string, params StrMap, skipSave bool) {
// 构造详细信息
details := make(map[string]interface{})
details["vulnerability_type"] = p.Name
details["vulnerability_name"] = p.Name // 使用POC名称作为漏洞名称
// 添加作者信息(如果有)
if p.Detail.Author != "" {
details["author"] = p.Detail.Author
}
// 添加参考链接(如果有)
if len(p.Detail.Links) != 0 {
details["references"] = p.Detail.Links
}
// 添加漏洞描述(如果有)
if p.Detail.Description != "" {
details["description"] = p.Detail.Description
}
// 添加参数信息(如果有)
if len(params) > 0 {
paramMap := make(map[string]string)
for _, item := range params {
paramMap[item.Key] = item.Value
}
details["parameters"] = paramMap
}
// 保存漏洞结果(除非明确指示跳过)
if !skipSave {
result := &Common.ScanResult{
Time: time.Now(),
Type: Common.VULN,
Target: targetURL,
Status: "vulnerable",
Details: details,
}
Common.SaveResult(result)
}
// 生成日志消息
var logMsg string
if p.Name == "poc-yaml-backup-file" || p.Name == "poc-yaml-sql-file" {
logMsg = fmt.Sprintf("检测到漏洞 %s %s", targetURL, p.Name)
} else {
logMsg = fmt.Sprintf("检测到漏洞 %s %s 参数:%v", targetURL, p.Name, params)
}
// 输出成功日志
Common.LogSuccess(logMsg)
}
// 遍历POC规则 // 遍历POC规则
for ruleIndex, rule := range p.Rules { for ruleIndex, rule := range p.Rules {
// 检查是否需要进行参数Fuzz测试 // 检查是否需要进行参数Fuzz测试
@ -497,22 +636,20 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{},
} }
if success { if success {
targetURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path)
// 处理成功情况 // 处理成功情况
if currentRule.Continue { if currentRule.Continue {
targetURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path) // 使用Continue标志时记录但继续测试其他参数
if p.Name == "poc-yaml-backup-file" || p.Name == "poc-yaml-sql-file" { recordVulnerability(targetURL, currentParams, false)
Common.LogSuccess(fmt.Sprintf("检测到漏洞 %s %s", targetURL, p.Name))
} else {
Common.LogSuccess(fmt.Sprintf("检测到漏洞 %s %s 参数:%v", targetURL, p.Name, currentParams))
}
continue continue
} }
// 记录成功的参数组合 // 记录成功的参数组合
strMap = append(strMap, currentParams...) strMap = append(strMap, currentParams...)
if ruleIndex == len(p.Rules)-1 { if ruleIndex == len(p.Rules)-1 {
targetURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path) // 最终规则成功,记录完整的结果并返回
Common.LogSuccess(fmt.Sprintf("检测到漏洞 %s %s 参数:%v", targetURL, p.Name, strMap)) recordVulnerability(targetURL, strMap, false)
return false, nil return false, nil
} }
break paramLoop break paramLoop
@ -698,11 +835,15 @@ func cloneRules(tags Rules) Rules {
FollowRedirects: tags.FollowRedirects, FollowRedirects: tags.FollowRedirects,
Expression: tags.Expression, Expression: tags.Expression,
Headers: cloneMap(tags.Headers), Headers: cloneMap(tags.Headers),
Continue: tags.Continue,
} }
} }
// cloneMap 深度复制字符串映射 // cloneMap 深度复制字符串映射
func cloneMap(tags map[string]string) map[string]string { func cloneMap(tags map[string]string) map[string]string {
if tags == nil {
return nil
}
cloneTags := make(map[string]string, len(tags)) cloneTags := make(map[string]string, len(tags))
for key, value := range tags { for key, value := range tags {
cloneTags[key] = value cloneTags[key] = value