diff --git a/Common/Config.go b/Common/Config.go index 6248286..a635796 100644 --- a/Common/Config.go +++ b/Common/Config.go @@ -847,7 +847,10 @@ var PortMap = map[int][]string{ var Passwords = []string{"123456", "admin", "admin123", "root", "", "pass123", "pass@123", "password", "Password", "P@ssword123", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456", "1q2w3e", "Charge123", "Aa123456789", "elastic123"} -var Outputfile = "result.txt" +var ( + Outputfile string // 输出文件路径 + OutputFormat string // 输出格式 +) // 添加一个全局的进度条变量 var ProgressBar *progressbar.ProgressBar diff --git a/Common/Flag.go b/Common/Flag.go index d615d09..b96db28 100644 --- a/Common/Flag.go +++ b/Common/Flag.go @@ -160,6 +160,7 @@ func Flag(Info *HostInfo) { // 输出配置 flag.StringVar(&Outputfile, "o", "result.txt", "指定结果输出文件名") + flag.StringVar(&OutputFormat, "f", "txt", "指定输出格式 (txt/json/csv)") flag.BoolVar(&DisableSave, "no", false, "禁止保存扫描结果") flag.BoolVar(&Silent, "silent", false, "启用静默扫描模式(减少屏幕输出)") flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示") diff --git a/Common/Log.go b/Common/Log.go index 6259bcd..47ab09f 100644 --- a/Common/Log.go +++ b/Common/Log.go @@ -1,12 +1,9 @@ package Common import ( - "bufio" - "encoding/json" "fmt" "io" "log" - "os" "path/filepath" "runtime" "strings" @@ -16,118 +13,123 @@ import ( "github.com/fatih/color" ) +// 全局变量定义 var ( - // 全局变量 + // 扫描状态管理器,记录最近一次成功和错误的时间 status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()} - // 扫描计数 - Num int64 // 总任务数 - End int64 // 已完成任务数 - - // 文件写入器 - fileWriter *bufferedFileWriter + // Num 表示待处理的总任务数量 + Num int64 + // End 表示已经完成的任务数量 + End int64 ) -// ScanStatus 记录扫描状态 +// ScanStatus 用于记录和管理扫描状态的结构体 type ScanStatus struct { - mu sync.RWMutex - total int64 - completed int64 - lastSuccess time.Time - lastError time.Time + mu sync.RWMutex // 读写互斥锁,用于保护并发访问 + total int64 // 总任务数 + completed int64 // 已完成任务数 + lastSuccess time.Time // 最近一次成功的时间 + lastError time.Time // 最近一次错误的时间 } -// LogEntry 日志条目 +// LogEntry 定义单条日志的结构 type LogEntry struct { - Level string // "ERROR", "INFO", "SUCCESS", "DEBUG" - Time time.Time - Content string + Level string // 日志级别: ERROR/INFO/SUCCESS/DEBUG + Time time.Time // 日志时间 + Content string // 日志内容 } -// LogLevel 定义日志等级常量 +// 定义系统支持的日志级别常量 const ( - LogLevelAll = "ALL" // 输出所有日志 - LogLevelError = "ERROR" // 错误日志 - LogLevelInfo = "INFO" // 信息日志 - LogLevelSuccess = "SUCCESS" // 成功日志 - LogLevelDebug = "DEBUG" // 调试日志 + 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, -} - -// JsonOutput JSON输出的结构体 -type JsonOutput struct { - Level string `json:"level"` - Timestamp time.Time `json:"timestamp"` - Message string `json:"message"` + LogLevelError: color.FgRed, // 错误日志显示红色 + LogLevelInfo: color.FgYellow, // 信息日志显示黄色 + LogLevelSuccess: color.FgGreen, // 成功日志显示绿色 + LogLevelDebug: color.FgBlue, // 调试日志显示蓝色 } +// InitLogger 初始化日志系统 func InitLogger() { + // 禁用标准日志输出 log.SetOutput(io.Discard) - if !DisableSave { - fileWriter = newBufferedFileWriter() - } } -// formatLogMessage 格式化日志消息 +// 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) } -// 修改 printLog 函数 +// printLog 根据日志级别打印日志 func printLog(entry *LogEntry) { - // 默认情况(LogLevelInfo)下打印 INFO、SUCCESS、ERROR - if LogLevel == LogLevelInfo { + // 根据当前设置的日志级别过滤日志 + switch LogLevel { + case LogLevelInfo: + // INFO模式下只打印 INFO、SUCCESS、ERROR 级别的日志 if entry.Level != LogLevelInfo && entry.Level != LogLevelSuccess && entry.Level != LogLevelError { return } - } else if LogLevel == LogLevelDebug || LogLevel == LogLevelAll { - // Debug或ALL模式打印所有日志 - } else if entry.Level != LogLevel { - // 其他情况只打印指定等级的日志 - return + case LogLevelDebug, LogLevelAll: + // Debug或ALL模式下打印所有日志 + default: + // 其他模式下只打印指定级别的日志 + if entry.Level != LogLevel { + return + } } OutputMutex.Lock() defer OutputMutex.Unlock() - // 确保清除当前进度条 - if ProgressBar != nil { - ProgressBar.Clear() - time.Sleep(10 * time.Millisecond) - } + // 处理进度条 + clearAndWaitProgress() - // 打印日志 + // 打印日志消息 logMsg := formatLogMessage(entry) if !NoColor { + // 使用彩色输出 if colorAttr, ok := logColors[entry.Level]; ok { color.New(colorAttr).Println(logMsg) } else { fmt.Println(logMsg) } } else { + // 普通输出 fmt.Println(logMsg) } - // 确保日志完全输出 + // 等待日志输出完成 time.Sleep(50 * time.Millisecond) - // 重新渲染进度条 + // 重新显示进度条 if ProgressBar != nil { ProgressBar.RenderBlank() } } +// clearAndWaitProgress 清除进度条并等待 +func clearAndWaitProgress() { + if ProgressBar != nil { + ProgressBar.Clear() + time.Sleep(10 * time.Millisecond) + } +} + +// LogError 记录错误日志,自动包含文件名和行号信息 func LogError(errMsg string) { + // 获取调用者的文件名和行号 _, file, line, ok := runtime.Caller(1) if !ok { file = "unknown" @@ -137,182 +139,60 @@ func LogError(errMsg string) { errorMsg := fmt.Sprintf("%s:%d - %s", file, line, errMsg) - if ProgressBar != nil { - ProgressBar.Clear() - } - entry := &LogEntry{ Level: LogLevelError, Time: time.Now(), Content: errorMsg, } - printLog(entry) - if fileWriter != nil { - fileWriter.write(entry) + handleLog(entry) +} + +// handleLog 统一处理日志的输出 +func handleLog(entry *LogEntry) { + if ProgressBar != nil { + ProgressBar.Clear() } + printLog(entry) + if ProgressBar != nil { ProgressBar.RenderBlank() } } +// LogInfo 记录信息日志 func LogInfo(msg string) { - if ProgressBar != nil { - ProgressBar.Clear() - } - - entry := &LogEntry{ + handleLog(&LogEntry{ Level: LogLevelInfo, Time: time.Now(), Content: msg, - } - - printLog(entry) - if fileWriter != nil { - fileWriter.write(entry) - } - - if ProgressBar != nil { - ProgressBar.RenderBlank() - } + }) } +// LogSuccess 记录成功日志,并更新最后成功时间 func LogSuccess(result string) { - if ProgressBar != nil { - ProgressBar.Clear() - } - entry := &LogEntry{ Level: LogLevelSuccess, Time: time.Now(), Content: result, } - printLog(entry) - if fileWriter != nil { - fileWriter.write(entry) - } + handleLog(entry) + // 更新最后成功时间 status.mu.Lock() status.lastSuccess = time.Now() status.mu.Unlock() - - if ProgressBar != nil { - ProgressBar.RenderBlank() - } } +// LogDebug 记录调试日志 func LogDebug(msg string) { - if ProgressBar != nil { - ProgressBar.Clear() - } - - entry := &LogEntry{ + handleLog(&LogEntry{ Level: LogLevelDebug, Time: time.Now(), Content: msg, - } - - printLog(entry) - if fileWriter != nil { - fileWriter.write(entry) - } - - if ProgressBar != nil { - ProgressBar.RenderBlank() - } -} - -func newBufferedFileWriter() *bufferedFileWriter { - file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - fmt.Printf("[ERROR] 打开输出文件失败 %s: %v\n", Outputfile, err) - return nil - } - - writer := bufio.NewWriter(file) - return &bufferedFileWriter{ - file: file, - writer: writer, - jsonEnc: json.NewEncoder(writer), - } -} - -type bufferedFileWriter struct { - file *os.File - writer *bufio.Writer - jsonEnc *json.Encoder - mu sync.Mutex // 添加互斥锁保护写入 -} - -func (w *bufferedFileWriter) write(entry *LogEntry) { - if w == nil { - return - } - - w.mu.Lock() - defer w.mu.Unlock() - - var err error - if JsonFormat { - output := JsonOutput{ - Level: entry.Level, - Timestamp: entry.Time, - Message: entry.Content, - } - err = w.jsonEnc.Encode(output) - } else { - logMsg := formatLogMessage(entry) + "\n" - _, err = w.writer.WriteString(logMsg) - } - - if err != nil { - fmt.Printf("[ERROR] 写入日志失败: %v\n", err) - // 尝试重新打开文件 - if err := w.reopen(); err != nil { - fmt.Printf("[ERROR] 重新打开文件失败: %v\n", err) - return - } - return - } - - // 每隔一定数量的写入才进行一次Flush - if err := w.writer.Flush(); err != nil { - fmt.Printf("[ERROR] 刷新缓冲区失败: %v\n", err) - if err := w.reopen(); err != nil { - fmt.Printf("[ERROR] 重新打开文件失败: %v\n", err) - } - } -} - -func (w *bufferedFileWriter) reopen() error { - if w.file != nil { - w.file.Close() - } - - file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - return err - } - - w.file = file - w.writer = bufio.NewWriter(file) - w.jsonEnc = json.NewEncoder(w.writer) - return nil -} - -func (w *bufferedFileWriter) close() { - if w != nil { - w.writer.Flush() - w.file.Close() - } -} - -func CloseLogger() { - if fileWriter != nil { - fileWriter.close() - } + }) } // CheckErrs 检查是否为需要重试的错误 diff --git a/Common/Output.go b/Common/Output.go new file mode 100644 index 0000000..be20737 --- /dev/null +++ b/Common/Output.go @@ -0,0 +1,247 @@ +// output.go + +package Common + +import ( + "encoding/csv" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "sync" + "time" +) + +// 全局输出管理器 +var ResultOutput *OutputManager + +// OutputManager 输出管理器结构体 +type OutputManager struct { + mu sync.Mutex + outputPath string + outputFormat string + file *os.File + csvWriter *csv.Writer + jsonEncoder *json.Encoder + isInitialized bool +} + +// ResultType 定义结果类型 +type ResultType string + +const ( + HOST ResultType = "HOST" // 主机存活 + PORT ResultType = "PORT" // 端口开放 + SERVICE ResultType = "SERVICE" // 服务识别 + VULN ResultType = "VULN" // 漏洞发现 +) + +// ScanResult 扫描结果结构 +type ScanResult struct { + Time time.Time `json:"time"` // 发现时间 + Type ResultType `json:"type"` // 结果类型 + Target string `json:"target"` // 目标(IP/域名/URL) + Status string `json:"status"` // 状态描述 + Details map[string]interface{} `json:"details"` // 详细信息 +} + +// InitOutput 初始化输出系统 +func InitOutput() error { + LogDebug("开始初始化输出系统") + + // 验证输出格式 + switch OutputFormat { + case "txt", "json", "csv": + // 有效的格式 + default: + return fmt.Errorf("不支持的输出格式: %s", OutputFormat) + } + + // 验证输出路径 + if Outputfile == "" { + return fmt.Errorf("输出文件路径不能为空") + } + + dir := filepath.Dir(Outputfile) + if err := os.MkdirAll(dir, 0755); err != nil { + LogDebug(fmt.Sprintf("创建输出目录失败: %v", err)) + return fmt.Errorf("创建输出目录失败: %v", err) + } + + manager := &OutputManager{ + outputPath: Outputfile, + outputFormat: OutputFormat, + } + + if err := manager.initialize(); err != nil { + LogDebug(fmt.Sprintf("初始化输出管理器失败: %v", err)) + return fmt.Errorf("初始化输出管理器失败: %v", err) + } + + ResultOutput = manager + LogDebug("输出系统初始化完成") + return nil +} + +func (om *OutputManager) initialize() error { + om.mu.Lock() + defer om.mu.Unlock() + + if om.isInitialized { + LogDebug("输出管理器已经初始化,跳过") + return nil + } + + LogDebug(fmt.Sprintf("正在打开输出文件: %s", om.outputPath)) + file, err := os.OpenFile(om.outputPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + LogDebug(fmt.Sprintf("打开输出文件失败: %v", err)) + return fmt.Errorf("打开输出文件失败: %v", err) + } + om.file = file + + switch om.outputFormat { + case "csv": + LogDebug("初始化CSV写入器") + om.csvWriter = csv.NewWriter(file) + headers := []string{"Time", "Type", "Target", "Status", "Details"} + if err := om.csvWriter.Write(headers); err != nil { + LogDebug(fmt.Sprintf("写入CSV头失败: %v", err)) + file.Close() + return fmt.Errorf("写入CSV头失败: %v", err) + } + om.csvWriter.Flush() + case "json": + LogDebug("初始化JSON编码器") + om.jsonEncoder = json.NewEncoder(file) + om.jsonEncoder.SetIndent("", " ") + case "txt": + LogDebug("初始化文本输出") + default: + LogDebug(fmt.Sprintf("不支持的输出格式: %s", om.outputFormat)) + } + + om.isInitialized = true + LogDebug("输出管理器初始化完成") + return nil +} + +// SaveResult 保存扫描结果 +func SaveResult(result *ScanResult) error { + if ResultOutput == nil { + LogDebug("输出系统未初始化") + return fmt.Errorf("输出系统未初始化") + } + + LogDebug(fmt.Sprintf("正在保存结果 - 类型: %s, 目标: %s", result.Type, result.Target)) + return ResultOutput.saveResult(result) +} + +func (om *OutputManager) saveResult(result *ScanResult) error { + om.mu.Lock() + defer om.mu.Unlock() + + if !om.isInitialized { + LogDebug("输出管理器未初始化") + return fmt.Errorf("输出管理器未初始化") + } + + var err error + switch om.outputFormat { + case "txt": + err = om.writeTxt(result) + case "json": + err = om.writeJson(result) + case "csv": + err = om.writeCsv(result) + default: + LogDebug(fmt.Sprintf("不支持的输出格式: %s", om.outputFormat)) + return fmt.Errorf("不支持的输出格式: %s", om.outputFormat) + } + + if err != nil { + LogDebug(fmt.Sprintf("保存结果失败: %v", err)) + } else { + LogDebug(fmt.Sprintf("成功保存结果 - 类型: %s, 目标: %s", result.Type, result.Target)) + } + return err +} + +func (om *OutputManager) writeTxt(result *ScanResult) error { + // 格式化 Details 为键值对字符串 + var details string + if len(result.Details) > 0 { + pairs := make([]string, 0, len(result.Details)) + for k, v := range result.Details { + pairs = append(pairs, fmt.Sprintf("%s=%v", k, v)) + } + details = strings.Join(pairs, ", ") + } + + txt := fmt.Sprintf("[%s] [%s] Target: %s, Status: %s, Details: {%s}\n", + result.Time.Format("2006-01-02 15:04:05"), + result.Type, + result.Target, + result.Status, + details, + ) + _, err := om.file.WriteString(txt) + return err +} + +func (om *OutputManager) writeJson(result *ScanResult) error { + return om.jsonEncoder.Encode(result) +} + +func (om *OutputManager) writeCsv(result *ScanResult) error { + details, err := json.Marshal(result.Details) + if err != nil { + details = []byte("{}") + } + + record := []string{ + result.Time.Format("2006-01-02 15:04:05"), + string(result.Type), + result.Target, + result.Status, + string(details), + } + + if err := om.csvWriter.Write(record); err != nil { + return err + } + om.csvWriter.Flush() + return om.csvWriter.Error() +} + +// CloseOutput 关闭输出系统 +func CloseOutput() error { + if ResultOutput == nil { + LogDebug("输出系统未初始化,无需关闭") + return nil + } + + LogDebug("正在关闭输出系统") + ResultOutput.mu.Lock() + defer ResultOutput.mu.Unlock() + + if !ResultOutput.isInitialized { + LogDebug("输出管理器未初始化,无需关闭") + return nil + } + + if ResultOutput.csvWriter != nil { + LogDebug("刷新CSV写入器缓冲区") + ResultOutput.csvWriter.Flush() + } + + if err := ResultOutput.file.Close(); err != nil { + LogDebug(fmt.Sprintf("关闭文件失败: %v", err)) + return fmt.Errorf("关闭文件失败: %v", err) + } + + ResultOutput.isInitialized = false + LogDebug("输出系统已关闭") + return nil +} diff --git a/Core/ICMP.go b/Core/ICMP.go index 18585e8..3cfe3bd 100644 --- a/Core/ICMP.go +++ b/Core/ICMP.go @@ -45,22 +45,33 @@ func CheckLive(hostslist []string, Ping bool) []string { return AliveHosts } -// handleAliveHosts 处理存活主机信息 func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) { for ip := range chanHosts { if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) { ExistHosts[ip] = struct{}{} + AliveHosts = append(AliveHosts, ip) - // 输出存活信息 - if !Common.Silent { - protocol := "ICMP" - if isPing { - protocol = "PING" - } - Common.LogSuccess(fmt.Sprintf("目标 %-15s 存活 (%s)", ip, protocol)) + // 使用Output系统保存存活主机信息 + protocol := "ICMP" + if isPing { + protocol = "PING" } - AliveHosts = append(AliveHosts, ip) + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.HOST, + Target: ip, + Status: "alive", + Details: map[string]interface{}{ + "protocol": protocol, + }, + } + Common.SaveResult(result) + + // 保留原有的控制台输出 + if !Common.Silent { + Common.LogSuccess(fmt.Sprintf("目标 %-15s 存活 (%s)", ip, protocol)) + } } livewg.Done() } diff --git a/Core/PortScan.go b/Core/PortScan.go index 79f4b6b..889a239 100644 --- a/Core/PortScan.go +++ b/Core/PortScan.go @@ -110,18 +110,31 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W address := fmt.Sprintf("%s:%d", addr.ip, addr.port) Common.LogSuccess(fmt.Sprintf("端口开放 %s", address)) + // 保存端口开放信息 + portResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.PORT, + Target: addr.ip, + Status: "open", + Details: map[string]interface{}{ + "port": addr.port, + }, + } + Common.SaveResult(portResult) + // 创建扫描结果 result := ScanResult{ Address: addr.ip, Port: addr.port, } - // 只在未跳过指纹识别时进行服务识别 + // 服务识别 if !Common.SkipFingerprint && conn != nil { scanner := NewPortInfoScanner(addr.ip, addr.port, conn, time.Duration(timeout)*time.Second) if serviceInfo, err := scanner.Identify(); err == nil { result.Service = serviceInfo + // 构造日志消息 var logMsg strings.Builder logMsg.WriteString(fmt.Sprintf("服务识别 %s => ", address)) @@ -133,20 +146,42 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W logMsg.WriteString(fmt.Sprintf(" 版本:%s", serviceInfo.Version)) } + // 构造服务详情 + details := map[string]interface{}{ + "port": addr.port, + "service": serviceInfo.Name, + } + + if serviceInfo.Version != "" { + details["version"] = serviceInfo.Version + } if v, ok := serviceInfo.Extras["vendor_product"]; ok && v != "" { + details["product"] = v logMsg.WriteString(fmt.Sprintf(" 产品:%s", v)) } if v, ok := serviceInfo.Extras["os"]; ok && v != "" { + details["os"] = v logMsg.WriteString(fmt.Sprintf(" 系统:%s", v)) } if v, ok := serviceInfo.Extras["info"]; ok && v != "" { + details["info"] = v logMsg.WriteString(fmt.Sprintf(" 信息:%s", v)) } - if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 { + details["banner"] = strings.TrimSpace(serviceInfo.Banner) logMsg.WriteString(fmt.Sprintf(" Banner:[%s]", strings.TrimSpace(serviceInfo.Banner))) } + // 保存服务识别结果 + serviceResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.SERVICE, + Target: addr.ip, + Status: "identified", + Details: details, + } + Common.SaveResult(serviceResult) + Common.LogSuccess(logMsg.String()) } } @@ -198,164 +233,3 @@ func excludeNoPorts(ports []int) []int { return newPorts } - -//func SynScan(ip string, port int, timeout int64) (bool, error) { -// ifName := getInterfaceName() -// -// sendConn, err := net.ListenPacket("ip4:tcp", "0.0.0.0") -// if err != nil { -// return false, fmt.Errorf("发送套接字错误: %v", err) -// } -// defer sendConn.Close() -// -// rawConn, err := ipv4.NewRawConn(sendConn) -// if err != nil { -// return false, fmt.Errorf("原始连接错误: %v", err) -// } -// -// dstIP := net.ParseIP(ip) -// if dstIP == nil { -// 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) -// } -// -// var found bool -// for _, iface := range ifaces { -// handle, err = pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever) -// if err == nil { -// found = true -// break -// } -// } -// -// if !found { -// return false, fmt.Errorf("未找到可用网络接口") -// } -// } -// defer handle.Close() -// -// 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) -// } -// -// // TCP头部设置保持不变 -// tcpHeader := &ipv4.Header{ -// Version: 4, -// Len: 20, -// TotalLen: 40, -// TTL: 64, -// Protocol: 6, -// Dst: dstIP, -// } -// -// // SYN包构造保持不变 -// synPacket := make([]byte, 20) -// binary.BigEndian.PutUint16(synPacket[0:2], uint16(srcPort)) -// binary.BigEndian.PutUint16(synPacket[2:4], uint16(port)) -// binary.BigEndian.PutUint32(synPacket[4:8], uint32(1)) -// binary.BigEndian.PutUint32(synPacket[8:12], uint32(0)) -// synPacket[12] = 0x50 -// synPacket[13] = 0x02 -// binary.BigEndian.PutUint16(synPacket[14:16], uint16(8192)) -// binary.BigEndian.PutUint16(synPacket[16:18], uint16(0)) -// binary.BigEndian.PutUint16(synPacket[18:20], uint16(0)) -// -// checksum := calculateTCPChecksum(synPacket, tcpHeader.Src, tcpHeader.Dst) -// binary.BigEndian.PutUint16(synPacket[16:18], checksum) -// -// if err := rawConn.WriteTo(tcpHeader, synPacket, nil); err != nil { -// return false, fmt.Errorf("SYN包发送错误: %v", err) -// } -// -// packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) -// packetSource.DecodeOptions.Lazy = true -// packetSource.NoCopy = true -// -// timeoutChan := time.After(time.Duration(timeout) * time.Second) -// -// for { -// select { -// case packet := <-packetSource.Packets(): -// tcpLayer := packet.Layer(layers.LayerTypeTCP) -// if tcpLayer == nil { -// continue -// } -// -// tcp, ok := tcpLayer.(*layers.TCP) -// if !ok { -// continue -// } -// -// if tcp.SYN && tcp.ACK { -// return true, nil -// } -// -// if tcp.RST { -// return false, nil -// } -// -// case <-timeoutChan: -// return false, nil -// } -// } -//} -// -//// calculateTCPChecksum 计算TCP校验和 -//func calculateTCPChecksum(tcpHeader []byte, srcIP, dstIP net.IP) uint16 { -// // 创建伪首部 -// pseudoHeader := make([]byte, 12) -// copy(pseudoHeader[0:4], srcIP.To4()) -// copy(pseudoHeader[4:8], dstIP.To4()) -// pseudoHeader[8] = 0 -// pseudoHeader[9] = 6 // TCP协议号 -// pseudoHeader[10] = byte(len(tcpHeader) >> 8) -// pseudoHeader[11] = byte(len(tcpHeader)) -// -// // 计算校验和 -// var sum uint32 -// -// // 计算伪首部的校验和 -// for i := 0; i < len(pseudoHeader)-1; i += 2 { -// sum += uint32(pseudoHeader[i])<<8 | uint32(pseudoHeader[i+1]) -// } -// -// // 计算TCP头的校验和 -// for i := 0; i < len(tcpHeader)-1; i += 2 { -// sum += uint32(tcpHeader[i])<<8 | uint32(tcpHeader[i+1]) -// } -// -// // 如果长度为奇数,处理最后一个字节 -// if len(tcpHeader)%2 == 1 { -// sum += uint32(tcpHeader[len(tcpHeader)-1]) << 8 -// } -// -// // 将高16位加到低16位 -// for sum > 0xffff { -// sum = (sum >> 16) + (sum & 0xffff) -// } -// -// // 取反 -// return ^uint16(sum) -//} -// -//// 获取系统对应的接口名 -//func getInterfaceName() string { -// switch runtime.GOOS { -// case "windows": -// return "\\Device\\NPF_Loopback" -// case "linux": -// return "lo" -// case "darwin": -// return "lo0" -// default: -// return "lo" -// } -//} diff --git a/Plugins/ActiveMQ.go b/Plugins/ActiveMQ.go index 2460fa3..3e3a8b2 100644 --- a/Plugins/ActiveMQ.go +++ b/Plugins/ActiveMQ.go @@ -14,8 +14,9 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug("尝试默认账户 admin:admin") // 首先测试默认账户 @@ -26,13 +27,29 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) { flag, err := ActiveMQConn(info, "admin", "admin") if flag { - Common.LogSuccess(fmt.Sprintf("ActiveMQ服务 %v:%v 成功爆破 用户名: admin 密码: admin", - info.Host, info.Ports)) + successMsg := fmt.Sprintf("ActiveMQ服务 %s 成功爆破 用户名: admin 密码: admin", target) + Common.LogSuccess(successMsg) + + // 保存结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "activemq", + "username": "admin", + "password": "admin", + "type": "weak-password", + }, + } + Common.SaveResult(result) return nil } if err != nil { - Common.LogError(fmt.Sprintf("ActiveMQ服务 %v:%v 默认账户尝试失败: %v", - info.Host, info.Ports, err)) + errMsg := fmt.Sprintf("ActiveMQ服务 %s 默认账户尝试失败: %v", target, err) + Common.LogError(errMsg) if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { @@ -46,8 +63,7 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) { totalUsers := len(Common.Userdict["activemq"]) totalPass := len(Common.Passwords) - Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", - totalUsers, totalPass)) + Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) tried := 0 total := totalUsers * totalPass @@ -65,7 +81,6 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行连接测试 done := make(chan struct { success bool err error @@ -82,14 +97,29 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success { - Common.LogSuccess(fmt.Sprintf("ActiveMQ服务 %v:%v 成功爆破 用户名: %v 密码: %v", - info.Host, info.Ports, user, pass)) + successMsg := fmt.Sprintf("ActiveMQ服务 %s 成功爆破 用户名: %v 密码: %v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "activemq", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): @@ -97,9 +127,8 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) { } if err != nil { - errlog := fmt.Sprintf("ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + errMsg := fmt.Sprintf("ActiveMQ服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", target, user, pass, err) + Common.LogError(errMsg) if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { @@ -149,14 +178,10 @@ func ActiveMQConn(info *Common.HostInfo, user string, pass string) (bool, error) response := string(respBuf[:n]) if strings.Contains(response, "CONNECTED") { - result := fmt.Sprintf("ActiveMQ服务 %v:%v 爆破成功 用户名: %v 密码: %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(result) return true, nil } - if strings.Contains(response, "Authentication failed") || - strings.Contains(response, "ERROR") { + if strings.Contains(response, "Authentication failed") || strings.Contains(response, "ERROR") { return false, fmt.Errorf("认证失败") } diff --git a/Plugins/Cassandra.go b/Plugins/Cassandra.go index 189f39d..7a8de35 100644 --- a/Plugins/Cassandra.go +++ b/Plugins/Cassandra.go @@ -14,9 +14,10 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) { return } + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) maxRetries := Common.MaxRetries - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug("尝试无认证访问...") // 首先测试无认证访问 @@ -27,8 +28,24 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) { flag, err := CassandraConn(info, "", "") if flag && err == nil { - Common.LogSuccess(fmt.Sprintf("Cassandra服务 %v:%v 无认证访问成功", - info.Host, info.Ports)) + successMsg := fmt.Sprintf("Cassandra服务 %s 无认证访问成功", target) + Common.LogSuccess(successMsg) + + // 保存无认证访问结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "cassandra", + "auth_type": "anonymous", + "type": "unauthorized-access", + "description": "数据库允许无认证访问", + }, + } + Common.SaveResult(result) return err } if err != nil && Common.CheckErrs(err) != nil { @@ -54,13 +71,11 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) { pass = strings.Replace(pass, "{user}", user, -1) Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass)) - // 重试循环 for retryCount := 0; retryCount < maxRetries; retryCount++ { if retryCount > 0 { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行连接 done := make(chan struct { success bool err error @@ -77,37 +92,47 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { - successLog := fmt.Sprintf("Cassandra服务 %v:%v 爆破成功 用户名: %v 密码: %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(successLog) + successMsg := fmt.Sprintf("Cassandra服务 %s 爆破成功 用户名: %v 密码: %v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存爆破成功结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "cassandra", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("Cassandra服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", target, user, pass, err) Common.LogError(errlog) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - - break // 如果不需要重试,跳出重试循环 + break } } } @@ -116,6 +141,7 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) { return tmperr } +// CassandraConn 清理后的连接测试函数 func CassandraConn(info *Common.HostInfo, user string, pass string) (bool, error) { host, port := info.Host, info.Ports timeout := time.Duration(Common.Timeout) * time.Second @@ -123,7 +149,7 @@ func CassandraConn(info *Common.HostInfo, user string, pass string) (bool, error cluster := gocql.NewCluster(host) cluster.Port, _ = strconv.Atoi(port) cluster.Timeout = timeout - cluster.ProtoVersion = 4 // 指定协议版本 + cluster.ProtoVersion = 4 cluster.Consistency = gocql.One if user != "" || pass != "" { @@ -133,7 +159,6 @@ func CassandraConn(info *Common.HostInfo, user string, pass string) (bool, error } } - // 增加重试机制 cluster.RetryPolicy = &gocql.SimpleRetryPolicy{NumRetries: 3} session, err := cluster.CreateSession() @@ -142,7 +167,6 @@ func CassandraConn(info *Common.HostInfo, user string, pass string) (bool, error } defer session.Close() - // 使用更简单的查询测试连接 var version string if err := session.Query("SELECT peer FROM system.peers").Scan(&version); err != nil { if err := session.Query("SELECT now() FROM system.local").Scan(&version); err != nil { @@ -150,13 +174,5 @@ func CassandraConn(info *Common.HostInfo, user string, pass string) (bool, error } } - result := fmt.Sprintf("Cassandra服务 %v:%v ", host, port) - if user != "" { - result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) - } else { - result += "无需认证即可访问" - } - Common.LogSuccess(result) - return true, nil } diff --git a/Plugins/Elasticsearch.go b/Plugins/Elasticsearch.go index bff0c8e..5d1dddc 100644 --- a/Plugins/Elasticsearch.go +++ b/Plugins/Elasticsearch.go @@ -16,8 +16,9 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug("尝试无认证访问...") // 首先测试无认证访问 @@ -27,8 +28,22 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) { } flag, err := ElasticConn(info, "", "") if flag && err == nil { - Common.LogSuccess(fmt.Sprintf("Elasticsearch服务 %v:%v 无需认证", - info.Host, info.Ports)) + successMsg := fmt.Sprintf("Elasticsearch服务 %s 无需认证", target) + Common.LogSuccess(successMsg) + + // 保存无认证访问结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "elasticsearch", + "type": "unauthorized-access", + }, + } + Common.SaveResult(result) return err } if err != nil && Common.CheckErrs(err) != nil { @@ -61,7 +76,6 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行连接尝试 done := make(chan struct { success bool err error @@ -78,36 +92,49 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { - Common.LogSuccess(fmt.Sprintf("Elasticsearch服务 %v:%v 爆破成功 用户名: %v 密码: %v", - info.Host, info.Ports, user, pass)) + successMsg := fmt.Sprintf("Elasticsearch服务 %s 爆破成功 用户名: %v 密码: %v", + target, user, pass) + Common.LogSuccess(successMsg) + + // 保存弱密码结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "elasticsearch", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("Elasticsearch服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", + target, user, pass, err) Common.LogError(errlog) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - - break // 如果不需要重试,跳出重试循环 + break } } } @@ -121,7 +148,6 @@ func ElasticConn(info *Common.HostInfo, user string, pass string) (bool, error) host, port := info.Host, info.Ports timeout := time.Duration(Common.Timeout) * time.Second - // 构造请求客户端 client := &http.Client{ Timeout: timeout, Transport: &http.Transport{ @@ -129,39 +155,22 @@ func ElasticConn(info *Common.HostInfo, user string, pass string) (bool, error) }, } - // 构造基础URL baseURL := fmt.Sprintf("http://%s:%s", host, port) - - // 创建请求 req, err := http.NewRequest("GET", baseURL+"/_cat/indices", nil) if err != nil { return false, err } - // 如果提供了认证信息,添加Basic认证头 if user != "" || pass != "" { auth := base64.StdEncoding.EncodeToString([]byte(user + ":" + pass)) req.Header.Add("Authorization", "Basic "+auth) } - // 发送请求 resp, err := client.Do(req) if err != nil { return false, err } defer resp.Body.Close() - // 检查响应状态 - if resp.StatusCode == 200 { - result := fmt.Sprintf("Elasticsearch服务 %v:%v ", host, port) - if user != "" { - result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) - } else { - result += "无需认证即可访问" - } - Common.LogSuccess(result) - return true, nil - } - - return false, fmt.Errorf("认证失败") + return resp.StatusCode == 200, nil } diff --git a/Plugins/FTP.go b/Plugins/FTP.go index 78394f4..75b983d 100644 --- a/Plugins/FTP.go +++ b/Plugins/FTP.go @@ -14,18 +14,36 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug("尝试匿名登录...") - // 先尝试匿名登录 + // 尝试匿名登录 for retryCount := 0; retryCount < maxRetries; retryCount++ { - flag, err := FtpConn(info, "anonymous", "") - if flag && err == nil { + success, dirs, err := FtpConn(info, "anonymous", "") + if success && err == nil { Common.LogSuccess("匿名登录成功!") + + // 保存匿名登录结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "ftp", + "username": "anonymous", + "password": "", + "type": "anonymous-login", + "directories": dirs, + }, + } + Common.SaveResult(result) return nil } - errlog := fmt.Sprintf("ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err) + errlog := fmt.Sprintf("ftp %s %v", target, err) Common.LogError(errlog) break } @@ -37,7 +55,7 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { tried := 0 total := totalUsers * totalPass - // 遍历所有用户名密码组合 + // 遍历用户名密码组合 for _, user := range Common.Userdict["ftp"] { for _, pass := range Common.Passwords { tried++ @@ -52,30 +70,46 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行FTP连接 done := make(chan struct { success bool + dirs []string err error }, 1) go func(user, pass string) { - success, err := FtpConn(info, user, pass) + success, dirs, err := FtpConn(info, user, pass) select { case done <- struct { success bool + dirs []string err error - }{success, err}: + }{success, dirs, err}: default: } }(user, pass) - // 等待结果或超时 select { case result := <-done: if result.success && result.err == nil { - successLog := fmt.Sprintf("FTP %v:%v %v %v", - info.Host, info.Ports, user, pass) + successLog := fmt.Sprintf("FTP服务 %s 成功爆破 用户名: %v 密码: %v", target, user, pass) Common.LogSuccess(successLog) + + // 保存爆破成功结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "ftp", + "username": user, + "password": pass, + "type": "weak-password", + "directories": result.dirs, + }, + } + Common.SaveResult(vulnResult) return nil } lastErr = result.err @@ -83,18 +117,16 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { lastErr = fmt.Errorf("连接超时") } - // 处理错误情况 + // 错误处理 if lastErr != nil { - errlog := fmt.Sprintf("ftp %v:%v %v %v %v", - info.Host, info.Ports, user, pass, lastErr) + errlog := fmt.Sprintf("FTP服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", + target, user, pass, lastErr) Common.LogError(errlog) - // 如果是密码错误,直接尝试下一个组合 if strings.Contains(lastErr.Error(), "Login incorrect") { break } - // 如果是连接数限制,等待后重试 if strings.Contains(lastErr.Error(), "too many connections") { Common.LogDebug("连接数过多,等待5秒...") time.Sleep(5 * time.Second) @@ -112,39 +144,45 @@ func FtpScan(info *Common.HostInfo) (tmperr error) { } // FtpConn 建立FTP连接并尝试登录 -func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err error) { - Host, Port, Username, Password := info.Host, info.Ports, user, pass +func FtpConn(info *Common.HostInfo, user string, pass string) (success bool, directories []string, err error) { + Host, Port := info.Host, info.Ports // 建立FTP连接 conn, err := ftp.DialTimeout(fmt.Sprintf("%v:%v", Host, Port), time.Duration(Common.Timeout)*time.Second) if err != nil { - return false, err + return false, nil, err } - // 确保连接被关闭 defer func() { if conn != nil { - conn.Quit() // 发送QUIT命令关闭连接 + conn.Quit() } }() // 尝试登录 - if err = conn.Login(Username, Password); err != nil { - return false, err + if err = conn.Login(user, pass); err != nil { + return false, nil, err } - // 登录成功,获取目录信息 - result := fmt.Sprintf("ftp %v:%v:%v %v", Host, Port, Username, Password) + // 获取目录信息 dirs, err := conn.List("") if err == nil && len(dirs) > 0 { - // 最多显示前6个目录 + directories = make([]string, 0, min(6, len(dirs))) for i := 0; i < len(dirs) && i < 6; i++ { name := dirs[i].Name if len(name) > 50 { name = name[:50] } - result += "\n [->]" + name + directories = append(directories, name) } } - return true, nil + return true, directories, nil +} + +// min 返回两个整数中的较小值 +func min(a, b int) int { + if a < b { + return a + } + return b } diff --git a/Plugins/FindNet.go b/Plugins/FindNet.go index a982bc4..8e3fc76 100644 --- a/Plugins/FindNet.go +++ b/Plugins/FindNet.go @@ -148,15 +148,7 @@ func read(text []byte, host string) error { name = "" } - // 构建基础结果 - result := fmt.Sprintf("NetInfo 扫描结果") - result += fmt.Sprintf("\n目标主机: %s", host) - if name != "" { - result += fmt.Sprintf("\n主机名: %s", name) - } - result += "\n发现的网络接口:" - - // 用于分类存储地址 + // 用于收集地址信息 var ipv4Addrs []string var ipv6Addrs []string seenAddresses := make(map[string]bool) @@ -184,7 +176,6 @@ func read(text []byte, host string) error { if addr != "" && !seenAddresses[addr] { seenAddresses[addr] = true - // 分类IPv4和IPv6地址 if strings.Contains(addr, ":") { ipv6Addrs = append(ipv6Addrs, addr) } else if net.ParseIP(addr) != nil { @@ -193,22 +184,46 @@ func read(text []byte, host string) error { } } - // 输出IPv4地址 + // 构建详细信息 + details := map[string]interface{}{ + "hostname": name, + "ipv4": ipv4Addrs, + "ipv6": ipv6Addrs, + } + + // 保存扫描结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.SERVICE, + Target: host, + Status: "identified", + Details: details, + } + Common.SaveResult(result) + + // 构建控制台输出 + var output strings.Builder + output.WriteString("NetInfo 扫描结果") + output.WriteString(fmt.Sprintf("\n目标主机: %s", host)) + if name != "" { + output.WriteString(fmt.Sprintf("\n主机名: %s", name)) + } + output.WriteString("\n发现的网络接口:") + if len(ipv4Addrs) > 0 { - result += "\n IPv4地址:" + output.WriteString("\n IPv4地址:") for _, addr := range ipv4Addrs { - result += fmt.Sprintf("\n └─ %s", addr) + output.WriteString(fmt.Sprintf("\n └─ %s", addr)) } } - // 输出IPv6地址 if len(ipv6Addrs) > 0 { - result += "\n IPv6地址:" + output.WriteString("\n IPv6地址:") for _, addr := range ipv6Addrs { - result += fmt.Sprintf("\n └─ %s", addr) + output.WriteString(fmt.Sprintf("\n └─ %s", addr)) } } - Common.LogSuccess(result) + Common.LogSuccess(output.String()) return nil } diff --git a/Plugins/IMAP.go b/Plugins/IMAP.go index 76a824c..533c9f3 100644 --- a/Plugins/IMAP.go +++ b/Plugins/IMAP.go @@ -11,14 +11,16 @@ import ( "time" ) +// IMAPScan 主扫描函数 func IMAPScan(info *Common.HostInfo) (tmperr error) { if Common.DisableBrute { return } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalUsers := len(Common.Userdict["imap"]) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) @@ -26,20 +28,17 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) { tried := 0 total := totalUsers * totalPass - // 遍历所有用户名密码组合 for _, user := range Common.Userdict["imap"] { for _, pass := range Common.Passwords { tried++ pass = strings.Replace(pass, "{user}", user, -1) Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass)) - // 重试循环 for retryCount := 0; retryCount < maxRetries; retryCount++ { if retryCount > 0 { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行IMAP连接 done := make(chan struct { success bool err error @@ -56,23 +55,38 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err - if result.success && err == nil { + if result.success { + successMsg := fmt.Sprintf("IMAP服务 %s 爆破成功 用户名: %v 密码: %v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "imap", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + errMsg := fmt.Sprintf("IMAP服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", target, user, pass, err) + Common.LogError(errMsg) if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { @@ -90,23 +104,22 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) { return tmperr } +// IMAPConn 连接测试函数 func IMAPConn(info *Common.HostInfo, user string, pass string) (bool, error) { host, port := info.Host, info.Ports timeout := time.Duration(Common.Timeout) * time.Second addr := fmt.Sprintf("%s:%s", host, port) - // 首先尝试普通连接 - Common.LogDebug(fmt.Sprintf("尝试普通连接: %s", addr)) + // 尝试普通连接 conn, err := net.DialTimeout("tcp", addr, timeout) if err == nil { - if flag, err := tryIMAPAuth(conn, host, port, user, pass, timeout); err == nil { + if flag, err := tryIMAPAuth(conn, user, pass, timeout); err == nil { return flag, nil } conn.Close() } - // 如果普通连接失败,尝试TLS连接 - Common.LogDebug(fmt.Sprintf("尝试TLS连接: %s", addr)) + // 尝试TLS连接 tlsConfig := &tls.Config{ InsecureSkipVerify: true, } @@ -116,10 +129,11 @@ func IMAPConn(info *Common.HostInfo, user string, pass string) (bool, error) { } defer conn.Close() - return tryIMAPAuth(conn, host, port, user, pass, timeout) + return tryIMAPAuth(conn, user, pass, timeout) } -func tryIMAPAuth(conn net.Conn, host string, port string, user string, pass string, timeout time.Duration) (bool, error) { +// tryIMAPAuth 尝试IMAP认证 +func tryIMAPAuth(conn net.Conn, user string, pass string, timeout time.Duration) (bool, error) { conn.SetDeadline(time.Now().Add(timeout)) reader := bufio.NewReader(conn) @@ -145,9 +159,6 @@ 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", - host, port, user, pass) - Common.LogSuccess(result) return true, nil } diff --git a/Plugins/Kafka.go b/Plugins/Kafka.go index 5f685f6..bd81312 100644 --- a/Plugins/Kafka.go +++ b/Plugins/Kafka.go @@ -14,9 +14,10 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) - // 首先测试无认证访问 + // 尝试无认证访问 Common.LogDebug("尝试无认证访问...") for retryCount := 0; retryCount < maxRetries; retryCount++ { if retryCount > 0 { @@ -24,6 +25,20 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) { } flag, err := KafkaConn(info, "", "") if flag && err == nil { + // 保存无认证访问结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "kafka", + "type": "unauthorized-access", + }, + } + Common.SaveResult(result) + Common.LogSuccess(fmt.Sprintf("Kafka服务 %s 无需认证即可访问", target)) return nil } if err != nil && Common.CheckErrs(err) != nil { @@ -49,13 +64,11 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) { pass = strings.Replace(pass, "{user}", user, -1) Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass)) - // 重试循环 for retryCount := 0; retryCount < maxRetries; retryCount++ { if retryCount > 0 { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行Kafka连接 done := make(chan struct { success bool err error @@ -72,33 +85,44 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { + // 保存爆破成功结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "kafka", + "type": "weak-password", + "username": user, + "password": pass, + }, + } + Common.SaveResult(vulnResult) + Common.LogSuccess(fmt.Sprintf("Kafka服务 %s 爆破成功 用户名: %s 密码: %s", target, user, pass)) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) - - // 检查是否需要重试 + Common.LogError(fmt.Sprintf("Kafka服务 %s 尝试失败 用户名: %s 密码: %s 错误: %v", + target, user, pass, err)) if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } } @@ -132,13 +156,6 @@ 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) - if user != "" { - result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) - } else { - result += "无需认证即可访问" - } - Common.LogSuccess(result) return true, nil } @@ -146,13 +163,6 @@ 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) - if user != "" { - result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) - } else { - result += "无需认证即可访问" - } - Common.LogSuccess(result) return true, nil } diff --git a/Plugins/LDAP.go b/Plugins/LDAP.go index c10608d..dbc18e5 100644 --- a/Plugins/LDAP.go +++ b/Plugins/LDAP.go @@ -14,13 +14,28 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug("尝试匿名访问...") // 首先尝试匿名访问 flag, err := LDAPConn(info, "", "") if flag && err == nil { + // 记录匿名访问成功 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "ldap", + "type": "anonymous-access", + }, + } + Common.SaveResult(result) + Common.LogSuccess(fmt.Sprintf("LDAP服务 %s 匿名访问成功", target)) return err } @@ -44,7 +59,6 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行LDAP连接 done := make(chan struct { success bool err error @@ -61,30 +75,42 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { + // 记录成功爆破的凭据 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "ldap", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) + Common.LogSuccess(fmt.Sprintf("LDAP服务 %s 爆破成功 用户名: %v 密码: %v", target, user, pass)) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("LDAP服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", target, user, pass, err) Common.LogError(errlog) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } break @@ -97,11 +123,8 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) { } func LDAPConn(info *Common.HostInfo, user string, pass string) (bool, error) { - host, port := info.Host, info.Ports + address := fmt.Sprintf("%s:%s", info.Host, info.Ports) timeout := time.Duration(Common.Timeout) * time.Second - address := fmt.Sprintf("%s:%s", host, port) - - Common.LogDebug(fmt.Sprintf("尝试连接: %s", address)) // 配置LDAP连接 l, err := ldap.Dial("tcp", address) @@ -115,11 +138,9 @@ func LDAPConn(info *Common.HostInfo, user string, pass string) (bool, error) { // 尝试绑定 if user != "" { - // 构造DN bindDN := fmt.Sprintf("cn=%s,dc=example,dc=com", user) err = l.Bind(bindDN, pass) } else { - // 匿名绑定 err = l.UnauthenticatedBind("") } @@ -141,14 +162,5 @@ func LDAPConn(info *Common.HostInfo, user string, pass string) (bool, error) { return false, err } - // 记录成功结果 - result := fmt.Sprintf("LDAP服务 %v:%v ", host, port) - if user != "" { - result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) - } else { - result += "匿名访问成功" - } - Common.LogSuccess(result) - return true, nil } diff --git a/Plugins/MS17010.go b/Plugins/MS17010.go index 18646f1..c40234c 100644 --- a/Plugins/MS17010.go +++ b/Plugins/MS17010.go @@ -203,15 +203,31 @@ func MS17010Scan(info *Common.HostInfo) error { return fmt.Errorf("管道响应不完整") } - // 漏洞检测 + // 漏洞检测部分添加 Output if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 { + // 构造基本详情 + details := map[string]interface{}{ + "port": "445", + "vulnerability": "MS17-010", + } if os != "" { + details["os"] = os Common.LogSuccess(fmt.Sprintf("发现漏洞 %s [%s] MS17-010", ip, os)) } else { Common.LogSuccess(fmt.Sprintf("发现漏洞 %s MS17-010", ip)) } - // DOUBLEPULSAR后门检测 + // 保存 MS17-010 漏洞结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: ip, + Status: "vulnerable", + Details: details, + } + Common.SaveResult(result) + + // DOUBLEPULSAR 后门检测 trans2SessionSetupRequest[28] = treeID[0] trans2SessionSetupRequest[29] = treeID[1] trans2SessionSetupRequest[32] = userID[0] @@ -230,14 +246,42 @@ func MS17010Scan(info *Common.HostInfo) error { if reply[34] == 0x51 { Common.LogSuccess(fmt.Sprintf("发现后门 %s DOUBLEPULSAR", ip)) + + // 保存 DOUBLEPULSAR 后门结果 + backdoorResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: ip, + Status: "backdoor", + Details: map[string]interface{}{ + "port": "445", + "type": "DOUBLEPULSAR", + "os": os, + }, + } + Common.SaveResult(backdoorResult) } - // Shellcode利用 + // Shellcode 利用部分保持不变 if Common.Shellcode != "" { defer MS17010EXP(info) } } else if os != "" { Common.LogInfo(fmt.Sprintf("系统信息 %s [%s]", ip, os)) + + // 保存系统信息 + sysResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.SERVICE, + Target: ip, + Status: "identified", + Details: map[string]interface{}{ + "port": "445", + "service": "smb", + "os": os, + }, + } + Common.SaveResult(sysResult) } return nil diff --git a/Plugins/MSSQL.go b/Plugins/MSSQL.go index 726548e..6b23d43 100644 --- a/Plugins/MSSQL.go +++ b/Plugins/MSSQL.go @@ -16,8 +16,9 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalUsers := len(Common.Userdict["mssql"]) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) @@ -61,8 +62,24 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) { case result := <-done: err = result.err if result.success && err == nil { - Common.LogSuccess(fmt.Sprintf("MSSQL %v:%v %v %v", - info.Host, info.Ports, user, pass)) + successMsg := fmt.Sprintf("MSSQL %s %v %v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "mssql", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): @@ -70,20 +87,18 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) { } if err != nil { - errlog := fmt.Sprintf("MSSQL %v:%v %v %v %v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("MSSQL %s %v %v %v", target, user, pass, err) Common.LogError(errlog) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } } @@ -120,8 +135,5 @@ func MssqlConn(info *Common.HostInfo, user string, pass string) (bool, error) { return false, err } - // 连接成功 - result := fmt.Sprintf("MSSQL %v:%v:%v %v", host, port, username, password) - Common.LogSuccess(result) return true, nil } diff --git a/Plugins/Memcached.go b/Plugins/Memcached.go index be144bd..71d988c 100644 --- a/Plugins/Memcached.go +++ b/Plugins/Memcached.go @@ -33,15 +33,27 @@ 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) - Common.LogError(errlog) + Common.LogError(fmt.Sprintf("Memcached %v:%v %v", info.Host, info.Ports, err)) return err } // 检查响应内容 if strings.Contains(string(rev[:n]), "STAT") { - result := fmt.Sprintf("Memcached %s 未授权访问", realhost) - Common.LogSuccess(result) + // 保存结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "memcached", + "type": "unauthorized-access", + "description": "Memcached unauthorized access", + }, + } + Common.SaveResult(result) + Common.LogSuccess(fmt.Sprintf("Memcached %s 未授权访问", realhost)) } return nil diff --git a/Plugins/Modbus.go b/Plugins/Modbus.go index bb80536..3445280 100644 --- a/Plugins/Modbus.go +++ b/Plugins/Modbus.go @@ -41,14 +41,30 @@ func ModbusScan(info *Common.HostInfo) error { // 验证响应 if isValidModbusResponse(response[:n]) { - result := fmt.Sprintf("Modbus服务 %v:%v 无认证访问", host, port) - Common.LogSuccess(result) - - // 尝试读取更多设备信息 + // 获取设备信息 deviceInfo := parseModbusResponse(response[:n]) + + // 保存扫描结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": port, + "service": "modbus", + "type": "unauthorized-access", + "device_id": deviceInfo, + }, + } + Common.SaveResult(result) + + // 控制台输出 + Common.LogSuccess(fmt.Sprintf("Modbus服务 %v:%v 无认证访问", host, port)) if deviceInfo != "" { Common.LogSuccess(fmt.Sprintf("设备信息: %s", deviceInfo)) } + return nil } diff --git a/Plugins/Mongodb.go b/Plugins/Mongodb.go index 27f88af..95d4b56 100644 --- a/Plugins/Mongodb.go +++ b/Plugins/Mongodb.go @@ -13,17 +13,37 @@ func MongodbScan(info *Common.HostInfo) error { return nil } - _, err := MongodbUnauth(info) + target := fmt.Sprintf("%s:%v", info.Host, info.Ports) + isUnauth, err := MongodbUnauth(info) + if err != nil { - errlog := fmt.Sprintf("MongoDB %v:%v %v", info.Host, info.Ports, err) + errlog := fmt.Sprintf("MongoDB %v %v", target, err) Common.LogError(errlog) + } else if isUnauth { + // 记录控制台输出 + Common.LogSuccess(fmt.Sprintf("MongoDB %v 未授权访问", target)) + + // 保存未授权访问结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "mongodb", + "type": "unauthorized-access", + "protocol": "mongodb", + }, + } + Common.SaveResult(result) } + return err } // MongodbUnauth 检测MongoDB未授权访问 func MongodbUnauth(info *Common.HostInfo) (bool, error) { - // MongoDB查询数据包 msgPacket := createOpMsgPacket() queryPacket := createOpQueryPacket() @@ -41,8 +61,6 @@ func MongodbUnauth(info *Common.HostInfo) (bool, error) { // 检查响应结果 if strings.Contains(reply, "totalLinesWritten") { - result := fmt.Sprintf("MongoDB %v 未授权访问", realhost) - Common.LogSuccess(result) return true, nil } diff --git a/Plugins/MySQL.go b/Plugins/MySQL.go index 5f4aff9..4ba6abc 100644 --- a/Plugins/MySQL.go +++ b/Plugins/MySQL.go @@ -16,8 +16,9 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalUsers := len(Common.Userdict["mysql"]) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) @@ -38,7 +39,6 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行MySQL连接 done := make(chan struct { success bool err error @@ -55,33 +55,43 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { - successLog := fmt.Sprintf("MySQL %v:%v %v %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(successLog) + successMsg := fmt.Sprintf("MySQL %s %v %v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "mysql", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("MySQL %v:%v %v %v %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + errMsg := fmt.Sprintf("MySQL %s %v %v %v", target, user, pass, err) + Common.LogError(errMsg) - // 特殊处理认证失败的情况 if strings.Contains(err.Error(), "Access denied") { - break // 跳出重试循环,继续下一个密码 + break // 认证失败,尝试下一个密码 } - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { tmperr = err @@ -89,9 +99,9 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) { continue } } - continue // 继续重试 + continue } - break // 如果不需要重试,跳出重试循环 + break } } } diff --git a/Plugins/Neo4j.go b/Plugins/Neo4j.go index 35286f8..0e5c111 100644 --- a/Plugins/Neo4j.go +++ b/Plugins/Neo4j.go @@ -14,8 +14,9 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) // 首先测试无认证访问和默认凭证 initialChecks := []struct { @@ -31,6 +32,44 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("尝试: %s:%s", check.user, check.pass)) flag, err := Neo4jConn(info, check.user, check.pass) if flag && err == nil { + var msg string + if check.user == "" { + msg = fmt.Sprintf("Neo4j服务 %s 无需认证即可访问", target) + Common.LogSuccess(msg) + + // 保存结果 - 无认证访问 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "neo4j", + "type": "unauthorized-access", + }, + } + Common.SaveResult(result) + } else { + msg = fmt.Sprintf("Neo4j服务 %s 默认凭证可用 用户名: %s 密码: %s", target, check.user, check.pass) + Common.LogSuccess(msg) + + // 保存结果 - 默认凭证 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "neo4j", + "type": "default-credentials", + "username": check.user, + "password": check.pass, + }, + } + Common.SaveResult(result) + } return err } } @@ -55,7 +94,6 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行Neo4j连接 done := make(chan struct { success bool err error @@ -72,33 +110,47 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { + msg := fmt.Sprintf("Neo4j服务 %s 爆破成功 用户名: %s 密码: %s", target, user, pass) + Common.LogSuccess(msg) + + // 保存结果 - 成功爆破 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "neo4j", + "type": "weak-password", + "username": user, + "password": pass, + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("Neo4j服务 %s 尝试失败 用户名: %s 密码: %s 错误: %v", target, user, pass, err) Common.LogError(errlog) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } } @@ -143,13 +195,5 @@ func Neo4jConn(info *Common.HostInfo, user string, pass string) (bool, error) { return false, err } - // 连接成功 - result := fmt.Sprintf("Neo4j服务 %v:%v ", host, port) - if user != "" { - result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) - } else { - result += "无需认证即可访问" - } - Common.LogSuccess(result) return true, nil } diff --git a/Plugins/NetBIOS.go b/Plugins/NetBIOS.go index 49d009b..90db645 100644 --- a/Plugins/NetBIOS.go +++ b/Plugins/NetBIOS.go @@ -20,6 +20,47 @@ func NetBIOS(info *Common.HostInfo) error { if len(output) > 0 { result := fmt.Sprintf("NetBios %-15s %s", info.Host, output) Common.LogSuccess(result) + + // 保存结果 + details := map[string]interface{}{ + "port": info.Ports, + } + + // 添加有效的 NetBIOS 信息 + if netbios.ComputerName != "" { + details["computer_name"] = netbios.ComputerName + } + if netbios.DomainName != "" { + details["domain_name"] = netbios.DomainName + } + if netbios.NetDomainName != "" { + details["netbios_domain"] = netbios.NetDomainName + } + if netbios.NetComputerName != "" { + details["netbios_computer"] = netbios.NetComputerName + } + if netbios.WorkstationService != "" { + details["workstation_service"] = netbios.WorkstationService + } + if netbios.ServerService != "" { + details["server_service"] = netbios.ServerService + } + if netbios.DomainControllers != "" { + details["domain_controllers"] = netbios.DomainControllers + } + if netbios.OsVersion != "" { + details["os_version"] = netbios.OsVersion + } + + scanResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.SERVICE, + Target: info.Host, + Status: "identified", + Details: details, + } + + Common.SaveResult(scanResult) return nil } return errNetBIOS diff --git a/Plugins/Oracle.go b/Plugins/Oracle.go index 8adfb54..50181e6 100644 --- a/Plugins/Oracle.go +++ b/Plugins/Oracle.go @@ -15,8 +15,9 @@ func OracleScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalUsers := len(Common.Userdict["oracle"]) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) @@ -60,9 +61,24 @@ func OracleScan(info *Common.HostInfo) (tmperr error) { case result := <-done: err = result.err if result.success && err == nil { - successLog := fmt.Sprintf("Oracle %v:%v %v %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(successLog) + successMsg := fmt.Sprintf("Oracle %s 成功爆破 用户名: %v 密码: %v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "oracle", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): @@ -71,19 +87,17 @@ func OracleScan(info *Common.HostInfo) (tmperr error) { // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("Oracle %v:%v %v %v %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + errMsg := fmt.Sprintf("Oracle %s 尝试失败 用户名: %v 密码: %v 错误: %v", target, user, pass, err) + Common.LogError(errMsg) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } } @@ -118,8 +132,5 @@ func OracleConn(info *Common.HostInfo, user string, pass string) (bool, error) { return false, err } - // 连接成功 - 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 7e13b36..45b6ce4 100644 --- a/Plugins/POP3.go +++ b/Plugins/POP3.go @@ -16,8 +16,9 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalUsers := len(Common.Userdict["pop3"]) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) @@ -38,53 +39,70 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行POP3连接 done := make(chan struct { success bool err error + isTLS bool }, 1) go func(user, pass string) { - success, err := POP3Conn(info, user, pass) + success, isTLS, err := POP3Conn(info, user, pass) select { case done <- struct { success bool err error - }{success, err}: + isTLS bool + }{success, err, isTLS}: default: } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { - successLog := fmt.Sprintf("POP3服务 %v:%v 用户名: %v 密码: %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(successLog) + successMsg := fmt.Sprintf("POP3服务 %s 用户名: %v 密码: %v", target, user, pass) + if result.isTLS { + successMsg += " (TLS)" + } + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "pop3", + "username": user, + "password": pass, + "type": "weak-password", + "tls": result.isTLS, + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + errMsg := fmt.Sprintf("POP3服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", + target, user, pass, err) + Common.LogError(errMsg) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } } @@ -93,16 +111,15 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) { return tmperr } -func POP3Conn(info *Common.HostInfo, user string, pass string) (bool, error) { - host, port := info.Host, info.Ports +func POP3Conn(info *Common.HostInfo, user string, pass string) (success bool, isTLS bool, err error) { timeout := time.Duration(Common.Timeout) * time.Second - addr := fmt.Sprintf("%s:%s", host, port) + addr := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 首先尝试普通连接 conn, err := net.DialTimeout("tcp", addr, timeout) if err == nil { - if flag, err := tryPOP3Auth(conn, host, port, user, pass, timeout, false); err == nil { - return flag, nil + if flag, err := tryPOP3Auth(conn, user, pass, timeout); err == nil { + return flag, false, nil } conn.Close() } @@ -113,14 +130,15 @@ func POP3Conn(info *Common.HostInfo, user string, pass string) (bool, error) { } conn, err = tls.DialWithDialer(&net.Dialer{Timeout: timeout}, "tcp", addr, tlsConfig) if err != nil { - return false, fmt.Errorf("连接失败: %v", err) + return false, false, fmt.Errorf("连接失败: %v", err) } defer conn.Close() - return tryPOP3Auth(conn, host, port, user, pass, timeout, true) + success, err = tryPOP3Auth(conn, user, pass, timeout) + return success, true, err } -func tryPOP3Auth(conn net.Conn, host string, port string, user string, pass string, timeout time.Duration, isTLS bool) (bool, error) { +func tryPOP3Auth(conn net.Conn, user string, pass string, timeout time.Duration) (bool, error) { reader := bufio.NewReader(conn) conn.SetDeadline(time.Now().Add(timeout)) @@ -162,11 +180,6 @@ 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) - if isTLS { - result += " (TLS)" - } - Common.LogSuccess(result) return true, nil } diff --git a/Plugins/Postgres.go b/Plugins/Postgres.go index d694588..2269ae9 100644 --- a/Plugins/Postgres.go +++ b/Plugins/Postgres.go @@ -15,9 +15,10 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) { return } + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) maxRetries := Common.MaxRetries - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalUsers := len(Common.Userdict["postgresql"]) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) @@ -25,20 +26,17 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) { tried := 0 total := totalUsers * totalPass - // 遍历所有用户名密码组合 for _, user := range Common.Userdict["postgresql"] { for _, pass := range Common.Passwords { tried++ pass = strings.Replace(pass, "{user}", user, -1) Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass)) - // 重试循环 for retryCount := 0; retryCount < maxRetries; retryCount++ { if retryCount > 0 { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行PostgreSQL连接 done := make(chan struct { success bool err error @@ -55,36 +53,47 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { - successLog := fmt.Sprintf("PostgreSQL %v:%v %v %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(successLog) + successMsg := fmt.Sprintf("PostgreSQL服务 %s 成功爆破 用户名: %v 密码: %v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "postgresql", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("PostgreSQL %v:%v %v %v %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + errMsg := fmt.Sprintf("PostgreSQL服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", target, user, pass, err) + Common.LogError(errMsg) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } } @@ -95,13 +104,12 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) { // PostgresConn 尝试PostgreSQL连接 func PostgresConn(info *Common.HostInfo, user string, pass string) (bool, error) { - host, port, username, password := info.Host, info.Ports, user, pass timeout := time.Duration(Common.Timeout) * time.Second // 构造连接字符串 connStr := fmt.Sprintf( "postgres://%v:%v@%v:%v/postgres?sslmode=disable", - username, password, host, port, + user, pass, info.Host, info.Ports, ) // 建立数据库连接 @@ -119,8 +127,5 @@ func PostgresConn(info *Common.HostInfo, user string, pass string) (bool, error) return false, err } - // 连接成功 - 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 acb772f..f1da6f6 100644 --- a/Plugins/RDP.go +++ b/Plugins/RDP.go @@ -40,6 +40,7 @@ func RdpScan(info *Common.HostInfo) (tmperr error) { port, _ := strconv.Atoi(info.Ports) total := len(Common.Userdict["rdp"]) * len(Common.Passwords) num := 0 + target := fmt.Sprintf("%v:%v", info.Host, port) // 遍历用户名密码组合 for _, user := range Common.Userdict["rdp"] { @@ -54,16 +55,39 @@ 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 Domain: %v\\%v Password: %v", target, Common.Domain, user, pass) } else { - result = fmt.Sprintf("RDP %v:%v:%v %v", info.Host, port, user, pass) + result = fmt.Sprintf("RDP %v Username: %v Password: %v", target, user, pass) } Common.LogSuccess(result) + + // 保存结果 + details := map[string]interface{}{ + "port": port, + "service": "rdp", + "username": user, + "password": pass, + "type": "weak-password", + } + if Common.Domain != "" { + details["domain"] = Common.Domain + } + + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: details, + } + Common.SaveResult(vulnResult) + return nil } // 连接失败 - errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", num, total, info.Host, port, user, pass, err) + errlog := fmt.Sprintf("(%v/%v) RDP %v Username: %v Password: %v Error: %v", + num, total, target, user, pass, err) Common.LogError(errlog) } } diff --git a/Plugins/RabbitMQ.go b/Plugins/RabbitMQ.go index 76ac7e8..4a71843 100644 --- a/Plugins/RabbitMQ.go +++ b/Plugins/RabbitMQ.go @@ -16,8 +16,9 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug("尝试默认账号 guest/guest") // 先测试默认账号 guest/guest @@ -27,7 +28,6 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试默认账号: guest/guest", retryCount+1)) } - // 执行RabbitMQ连接 done := make(chan struct { success bool err error @@ -44,15 +44,29 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { } }() - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { - result := fmt.Sprintf("RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(result) + successMsg := fmt.Sprintf("RabbitMQ服务 %s 连接成功 用户名: %v 密码: %v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "rabbitmq", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): @@ -60,8 +74,8 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { } if err != nil { - errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("RabbitMQ服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", + target, user, pass, err) Common.LogError(errlog) if retryErr := Common.CheckErrs(err); retryErr != nil { @@ -74,7 +88,6 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { break } - // 计算总尝试次数 totalUsers := len(Common.Userdict["rabbitmq"]) totalPass := len(Common.Passwords) total := totalUsers * totalPass @@ -89,13 +102,11 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { pass = strings.Replace(pass, "{user}", user, -1) Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass)) - // 重试循环 for retryCount := 0; retryCount < maxRetries; retryCount++ { if retryCount > 0 { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行RabbitMQ连接 done := make(chan struct { success bool err error @@ -112,15 +123,30 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { - result := fmt.Sprintf("RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(result) + successMsg := fmt.Sprintf("RabbitMQ服务 %s 连接成功 用户名: %v 密码: %v", + target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "rabbitmq", + "username": user, + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): @@ -128,8 +154,8 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { } if err != nil { - errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("RabbitMQ服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", + target, user, pass, err) Common.LogError(errlog) if retryErr := Common.CheckErrs(err); retryErr != nil { @@ -144,7 +170,7 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { } } - Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried+1)) // +1 包含默认账号 + Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried+1)) return tmperr } @@ -172,8 +198,6 @@ 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) - Common.LogSuccess(result) return true, nil } diff --git a/Plugins/Redis.go b/Plugins/Redis.go index ae0d25b..abbe836 100644 --- a/Plugins/Redis.go +++ b/Plugins/Redis.go @@ -16,7 +16,6 @@ var ( dir string // Redis数据库目录 ) -// RedisScan 执行Redis服务扫描 func RedisScan(info *Common.HostInfo) error { Common.LogDebug(fmt.Sprintf("开始Redis扫描: %s:%v", info.Host, info.Ports)) starttime := time.Now().Unix() @@ -25,6 +24,20 @@ func RedisScan(info *Common.HostInfo) error { flag, err := RedisUnauth(info) if flag && err == nil { Common.LogSuccess(fmt.Sprintf("Redis无密码连接成功: %s:%v", info.Host, info.Ports)) + + // 保存未授权访问结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "redis", + "type": "unauthorized", + }, + } + Common.SaveResult(result) return nil } @@ -42,19 +55,15 @@ func RedisScan(info *Common.HostInfo) error { return fmt.Errorf(errMsg) } - // 替换密码模板 pass = strings.Replace(pass, "{user}", "redis", -1) Common.LogDebug(fmt.Sprintf("尝试密码: %s", pass)) - // 密码重试逻辑 var lastErr error for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ { - // 如果不是第一次重试,添加重试日志 if retryCount > 0 { Common.LogDebug(fmt.Sprintf("第 %d 次重试: %s", retryCount+1, pass)) } - // 执行Redis连接 done := make(chan struct { success bool err error @@ -68,13 +77,27 @@ func RedisScan(info *Common.HostInfo) error { }{success, err} }() - // 等待结果或超时 var connErr error select { case result := <-done: if result.success { Common.LogSuccess(fmt.Sprintf("Redis登录成功 %s:%v [%s]", info.Host, info.Ports, pass)) + + // 保存弱密码结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "redis", + "type": "weak-password", + "password": pass, + }, + } + Common.SaveResult(vulnResult) return nil } connErr = result.err @@ -82,27 +105,23 @@ func RedisScan(info *Common.HostInfo) error { connErr = fmt.Errorf("连接超时") } - // 处理错误情况 if connErr != nil { lastErr = connErr errMsg := fmt.Sprintf("Redis尝试失败 %s:%v [%s] %v", info.Host, info.Ports, pass, connErr) Common.LogError(errMsg) - // 检查是否需要重试 if retryErr := Common.CheckErrs(connErr); retryErr != nil { if retryCount == Common.MaxRetries-1 { Common.LogDebug(fmt.Sprintf("达到最大重试次数: %s", pass)) break } - continue // 继续重试 + continue } } - - break // 如果不需要重试,跳出重试循环 + break } - // 如果最后一次尝试遇到需要重试的错误,返回该错误 if lastErr != nil && Common.CheckErrs(lastErr) != nil { Common.LogDebug(fmt.Sprintf("Redis扫描中断: %v", lastErr)) return lastErr diff --git a/Plugins/Rsync.go b/Plugins/Rsync.go index a0771a1..e77dac3 100644 --- a/Plugins/Rsync.go +++ b/Plugins/Rsync.go @@ -8,15 +8,15 @@ import ( "time" ) -// RsyncScan 执行 Rsync 服务扫描 func RsyncScan(info *Common.HostInfo) (tmperr error) { if Common.DisableBrute { return } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug("尝试匿名访问...") // 首先测试匿名访问 @@ -27,14 +27,26 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) { flag, err := RsyncConn(info, "", "") if flag && err == nil { - Common.LogSuccess(fmt.Sprintf("Rsync服务 %v:%v 匿名访问成功", info.Host, info.Ports)) + Common.LogSuccess(fmt.Sprintf("Rsync服务 %s 匿名访问成功", target)) + + // 保存匿名访问结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "rsync", + "type": "anonymous-access", + }, + } + Common.SaveResult(result) return err } if err != nil { - errlog := fmt.Sprintf("Rsync服务 %v:%v 匿名访问失败: %v", info.Host, info.Ports, err) - Common.LogError(errlog) - + Common.LogError(fmt.Sprintf("Rsync服务 %s 匿名访问失败: %v", target, err)) if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { return err @@ -52,20 +64,17 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) { tried := 0 total := totalUsers * totalPass - // 遍历所有用户名密码组合 for _, user := range Common.Userdict["rsync"] { for _, pass := range Common.Passwords { tried++ pass = strings.Replace(pass, "{user}", user, -1) Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass)) - // 重试循环 for retryCount := 0; retryCount < maxRetries; retryCount++ { if retryCount > 0 { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行Rsync连接 done := make(chan struct { success bool err error @@ -82,37 +91,46 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success { - successLog := fmt.Sprintf("Rsync服务 %v:%v 爆破成功 用户名: %v 密码: %v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(successLog) + Common.LogSuccess(fmt.Sprintf("Rsync服务 %s 爆破成功 用户名: %v 密码: %v", + target, user, pass)) + + // 保存爆破成功结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "rsync", + "type": "weak-password", + "username": user, + "password": pass, + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) - - // 检查是否需要重试 + Common.LogError(fmt.Sprintf("Rsync服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", + target, user, pass, err)) if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - - break // 如果不需要重试,跳出重试循环 + break } } } diff --git a/Plugins/SMB.go b/Plugins/SMB.go index e10ad21..64f62e7 100644 --- a/Plugins/SMB.go +++ b/Plugins/SMB.go @@ -13,6 +13,8 @@ func SmbScan(info *Common.HostInfo) (tmperr error) { return nil } + target := fmt.Sprintf("%s:%s", info.Host, info.Ports) + // 遍历所有用户 for _, user := range Common.Userdict["smb"] { // 遍历该用户的所有密码 @@ -21,19 +23,41 @@ func SmbScan(info *Common.HostInfo) (tmperr error) { success, err := doWithTimeOut(info, user, pass) if success { - if Common.Domain != "" { - Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s\\%s:%s", - info.Host, info.Ports, Common.Domain, user, pass)) - } else { - Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s:%s", - info.Host, info.Ports, user, pass)) + // 构建结果消息 + var successMsg string + details := map[string]interface{}{ + "port": info.Ports, + "service": "smb", + "username": user, + "password": pass, + "type": "weak-password", } + + if Common.Domain != "" { + successMsg = fmt.Sprintf("SMB认证成功 %s %s\\%s:%s", target, Common.Domain, user, pass) + details["domain"] = Common.Domain + } else { + successMsg = fmt.Sprintf("SMB认证成功 %s %s:%s", target, user, pass) + } + + // 记录成功日志 + Common.LogSuccess(successMsg) + + // 保存结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: details, + } + Common.SaveResult(result) return nil } if err != nil { - Common.LogError(fmt.Sprintf("SMB认证失败 %s:%s %s:%s %v", - info.Host, info.Ports, user, pass, err)) + errMsg := fmt.Sprintf("SMB认证失败 %s %s:%s %v", target, user, pass, err) + Common.LogError(errMsg) // 等待失败日志打印完成 time.Sleep(100 * time.Millisecond) @@ -68,9 +92,6 @@ func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struc return false, fmt.Errorf("认证失败") } - // 添加 debug 输出原始错误信息 - Common.LogDebug(fmt.Sprintf("SMB original error: %v", err)) - // 清理错误信息中的换行符和多余空格 errMsg := strings.TrimSpace(strings.ReplaceAll(err.Error(), "\n", " ")) if strings.Contains(errMsg, "NT Status Error") { diff --git a/Plugins/SMB2.go b/Plugins/SMB2.go index 4c0f576..5873e99 100644 --- a/Plugins/SMB2.go +++ b/Plugins/SMB2.go @@ -145,21 +145,43 @@ func smbHashScan(info *Common.HostInfo) error { // logSuccessfulAuth 记录成功的认证 func logSuccessfulAuth(info *Common.HostInfo, user, pass string, hash []byte) { - var result string + credential := pass + if len(hash) > 0 { + credential = Common.HashValue + } + + // 保存认证成功结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "success", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "smb2", + "username": user, + "domain": Common.Domain, + "type": "weak-auth", + "credential": credential, + "auth_type": map[bool]string{true: "hash", false: "password"}[len(hash) > 0], + }, + } + Common.SaveResult(result) + + // 控制台输出 + var msg string if Common.Domain != "" { - result = fmt.Sprintf("SMB2认证成功 %s:%s %s\\%s", - info.Host, info.Ports, Common.Domain, user) + msg = fmt.Sprintf("SMB2认证成功 %s:%s %s\\%s", info.Host, info.Ports, Common.Domain, user) } else { - result = fmt.Sprintf("SMB2认证成功 %s:%s %s", - info.Host, info.Ports, user) + msg = fmt.Sprintf("SMB2认证成功 %s:%s %s", info.Host, info.Ports, user) } if len(hash) > 0 { - result += fmt.Sprintf(" Hash:%s", Common.HashValue) + msg += fmt.Sprintf(" Hash:%s", Common.HashValue) } else { - result += fmt.Sprintf(" Pass:%s", pass) + msg += fmt.Sprintf(" Pass:%s", pass) } - Common.LogSuccess(result) + Common.LogSuccess(msg) } // logFailedAuth 记录失败的认证 @@ -241,21 +263,42 @@ 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 + credential := pass + if len(hash) > 0 { + credential = Common.HashValue + } + + // 保存共享信息结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "shares-found", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "smb2", + "username": user, + "domain": Common.Domain, + "shares": shares, + "credential": credential, + "auth_type": map[bool]string{true: "hash", false: "password"}[len(hash) > 0], + }, + } + Common.SaveResult(result) + + // 控制台输出 + var msg string if Common.Domain != "" { - result = fmt.Sprintf("SMB2共享信息 %s:%s %s\\%s", - info.Host, info.Ports, Common.Domain, user) + msg = fmt.Sprintf("SMB2共享信息 %s:%s %s\\%s", info.Host, info.Ports, Common.Domain, user) } else { - result = fmt.Sprintf("SMB2共享信息 %s:%s %s", - info.Host, info.Ports, user) + msg = fmt.Sprintf("SMB2共享信息 %s:%s %s", info.Host, info.Ports, user) } if len(hash) > 0 { - result += fmt.Sprintf(" Hash:%s", Common.HashValue) + msg += fmt.Sprintf(" Hash:%s", Common.HashValue) } else { - result += fmt.Sprintf(" Pass:%s", pass) + msg += fmt.Sprintf(" Pass:%s", pass) } - - result += fmt.Sprintf(" 共享:%v", shares) - Common.LogInfo(result) + msg += fmt.Sprintf(" 共享:%v", shares) + Common.LogInfo(msg) } diff --git a/Plugins/SMTP.go b/Plugins/SMTP.go index 9e176c2..6966a53 100644 --- a/Plugins/SMTP.go +++ b/Plugins/SMTP.go @@ -16,19 +16,36 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug("尝试匿名访问...") // 先测试匿名访问 for retryCount := 0; retryCount < maxRetries; retryCount++ { flag, err := SmtpConn(info, "", "") if flag && err == nil { - Common.LogSuccess("匿名访问成功!") + msg := fmt.Sprintf("SMTP服务 %s 允许匿名访问", target) + Common.LogSuccess(msg) + + // 保存匿名访问结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "smtp", + "type": "anonymous-access", + "anonymous": true, + }, + } + Common.SaveResult(result) return err } if err != nil { - errlog := fmt.Sprintf("smtp %v:%v anonymous %v", info.Host, info.Ports, err) + errlog := fmt.Sprintf("smtp %s anonymous %v", target, err) Common.LogError(errlog) if retryErr := Common.CheckErrs(err); retryErr != nil { @@ -61,7 +78,6 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行SMTP连接 done := make(chan struct { success bool err error @@ -78,34 +94,48 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { + msg := fmt.Sprintf("SMTP服务 %s 爆破成功 用户名: %v 密码: %v", target, user, pass) + Common.LogSuccess(msg) + + // 保存成功爆破结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "smtp", + "type": "weak-password", + "username": user, + "password": pass, + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("SMTP服务 %s 尝试失败 用户名: %v 密码: %v 错误: %v", + target, user, pass, err) Common.LogError(errlog) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - - break // 如果不需要重试,跳出重试循环 + break } } } @@ -118,25 +148,20 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) { func SmtpConn(info *Common.HostInfo, user string, pass string) (bool, error) { host, port := info.Host, info.Ports timeout := time.Duration(Common.Timeout) * time.Second - - // 构造地址 addr := fmt.Sprintf("%s:%s", host, port) - // 创建带超时的连接 conn, err := net.DialTimeout("tcp", addr, timeout) if err != nil { return false, err } defer conn.Close() - // 创建SMTP客户端 client, err := smtp.NewClient(conn, host) if err != nil { return false, err } defer client.Close() - // 如果提供了认证信息 if user != "" { auth := smtp.PlainAuth("", user, pass, host) err = client.Auth(auth) @@ -145,20 +170,10 @@ func SmtpConn(info *Common.HostInfo, user string, pass string) (bool, error) { } } - // 验证是否可以发送邮件 err = client.Mail("test@test.com") if err != nil { return false, err } - // 如果成功 - result := fmt.Sprintf("SMTP服务 %v:%v ", host, port) - if user != "" { - result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass) - } else { - result += "允许匿名访问" - } - Common.LogSuccess(result) - return true, nil } diff --git a/Plugins/SNMP.go b/Plugins/SNMP.go index e38824e..8b2c193 100644 --- a/Plugins/SNMP.go +++ b/Plugins/SNMP.go @@ -19,73 +19,86 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) { portNum, _ := strconv.Atoi(info.Ports) defaultCommunities := []string{"public", "private", "cisco", "community"} timeout := time.Duration(Common.Timeout) * time.Second + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) Common.LogDebug(fmt.Sprintf("尝试默认 community 列表 (总数: %d)", len(defaultCommunities))) tried := 0 total := len(defaultCommunities) - // 遍历所有 community for _, community := range defaultCommunities { tried++ Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试 community: %s", tried, total, community)) - // 重试循环 for retryCount := 0; retryCount < maxRetries; retryCount++ { if retryCount > 0 { Common.LogDebug(fmt.Sprintf("第%d次重试: community: %s", retryCount+1, community)) } - // 执行SNMP连接 done := make(chan struct { success bool + sysDesc string err error }, 1) go func(community string) { - success, err := SNMPConnect(info, community, portNum) + success, sysDesc, err := SNMPConnect(info, community, portNum) select { case done <- struct { success bool + sysDesc string err error - }{success, err}: + }{success, sysDesc, err}: default: } }(community) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { - // 连接成功 - successLog := fmt.Sprintf("SNMP服务 %v:%v community: %v 连接成功", - info.Host, info.Ports, community) - Common.LogSuccess(successLog) + successMsg := fmt.Sprintf("SNMP服务 %s community: %v 连接成功", target, community) + if result.sysDesc != "" { + successMsg += fmt.Sprintf(" System: %v", result.sysDesc) + } + Common.LogSuccess(successMsg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "snmp", + "community": community, + "type": "weak-community", + "system": result.sysDesc, + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(timeout): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("SNMP服务 %v:%v 尝试失败 community: %v 错误: %v", - info.Host, info.Ports, community, err) + errlog := fmt.Sprintf("SNMP服务 %s 尝试失败 community: %v 错误: %v", + target, community, err) Common.LogError(errlog) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - - break // 如果不需要重试,跳出重试循环 + break } } @@ -94,7 +107,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) { } // SNMPConnect 尝试SNMP连接 -func SNMPConnect(info *Common.HostInfo, community string, portNum int) (bool, error) { +func SNMPConnect(info *Common.HostInfo, community string, portNum int) (bool, string, error) { host := info.Host timeout := time.Duration(Common.Timeout) * time.Second @@ -109,28 +122,23 @@ func SNMPConnect(info *Common.HostInfo, community string, portNum int) (bool, er err := snmp.Connect() if err != nil { - return false, err + return false, "", err } defer snmp.Conn.Close() oids := []string{"1.3.6.1.2.1.1.1.0"} result, err := snmp.Get(oids) if err != nil { - return false, err + return false, "", err } if len(result.Variables) > 0 { - success := fmt.Sprintf("SNMP服务 %v:%v community: %v", - host, portNum, community) // 使用portNum替换port - + var sysDesc string if result.Variables[0].Type != gosnmp.NoSuchObject { - sysDesc := strings.TrimSpace(string(result.Variables[0].Value.([]byte))) - success += fmt.Sprintf(" System: %v", sysDesc) + sysDesc = strings.TrimSpace(string(result.Variables[0].Value.([]byte))) } - - Common.LogSuccess(success) - return true, nil + return true, sysDesc, nil } - return false, fmt.Errorf("认证失败") + return false, "", fmt.Errorf("认证失败") } diff --git a/Plugins/SSH.go b/Plugins/SSH.go index 071cce1..d3f881a 100644 --- a/Plugins/SSH.go +++ b/Plugins/SSH.go @@ -17,8 +17,9 @@ func SshScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalUsers := len(Common.Userdict["ssh"]) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) @@ -61,9 +62,39 @@ func SshScan(info *Common.HostInfo) (tmperr error) { case result := <-done: err = result.err if result.success { - successLog := fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(successLog) + successMsg := fmt.Sprintf("SSH认证成功 %s User:%v Pass:%v", target, user, pass) + Common.LogSuccess(successMsg) + + // 保存结果 + details := map[string]interface{}{ + "port": info.Ports, + "service": "ssh", + "username": user, + "password": pass, + "type": "weak-password", + } + + // 如果使用了密钥认证,添加密钥信息 + if Common.SshKeyPath != "" { + details["auth_type"] = "key" + details["key_path"] = Common.SshKeyPath + details["password"] = nil + } + + // 如果执行了命令,添加命令信息 + if Common.Command != "" { + details["command"] = Common.Command + } + + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: details, + } + Common.SaveResult(vulnResult) + time.Sleep(100 * time.Millisecond) cancel() return nil @@ -75,9 +106,9 @@ func SshScan(info *Common.HostInfo) (tmperr error) { cancel() if err != nil { - errlog := fmt.Sprintf("SSH认证失败 %v:%v User:%v Pass:%v Err:%v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + errMsg := fmt.Sprintf("SSH认证失败 %s User:%v Pass:%v Err:%v", + target, user, pass, err) + Common.LogError(errMsg) if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { diff --git a/Plugins/Telnet.go b/Plugins/Telnet.go index cf8e9b5..bafb943 100644 --- a/Plugins/Telnet.go +++ b/Plugins/Telnet.go @@ -18,8 +18,9 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) { } maxRetries := Common.MaxRetries + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalUsers := len(Common.Userdict["telnet"]) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass)) @@ -40,7 +41,6 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass)) } - // 执行Telnet连接 done := make(chan struct { success bool noAuth bool @@ -59,43 +59,69 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) { } }(user, pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.noAuth { // 无需认证 - result := fmt.Sprintf("Telnet服务 %v:%v 无需认证", - info.Host, info.Ports) - Common.LogSuccess(result) + msg := fmt.Sprintf("Telnet服务 %s 无需认证", target) + Common.LogSuccess(msg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "telnet", + "type": "unauthorized-access", + }, + } + Common.SaveResult(vulnResult) return nil + } else if result.success { // 成功爆破 - result := fmt.Sprintf("Telnet服务 %v:%v 用户名:%v 密码:%v", - info.Host, info.Ports, user, pass) - Common.LogSuccess(result) + msg := fmt.Sprintf("Telnet服务 %s 用户名:%v 密码:%v", target, user, pass) + Common.LogSuccess(msg) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "telnet", + "type": "weak-password", + "username": user, + "password": pass, + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v", - info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("Telnet连接失败 %s 用户名:%v 密码:%v 错误:%v", + target, user, pass, err) Common.LogError(errlog) - // 检查是否需要重试 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } } @@ -106,28 +132,21 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) { // telnetConn 尝试建立Telnet连接并进行身份验证 func telnetConn(info *Common.HostInfo, user, pass string) (flag bool, err error) { - // 创建telnet客户端 client := NewTelnet(info.Host, info.Ports) - // 建立连接 if err = client.Connect(); err != nil { return false, err } defer client.Close() - // 设置认证信息 client.UserName = user client.Password = pass - - // 检测服务器类型 client.ServerType = client.MakeServerType() - // 如果是无需认证的服务器,直接返回成功 if client.ServerType == UnauthorizedAccess { return true, nil } - // 尝试登录认证 err = client.Login() return false, err } diff --git a/Plugins/VNC.go b/Plugins/VNC.go index 180caca..0b1ecef 100644 --- a/Plugins/VNC.go +++ b/Plugins/VNC.go @@ -15,8 +15,9 @@ func VncScan(info *Common.HostInfo) (tmperr error) { maxRetries := Common.MaxRetries modename := "vnc" + target := fmt.Sprintf("%v:%v", info.Host, info.Ports) - Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports)) + Common.LogDebug(fmt.Sprintf("开始扫描 %s", target)) totalPass := len(Common.Passwords) Common.LogDebug(fmt.Sprintf("开始尝试密码组合 (总密码数: %d)", totalPass)) @@ -33,7 +34,6 @@ func VncScan(info *Common.HostInfo) (tmperr error) { Common.LogDebug(fmt.Sprintf("第%d次重试密码: %s", retryCount+1, pass)) } - // 执行VNC连接 done := make(chan struct { success bool err error @@ -50,37 +50,48 @@ func VncScan(info *Common.HostInfo) (tmperr error) { } }(pass) - // 等待结果或超时 var err error select { case result := <-done: err = result.err if result.success && err == nil { // 连接成功 - successLog := fmt.Sprintf("%s://%v:%v 密码: %v", - modename, info.Host, info.Ports, pass) + successLog := fmt.Sprintf("%s://%s 密码: %v", modename, target, pass) Common.LogSuccess(successLog) + + // 保存结果 + vulnResult := &Common.ScanResult{ + Time: time.Now(), + Type: Common.VULN, + Target: info.Host, + Status: "vulnerable", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "vnc", + "password": pass, + "type": "weak-password", + }, + } + Common.SaveResult(vulnResult) return nil } case <-time.After(time.Duration(Common.Timeout) * time.Second): err = fmt.Errorf("连接超时") } - // 处理错误情况 if err != nil { - errlog := fmt.Sprintf("%s://%v:%v 尝试密码: %v 错误: %v", - modename, info.Host, info.Ports, pass, err) + errlog := fmt.Sprintf("%s://%s 尝试密码: %v 错误: %v", + modename, target, pass, err) Common.LogError(errlog) - // 检查是否是需要重试的错误 if retryErr := Common.CheckErrs(err); retryErr != nil { if retryCount == maxRetries-1 { continue } - continue // 继续重试 + continue } } - break // 如果不需要重试,跳出重试循环 + break } } diff --git a/Plugins/WebTitle.go b/Plugins/WebTitle.go index b828425..3ee3325 100644 --- a/Plugins/WebTitle.go +++ b/Plugins/WebTitle.go @@ -198,7 +198,6 @@ func geturl(info *Common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er if flag != 2 { // 处理编码 if !utf8.Valid(body) { - Common.LogDebug("检测到非UTF8编码,尝试GBK解码") body, _ = simplifiedchinese.GBK.NewDecoder().Bytes(body) } @@ -208,22 +207,53 @@ func geturl(info *Common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er if length == "" { length = fmt.Sprintf("%v", len(body)) } - Common.LogDebug(fmt.Sprintf("提取的标题: %s, 内容长度: %s", title, length)) - // 处理重定向 + // 收集服务器信息 + serverInfo := make(map[string]interface{}) + serverInfo["title"] = title + serverInfo["length"] = length + serverInfo["status_code"] = resp.StatusCode + + // 收集响应头信息 + for k, v := range resp.Header { + if len(v) > 0 { + serverInfo[strings.ToLower(k)] = v[0] + } + } + + // 检查重定向 redirURL, err1 := resp.Location() if err1 == nil { reurl = redirURL.String() - Common.LogDebug(fmt.Sprintf("检测到重定向URL: %s", reurl)) + serverInfo["redirect_url"] = reurl } - // 输出结果 - result := fmt.Sprintf("网站标题 %-25v 状态码:%-3v 长度:%-6v 标题:%v", + // 保存扫描结果 + result := &Common.ScanResult{ + Time: time.Now(), + Type: Common.SERVICE, + Target: info.Host, + Status: "identified", + Details: map[string]interface{}{ + "port": info.Ports, + "service": "http", + "title": title, + "url": resp.Request.URL.String(), + "status_code": resp.StatusCode, + "length": length, + "server_info": serverInfo, + "fingerprints": info.Infostr, // 指纹信息 + }, + } + Common.SaveResult(result) + + // 输出控制台日志 + logMsg := fmt.Sprintf("网站标题 %-25v 状态码:%-3v 长度:%-6v 标题:%v", resp.Request.URL, resp.StatusCode, length, title) if reurl != "" { - result += fmt.Sprintf(" 重定向地址: %s", reurl) + logMsg += fmt.Sprintf(" 重定向地址: %s", reurl) } - Common.LogSuccess(result) + Common.LogSuccess(logMsg) } // 返回结果 diff --git a/main.go b/main.go index 88a0f35..dea1f10 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "github.com/shadow1ng/fscan/Common" "github.com/shadow1ng/fscan/Core" "os" @@ -8,12 +9,17 @@ import ( func main() { Common.InitLogger() - defer Common.CloseLogger() // 确保程序退出时关闭日志文件 var Info Common.HostInfo Common.Flag(&Info) if err := Common.Parse(&Info); err != nil { - os.Exit(1) // 直接退出即可,日志已经同步写入 + os.Exit(1) } + // 初始化输出系统,如果失败则直接退出 + if err := Common.InitOutput(); err != nil { + Common.LogError(fmt.Sprintf("初始化输出系统失败: %v", err)) + os.Exit(1) // 关键修改:初始化失败时直接退出 + } + defer Common.CloseOutput() Core.Scan(Info) }