Files
fscan/WebScan/WebScan.go
T

168 lines
4.5 KiB
Go

package WebScan
import (
"embed"
"fmt"
"github.com/shadow1ng/fscan/Common"
"github.com/shadow1ng/fscan/WebScan/lib"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"sync"
)
//go:embed pocs
var Pocs embed.FS
var once sync.Once
var AllPocs []*lib.Poc
// WebScan 执行Web漏洞扫描
func WebScan(info *Common.HostInfo) {
once.Do(initpoc)
var pocinfo = Common.Pocinfo
// 自动构建URL
if info.Url == "" {
info.Url = fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
}
urlParts := strings.Split(info.Url, "/")
// 检查切片长度并构建目标URL
if len(urlParts) >= 3 {
pocinfo.Target = strings.Join(urlParts[:3], "/")
} else {
pocinfo.Target = info.Url
}
Common.LogDebug(fmt.Sprintf("扫描目标: %s", pocinfo.Target))
// 如果是直接调用WebPoc(没有指定pocName),执行所有POC
if pocinfo.PocName == "" && len(info.Infostr) == 0 {
Common.LogDebug("直接调用WebPoc,执行所有POC")
Execute(pocinfo)
} else {
// 根据指纹信息选择性执行POC
if len(info.Infostr) > 0 {
for _, infostr := range info.Infostr {
pocinfo.PocName = lib.CheckInfoPoc(infostr)
if pocinfo.PocName != "" {
Common.LogDebug(fmt.Sprintf("根据指纹 %s 执行对应POC", infostr))
Execute(pocinfo)
}
}
} else if pocinfo.PocName != "" {
// 指定了特定的POC
Common.LogDebug(fmt.Sprintf("执行指定POC: %s", pocinfo.PocName))
Execute(pocinfo)
}
}
}
// Execute 执行具体的POC检测
func Execute(PocInfo Common.PocInfo) {
Common.LogDebug(fmt.Sprintf("开始执行POC检测,目标: %s", PocInfo.Target))
// 确保URL格式正确
if !strings.HasPrefix(PocInfo.Target, "http://") && !strings.HasPrefix(PocInfo.Target, "https://") {
PocInfo.Target = "http://" + PocInfo.Target
}
// 验证URL格式
_, err := url.Parse(PocInfo.Target)
if err != nil {
Common.LogError(fmt.Sprintf("无效的URL格式 %v: %v", PocInfo.Target, err))
return
}
// 创建基础HTTP请求
req, err := http.NewRequest("GET", PocInfo.Target, nil)
if err != nil {
Common.LogError(fmt.Sprintf("初始化请求失败 %v: %v", PocInfo.Target, err))
return
}
// 设置请求头
req.Header.Set("User-agent", Common.UserAgent)
req.Header.Set("Accept", Common.Accept)
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
if Common.Cookie != "" {
req.Header.Set("Cookie", Common.Cookie)
}
// 根据名称筛选POC并执行
pocs := filterPoc(PocInfo.PocName)
Common.LogDebug(fmt.Sprintf("筛选到的POC数量: %d", len(pocs)))
lib.CheckMultiPoc(req, pocs, Common.PocNum)
}
// initpoc 初始化POC加载
func initpoc() {
Common.LogDebug("开始初始化POC")
if Common.PocPath == "" {
Common.LogDebug("从内置目录加载POC")
// 从嵌入的POC目录加载
entries, err := Pocs.ReadDir("pocs")
if err != nil {
Common.LogError(fmt.Sprintf("加载内置POC失败: %v", err))
return
}
// 加载YAML格式的POC文件
for _, entry := range entries {
filename := entry.Name()
if strings.HasSuffix(filename, ".yaml") || strings.HasSuffix(filename, ".yml") {
if poc, err := lib.LoadPoc(filename, Pocs); err == nil && poc != nil {
AllPocs = append(AllPocs, poc)
} else if err != nil {
}
}
}
Common.LogDebug(fmt.Sprintf("内置POC加载完成,共加载 %d 个", len(AllPocs)))
} else {
// 从指定目录加载POC
Common.LogSuccess(fmt.Sprintf("从目录加载POC: %s", Common.PocPath))
err := filepath.Walk(Common.PocPath, func(path string, info os.FileInfo, err error) error {
if err != nil || info == nil {
return err
}
if !info.IsDir() && (strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")) {
if poc, err := lib.LoadPocbyPath(path); err == nil && poc != nil {
AllPocs = append(AllPocs, poc)
} else if err != nil {
}
}
return nil
})
if err != nil {
Common.LogError(fmt.Sprintf("加载外部POC失败: %v", err))
}
Common.LogDebug(fmt.Sprintf("外部POC加载完成,共加载 %d 个", len(AllPocs)))
}
}
// filterPoc 根据POC名称筛选
func filterPoc(pocname string) []*lib.Poc {
Common.LogDebug(fmt.Sprintf("开始筛选POC,筛选条件: %s", pocname))
if pocname == "" {
Common.LogDebug(fmt.Sprintf("未指定POC名称,返回所有POC: %d 个", len(AllPocs)))
return AllPocs
}
var matchedPocs []*lib.Poc
for _, poc := range AllPocs {
if strings.Contains(poc.Name, pocname) {
matchedPocs = append(matchedPocs, poc)
}
}
Common.LogDebug(fmt.Sprintf("POC筛选完成,匹配到 %d 个", len(matchedPocs)))
return matchedPocs
}