refactor: 全量替换 WrapperTcpWithTimeout 为 session.DialTCP (Phase 4)

- core/port_scan.go: EnhancedPortScan/connectWithRetry/scanSinglePort 接入 session
- core/service_probe.go: SmartPortInfoScanner 持有 session,重连走 session.DialTCP
- core/icmp.go: CheckLive/tcpProbeAlive 接入 session
- 17 个 service 插件: 内部 helper 函数全部穿透 ctx+session
- 移除插件中冗余的手动 TCP 计数(DialTCP 内部已处理)
- plugins/core 下已无 WrapperTcpWithTimeout/SafeTCPDial 调用残留
This commit is contained in:
ZacharyZcR
2026-04-27 23:27:21 +08:00
parent a865e5d45e
commit c98805e85a
24 changed files with 266 additions and 339 deletions
+3 -3
View File
@@ -62,14 +62,14 @@ func (s *AliveScanStrategy) Execute(_ context.Context, session *common.ScanSessi
} }
// 执行存活探测 // 执行存活探测
s.performAliveScan(info, session.Config, session.State) s.performAliveScan(info, session)
// 输出统计信息 // 输出统计信息
s.outputStats() s.outputStats()
} }
// performAliveScan 执行存活探测 // performAliveScan 执行存活探测
func (s *AliveScanStrategy) performAliveScan(info common.HostInfo, config *common.Config, state *common.State) { func (s *AliveScanStrategy) performAliveScan(info common.HostInfo, session *common.ScanSession) {
// 解析目标主机 // 解析目标主机
fv := common.GetFlagVars() fv := common.GetFlagVars()
hosts, err := parsers.ParseIP(info.Host, fv.HostsFile, fv.ExcludeHosts) hosts, err := parsers.ParseIP(info.Host, fv.HostsFile, fv.ExcludeHosts)
@@ -90,7 +90,7 @@ func (s *AliveScanStrategy) performAliveScan(info common.HostInfo, config *commo
// 执行存活检测 // 执行存活检测
aliveList := CheckLive(hosts, false, config, state) // 使用ICMP探测 aliveList := CheckLive(hosts, false, session) // 使用ICMP探测
// 更新统计信息 // 更新统计信息
s.stats.AliveHosts = len(aliveList) s.stats.AliveHosts = len(aliveList)
+12 -8
View File
@@ -2,6 +2,7 @@ package core
import ( import (
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"net" "net"
@@ -39,7 +40,9 @@ var pingErrorKeywords = []string{
// CheckLive 检测主机存活状态 // CheckLive 检测主机存活状态
// 支持 ICMP/Ping 探测,并在响应率过低时自动启用 TCP 补充探测 // 支持 ICMP/Ping 探测,并在响应率过低时自动启用 TCP 补充探测
func CheckLive(hostslist []string, Ping bool, config *common.Config, state *common.State) []string { func CheckLive(hostslist []string, Ping bool, session *common.ScanSession) []string {
config := session.Config
state := session.State
// 创建局部WaitGroup // 创建局部WaitGroup
var livewg sync.WaitGroup var livewg sync.WaitGroup
@@ -68,7 +71,7 @@ func CheckLive(hostslist []string, Ping bool, config *common.Config, state *comm
// TCP 补充探测:当 ICMP/Ping 响应率过低时自动启用 // TCP 补充探测:当 ICMP/Ping 响应率过低时自动启用
// 这对防火墙过滤 ICMP 的环境特别有用 // 这对防火墙过滤 ICMP 的环境特别有用
aliveHosts = tcpSupplementaryProbe(hostslist, aliveHosts, config) aliveHosts = tcpSupplementaryProbe(hostslist, aliveHosts, session)
// 输出存活统计信息 // 输出存活统计信息
printAliveStats(aliveHosts, hostslist) printAliveStats(aliveHosts, hostslist)
@@ -78,7 +81,7 @@ func CheckLive(hostslist []string, Ping bool, config *common.Config, state *comm
// tcpSupplementaryProbe TCP 补充探测 // tcpSupplementaryProbe TCP 补充探测
// 当 ICMP 响应率过低时(<10%),对未响应主机进行 TCP 探测 // 当 ICMP 响应率过低时(<10%),对未响应主机进行 TCP 探测
func tcpSupplementaryProbe(allHosts []string, aliveHosts []string, config *common.Config) []string { func tcpSupplementaryProbe(allHosts []string, aliveHosts []string, session *common.ScanSession) []string {
totalHosts := len(allHosts) totalHosts := len(allHosts)
if totalHosts == 0 { if totalHosts == 0 {
return aliveHosts return aliveHosts
@@ -102,7 +105,7 @@ func tcpSupplementaryProbe(allHosts []string, aliveHosts []string, config *commo
common.LogInfo(i18n.Tr("tcp_probe_low_icmp_rate", fmt.Sprintf("%.1f%%", responseRate*100), len(unrespondedHosts))) common.LogInfo(i18n.Tr("tcp_probe_low_icmp_rate", fmt.Sprintf("%.1f%%", responseRate*100), len(unrespondedHosts)))
// 执行 TCP 补充探测 // 执行 TCP 补充探测
tcpAliveHosts := runTcpProbeForHosts(unrespondedHosts, config) tcpAliveHosts := runTcpProbeForHosts(unrespondedHosts, session)
// 合并结果 // 合并结果
if len(tcpAliveHosts) > 0 { if len(tcpAliveHosts) > 0 {
@@ -682,10 +685,10 @@ const tcpProbeThreshold = 0.1 // 10%
// tcpProbeAlive 使用 TCP 探测主机是否存活 // tcpProbeAlive 使用 TCP 探测主机是否存活
// 尝试连接常用端口,任一端口响应即认为存活 // 尝试连接常用端口,任一端口响应即认为存活
func tcpProbeAlive(host string) bool { func tcpProbeAlive(session *common.ScanSession, host string) bool {
for _, port := range tcpProbeCommonPorts { for _, port := range tcpProbeCommonPorts {
addr := fmt.Sprintf("%s:%d", host, port) addr := fmt.Sprintf("%s:%d", host, port)
conn, err := common.WrapperTcpWithTimeout("tcp", addr, tcpProbeTimeout) conn, err := session.DialTCP(context.Background(), "tcp", addr, tcpProbeTimeout)
if err == nil { if err == nil {
_ = conn.Close() _ = conn.Close()
return true return true
@@ -696,7 +699,8 @@ func tcpProbeAlive(host string) bool {
// runTcpProbeForHosts 对指定主机列表进行 TCP 补充探测 // runTcpProbeForHosts 对指定主机列表进行 TCP 补充探测
// 返回存活的主机列表 // 返回存活的主机列表
func runTcpProbeForHosts(hosts []string, config *common.Config) []string { func runTcpProbeForHosts(hosts []string, session *common.ScanSession) []string {
config := session.Config
if len(hosts) == 0 { if len(hosts) == 0 {
return nil return nil
} }
@@ -722,7 +726,7 @@ func runTcpProbeForHosts(hosts []string, config *common.Config) []string {
wg.Done() wg.Done()
}() }()
if tcpProbeAlive(h) { if tcpProbeAlive(session, h) {
mu.Lock() mu.Lock()
aliveHosts = append(aliveHosts, h) aliveHosts = append(aliveHosts, h)
mu.Unlock() mu.Unlock()
+13 -9
View File
@@ -1,6 +1,7 @@
package core package core
import ( import (
"context"
"fmt" "fmt"
"net" "net"
"strings" "strings"
@@ -110,7 +111,9 @@ func (f *failedPortCollector) Count() int {
// EnhancedPortScan 高性能端口扫描函数 // EnhancedPortScan 高性能端口扫描函数
// 使用滑动窗口调度 + 自适应线程池 + 流式迭代器 // 使用滑动窗口调度 + 自适应线程池 + 流式迭代器
func EnhancedPortScan(hosts []string, ports string, timeout int64, config *common.Config, state *common.State) []string { func EnhancedPortScan(hosts []string, ports string, timeout int64, session *common.ScanSession) []string {
config := session.Config
state := session.State
common.LogDebug(fmt.Sprintf("[PortScan] 开始: %d个主机, 线程数=%d", len(hosts), config.ThreadNum)) common.LogDebug(fmt.Sprintf("[PortScan] 开始: %d个主机, 线程数=%d", len(hosts), config.ThreadNum))
// 解析端口和排除端口 // 解析端口和排除端口
@@ -179,7 +182,7 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64, config *commo
}() }()
addr := fmt.Sprintf("%s:%d", taskInfo.host, taskInfo.port) addr := fmt.Sprintf("%s:%d", taskInfo.host, taskInfo.port)
scanSinglePort(taskInfo.host, taskInfo.port, addr, to, &count, collector, failedCollector, config, state) scanSinglePort(taskInfo.host, taskInfo.port, addr, to, &count, collector, failedCollector, session)
common.UpdateProgressBar(1) common.UpdateProgressBar(1)
}, state) }, state)
if err != nil { if err != nil {
@@ -263,11 +266,11 @@ func slidingWindowSchedule(iter *SocketIterator, pool *AdaptivePool, wg *sync.Wa
} }
// connectWithRetry 带重试的TCP连接 - 只对资源耗尽错误重试 // connectWithRetry 带重试的TCP连接 - 只对资源耗尽错误重试
func connectWithRetry(addr string, timeout time.Duration, maxRetries int, state *common.State) (net.Conn, error) { func connectWithRetry(ctx context.Context, session *common.ScanSession, addr string, timeout time.Duration, maxRetries int) (net.Conn, error) {
var lastErr error var lastErr error
for attempt := 0; attempt < maxRetries; attempt++ { for attempt := 0; attempt < maxRetries; attempt++ {
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout) conn, err := session.DialTCP(ctx, "tcp", addr, timeout)
if err == nil { if err == nil {
return conn, nil return conn, nil
@@ -281,7 +284,7 @@ func connectWithRetry(addr string, timeout time.Duration, maxRetries int, state
} }
// 记录资源耗尽错误 // 记录资源耗尽错误
state.IncrementResourceExhaustedCount() session.State.IncrementResourceExhaustedCount()
// 指数退避:第1次等50ms,第2次等150ms // 指数退避:第1次等50ms,第2次等150ms
if attempt < maxRetries-1 { if attempt < maxRetries-1 {
@@ -344,9 +347,10 @@ func buildServiceLogMessage(addr string, serviceInfo *ServiceInfo, isWeb bool) s
} }
// scanSinglePort 扫描单个端口并进行服务识别(重构后的简洁版本) // scanSinglePort 扫描单个端口并进行服务识别(重构后的简洁版本)
func scanSinglePort(host string, port int, addr string, timeout time.Duration, count *int64, collector *resultCollector, failedCollector *failedPortCollector, config *common.Config, state *common.State) { func scanSinglePort(host string, port int, addr string, timeout time.Duration, count *int64, collector *resultCollector, failedCollector *failedPortCollector, session *common.ScanSession) {
config := session.Config
// 步骤1:建立连接 // 步骤1:建立连接
conn, err := connectWithRetry(addr, timeout, 3, state) conn, err := connectWithRetry(context.Background(), session, addr, timeout, 3)
if err != nil { if err != nil {
handleConnectionFailure(err, host, port, addr, failedCollector) handleConnectionFailure(err, host, port, addr, failedCollector)
return return
@@ -365,7 +369,7 @@ func scanSinglePort(host string, port int, addr string, timeout time.Duration, c
if common.IsProxyEnabled() && verifyMethod != "direct" { if common.IsProxyEnabled() && verifyMethod != "direct" {
_ = conn.Close() _ = conn.Close()
// 重新建立干净的连接用于服务识别 // 重新建立干净的连接用于服务识别
conn, err = connectWithRetry(addr, timeout, 3, state) conn, err = connectWithRetry(context.Background(), session, addr, timeout, 3)
if err != nil { if err != nil {
handleConnectionFailure(err, host, port, addr, failedCollector) handleConnectionFailure(err, host, port, addr, failedCollector)
return return
@@ -378,7 +382,7 @@ func scanSinglePort(host string, port int, addr string, timeout time.Duration, c
saveOpenPort(host, port) saveOpenPort(host, port)
// 步骤3:服务识别(Scanner负责关闭连接,包括探测中可能创建的新连接) // 步骤3:服务识别(Scanner负责关闭连接,包括探测中可能创建的新连接)
scanner := NewSmartPortInfoScanner(host, port, conn, timeout, config) scanner := NewSmartPortInfoScanner(host, port, conn, timeout, config, session)
defer scanner.Close() defer scanner.Close()
serviceInfo, _ := scanner.SmartIdentify() serviceInfo, _ := scanner.SmartIdentify()
+8 -3
View File
@@ -1,6 +1,7 @@
package core package core
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@@ -76,6 +77,7 @@ type Info struct {
Result Result // 探测结果 Result Result // 探测结果
Found bool // 是否成功识别服务 Found bool // 是否成功识别服务
config *common.Config // 配置引用 config *common.Config // 配置引用
session *common.ScanSession // 会话引用
readTimeoutMS int // 当前读取超时时间(毫秒) readTimeoutMS int // 当前读取超时时间(毫秒)
} }
@@ -87,23 +89,26 @@ type SmartPortInfoScanner struct {
Timeout time.Duration Timeout time.Duration
info *Info info *Info
config *common.Config // 配置引用 config *common.Config // 配置引用
session *common.ScanSession // 会话引用
} }
// 预定义的基础探测器已在PortFinger.go中定义,这里不再重复定义 // 预定义的基础探测器已在PortFinger.go中定义,这里不再重复定义
// NewSmartPortInfoScanner 创建智能服务识别器 // NewSmartPortInfoScanner 创建智能服务识别器
func NewSmartPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Duration, config *common.Config) *SmartPortInfoScanner { func NewSmartPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Duration, config *common.Config, session *common.ScanSession) *SmartPortInfoScanner {
return &SmartPortInfoScanner{ return &SmartPortInfoScanner{
Address: addr, Address: addr,
Port: port, Port: port,
Conn: conn, Conn: conn,
Timeout: timeout, Timeout: timeout,
config: config, config: config,
session: session,
info: &Info{ info: &Info{
Address: addr, Address: addr,
Port: port, Port: port,
Conn: conn, Conn: conn,
config: config, config: config,
session: session,
Result: Result{ Result: Result{
Service: Service{}, Service: Service{},
}, },
@@ -251,7 +256,7 @@ func (s *SmartPortInfoScanner) reconnectIfNeeded() {
} }
// 重新建立连接 // 重新建立连接
newConn, err := common.WrapperTcpWithTimeout("tcp", fmt.Sprintf("%s:%d", s.Address, s.Port), s.Timeout) newConn, err := s.session.DialTCP(context.Background(), "tcp", fmt.Sprintf("%s:%d", s.Address, s.Port), s.Timeout)
if err != nil { if err != nil {
return return
} }
@@ -511,7 +516,7 @@ func (i *Info) Write(msg []byte) error {
_ = oldConn.Close() _ = oldConn.Close()
// 尝试重新连接 - 支持SOCKS5代理 // 尝试重新连接 - 支持SOCKS5代理
newConn, retryErr := common.WrapperTcpWithTimeout("tcp", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second) newConn, retryErr := i.session.DialTCP(context.Background(), "tcp", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second)
if retryErr != nil { if retryErr != nil {
return retryErr return retryErr
} }
+1 -1
View File
@@ -155,7 +155,7 @@ func TestSmartPortInfoScanner_Creation(t *testing.T) {
} }
// 使用 nil 连接(实际测试中会使用真实连接) // 使用 nil 连接(实际测试中会使用真实连接)
scanner := NewSmartPortInfoScanner("127.0.0.1", 80, nil, 3*time.Second, config) scanner := NewSmartPortInfoScanner("127.0.0.1", 80, nil, 3*time.Second, config, nil)
if scanner == nil { if scanner == nil {
t.Fatal("Scanner 创建失败") t.Fatal("Scanner 创建失败")
+12 -8
View File
@@ -141,7 +141,7 @@ func (s *ServiceScanStrategy) Execute(ctx context.Context, session *common.ScanS
// performHostScan 执行主机扫描的完整流程 // performHostScan 执行主机扫描的完整流程
func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *common.ScanSession, info common.HostInfo, ch chan struct{}, wg *sync.WaitGroup) { func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *common.ScanSession, info common.HostInfo, ch chan struct{}, wg *sync.WaitGroup) {
// 发现目标主机和端口 // 发现目标主机和端口
targetInfos, err := s.discoverTargets(info.Host, info, session.Config, session.State) targetInfos, err := s.discoverTargets(info.Host, info, session)
if err != nil { if err != nil {
common.LogError(err.Error()) common.LogError(err.Error())
return return
@@ -154,9 +154,9 @@ func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *comm
} }
// PrepareTargets 准备目标信息 // PrepareTargets 准备目标信息
func (s *ServiceScanStrategy) PrepareTargets(info common.HostInfo, config *common.Config, state *common.State) []common.HostInfo { func (s *ServiceScanStrategy) PrepareTargets(info common.HostInfo, session *common.ScanSession) []common.HostInfo {
// 发现目标主机和端口 // 发现目标主机和端口
targetInfos, err := s.discoverTargets(info.Host, info, config, state) targetInfos, err := s.discoverTargets(info.Host, info, session)
if err != nil { if err != nil {
common.LogError(err.Error()) common.LogError(err.Error())
return nil return nil
@@ -215,7 +215,9 @@ func (s *ServiceScanStrategy) LogVulnerabilityPluginInfo(targets []common.HostIn
// ============================================================================= // =============================================================================
// discoverTargets 发现目标主机和端口 // discoverTargets 发现目标主机和端口
func (s *ServiceScanStrategy) discoverTargets(hostInput string, baseInfo common.HostInfo, config *common.Config, state *common.State) ([]common.HostInfo, error) { func (s *ServiceScanStrategy) discoverTargets(hostInput string, baseInfo common.HostInfo, session *common.ScanSession) ([]common.HostInfo, error) {
config := session.Config
state := session.State
// 标准流程:解析目标主机 // 标准流程:解析目标主机
fv := common.GetFlagVars() fv := common.GetFlagVars()
hosts, err := parsers.ParseIP(hostInput, fv.HostsFile, fv.ExcludeHosts) hosts, err := parsers.ParseIP(hostInput, fv.HostsFile, fv.ExcludeHosts)
@@ -229,12 +231,12 @@ func (s *ServiceScanStrategy) discoverTargets(hostInput string, baseInfo common.
if len(hosts) > 0 || len(state.GetHostPorts()) > 0 { if len(hosts) > 0 || len(state.GetHostPorts()) > 0 {
// 主机存活检测 // 主机存活检测
if s.shouldPerformLivenessCheck(hosts, config) { if s.shouldPerformLivenessCheck(hosts, config) {
hosts = CheckLive(hosts, false, config, state) hosts = CheckLive(hosts, false, session)
common.LogInfo(i18n.Tr("alive_hosts_count_info", len(hosts))) common.LogInfo(i18n.Tr("alive_hosts_count_info", len(hosts)))
} }
// 端口扫描 // 端口扫描
alivePorts := s.discoverAlivePorts(hosts, config, state) alivePorts := s.discoverAlivePorts(hosts, session)
if len(alivePorts) > 0 { if len(alivePorts) > 0 {
targetInfos = s.convertToTargetInfos(alivePorts, baseInfo) targetInfos = s.convertToTargetInfos(alivePorts, baseInfo)
} }
@@ -249,7 +251,9 @@ func (s *ServiceScanStrategy) shouldPerformLivenessCheck(hosts []string, config
} }
// discoverAlivePorts 发现存活的端口 // discoverAlivePorts 发现存活的端口
func (s *ServiceScanStrategy) discoverAlivePorts(hosts []string, config *common.Config, state *common.State) []string { func (s *ServiceScanStrategy) discoverAlivePorts(hosts []string, session *common.ScanSession) []string {
config := session.Config
state := session.State
var alivePorts []string var alivePorts []string
// 如果已经有明确指定的host:port,直接使用(让后续SmartIdentify统一验证和识别) // 如果已经有明确指定的host:port,直接使用(让后续SmartIdentify统一验证和识别)
@@ -263,7 +267,7 @@ func (s *ServiceScanStrategy) discoverAlivePorts(hosts []string, config *common.
// 根据扫描模式选择端口扫描方式 // 根据扫描模式选择端口扫描方式
if len(hosts) > 0 { if len(hosts) > 0 {
alivePorts = EnhancedPortScan(hosts, config.Target.Ports, int64(config.Timeout.Seconds()), config, state) alivePorts = EnhancedPortScan(hosts, config.Target.Ports, int64(config.Timeout.Seconds()), session)
} }
return alivePorts return alivePorts
+10 -18
View File
@@ -27,11 +27,10 @@ func NewActiveMQPlugin() *ActiveMQPlugin {
func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
target := info.Target() target := info.Target()
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(ctx, info, config, state) return p.identifyService(ctx, info, session)
} }
// 生成测试凭据 // 生成测试凭据
@@ -50,7 +49,7 @@ func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
} }
// 使用公共框架进行并发凭据测试 // 使用公共框架进行并发凭据测试
authFn := p.createAuthFunc(info, config, state) authFn := p.createAuthFunc(info, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
result := TestCredentialsConcurrently(ctx, credentials, authFn, "activemq", testConfig) result := TestCredentialsConcurrently(ctx, credentials, authFn, "activemq", testConfig)
@@ -63,23 +62,23 @@ func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
} }
// createAuthFunc 创建ActiveMQ认证函数 // createAuthFunc 创建ActiveMQ认证函数
func (p *ActiveMQPlugin) createAuthFunc(info *common.HostInfo, config *common.Config, state *common.State) AuthFunc { func (p *ActiveMQPlugin) createAuthFunc(info *common.HostInfo, session *common.ScanSession) AuthFunc {
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
return p.doActiveMQAuth(ctx, info, cred, config, state) return p.doActiveMQAuth(ctx, info, cred, session)
} }
} }
// doActiveMQAuth 执行ActiveMQ认证 // doActiveMQAuth 执行ActiveMQ认证
func (p *ActiveMQPlugin) doActiveMQAuth(ctx context.Context, info *common.HostInfo, cred Credential, config *common.Config, state *common.State) *AuthResult { func (p *ActiveMQPlugin) doActiveMQAuth(ctx context.Context, info *common.HostInfo, cred Credential, session *common.ScanSession) *AuthResult {
target := info.Target() target := info.Target()
config := session.Config
timeout := config.Timeout timeout := config.Timeout
resultChan := make(chan *AuthResult, 1) resultChan := make(chan *AuthResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) conn, err := session.DialTCP(ctx, "tcp", target, timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifyActiveMQErrorType(err), ErrorType: classifyActiveMQErrorType(err),
@@ -90,7 +89,6 @@ func (p *ActiveMQPlugin) doActiveMQAuth(ctx context.Context, info *common.HostIn
success, err := p.authenticateSTOMP(conn, cred.Username, cred.Password, config) success, err := p.authenticateSTOMP(conn, cred.Username, cred.Password, config)
if success { if success {
state.IncrementTCPSuccessPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: true, Success: true,
Conn: &activeMQConnWrapper{conn}, Conn: &activeMQConnWrapper{conn},
@@ -101,7 +99,6 @@ func (p *ActiveMQPlugin) doActiveMQAuth(ctx context.Context, info *common.HostIn
} }
_ = conn.Close() _ = conn.Close()
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifyActiveMQErrorType(err), ErrorType: classifyActiveMQErrorType(err),
@@ -113,7 +110,6 @@ func (p *ActiveMQPlugin) doActiveMQAuth(ctx context.Context, info *common.HostIn
case result := <-resultChan: case result := <-resultChan:
return result return result
case <-ctx.Done(): case <-ctx.Done():
// context 被取消,启动清理协程等待并关闭可能创建的连接
go func() { go func() {
result := <-resultChan result := <-resultChan
if result != nil && result.Conn != nil { if result != nil && result.Conn != nil {
@@ -201,13 +197,12 @@ func (p *ActiveMQPlugin) authenticateSTOMP(conn net.Conn, username, password str
} }
// identifyService ActiveMQ服务识别 // identifyService ActiveMQ服务识别
func (p *ActiveMQPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *ActiveMQPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
timeout := config.Timeout timeout := session.Config.Timeout
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) conn, err := session.DialTCP(ctx, "tcp", target, timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "activemq", Service: "activemq",
@@ -220,7 +215,6 @@ func (p *ActiveMQPlugin) identifyService(ctx context.Context, info *common.HostI
_ = conn.SetWriteDeadline(time.Now().Add(timeout)) _ = conn.SetWriteDeadline(time.Now().Add(timeout))
if _, writeErr := conn.Write([]byte(stompConnect)); writeErr != nil { if _, writeErr := conn.Write([]byte(stompConnect)); writeErr != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "activemq", Service: "activemq",
@@ -232,7 +226,6 @@ func (p *ActiveMQPlugin) identifyService(ctx context.Context, info *common.HostI
response := make([]byte, 512) response := make([]byte, 512)
n, err := conn.Read(response) n, err := conn.Read(response)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "activemq", Service: "activemq",
@@ -247,7 +240,6 @@ func (p *ActiveMQPlugin) identifyService(ctx context.Context, info *common.HostI
} }
} }
state.IncrementTCPSuccessPacketCount()
responseStr := string(response[:n]) responseStr := string(response[:n])
if common.ContainsAny(responseStr, "CONNECTED", "ERROR") { if common.ContainsAny(responseStr, "CONNECTED", "ERROR") {
+1 -7
View File
@@ -38,7 +38,6 @@ func NewFindNetPlugin() *FindNetPlugin {
// Scan 执行FindNet扫描 - Windows网络信息收集 // Scan 执行FindNet扫描 - Windows网络信息收集
func (p *FindNetPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *FindNetPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
target := info.Target() target := info.Target()
// 检查是否为RPC端口 // 检查是否为RPC端口
@@ -50,10 +49,8 @@ func (p *FindNetPlugin) Scan(ctx context.Context, info *common.HostInfo, session
} }
} }
// WrapperTcpWithTimeout内部已包含发包限制检查 conn, err := session.DialTCP(ctx, "tcp", target, config.Timeout)
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "findnet", Service: "findnet",
@@ -68,7 +65,6 @@ func (p *FindNetPlugin) Scan(ctx context.Context, info *common.HostInfo, session
// 执行RPC网络发现 // 执行RPC网络发现
networkInfo, err := p.performNetworkDiscovery(conn) networkInfo, err := p.performNetworkDiscovery(conn)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "findnet", Service: "findnet",
@@ -76,8 +72,6 @@ func (p *FindNetPlugin) Scan(ctx context.Context, info *common.HostInfo, session
} }
} }
state.IncrementTCPSuccessPacketCount()
// 记录发现的网络信息 (一次性输出,避免被其他日志打断) // 记录发现的网络信息 (一次性输出,避免被其他日志打断)
if networkInfo.Valid { if networkInfo.Valid {
var lines []string var lines []string
+16 -23
View File
@@ -25,16 +25,15 @@ func NewLDAPPlugin() *LDAPPlugin {
func (p *LDAPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *LDAPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(ctx, info, config, state) return p.identifyService(ctx, info, session)
} }
target := info.Target() target := info.Target()
// Hash 认证优先:检查是否配置了 Hash 和 Domain // Hash 认证优先:检查是否配置了 Hash 和 Domain
if len(config.Credentials.HashValues) > 0 && config.Credentials.Domain != "" { if len(config.Credentials.HashValues) > 0 && config.Credentials.Domain != "" {
result := p.tryHashAuth(ctx, info, config, state) result := p.tryHashAuth(ctx, info, session)
if result != nil && result.Success { if result != nil && result.Success {
return result return result
} }
@@ -50,7 +49,7 @@ func (p *LDAPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c
} }
// 使用公共框架进行并发凭据测试 // 使用公共框架进行并发凭据测试
authFn := p.createAuthFunc(info, config, state) authFn := p.createAuthFunc(info, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
result := TestCredentialsConcurrently(ctx, credentials, authFn, "ldap", testConfig) result := TestCredentialsConcurrently(ctx, credentials, authFn, "ldap", testConfig)
@@ -63,24 +62,22 @@ func (p *LDAPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c
} }
// createAuthFunc 创建LDAP认证函数 // createAuthFunc 创建LDAP认证函数
func (p *LDAPPlugin) createAuthFunc(info *common.HostInfo, config *common.Config, state *common.State) AuthFunc { func (p *LDAPPlugin) createAuthFunc(info *common.HostInfo, session *common.ScanSession) AuthFunc {
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
return p.doLDAPAuth(ctx, info, cred, config, state) return p.doLDAPAuth(ctx, info, cred, session)
} }
} }
// doLDAPAuth 执行LDAP认证 // doLDAPAuth 执行LDAP认证
func (p *LDAPPlugin) doLDAPAuth(ctx context.Context, info *common.HostInfo, cred Credential, config *common.Config, state *common.State) *AuthResult { func (p *LDAPPlugin) doLDAPAuth(ctx context.Context, info *common.HostInfo, cred Credential, session *common.ScanSession) *AuthResult {
conn, err := p.connectLDAP(ctx, info, config) conn, err := p.connectLDAP(ctx, info, session)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &AuthResult{ return &AuthResult{
Success: false, Success: false,
ErrorType: classifyLDAPErrorType(err), ErrorType: classifyLDAPErrorType(err),
Error: err, Error: err,
} }
} }
state.IncrementTCPSuccessPacketCount()
// 尝试多种DN格式进行绑定测试 // 尝试多种DN格式进行绑定测试
dnFormats := []string{ dnFormats := []string{
@@ -119,7 +116,8 @@ func (w *ldapConnWrapper) Close() error {
} }
// tryHashAuth 尝试 NTLM Hash 认证 // tryHashAuth 尝试 NTLM Hash 认证
func (p *LDAPPlugin) tryHashAuth(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *LDAPPlugin) tryHashAuth(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config
target := info.Target() target := info.Target()
domain := config.Credentials.Domain domain := config.Credentials.Domain
users := config.Credentials.Userdict["ldap"] users := config.Credentials.Userdict["ldap"]
@@ -141,7 +139,7 @@ func (p *LDAPPlugin) tryHashAuth(ctx context.Context, info *common.HostInfo, con
default: default:
} }
result := p.doNTLMHashAuth(ctx, info, domain, user, hash, config, state) result := p.doNTLMHashAuth(ctx, info, domain, user, hash, session)
if result.Success { if result.Success {
// 截断 hash 用于显示 // 截断 hash 用于显示
displayHash := hash displayHash := hash
@@ -164,17 +162,15 @@ func (p *LDAPPlugin) tryHashAuth(ctx context.Context, info *common.HostInfo, con
} }
// doNTLMHashAuth 执行单次 NTLM Hash 认证 // doNTLMHashAuth 执行单次 NTLM Hash 认证
func (p *LDAPPlugin) doNTLMHashAuth(ctx context.Context, info *common.HostInfo, domain, username, hash string, config *common.Config, state *common.State) *AuthResult { func (p *LDAPPlugin) doNTLMHashAuth(ctx context.Context, info *common.HostInfo, domain, username, hash string, session *common.ScanSession) *AuthResult {
conn, err := p.connectLDAP(ctx, info, config) conn, err := p.connectLDAP(ctx, info, session)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &AuthResult{ return &AuthResult{
Success: false, Success: false,
ErrorType: classifyLDAPErrorType(err), ErrorType: classifyLDAPErrorType(err),
Error: err, Error: err,
} }
} }
state.IncrementTCPSuccessPacketCount()
if err := conn.NTLMBindWithHash(domain, username, hash); err == nil { if err := conn.NTLMBindWithHash(domain, username, hash); err == nil {
return &AuthResult{ return &AuthResult{
@@ -194,7 +190,7 @@ func (p *LDAPPlugin) doNTLMHashAuth(ctx context.Context, info *common.HostInfo,
} }
// connectLDAP 连接LDAP服务器 // connectLDAP 连接LDAP服务器
func (p *LDAPPlugin) connectLDAP(ctx context.Context, info *common.HostInfo, config *common.Config) (*ldaplib.Conn, error) { func (p *LDAPPlugin) connectLDAP(ctx context.Context, info *common.HostInfo, session *common.ScanSession) (*ldaplib.Conn, error) {
target := info.Target() target := info.Target()
type result struct { type result struct {
@@ -204,7 +200,7 @@ func (p *LDAPPlugin) connectLDAP(ctx context.Context, info *common.HostInfo, con
resultChan := make(chan result, 1) resultChan := make(chan result, 1)
go func() { go func() {
tcpConn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) tcpConn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
resultChan <- result{nil, err} resultChan <- result{nil, err}
return return
@@ -225,7 +221,6 @@ func (p *LDAPPlugin) connectLDAP(ctx context.Context, info *common.HostInfo, con
case res := <-resultChan: case res := <-resultChan:
return res.conn, res.err return res.conn, res.err
case <-ctx.Done(): case <-ctx.Done():
// context 被取消,启动清理协程等待并关闭可能创建的连接
go func() { go func() {
res := <-resultChan res := <-resultChan
if res.conn != nil { if res.conn != nil {
@@ -259,19 +254,17 @@ func classifyLDAPErrorType(err error) ErrorType {
return ClassifyError(err, ldapAuthErrors, ldapNetworkErrors) return ClassifyError(err, ldapAuthErrors, ldapNetworkErrors)
} }
func (p *LDAPPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *LDAPPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
conn, err := p.connectLDAP(ctx, info, config) conn, err := p.connectLDAP(ctx, info, session)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "ldap", Service: "ldap",
Error: err, Error: err,
} }
} }
state.IncrementTCPSuccessPacketCount()
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
banner := "LDAP" banner := "LDAP"
+12 -15
View File
@@ -26,15 +26,14 @@ func NewMemcachedPlugin() *MemcachedPlugin {
func (p *MemcachedPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *MemcachedPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
target := info.Target() target := info.Target()
if config.DisableBrute { 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 { if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success {
common.LogVuln(i18n.Tr("memcached_unauth", target)) common.LogVuln(i18n.Tr("memcached_unauth", target))
return result return result
} }
@@ -48,14 +47,14 @@ func (p *MemcachedPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi
} }
// testUnauthorizedAccess 测试Memcached未授权访问 // testUnauthorizedAccess 测试Memcached未授权访问
func (p *MemcachedPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *MemcachedPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
conn := p.connectToMemcached(ctx, info, config, state) conn := p.connectToMemcached(ctx, info, session)
if conn == nil { if conn == nil {
return nil return nil
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
if p.testBasicCommand(conn, config) { if p.testBasicCommand(conn, session.Config) {
return &ScanResult{ return &ScanResult{
Type: plugins.ResultTypeVuln, Type: plugins.ResultTypeVuln,
Success: true, Success: true,
@@ -67,20 +66,19 @@ func (p *MemcachedPlugin) testUnauthorizedAccess(ctx context.Context, info *comm
return nil return nil
} }
func (p *MemcachedPlugin) connectToMemcached(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) net.Conn { func (p *MemcachedPlugin) connectToMemcached(ctx context.Context, info *common.HostInfo, session *common.ScanSession) net.Conn {
target := info.Target() target := info.Target()
timeout := session.Config.Timeout
connChan := make(chan net.Conn, 1) connChan := make(chan net.Conn, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
connChan <- nil connChan <- nil
return return
} }
state.IncrementTCPSuccessPacketCount() _ = conn.SetDeadline(time.Now().Add(timeout))
_ = conn.SetDeadline(time.Now().Add(config.Timeout))
connChan <- conn connChan <- conn
}() }()
@@ -88,7 +86,6 @@ func (p *MemcachedPlugin) connectToMemcached(ctx context.Context, info *common.H
case conn := <-connChan: case conn := <-connChan:
return conn return conn
case <-ctx.Done(): case <-ctx.Done():
// context 被取消,启动清理协程等待并关闭可能创建的连接
go func() { go func() {
conn := <-connChan conn := <-connChan
if conn != nil { if conn != nil {
@@ -116,10 +113,10 @@ func (p *MemcachedPlugin) testBasicCommand(conn net.Conn, config *common.Config)
return common.ContainsAny(responseStr, "VERSION", "memcached") return common.ContainsAny(responseStr, "VERSION", "memcached")
} }
func (p *MemcachedPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *MemcachedPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
conn := p.connectToMemcached(ctx, info, config, state) conn := p.connectToMemcached(ctx, info, session)
if conn == nil { if conn == nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
@@ -129,7 +126,7 @@ func (p *MemcachedPlugin) identifyService(ctx context.Context, info *common.Host
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
if p.testBasicCommand(conn, config) { if p.testBasicCommand(conn, session.Config) {
banner := "Memcached" banner := "Memcached"
common.LogSuccess(i18n.Tr("memcached_service", target, banner)) common.LogSuccess(i18n.Tr("memcached_service", target, banner))
return &ScanResult{ return &ScanResult{
+10 -10
View File
@@ -34,11 +34,11 @@ func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo, session
target := info.Target() target := info.Target()
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(ctx, info, config) return p.identifyService(ctx, info, session)
} }
// 首先检测未授权访问 // 首先检测未授权访问
isUnauth, err := p.mongodbUnauth(ctx, info, config) isUnauth, err := p.mongodbUnauth(ctx, info, session)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
@@ -184,10 +184,10 @@ func classifyMongoDBErrorType(err error) ErrorType {
return ClassifyError(err, mongoAuthErrors, mongoNetworkErrors) return ClassifyError(err, mongoAuthErrors, mongoNetworkErrors)
} }
func (p *MongoDBPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config) *ScanResult { func (p *MongoDBPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
isUnauth, err := p.mongodbUnauth(ctx, info, config) isUnauth, err := p.mongodbUnauth(ctx, info, session)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
@@ -216,14 +216,14 @@ func (p *MongoDBPlugin) identifyService(ctx context.Context, info *common.HostIn
} }
// mongodbUnauth 检测MongoDB未授权访问 // mongodbUnauth 检测MongoDB未授权访问
func (p *MongoDBPlugin) mongodbUnauth(ctx context.Context, info *common.HostInfo, config *common.Config) (bool, error) { func (p *MongoDBPlugin) mongodbUnauth(ctx context.Context, info *common.HostInfo, session *common.ScanSession) (bool, error) {
msgPacket := p.createOpMsgPacket() msgPacket := p.createOpMsgPacket()
queryPacket := p.createOpQueryPacket() queryPacket := p.createOpQueryPacket()
realhost := fmt.Sprintf("%s:%d", info.Host, info.Port) realhost := fmt.Sprintf("%s:%d", info.Host, info.Port)
reply, err := p.checkMongoAuth(ctx, realhost, msgPacket, config) reply, err := p.checkMongoAuth(ctx, realhost, msgPacket, session)
if err != nil { if err != nil {
reply, err = p.checkMongoAuth(ctx, realhost, queryPacket, config) reply, err = p.checkMongoAuth(ctx, realhost, queryPacket, session)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -241,8 +241,8 @@ func (p *MongoDBPlugin) mongodbUnauth(ctx context.Context, info *common.HostInfo
} }
// checkMongoAuth 检查MongoDB认证状态 // checkMongoAuth 检查MongoDB认证状态
func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, packet []byte, config *common.Config) (string, error) { func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, packet []byte, session *common.ScanSession) (string, error) {
conn, err := common.WrapperTcpWithTimeout("tcp", address, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", address, session.Config.Timeout)
if err != nil { if err != nil {
return "", fmt.Errorf("连接失败: %w", err) return "", fmt.Errorf("连接失败: %w", err)
} }
@@ -254,7 +254,7 @@ func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, pack
default: default:
} }
if deadlineErr := conn.SetDeadline(time.Now().Add(config.Timeout)); deadlineErr != nil { if deadlineErr := conn.SetDeadline(time.Now().Add(session.Config.Timeout)); deadlineErr != nil {
return "", fmt.Errorf("设置超时失败: %w", deadlineErr) return "", fmt.Errorf("设置超时失败: %w", deadlineErr)
} }
+14 -25
View File
@@ -36,7 +36,6 @@ func NewMS17010Plugin() *MS17010Plugin {
// Scan 执行MS17-010扫描 // Scan 执行MS17-010扫描
func (p *MS17010Plugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *MS17010Plugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
// 如果禁用暴力破解,也禁用漏洞检测 // 如果禁用暴力破解,也禁用漏洞检测
if config.DisableBrute { if config.DisableBrute {
return &ScanResult{ return &ScanResult{
@@ -58,7 +57,7 @@ func (p *MS17010Plugin) Scan(ctx context.Context, info *common.HostInfo, session
} }
// 执行MS17010漏洞检测 // 执行MS17010漏洞检测
vulnerable, osVersion, err := p.checkMS17010Vulnerability(info.Host, config, state) vulnerable, osVersion, err := p.checkMS17010Vulnerability(ctx, info.Host, session)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
@@ -90,7 +89,8 @@ func (p *MS17010Plugin) Scan(ctx context.Context, info *common.HostInfo, session
} }
// Exploit 执行MS17-010漏洞利用 // Exploit 执行MS17-010漏洞利用
func (p *MS17010Plugin) Exploit(ctx context.Context, info *common.HostInfo, creds Credential, config *common.Config) *ExploitResult { func (p *MS17010Plugin) Exploit(ctx context.Context, info *common.HostInfo, creds Credential, session *common.ScanSession) *ExploitResult {
config := session.Config
target := info.Target() target := info.Target()
common.LogSuccess(i18n.Tr("ms17010_start", target)) common.LogSuccess(i18n.Tr("ms17010_start", target))
@@ -98,7 +98,7 @@ func (p *MS17010Plugin) Exploit(ctx context.Context, info *common.HostInfo, cred
output.WriteString(fmt.Sprintf("=== MS17-010漏洞利用结果 - %s ===\n", target)) output.WriteString(fmt.Sprintf("=== MS17-010漏洞利用结果 - %s ===\n", target))
// 首先确认漏洞存在 // 首先确认漏洞存在
vulnerable, osVersion, err := p.checkMS17010Vulnerability(info.Host, config, nil) vulnerable, osVersion, err := p.checkMS17010Vulnerability(ctx, info.Host, session)
if err != nil { if err != nil {
output.WriteString(fmt.Sprintf("\n[漏洞检测失败] %v\n", err)) output.WriteString(fmt.Sprintf("\n[漏洞检测失败] %v\n", err))
return &ExploitResult{ return &ExploitResult{
@@ -123,7 +123,7 @@ func (p *MS17010Plugin) Exploit(ctx context.Context, info *common.HostInfo, cred
} }
// 检测DOUBLEPULSAR后门 // 检测DOUBLEPULSAR后门
hasBackdoor := p.checkDoublePulsar(info.Host, config) hasBackdoor := p.checkDoublePulsar(ctx, info.Host, session)
if hasBackdoor { if hasBackdoor {
output.WriteString("\n[后门检测] ⚠️ 发现DOUBLEPULSAR后门\n") output.WriteString("\n[后门检测] ⚠️ 发现DOUBLEPULSAR后门\n")
} else { } else {
@@ -136,7 +136,7 @@ func (p *MS17010Plugin) Exploit(ctx context.Context, info *common.HostInfo, cred
output.WriteString("[利用状态] 开始执行EternalBlue攻击...\n") output.WriteString("[利用状态] 开始执行EternalBlue攻击...\n")
// 执行实际的MS17010利用 // 执行实际的MS17010利用
err = p.executeMS17010Exploit(info, config) err = p.executeMS17010Exploit(info, session)
if err != nil { if err != nil {
output.WriteString(fmt.Sprintf("[利用结果] ❌ 利用失败: %v\n", err)) output.WriteString(fmt.Sprintf("[利用结果] ❌ 利用失败: %v\n", err))
return &ExploitResult{ return &ExploitResult{
@@ -284,18 +284,14 @@ func init() {
} }
// checkMS17010Vulnerability 检测MS17-010漏洞 (从原始MS17010.go复制和适配) // checkMS17010Vulnerability 检测MS17-010漏洞 (从原始MS17010.go复制和适配)
func (p *MS17010Plugin) checkMS17010Vulnerability(ip string, config *common.Config, state *common.State) (bool, string, error) { func (p *MS17010Plugin) checkMS17010Vulnerability(ctx context.Context, ip string, session *common.ScanSession) (bool, string, error) {
// 使用统一TCP包装器,支持代理和限流 conn, err := session.DialTCP(ctx, "tcp", ip+":445", session.Config.Timeout)
conn, err := common.WrapperTcpWithTimeout("tcp", ip+":445", config.Timeout)
if err != nil { if err != nil {
if state != nil {
state.IncrementTCPFailedPacketCount()
}
return false, "", fmt.Errorf("连接错误: %w", err) return false, "", fmt.Errorf("连接错误: %w", err)
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
if err = conn.SetDeadline(time.Now().Add(config.Timeout)); err != nil { if err = conn.SetDeadline(time.Now().Add(session.Config.Timeout)); err != nil {
return false, "", fmt.Errorf("设置超时错误: %w", err) return false, "", fmt.Errorf("设置超时错误: %w", err)
} }
@@ -383,29 +379,22 @@ func (p *MS17010Plugin) checkMS17010Vulnerability(ip string, config *common.Conf
// 漏洞检测 - 关键检查点 // 漏洞检测 - 关键检查点
if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 { if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 {
if state != nil {
state.IncrementTCPSuccessPacketCount()
}
return true, osVersion, nil return true, osVersion, nil
} }
if state != nil {
state.IncrementTCPSuccessPacketCount()
}
return false, osVersion, nil return false, osVersion, nil
} }
// checkDoublePulsar 检测DOUBLEPULSAR后门 // checkDoublePulsar 检测DOUBLEPULSAR后门
func (p *MS17010Plugin) checkDoublePulsar(ip string, config *common.Config) bool { func (p *MS17010Plugin) checkDoublePulsar(ctx context.Context, ip string, session *common.ScanSession) bool {
// 使用统一TCP包装器,支持代理和限流 conn, err := session.DialTCP(ctx, "tcp", ip+":445", session.Config.Timeout)
conn, err := common.WrapperTcpWithTimeout("tcp", ip+":445", config.Timeout)
if err != nil { if err != nil {
return false return false
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
// 简化的后门检测逻辑 // 简化的后门检测逻辑
vulnerable, _, err := p.checkMS17010Vulnerability(ip, config, nil) vulnerable, _, err := p.checkMS17010Vulnerability(ctx, ip, session)
if err != nil || !vulnerable { if err != nil || !vulnerable {
return false return false
} }
@@ -416,8 +405,8 @@ func (p *MS17010Plugin) checkDoublePulsar(ip string, config *common.Config) bool
} }
// executeMS17010Exploit 执行MS17010漏洞利用 (简化版,保留接口) // executeMS17010Exploit 执行MS17010漏洞利用 (简化版,保留接口)
func (p *MS17010Plugin) executeMS17010Exploit(info *common.HostInfo, config *common.Config) error { func (p *MS17010Plugin) executeMS17010Exploit(info *common.HostInfo, session *common.ScanSession) error {
// address := info.Host + ":445" // 暂时不使用,为了保持原始复杂度 config := session.Config
var sc string var sc string
// 根据不同类型选择shellcode (从MS17010-Exp.go复制) // 根据不同类型选择shellcode (从MS17010-Exp.go复制)
+4 -4
View File
@@ -40,7 +40,7 @@ func (p *MySQLPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
config := session.Config config := session.Config
state := session.State state := session.State
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(info, config) return p.identifyService(ctx, info, session)
} }
credentials := GenerateCredentials("mysql", config) credentials := GenerateCredentials("mysql", config)
@@ -139,10 +139,10 @@ func classifyMySQLErrorType(err error) ErrorType {
return ClassifyError(err, mysqlAuthErrors, mysqlNetworkErrors) return ClassifyError(err, mysqlAuthErrors, mysqlNetworkErrors)
} }
func (p *MySQLPlugin) identifyService(info *common.HostInfo, config *common.Config) *ScanResult { func (p *MySQLPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
conn, err := common.SafeTCPDial(target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
@@ -152,7 +152,7 @@ func (p *MySQLPlugin) identifyService(info *common.HostInfo, config *common.Conf
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
if banner := p.readMySQLBanner(conn, config); banner != "" { if banner := p.readMySQLBanner(conn, session.Config); banner != "" {
common.LogSuccess(i18n.Tr("mysql_service", target, banner)) common.LogSuccess(i18n.Tr("mysql_service", target, banner))
return &ScanResult{ return &ScanResult{
Type: plugins.ResultTypeService, Type: plugins.ResultTypeService,
+4 -4
View File
@@ -51,7 +51,7 @@ func (p *NetBIOSPlugin) Scan(ctx context.Context, info *common.HostInfo, session
netbiosInfo, err = p.queryNetBIOSNames(info.Host, config, state) netbiosInfo, err = p.queryNetBIOSNames(info.Host, config, state)
} else { } else {
// TCP端口139 - NetBIOS会话服务 // TCP端口139 - NetBIOS会话服务
netbiosInfo, err = p.queryNetBIOSSession(info.Host, config) netbiosInfo, err = p.queryNetBIOSSession(ctx, info.Host, session)
} }
if err != nil { if err != nil {
@@ -186,16 +186,16 @@ func (p *NetBIOSPlugin) queryNetBIOSNames(host string, config *common.Config, st
} }
// queryNetBIOSSession 查询NetBIOS会话服务(TCP 139) // queryNetBIOSSession 查询NetBIOS会话服务(TCP 139)
func (p *NetBIOSPlugin) queryNetBIOSSession(host string, config *common.Config) (*NetBIOSInfo, error) { func (p *NetBIOSPlugin) queryNetBIOSSession(ctx context.Context, host string, session *common.ScanSession) (*NetBIOSInfo, error) {
target := fmt.Sprintf("%s:139", host) target := fmt.Sprintf("%s:139", host)
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
return nil, fmt.Errorf("连接NetBIOS会话服务失败: %w", err) return nil, fmt.Errorf("连接NetBIOS会话服务失败: %w", err)
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(config.Timeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout))
// 发送SMB协商数据包 // 发送SMB协商数据包
smbNegotiate1 := []byte{ smbNegotiate1 := []byte{
+3 -3
View File
@@ -30,7 +30,7 @@ func (p *OraclePlugin) Scan(ctx context.Context, info *common.HostInfo, session
target := info.Target() target := info.Target()
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(ctx, info, config, state) return p.identifyService(ctx, info, session)
} }
// 先测试未授权访问 // 先测试未授权访问
@@ -180,10 +180,10 @@ func (p *OraclePlugin) testUnauthorizedAccess(ctx context.Context, info *common.
return nil return nil
} }
func (p *OraclePlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *OraclePlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
+10 -8
View File
@@ -32,7 +32,7 @@ func (p *RabbitMQPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
target := info.Target() target := info.Target()
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(ctx, info, config, state) return p.identifyService(ctx, info, session)
} }
// 先检测未授权访问 // 先检测未授权访问
@@ -211,16 +211,16 @@ func (p *RabbitMQPlugin) testUnauthorizedAccess(ctx context.Context, info *commo
} }
// testAMQPProtocol 检测AMQP协议 // testAMQPProtocol 检测AMQP协议
func (p *RabbitMQPlugin) testAMQPProtocol(ctx context.Context, info *common.HostInfo, config *common.Config) *ScanResult { func (p *RabbitMQPlugin) testAMQPProtocol(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
return nil return nil
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(config.Timeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout))
// 发送AMQP协议头 // 发送AMQP协议头
amqpHeader := []byte{0x41, 0x4d, 0x51, 0x50, 0x00, 0x00, 0x09, 0x01} amqpHeader := []byte{0x41, 0x4d, 0x51, 0x50, 0x00, 0x00, 0x09, 0x01}
@@ -249,19 +249,21 @@ func (p *RabbitMQPlugin) testAMQPProtocol(ctx context.Context, info *common.Host
return nil return nil
} }
func (p *RabbitMQPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *RabbitMQPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
// 对于AMQP端口,检测AMQP协议 // 对于AMQP端口,检测AMQP协议
if info.Port == 5672 || info.Port == 5671 { if info.Port == 5672 || info.Port == 5671 {
if result := p.testAMQPProtocol(ctx, info, config); result != nil && result.Success { if result := p.testAMQPProtocol(ctx, info, session); result != nil && result.Success {
return result return result
} }
} }
// 检测HTTP管理界面 // 检测HTTP管理界面
return p.testManagementInterface(ctx, info, config, state) return p.testManagementInterface(ctx, info, session)
} }
func (p *RabbitMQPlugin) testManagementInterface(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *RabbitMQPlugin) testManagementInterface(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config
state := session.State
target := info.Target() target := info.Target()
baseURL := fmt.Sprintf("http://%s:%d", info.Host, info.Port) baseURL := fmt.Sprintf("http://%s:%d", info.Host, info.Port)
+20 -26
View File
@@ -33,21 +33,20 @@ func NewRedisPlugin() *RedisPlugin {
// Scan 执行Redis扫描 // Scan 执行Redis扫描
func (p *RedisPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *RedisPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
target := info.Target() target := info.Target()
// 如果禁用暴力破解,只做服务识别 // 如果禁用暴力破解,只做服务识别
if config.DisableBrute { 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 { if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success {
common.LogVuln(i18n.Tr("redis_unauth_success", target)) //nolint:govet common.LogVuln(i18n.Tr("redis_unauth_success", target)) //nolint:govet
// 如果需要利用,重新建立连接执行 // 如果需要利用,重新建立连接执行
if p.shouldExploit(config) { if p.shouldExploit(config) {
p.exploitWithPassword(ctx, info, "", config) p.exploitWithPassword(ctx, info, "", session)
} }
return result return result
} }
@@ -56,7 +55,7 @@ func (p *RedisPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
credentials := GenerateCredentials("redis", config) credentials := GenerateCredentials("redis", config)
// 使用公共框架进行并发凭据测试 // 使用公共框架进行并发凭据测试
authFn := p.createAuthFunc(info, config, state) authFn := p.createAuthFunc(info, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
testConfig.Concurrency = 20 // Redis 默认并发度更高 testConfig.Concurrency = 20 // Redis 默认并发度更高
@@ -68,7 +67,7 @@ func (p *RedisPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
// 如果需要利用,重新建立连接执行 // 如果需要利用,重新建立连接执行
if p.shouldExploit(config) { if p.shouldExploit(config) {
p.exploitWithPassword(ctx, info, result.Password, config) p.exploitWithPassword(ctx, info, result.Password, session)
} }
} }
@@ -76,21 +75,20 @@ func (p *RedisPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
} }
// createAuthFunc 创建Redis认证函数 // createAuthFunc 创建Redis认证函数
func (p *RedisPlugin) createAuthFunc(info *common.HostInfo, config *common.Config, state *common.State) AuthFunc { func (p *RedisPlugin) createAuthFunc(info *common.HostInfo, session *common.ScanSession) AuthFunc {
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
return p.doRedisAuth(ctx, info, cred, config, state) return p.doRedisAuth(ctx, info, cred, session)
} }
} }
// doRedisAuth 执行Redis认证 // doRedisAuth 执行Redis认证
func (p *RedisPlugin) doRedisAuth(ctx context.Context, info *common.HostInfo, cred Credential, config *common.Config, state *common.State) *AuthResult { func (p *RedisPlugin) doRedisAuth(ctx context.Context, info *common.HostInfo, cred Credential, session *common.ScanSession) *AuthResult {
target := info.Target() target := info.Target()
timeout := config.Timeout timeout := session.Config.Timeout
// 建立TCP连接 // 建立TCP连接
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) conn, err := session.DialTCP(ctx, "tcp", target, timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &AuthResult{ return &AuthResult{
Success: false, Success: false,
ErrorType: classifyRedisErrorType(err), ErrorType: classifyRedisErrorType(err),
@@ -169,7 +167,6 @@ func (p *RedisPlugin) doRedisAuth(ctx context.Context, info *common.HostInfo, cr
responseStr := string(response[:n]) responseStr := string(response[:n])
if !strings.Contains(responseStr, "PONG") { if !strings.Contains(responseStr, "PONG") {
_ = conn.Close() _ = conn.Close()
state.IncrementTCPFailedPacketCount()
return &AuthResult{ return &AuthResult{
Success: false, Success: false,
ErrorType: ErrorTypeUnknown, ErrorType: ErrorTypeUnknown,
@@ -177,7 +174,6 @@ func (p *RedisPlugin) doRedisAuth(ctx context.Context, info *common.HostInfo, cr
} }
} }
state.IncrementTCPSuccessPacketCount()
return &AuthResult{ return &AuthResult{
Success: true, Success: true,
Conn: conn, Conn: conn,
@@ -204,10 +200,10 @@ func classifyRedisErrorType(err error) ErrorType {
} }
// testUnauthorizedAccess 测试未授权访问 // testUnauthorizedAccess 测试未授权访问
func (p *RedisPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *RedisPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
emptyCred := Credential{Username: "", Password: ""} emptyCred := Credential{Username: "", Password: ""}
result := p.doRedisAuth(ctx, info, emptyCred, config, state) result := p.doRedisAuth(ctx, info, emptyCred, session)
if result.Success { if result.Success {
if result.Conn != nil { if result.Conn != nil {
_ = result.Conn.Close() _ = result.Conn.Close()
@@ -224,10 +220,10 @@ func (p *RedisPlugin) testUnauthorizedAccess(ctx context.Context, info *common.H
} }
// exploitWithPassword 使用指定密码建立连接并执行利用 // exploitWithPassword 使用指定密码建立连接并执行利用
func (p *RedisPlugin) exploitWithPassword(ctx context.Context, info *common.HostInfo, password string, config *common.Config) { func (p *RedisPlugin) exploitWithPassword(ctx context.Context, info *common.HostInfo, password string, session *common.ScanSession) {
target := info.Target() target := info.Target()
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
common.LogError(i18n.Tr("redis_reconnect_failed", err)) common.LogError(i18n.Tr("redis_reconnect_failed", err))
return return
@@ -237,28 +233,27 @@ func (p *RedisPlugin) exploitWithPassword(ctx context.Context, info *common.Host
// 如果有密码,先认证 // 如果有密码,先认证
if password != "" { if password != "" {
authCmd := fmt.Sprintf("AUTH %s\r\n", password) authCmd := fmt.Sprintf("AUTH %s\r\n", password)
_ = conn.SetWriteDeadline(time.Now().Add(config.Timeout)) _ = conn.SetWriteDeadline(time.Now().Add(session.Config.Timeout))
if _, writeErr := conn.Write([]byte(authCmd)); writeErr != nil { if _, writeErr := conn.Write([]byte(authCmd)); writeErr != nil {
return return
} }
_ = conn.SetReadDeadline(time.Now().Add(config.Timeout)) _ = conn.SetReadDeadline(time.Now().Add(session.Config.Timeout))
response := make([]byte, 512) response := make([]byte, 512)
if _, readErr := conn.Read(response); readErr != nil { if _, readErr := conn.Read(response); readErr != nil {
return return
} }
} }
p.exploit(ctx, info, conn, password, config) p.exploit(ctx, info, conn, password, session.Config)
} }
// identifyService 服务识别 // identifyService 服务识别
func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
timeout := config.Timeout timeout := session.Config.Timeout
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) conn, err := session.DialTCP(ctx, "tcp", target, timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "redis", Service: "redis",
@@ -302,7 +297,6 @@ func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo
banner = "Redis服务" banner = "Redis服务"
} }
state.IncrementTCPSuccessPacketCount()
common.LogSuccess(i18n.Tr("redis_service_identified", target, banner)) //nolint:govet common.LogSuccess(i18n.Tr("redis_service_identified", target, banner)) //nolint:govet
return &ScanResult{ return &ScanResult{
+17 -25
View File
@@ -30,17 +30,16 @@ func NewRsyncPlugin() *RsyncPlugin {
func (p *RsyncPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *RsyncPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
target := info.Target() target := info.Target()
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(ctx, info, config, state) return p.identifyService(ctx, info, session)
} }
var findings []string var findings []string
// 检测未授权访问 // 检测未授权访问
if result := p.testUnauthorizedAccess(ctx, info, config, state); result != nil && result.Success { if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success {
common.LogSuccess(i18n.Tr("rsync_service", target, result.Banner)) common.LogSuccess(i18n.Tr("rsync_service", target, result.Banner))
findings = append(findings, result.Banner) findings = append(findings, result.Banner)
} }
@@ -70,7 +69,7 @@ func (p *RsyncPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
} }
// 使用公共框架进行并发凭据测试 // 使用公共框架进行并发凭据测试
authFn := p.createAuthFunc(info, config, state) authFn := p.createAuthFunc(info, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
result := TestCredentialsConcurrently(ctx, creds, authFn, "rsync", testConfig) result := TestCredentialsConcurrently(ctx, creds, authFn, "rsync", testConfig)
@@ -97,16 +96,16 @@ func (p *RsyncPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
} }
// createAuthFunc 创建Rsync认证函数 // createAuthFunc 创建Rsync认证函数
func (p *RsyncPlugin) createAuthFunc(info *common.HostInfo, config *common.Config, state *common.State) AuthFunc { func (p *RsyncPlugin) createAuthFunc(info *common.HostInfo, session *common.ScanSession) AuthFunc {
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
return p.doRsyncAuth(ctx, info, cred, config, state) return p.doRsyncAuth(ctx, info, cred, session)
} }
} }
// doRsyncAuth 执行Rsync认证 // doRsyncAuth 执行Rsync认证
func (p *RsyncPlugin) doRsyncAuth(ctx context.Context, info *common.HostInfo, cred Credential, config *common.Config, state *common.State) *AuthResult { func (p *RsyncPlugin) doRsyncAuth(ctx context.Context, info *common.HostInfo, cred Credential, session *common.ScanSession) *AuthResult {
// 先获取可用模块列表 // 先获取可用模块列表
conn := p.connectToRsync(ctx, info, config, state) conn := p.connectToRsync(ctx, info, session)
if conn == nil { if conn == nil {
return &AuthResult{ return &AuthResult{
Success: false, Success: false,
@@ -114,7 +113,7 @@ func (p *RsyncPlugin) doRsyncAuth(ctx context.Context, info *common.HostInfo, cr
Error: fmt.Errorf("无法连接到Rsync服务"), Error: fmt.Errorf("无法连接到Rsync服务"),
} }
} }
modules := p.getModules(conn, config) modules := p.getModules(conn, session.Config)
_ = conn.Close() _ = conn.Close()
if len(modules) == 0 { if len(modules) == 0 {
@@ -142,7 +141,6 @@ func (p *RsyncPlugin) doRsyncAuth(ctx context.Context, info *common.HostInfo, cr
) )
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
errMsg := err.Error() errMsg := err.Error()
if common.ContainsAny(errMsg, "auth", "password") { if common.ContainsAny(errMsg, "auth", "password") {
return &AuthResult{ return &AuthResult{
@@ -158,7 +156,6 @@ func (p *RsyncPlugin) doRsyncAuth(ctx context.Context, info *common.HostInfo, cr
} }
} }
state.IncrementTCPSuccessPacketCount()
return &AuthResult{ return &AuthResult{
Success: true, Success: true,
Conn: &rsyncConnWrapper{}, Conn: &rsyncConnWrapper{},
@@ -208,14 +205,14 @@ func classifyRsyncErrorType(err error) ErrorType {
} }
// testUnauthorizedAccess 测试未授权访问 // testUnauthorizedAccess 测试未授权访问
func (p *RsyncPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *RsyncPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
conn := p.connectToRsync(ctx, info, config, state) conn := p.connectToRsync(ctx, info, session)
if conn == nil { if conn == nil {
return nil return nil
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
modules := p.getModules(conn, config) modules := p.getModules(conn, session.Config)
if len(modules) > 0 { if len(modules) > 0 {
banner := fmt.Sprintf("未授权访问 - 可用模块: %s", strings.Join(modules, ", ")) banner := fmt.Sprintf("未授权访问 - 可用模块: %s", strings.Join(modules, ", "))
@@ -231,22 +228,18 @@ func (p *RsyncPlugin) testUnauthorizedAccess(ctx context.Context, info *common.H
} }
// connectToRsync 连接到Rsync服务 // connectToRsync 连接到Rsync服务
func (p *RsyncPlugin) connectToRsync(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) net.Conn { func (p *RsyncPlugin) connectToRsync(ctx context.Context, info *common.HostInfo, session *common.ScanSession) net.Conn {
target := info.Target() target := info.Target()
timeout := session.Config.Timeout
connChan := make(chan net.Conn, 1) connChan := make(chan net.Conn, 1)
go func() { go func() {
timeout := config.Timeout conn, err := session.DialTCP(ctx, "tcp", target, timeout)
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
connChan <- nil connChan <- nil
return return
} }
state.IncrementTCPSuccessPacketCount()
_ = conn.SetDeadline(time.Now().Add(timeout)) _ = conn.SetDeadline(time.Now().Add(timeout))
connChan <- conn connChan <- conn
}() }()
@@ -255,7 +248,6 @@ func (p *RsyncPlugin) connectToRsync(ctx context.Context, info *common.HostInfo,
case conn := <-connChan: case conn := <-connChan:
return conn return conn
case <-ctx.Done(): case <-ctx.Done():
// context 被取消,启动清理协程等待并关闭可能创建的连接
go func() { go func() {
conn := <-connChan conn := <-connChan
if conn != nil { if conn != nil {
@@ -328,10 +320,10 @@ func (p *RsyncPlugin) getModules(conn net.Conn, config *common.Config) []string
} }
// identifyService Rsync服务识别 // identifyService Rsync服务识别
func (p *RsyncPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *RsyncPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
conn := p.connectToRsync(ctx, info, config, state) conn := p.connectToRsync(ctx, info, session)
if conn == nil { if conn == nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
@@ -341,7 +333,7 @@ func (p *RsyncPlugin) identifyService(ctx context.Context, info *common.HostInfo
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
timeout := config.Timeout timeout := session.Config.Timeout
_ = conn.SetWriteDeadline(time.Now().Add(timeout)) _ = conn.SetWriteDeadline(time.Now().Add(timeout))
if _, err := conn.Write([]byte("\n")); err != nil { if _, err := conn.Write([]byte("\n")); err != nil {
+6 -12
View File
@@ -39,23 +39,21 @@ func (p *SmbPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
} }
// 1. 协议探测和信息收集 // 1. 协议探测和信息收集
smbTarget, err := probeTarget(info.Host, info.Port, config.Timeout) smbTarget, err := probeTarget(ctx, info.Host, info.Port, config.Timeout, session)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "smb", Service: "smb",
Error: fmt.Errorf("SMB协议探测失败: %w", err), Error: fmt.Errorf("SMB协议探测失败: %w", err),
} }
} }
state.IncrementTCPSuccessPacketCount()
// 输出信息收集结果 // 输出信息收集结果
p.logSMBInfo(target, smbTarget) p.logSMBInfo(target, smbTarget)
// 2. 漏洞检测 (仅SMBv2+且端口445) // 2. 漏洞检测 (仅SMBv2+且端口445)
if smbTarget.Protocol == SMBProtocol2 && info.Port == 445 { if smbTarget.Protocol == SMBProtocol2 && info.Port == 445 {
if checkSMBGhost(info.Host, config.Timeout) { if checkSMBGhost(ctx, info.Host, config.Timeout, session) {
smbTarget.Vulnerable = &SMBVuln{CVE20200796: true} smbTarget.Vulnerable = &SMBVuln{CVE20200796: true}
common.LogVuln(i18n.Tr("smbghost_vuln", target)) common.LogVuln(i18n.Tr("smbghost_vuln", target))
} }
@@ -92,7 +90,7 @@ func (p *SmbPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
creds[i] = Credential{Username: c.Username, Password: c.Password} creds[i] = Credential{Username: c.Username, Password: c.Password}
} }
authFn := p.createAuthFunc(info, auth, config, state) authFn := p.createAuthFunc(info, auth, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
result := TestCredentialsConcurrently(ctx, creds, authFn, "smb", testConfig) result := TestCredentialsConcurrently(ctx, creds, authFn, "smb", testConfig)
@@ -119,14 +117,10 @@ func (p *SmbPlugin) getAuthenticator(protocol SMBProtocol) SMBAuthenticator {
} }
// createAuthFunc 创建认证函数 // createAuthFunc 创建认证函数
func (p *SmbPlugin) createAuthFunc(info *common.HostInfo, auth SMBAuthenticator, config *common.Config, state *common.State) AuthFunc { func (p *SmbPlugin) createAuthFunc(info *common.HostInfo, auth SMBAuthenticator, session *common.ScanSession) AuthFunc {
config := session.Config
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
result, _ := auth.Authenticate(ctx, info.Host, info.Port, cred, config.Credentials.Domain, config.Timeout) result, _ := auth.Authenticate(ctx, info.Host, info.Port, cred, config.Credentials.Domain, config.Timeout, session)
if result.Success {
state.IncrementTCPSuccessPacketCount()
} else {
state.IncrementTCPFailedPacketCount()
}
return result return result
} }
} }
+11 -11
View File
@@ -201,10 +201,10 @@ var (
) )
// probeTarget 探测目标SMB信息(协议版本、系统信息) // probeTarget 探测目标SMB信息(协议版本、系统信息)
func probeTarget(host string, port int, timeout time.Duration) (*SMBTarget, error) { func probeTarget(ctx context.Context, host string, port int, timeout time.Duration, session *common.ScanSession) (*SMBTarget, error) {
target := fmt.Sprintf("%s:%d", host, port) target := fmt.Sprintf("%s:%d", host, port)
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) conn, err := session.DialTCP(ctx, "tcp", target, timeout)
if err != nil { if err != nil {
return nil, fmt.Errorf("连接失败: %w", err) return nil, fmt.Errorf("连接失败: %w", err)
} }
@@ -230,7 +230,7 @@ func probeTarget(host string, port int, timeout time.Duration) (*SMBTarget, erro
} }
// SMBv2路径 // SMBv2路径
return probeSMBv2(target, timeout) return probeSMBv2(ctx, target, timeout, session)
} }
// probeSMBv1 处理SMBv1协议信息收集 // probeSMBv1 处理SMBv1协议信息收集
@@ -288,8 +288,8 @@ func probeSMBv1(conn net.Conn, target string, timeout time.Duration) (*SMBTarget
} }
// probeSMBv2 处理SMBv2协议信息收集 // probeSMBv2 处理SMBv2协议信息收集
func probeSMBv2(target string, timeout time.Duration) (*SMBTarget, error) { func probeSMBv2(ctx context.Context, target string, timeout time.Duration, session *common.ScanSession) (*SMBTarget, error) {
conn2, err := common.WrapperTcpWithTimeout("tcp", target, timeout) conn2, err := session.DialTCP(ctx, "tcp", target, timeout)
if err != nil { if err != nil {
return nil, fmt.Errorf("SMBv2连接失败: %w", err) return nil, fmt.Errorf("SMBv2连接失败: %w", err)
} }
@@ -354,10 +354,10 @@ func probeSMBv2(target string, timeout time.Duration) (*SMBTarget, error) {
} }
// checkSMBGhost 检测CVE-2020-0796漏洞 // checkSMBGhost 检测CVE-2020-0796漏洞
func checkSMBGhost(host string, timeout time.Duration) bool { func checkSMBGhost(ctx context.Context, host string, timeout time.Duration, session *common.ScanSession) bool {
addr := fmt.Sprintf("%s:445", host) addr := fmt.Sprintf("%s:445", host)
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout) conn, err := session.DialTCP(ctx, "tcp", addr, timeout)
if err != nil { if err != nil {
return false return false
} }
@@ -390,7 +390,7 @@ func checkSMBGhost(host string, timeout time.Duration) bool {
// SMBAuthenticator 统一认证接口 // SMBAuthenticator 统一认证接口
type SMBAuthenticator interface { type SMBAuthenticator interface {
Authenticate(ctx context.Context, host string, port int, cred Credential, domain string, timeout time.Duration) (*AuthResult, error) Authenticate(ctx context.Context, host string, port int, cred Credential, domain string, timeout time.Duration, session *common.ScanSession) (*AuthResult, error)
ListShares(ctx context.Context, host string, port int, cred Credential, domain string, timeout time.Duration) ([]string, error) ListShares(ctx context.Context, host string, port int, cred Credential, domain string, timeout time.Duration) ([]string, error)
} }
@@ -398,7 +398,7 @@ type SMBAuthenticator interface {
type SMB1Authenticator struct{} type SMB1Authenticator struct{}
// Authenticate 执行SMB1认证 // Authenticate 执行SMB1认证
func (a *SMB1Authenticator) Authenticate(ctx context.Context, host string, port int, cred Credential, domain string, timeout time.Duration) (*AuthResult, error) { func (a *SMB1Authenticator) Authenticate(ctx context.Context, host string, port int, cred Credential, domain string, timeout time.Duration, session *common.ScanSession) (*AuthResult, error) {
options := smb.Options{ options := smb.Options{
Host: host, Host: host,
Port: port, Port: port,
@@ -480,11 +480,11 @@ func (a *SMB1Authenticator) ListShares(ctx context.Context, host string, port in
type SMB2Authenticator struct{} type SMB2Authenticator struct{}
// Authenticate 执行SMB2认证 // Authenticate 执行SMB2认证
func (a *SMB2Authenticator) Authenticate(ctx context.Context, host string, port int, cred Credential, domain string, timeout time.Duration) (*AuthResult, error) { func (a *SMB2Authenticator) Authenticate(ctx context.Context, host string, port int, cred Credential, domain string, timeout time.Duration, session *common.ScanSession) (*AuthResult, error) {
timeoutCtx, cancel := context.WithTimeout(ctx, timeout) timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel() defer cancel()
conn, err := common.WrapperTcpWithTimeout("tcp", fmt.Sprintf("%s:%d", host, port), timeout) conn, err := session.DialTCP(ctx, "tcp", fmt.Sprintf("%s:%d", host, port), timeout)
if err != nil { if err != nil {
return &AuthResult{ return &AuthResult{
Success: false, Success: false,
+29 -47
View File
@@ -27,15 +27,14 @@ func NewSMTPPlugin() *SMTPPlugin {
func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
target := info.Target() target := info.Target()
if config.DisableBrute { 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 { if result := p.testUnauthorizedAccess(ctx, info, session); result != nil && result.Success {
common.LogSuccess(i18n.Tr("smtp_service", target, result.Banner)) common.LogSuccess(i18n.Tr("smtp_service", target, result.Banner))
return result return result
} }
@@ -57,7 +56,7 @@ func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c
} }
// 使用公共框架进行并发凭据测试 // 使用公共框架进行并发凭据测试
authFn := p.createAuthFunc(info, config, state) authFn := p.createAuthFunc(info, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
result := TestCredentialsConcurrently(ctx, creds, authFn, "smtp", testConfig) result := TestCredentialsConcurrently(ctx, creds, authFn, "smtp", testConfig)
@@ -70,23 +69,22 @@ func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c
} }
// createAuthFunc 创建SMTP认证函数 // createAuthFunc 创建SMTP认证函数
func (p *SMTPPlugin) createAuthFunc(info *common.HostInfo, config *common.Config, state *common.State) AuthFunc { func (p *SMTPPlugin) createAuthFunc(info *common.HostInfo, session *common.ScanSession) AuthFunc {
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
return p.doSMTPAuth(ctx, info, cred, config, state) return p.doSMTPAuth(ctx, info, cred, session)
} }
} }
// doSMTPAuth 执行SMTP认证 // doSMTPAuth 执行SMTP认证
func (p *SMTPPlugin) doSMTPAuth(ctx context.Context, info *common.HostInfo, cred Credential, config *common.Config, state *common.State) *AuthResult { func (p *SMTPPlugin) doSMTPAuth(ctx context.Context, info *common.HostInfo, cred Credential, session *common.ScanSession) *AuthResult {
target := info.Target() target := info.Target()
timeout := config.Timeout timeout := session.Config.Timeout
resultChan := make(chan *AuthResult, 1) resultChan := make(chan *AuthResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) conn, err := session.DialTCP(ctx, "tcp", target, timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifySMTPErrorType(err), ErrorType: classifySMTPErrorType(err),
@@ -100,7 +98,6 @@ func (p *SMTPPlugin) doSMTPAuth(ctx context.Context, info *common.HostInfo, cred
client, err := smtp.NewClient(conn, info.Host) client, err := smtp.NewClient(conn, info.Host)
if err != nil { if err != nil {
_ = conn.Close() _ = conn.Close()
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifySMTPErrorType(err), ErrorType: classifySMTPErrorType(err),
@@ -113,7 +110,6 @@ func (p *SMTPPlugin) doSMTPAuth(ctx context.Context, info *common.HostInfo, cred
auth := smtp.PlainAuth("", cred.Username, cred.Password, info.Host) auth := smtp.PlainAuth("", cred.Username, cred.Password, info.Host)
if err := client.Auth(auth); err != nil { if err := client.Auth(auth); err != nil {
_ = client.Close() _ = client.Close()
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifySMTPErrorType(err), ErrorType: classifySMTPErrorType(err),
@@ -125,7 +121,6 @@ func (p *SMTPPlugin) doSMTPAuth(ctx context.Context, info *common.HostInfo, cred
if err := client.Mail("[email protected]"); err != nil { if err := client.Mail("[email protected]"); err != nil {
_ = client.Close() _ = client.Close()
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifySMTPErrorType(err), ErrorType: classifySMTPErrorType(err),
@@ -134,7 +129,6 @@ func (p *SMTPPlugin) doSMTPAuth(ctx context.Context, info *common.HostInfo, cred
return return
} }
state.IncrementTCPSuccessPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: true, Success: true,
Conn: &smtpClientWrapper{client}, Conn: &smtpClientWrapper{client},
@@ -211,24 +205,24 @@ func classifySMTPErrorType(err error) ErrorType {
} }
// testUnauthorizedAccess 测试SMTP未授权访问 // testUnauthorizedAccess 测试SMTP未授权访问
func (p *SMTPPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *SMTPPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
// 测试匿名访问 // 测试匿名访问
if result := p.testAnonymousAccess(ctx, info, config, state); result != nil { if result := p.testAnonymousAccess(ctx, info, session); result != nil {
return result return result
} }
// 测试开放中继 // 测试开放中继
if result := p.testOpenRelay(ctx, info, config, state); result != nil { if result := p.testOpenRelay(ctx, info, session); result != nil {
return result return result
} }
// 测试VRFY命令 // 测试VRFY命令
if result := p.testVRFYCommand(ctx, info, config, state); result != nil { if result := p.testVRFYCommand(ctx, info, session); result != nil {
return result return result
} }
// 测试EXPN命令 // 测试EXPN命令
if result := p.testEXPNCommand(ctx, info, config, state); result != nil { if result := p.testEXPNCommand(ctx, info, session); result != nil {
return result return result
} }
@@ -236,15 +230,14 @@ func (p *SMTPPlugin) testUnauthorizedAccess(ctx context.Context, info *common.Ho
} }
// testAnonymousAccess 测试匿名邮件发送 // testAnonymousAccess 测试匿名邮件发送
func (p *SMTPPlugin) testAnonymousAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *SMTPPlugin) testAnonymousAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
resultChan := make(chan *ScanResult, 1) resultChan := make(chan *ScanResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- nil resultChan <- nil
return return
} }
@@ -272,7 +265,6 @@ func (p *SMTPPlugin) testAnonymousAccess(ctx context.Context, info *common.HostI
return return
} }
state.IncrementTCPSuccessPacketCount()
resultChan <- &ScanResult{ resultChan <- &ScanResult{
Success: true, Success: true,
Type: plugins.ResultTypeVuln, Type: plugins.ResultTypeVuln,
@@ -290,15 +282,14 @@ func (p *SMTPPlugin) testAnonymousAccess(ctx context.Context, info *common.HostI
} }
// testOpenRelay 测试开放中继 // testOpenRelay 测试开放中继
func (p *SMTPPlugin) testOpenRelay(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *SMTPPlugin) testOpenRelay(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
resultChan := make(chan *ScanResult, 1) resultChan := make(chan *ScanResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- nil resultChan <- nil
return return
} }
@@ -326,7 +317,6 @@ func (p *SMTPPlugin) testOpenRelay(ctx context.Context, info *common.HostInfo, c
return return
} }
state.IncrementTCPSuccessPacketCount()
resultChan <- &ScanResult{ resultChan <- &ScanResult{
Success: true, Success: true,
Type: plugins.ResultTypeVuln, Type: plugins.ResultTypeVuln,
@@ -344,21 +334,20 @@ func (p *SMTPPlugin) testOpenRelay(ctx context.Context, info *common.HostInfo, c
} }
// testVRFYCommand 测试VRFY命令用户枚举 // testVRFYCommand 测试VRFY命令用户枚举
func (p *SMTPPlugin) testVRFYCommand(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *SMTPPlugin) testVRFYCommand(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
resultChan := make(chan *ScanResult, 1) resultChan := make(chan *ScanResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- nil resultChan <- nil
return return
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(config.Timeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout))
if _, heloWriteErr := fmt.Fprintf(conn, "HELO fscan.test\r\n"); heloWriteErr != nil { if _, heloWriteErr := fmt.Fprintf(conn, "HELO fscan.test\r\n"); heloWriteErr != nil {
resultChan <- nil resultChan <- nil
@@ -393,7 +382,6 @@ func (p *SMTPPlugin) testVRFYCommand(ctx context.Context, info *common.HostInfo,
vrfyResponse := strings.TrimSpace(string(buffer[:n])) vrfyResponse := strings.TrimSpace(string(buffer[:n]))
if strings.HasPrefix(vrfyResponse, "250") { if strings.HasPrefix(vrfyResponse, "250") {
state.IncrementTCPSuccessPacketCount()
resultChan <- &ScanResult{ resultChan <- &ScanResult{
Success: true, Success: true,
Type: plugins.ResultTypeVuln, Type: plugins.ResultTypeVuln,
@@ -416,21 +404,20 @@ func (p *SMTPPlugin) testVRFYCommand(ctx context.Context, info *common.HostInfo,
} }
// testEXPNCommand 测试EXPN命令邮件列表枚举 // testEXPNCommand 测试EXPN命令邮件列表枚举
func (p *SMTPPlugin) testEXPNCommand(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *SMTPPlugin) testEXPNCommand(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
resultChan := make(chan *ScanResult, 1) resultChan := make(chan *ScanResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- nil resultChan <- nil
return return
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(config.Timeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout))
if _, heloWriteErr := fmt.Fprintf(conn, "HELO fscan.test\r\n"); heloWriteErr != nil { if _, heloWriteErr := fmt.Fprintf(conn, "HELO fscan.test\r\n"); heloWriteErr != nil {
resultChan <- nil resultChan <- nil
@@ -465,7 +452,6 @@ func (p *SMTPPlugin) testEXPNCommand(ctx context.Context, info *common.HostInfo,
expnResponse := strings.TrimSpace(string(buffer[:n])) expnResponse := strings.TrimSpace(string(buffer[:n]))
if strings.HasPrefix(expnResponse, "250") { if strings.HasPrefix(expnResponse, "250") {
state.IncrementTCPSuccessPacketCount()
resultChan <- &ScanResult{ resultChan <- &ScanResult{
Success: true, Success: true,
Type: plugins.ResultTypeVuln, Type: plugins.ResultTypeVuln,
@@ -488,21 +474,20 @@ func (p *SMTPPlugin) testEXPNCommand(ctx context.Context, info *common.HostInfo,
} }
// getServerInfo 获取SMTP服务器信息 // getServerInfo 获取SMTP服务器信息
func (p *SMTPPlugin) getServerInfo(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) string { func (p *SMTPPlugin) getServerInfo(ctx context.Context, info *common.HostInfo, session *common.ScanSession) string {
target := info.Target() target := info.Target()
resultChan := make(chan string, 1) resultChan := make(chan string, 1)
go func() { go func() {
conn, err := common.SafeTCPDial(target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- "" resultChan <- ""
return return
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
_ = conn.SetReadDeadline(time.Now().Add(config.Timeout)) _ = conn.SetReadDeadline(time.Now().Add(session.Config.Timeout))
buffer := make([]byte, 1024) buffer := make([]byte, 1024)
n, err := conn.Read(buffer) n, err := conn.Read(buffer)
if err != nil { if err != nil {
@@ -510,7 +495,6 @@ func (p *SMTPPlugin) getServerInfo(ctx context.Context, info *common.HostInfo, c
return return
} }
state.IncrementTCPSuccessPacketCount()
welcome := strings.TrimSpace(string(buffer[:n])) welcome := strings.TrimSpace(string(buffer[:n]))
if strings.HasPrefix(welcome, "220") { if strings.HasPrefix(welcome, "220") {
@@ -531,18 +515,17 @@ func (p *SMTPPlugin) getServerInfo(ctx context.Context, info *common.HostInfo, c
} }
// identifyService SMTP服务识别 // identifyService SMTP服务识别
func (p *SMTPPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *SMTPPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
serverInfo := p.getServerInfo(ctx, info, config, state) serverInfo := p.getServerInfo(ctx, info, session)
var banner string var banner string
if serverInfo != "" { if serverInfo != "" {
banner = fmt.Sprintf("SMTP邮件服务 (%s)", serverInfo) banner = fmt.Sprintf("SMTP邮件服务 (%s)", serverInfo)
} else { } else {
conn, err := common.SafeTCPDial(target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "smtp", Service: "smtp",
@@ -550,7 +533,6 @@ func (p *SMTPPlugin) identifyService(ctx context.Context, info *common.HostInfo,
} }
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
state.IncrementTCPSuccessPacketCount()
banner = "SMTP邮件服务" banner = "SMTP邮件服务"
} }
+14 -19
View File
@@ -36,12 +36,11 @@ func NewSSHPlugin() *SSHPlugin {
// Scan 执行SSH扫描 // Scan 执行SSH扫描
func (p *SSHPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *SSHPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
target := info.Target() target := info.Target()
// 如果指定了SSH密钥,优先使用密钥认证 // 如果指定了SSH密钥,优先使用密钥认证
if config.Credentials.SSHKeyPath != "" { if config.Credentials.SSHKeyPath != "" {
if result := p.scanWithKey(ctx, info, config, state); result != nil && result.Success { if result := p.scanWithKey(ctx, info, session); result != nil && result.Success {
common.LogVuln(i18n.Tr("ssh_key_auth_success", target, result.Username)) //nolint:govet common.LogVuln(i18n.Tr("ssh_key_auth_success", target, result.Username)) //nolint:govet
return result return result
} }
@@ -49,7 +48,7 @@ func (p *SSHPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
// 如果禁用暴力破解,只做服务识别 // 如果禁用暴力破解,只做服务识别
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(info, config, state) return p.identifyService(ctx, info, session)
} }
// 生成测试凭据 // 生成测试凭据
@@ -65,7 +64,7 @@ func (p *SSHPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
} }
// 使用公共框架进行并发凭据测试 // 使用公共框架进行并发凭据测试
authFn := p.createAuthFunc(info, config, state) authFn := p.createAuthFunc(info, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
result := TestCredentialsConcurrently(ctx, credentials, authFn, "ssh", testConfig) result := TestCredentialsConcurrently(ctx, credentials, authFn, "ssh", testConfig)
@@ -79,14 +78,15 @@ func (p *SSHPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
} }
// createAuthFunc 创建SSH认证函数 // createAuthFunc 创建SSH认证函数
func (p *SSHPlugin) createAuthFunc(info *common.HostInfo, config *common.Config, state *common.State) AuthFunc { func (p *SSHPlugin) createAuthFunc(info *common.HostInfo, session *common.ScanSession) AuthFunc {
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
return p.doSSHAuth(ctx, info, cred, config, state) return p.doSSHAuth(ctx, info, cred, session)
} }
} }
// doSSHAuth 执行SSH认证 // doSSHAuth 执行SSH认证
func (p *SSHPlugin) doSSHAuth(ctx context.Context, info *common.HostInfo, cred Credential, config *common.Config, state *common.State) *AuthResult { func (p *SSHPlugin) doSSHAuth(ctx context.Context, info *common.HostInfo, cred Credential, session *common.ScanSession) *AuthResult {
config := session.Config
target := info.Target() target := info.Target()
// 创建SSH配置 // 创建SSH配置
@@ -113,9 +113,8 @@ func (p *SSHPlugin) doSSHAuth(ctx context.Context, info *common.HostInfo, cred C
} }
// 建立TCP连接 // 建立TCP连接
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &AuthResult{ return &AuthResult{
Success: false, Success: false,
ErrorType: classifySSHErrorType(err), ErrorType: classifySSHErrorType(err),
@@ -127,7 +126,6 @@ func (p *SSHPlugin) doSSHAuth(ctx context.Context, info *common.HostInfo, cred C
sshConn, chans, reqs, err := ssh.NewClientConn(conn, target, sshConfig) sshConn, chans, reqs, err := ssh.NewClientConn(conn, target, sshConfig)
if err != nil { if err != nil {
_ = conn.Close() _ = conn.Close()
state.IncrementTCPFailedPacketCount()
return &AuthResult{ return &AuthResult{
Success: false, Success: false,
ErrorType: classifySSHErrorType(err), ErrorType: classifySSHErrorType(err),
@@ -138,7 +136,6 @@ func (p *SSHPlugin) doSSHAuth(ctx context.Context, info *common.HostInfo, cred C
// 创建SSH客户端 // 创建SSH客户端
client := ssh.NewClient(sshConn, chans, reqs) client := ssh.NewClient(sshConn, chans, reqs)
state.IncrementTCPSuccessPacketCount()
return &AuthResult{ return &AuthResult{
Success: true, Success: true,
Conn: &sshClientWrapper{client}, Conn: &sshClientWrapper{client},
@@ -181,7 +178,8 @@ func classifySSHErrorType(err error) ErrorType {
} }
// scanWithKey 使用SSH私钥扫描 // scanWithKey 使用SSH私钥扫描
func (p *SSHPlugin) scanWithKey(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *SSHPlugin) scanWithKey(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config
keyData, err := os.ReadFile(config.Credentials.SSHKeyPath) keyData, err := os.ReadFile(config.Credentials.SSHKeyPath)
if err != nil { if err != nil {
common.LogError(i18n.Tr("ssh_key_read_failed", err)) //nolint:govet common.LogError(i18n.Tr("ssh_key_read_failed", err)) //nolint:govet
@@ -206,7 +204,7 @@ func (p *SSHPlugin) scanWithKey(ctx context.Context, info *common.HostInfo, conf
KeyData: keyData, KeyData: keyData,
} }
result := p.doSSHAuth(ctx, info, cred, config, state) result := p.doSSHAuth(ctx, info, cred, session)
if result.Success { if result.Success {
if result.Conn != nil { if result.Conn != nil {
_ = result.Conn.Close() _ = result.Conn.Close()
@@ -224,12 +222,11 @@ func (p *SSHPlugin) scanWithKey(ctx context.Context, info *common.HostInfo, conf
} }
// identifyService 服务识别 // identifyService 服务识别
func (p *SSHPlugin) identifyService(info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *SSHPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
conn, err := common.SafeTCPDial(target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "ssh", Service: "ssh",
@@ -238,8 +235,7 @@ func (p *SSHPlugin) identifyService(info *common.HostInfo, config *common.Config
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
if banner := p.readSSHBanner(conn, config); banner != "" { if banner := p.readSSHBanner(conn, session.Config); banner != "" {
state.IncrementTCPSuccessPacketCount()
common.LogSuccess(i18n.Tr("ssh_service_identified", target, banner)) //nolint:govet common.LogSuccess(i18n.Tr("ssh_service_identified", target, banner)) //nolint:govet
return &ScanResult{ return &ScanResult{
Type: plugins.ResultTypeService, Type: plugins.ResultTypeService,
@@ -249,7 +245,6 @@ func (p *SSHPlugin) identifyService(info *common.HostInfo, config *common.Config
} }
} }
state.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "ssh", Service: "ssh",
+19 -28
View File
@@ -56,14 +56,14 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo, session
target := info.Target() target := info.Target()
if config.DisableBrute { if config.DisableBrute {
return p.identifyService(ctx, info, config, state) return p.identifyService(ctx, info, session)
} }
// 检测未授权访问 // 检测未授权访问
if result := p.testUnauthAccess(ctx, info, config, state); result != nil && result.Success { if result := p.testUnauthAccess(ctx, info, session); result != nil && result.Success {
common.LogVuln(i18n.Tr("telnet_service", target, result.Banner)) common.LogVuln(i18n.Tr("telnet_service", target, result.Banner))
// 验证命令执行能力 // 验证命令执行能力
if ok, osType, evidence := p.verifyCommandExecution(ctx, info, "", "", config, state); ok { if ok, osType, evidence := p.verifyCommandExecution(ctx, info, "", "", session); ok {
common.LogVuln(i18n.Tr("telnet_unauth_rce", target, osType, evidence)) common.LogVuln(i18n.Tr("telnet_unauth_rce", target, osType, evidence))
} }
return result return result
@@ -103,7 +103,7 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo, session
} }
// 使用公共框架进行并发凭据测试 // 使用公共框架进行并发凭据测试
authFn := p.createAuthFunc(info, config, state) authFn := p.createAuthFunc(info, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
result := TestCredentialsConcurrently(ctx, creds, authFn, "telnet", testConfig) result := TestCredentialsConcurrently(ctx, creds, authFn, "telnet", testConfig)
@@ -111,7 +111,7 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo, session
if result.Success { if result.Success {
common.LogVuln(i18n.Tr("telnet_credential", target, result.Username, result.Password)) common.LogVuln(i18n.Tr("telnet_credential", target, result.Username, result.Password))
// 验证命令执行能力 // 验证命令执行能力
if ok, osType, evidence := p.verifyCommandExecution(ctx, info, result.Username, result.Password, config, state); ok { 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)) common.LogVuln(i18n.Tr("telnet_credential_rce", target, result.Username, result.Password, osType, evidence))
} }
} }
@@ -120,22 +120,21 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo, session
} }
// createAuthFunc 创建Telnet认证函数 // createAuthFunc 创建Telnet认证函数
func (p *TelnetPlugin) createAuthFunc(info *common.HostInfo, config *common.Config, state *common.State) AuthFunc { func (p *TelnetPlugin) createAuthFunc(info *common.HostInfo, session *common.ScanSession) AuthFunc {
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
return p.doTelnetAuth(ctx, info, cred, config, state) return p.doTelnetAuth(ctx, info, cred, session)
} }
} }
// doTelnetAuth 执行Telnet认证 // doTelnetAuth 执行Telnet认证
func (p *TelnetPlugin) doTelnetAuth(ctx context.Context, info *common.HostInfo, cred Credential, config *common.Config, state *common.State) *AuthResult { func (p *TelnetPlugin) doTelnetAuth(ctx context.Context, info *common.HostInfo, cred Credential, session *common.ScanSession) *AuthResult {
target := info.Target() target := info.Target()
resultChan := make(chan *AuthResult, 1) resultChan := make(chan *AuthResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifyTelnetErrorType(err), ErrorType: classifyTelnetErrorType(err),
@@ -144,10 +143,9 @@ func (p *TelnetPlugin) doTelnetAuth(ctx context.Context, info *common.HostInfo,
return return
} }
_ = conn.SetDeadline(time.Now().Add(config.Timeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout))
if p.performTelnetAuth(conn, cred.Username, cred.Password) { if p.performTelnetAuth(conn, cred.Username, cred.Password) {
state.IncrementTCPSuccessPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: true, Success: true,
Conn: &telnetConnWrapper{conn}, Conn: &telnetConnWrapper{conn},
@@ -156,7 +154,6 @@ func (p *TelnetPlugin) doTelnetAuth(ctx context.Context, info *common.HostInfo,
} }
} else { } else {
_ = conn.Close() _ = conn.Close()
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: ErrorTypeAuth, ErrorType: ErrorTypeAuth,
@@ -224,21 +221,20 @@ func classifyTelnetErrorType(err error) ErrorType {
} }
// testUnauthAccess 测试Telnet未授权访问 // testUnauthAccess 测试Telnet未授权访问
func (p *TelnetPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *TelnetPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
resultChan := make(chan *ScanResult, 1) resultChan := make(chan *ScanResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- nil resultChan <- nil
return return
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(config.Timeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout))
buffer := make([]byte, 1024) buffer := make([]byte, 1024)
attempts := 0 attempts := 0
@@ -261,7 +257,6 @@ func (p *TelnetPlugin) testUnauthAccess(ctx context.Context, info *common.HostIn
p.handleIACNegotiation(conn, buffer[:n]) p.handleIACNegotiation(conn, buffer[:n])
if p.isShellPrompt(cleaned) { if p.isShellPrompt(cleaned) {
state.IncrementTCPSuccessPacketCount()
resultChan <- &ScanResult{ resultChan <- &ScanResult{
Success: true, Success: true,
Type: plugins.ResultTypeVuln, Type: plugins.ResultTypeVuln,
@@ -521,15 +516,14 @@ func (p *TelnetPlugin) isLoginFailed(data string) bool {
} }
// identifyService Telnet服务识别 // identifyService Telnet服务识别
func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
target := info.Target() target := info.Target()
resultChan := make(chan *ScanResult, 1) resultChan := make(chan *ScanResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- &ScanResult{ resultChan <- &ScanResult{
Success: false, Success: false,
Service: "telnet", Service: "telnet",
@@ -539,12 +533,11 @@ func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInf
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(config.Timeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout))
buffer := make([]byte, 2048) buffer := make([]byte, 2048)
n, err := conn.Read(buffer) n, err := conn.Read(buffer)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- &ScanResult{ resultChan <- &ScanResult{
Success: false, Success: false,
Service: "telnet", Service: "telnet",
@@ -553,8 +546,6 @@ func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInf
return return
} }
state.IncrementTCPSuccessPacketCount()
p.handleIACNegotiation(conn, buffer[:n]) p.handleIACNegotiation(conn, buffer[:n])
cleaned := p.cleanResponse(string(buffer[:n])) cleaned := p.cleanResponse(string(buffer[:n]))
cleanedLower := strings.ToLower(cleaned) cleanedLower := strings.ToLower(cleaned)
@@ -606,7 +597,7 @@ func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInf
} }
// verifyCommandExecution 验证Telnet命令执行能力(RCE检测) // verifyCommandExecution 验证Telnet命令执行能力(RCE检测)
func (p *TelnetPlugin) verifyCommandExecution(ctx context.Context, info *common.HostInfo, username, password string, config *common.Config, state *common.State) (bool, string, string) { func (p *TelnetPlugin) verifyCommandExecution(ctx context.Context, info *common.HostInfo, username, password string, session *common.ScanSession) (bool, string, string) {
target := info.Target() target := info.Target()
type rceResult struct { type rceResult struct {
@@ -618,14 +609,14 @@ func (p *TelnetPlugin) verifyCommandExecution(ctx context.Context, info *common.
resultChan := make(chan rceResult, 1) resultChan := make(chan rceResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
resultChan <- rceResult{} resultChan <- rceResult{}
return return
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(config.Timeout + telnetRCEExtraTimeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout + telnetRCEExtraTimeout))
// 需要认证时先登录 // 需要认证时先登录
if username != "" || password != "" { if username != "" || password != "" {
+9 -14
View File
@@ -26,11 +26,10 @@ func NewVNCPlugin() *VNCPlugin {
func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult { func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
config := session.Config config := session.Config
state := session.State
target := info.Target() target := info.Target()
// 检查未授权访问 // 检查未授权访问
if result := p.testUnauthAccess(ctx, info, config, state); result != nil && result.Success { if result := p.testUnauthAccess(ctx, info, session); result != nil && result.Success {
common.LogVuln(i18n.Tr("vnc_unauth", target)) common.LogVuln(i18n.Tr("vnc_unauth", target))
return result return result
} }
@@ -49,7 +48,7 @@ func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
} }
// 使用公共框架进行并发凭据测试 // 使用公共框架进行并发凭据测试
authFn := p.createAuthFunc(info, config, state) authFn := p.createAuthFunc(info, session)
testConfig := DefaultConcurrentTestConfig(config) testConfig := DefaultConcurrentTestConfig(config)
result := TestCredentialsConcurrently(ctx, credentials, authFn, "vnc", testConfig) result := TestCredentialsConcurrently(ctx, credentials, authFn, "vnc", testConfig)
@@ -62,22 +61,21 @@ func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
} }
// createAuthFunc 创建VNC认证函数 // createAuthFunc 创建VNC认证函数
func (p *VNCPlugin) createAuthFunc(info *common.HostInfo, config *common.Config, state *common.State) AuthFunc { func (p *VNCPlugin) createAuthFunc(info *common.HostInfo, session *common.ScanSession) AuthFunc {
return func(ctx context.Context, cred Credential) *AuthResult { return func(ctx context.Context, cred Credential) *AuthResult {
return p.doVNCAuth(ctx, info, cred, config, state) return p.doVNCAuth(ctx, info, cred, session)
} }
} }
// doVNCAuth 执行VNC认证 // doVNCAuth 执行VNC认证
func (p *VNCPlugin) doVNCAuth(ctx context.Context, info *common.HostInfo, cred Credential, config *common.Config, state *common.State) *AuthResult { func (p *VNCPlugin) doVNCAuth(ctx context.Context, info *common.HostInfo, cred Credential, session *common.ScanSession) *AuthResult {
target := info.Target() target := info.Target()
resultChan := make(chan *AuthResult, 1) resultChan := make(chan *AuthResult, 1)
go func() { go func() {
conn, err := common.WrapperTcpWithTimeout("tcp", target, config.Timeout) conn, err := session.DialTCP(ctx, "tcp", target, session.Config.Timeout)
if err != nil { if err != nil {
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifyVNCErrorType(err), ErrorType: classifyVNCErrorType(err),
@@ -86,7 +84,7 @@ func (p *VNCPlugin) doVNCAuth(ctx context.Context, info *common.HostInfo, cred C
return return
} }
_ = conn.SetDeadline(time.Now().Add(config.Timeout)) _ = conn.SetDeadline(time.Now().Add(session.Config.Timeout))
vncConfig := &vnc.ClientConfig{ vncConfig := &vnc.ClientConfig{
Auth: []vnc.ClientAuth{ Auth: []vnc.ClientAuth{
@@ -97,7 +95,6 @@ func (p *VNCPlugin) doVNCAuth(ctx context.Context, info *common.HostInfo, cred C
client, err := vnc.Client(conn, vncConfig) client, err := vnc.Client(conn, vncConfig)
if err != nil { if err != nil {
_ = conn.Close() _ = conn.Close()
state.IncrementTCPFailedPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: false, Success: false,
ErrorType: classifyVNCErrorType(err), ErrorType: classifyVNCErrorType(err),
@@ -106,8 +103,6 @@ func (p *VNCPlugin) doVNCAuth(ctx context.Context, info *common.HostInfo, cred C
return return
} }
state.IncrementTCPSuccessPacketCount()
resultChan <- &AuthResult{ resultChan <- &AuthResult{
Success: true, Success: true,
Conn: &vncClientWrapper{client, conn}, Conn: &vncClientWrapper{client, conn},
@@ -175,9 +170,9 @@ func classifyVNCErrorType(err error) ErrorType {
return ClassifyError(err, nil, CommonNetworkErrors) return ClassifyError(err, nil, CommonNetworkErrors)
} }
func (p *VNCPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult { func (p *VNCPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
cred := Credential{Username: "", Password: ""} cred := Credential{Username: "", Password: ""}
result := p.doVNCAuth(ctx, info, cred, config, state) result := p.doVNCAuth(ctx, info, cred, session)
if result.Success { if result.Success {
if result.Conn != nil { if result.Conn != nil {