mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-26 21:21:53 +08:00
add session-aware scan logging
This commit is contained in:
+42
-3
@@ -48,18 +48,57 @@ func (s *ScanSession) SaveResult(result *output.ScanResult) error {
|
|||||||
return SaveResult(result)
|
return SaveResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ScanSession) loggingEnabled() bool {
|
||||||
|
return s == nil || s.Config == nil || !s.Config.Output.Silent
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogDebug writes through the session's logging policy.
|
||||||
|
func (s *ScanSession) LogDebug(msg string) {
|
||||||
|
if s.loggingEnabled() {
|
||||||
|
LogDebug(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogInfo writes through the session's logging policy.
|
||||||
|
func (s *ScanSession) LogInfo(msg string) {
|
||||||
|
if s.loggingEnabled() {
|
||||||
|
LogInfo(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogSuccess writes through the session's logging policy.
|
||||||
|
func (s *ScanSession) LogSuccess(result string) {
|
||||||
|
if s.loggingEnabled() {
|
||||||
|
LogSuccess(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogVuln writes through the session's logging policy.
|
||||||
|
func (s *ScanSession) LogVuln(result string) {
|
||||||
|
if s.loggingEnabled() {
|
||||||
|
LogVuln(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogError writes through the session's logging policy.
|
||||||
|
func (s *ScanSession) LogError(errMsg string) {
|
||||||
|
if s.loggingEnabled() {
|
||||||
|
LogError(errMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DialTCP 创建 TCP 连接,内含限速检查、代理、计数
|
// DialTCP 创建 TCP 连接,内含限速检查、代理、计数
|
||||||
func (s *ScanSession) DialTCP(ctx context.Context, network, address string, timeout time.Duration) (net.Conn, error) {
|
func (s *ScanSession) DialTCP(ctx context.Context, network, address string, timeout time.Duration) (net.Conn, error) {
|
||||||
// 检查发包限制
|
// 检查发包限制
|
||||||
if ok, err := CanSendPacketWith(s.Config, s.State); !ok {
|
if ok, err := CanSendPacketWith(s.Config, s.State); !ok {
|
||||||
LogError(fmt.Sprintf("TCP连接 %s 受限: %s", address, err.Error()))
|
s.LogError(fmt.Sprintf("TCP连接 %s 受限: %s", address, err.Error()))
|
||||||
return nil, fmt.Errorf("%s", i18n.Tr("network_rate_limited", err.Error()))
|
return nil, fmt.Errorf("%s", i18n.Tr("network_rate_limited", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取 dialer
|
// 获取 dialer
|
||||||
dialer, err := s.getDialer()
|
dialer, err := s.getDialer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError(fmt.Sprintf("获取代理拨号器失败: %v", err))
|
s.LogError(fmt.Sprintf("获取代理拨号器失败: %v", err))
|
||||||
s.State.IncrementTCPFailedPacketCount()
|
s.State.IncrementTCPFailedPacketCount()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -67,7 +106,7 @@ func (s *ScanSession) DialTCP(ctx context.Context, network, address string, time
|
|||||||
conn, err := dialer.DialContext(ctx, network, address)
|
conn, err := dialer.DialContext(ctx, network, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.State.IncrementTCPFailedPacketCount()
|
s.State.IncrementTCPFailedPacketCount()
|
||||||
LogDebug(fmt.Sprintf("连接 %s 失败: %v", address, err))
|
s.LogDebug(fmt.Sprintf("连接 %s 失败: %v", address, err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestScanSessionLogMethodsHonorSilentConfig(t *testing.T) {
|
||||||
|
loggerMu.Lock()
|
||||||
|
silentLoggerRefs = 0
|
||||||
|
resetLoggerLocked()
|
||||||
|
loggerMu.Unlock()
|
||||||
|
t.Cleanup(func() {
|
||||||
|
loggerMu.Lock()
|
||||||
|
silentLoggerRefs = 0
|
||||||
|
resetLoggerLocked()
|
||||||
|
loggerMu.Unlock()
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg := NewConfig()
|
||||||
|
cfg.Output.Silent = true
|
||||||
|
session := NewScanSession(cfg, NewState(), &FlagVars{})
|
||||||
|
|
||||||
|
session.LogDebug("debug")
|
||||||
|
session.LogInfo("info")
|
||||||
|
session.LogSuccess("success")
|
||||||
|
session.LogVuln("vuln")
|
||||||
|
session.LogError("error")
|
||||||
|
|
||||||
|
loggerMu.Lock()
|
||||||
|
defer loggerMu.Unlock()
|
||||||
|
if globalLogger != nil {
|
||||||
|
t.Fatal("silent session log methods initialized global logger")
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-10
@@ -106,7 +106,7 @@ func tcpSupplementaryProbe(ctx context.Context, allHosts []string, aliveHosts []
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提示用户正在进行 TCP 补充探测
|
// 提示用户正在进行 TCP 补充探测
|
||||||
common.LogInfo(i18n.Tr("tcp_probe_low_icmp_rate", fmt.Sprintf("%.1f%%", responseRate*100), len(unrespondedHosts)))
|
session.LogInfo(i18n.Tr("tcp_probe_low_icmp_rate", fmt.Sprintf("%.1f%%", responseRate*100), len(unrespondedHosts)))
|
||||||
|
|
||||||
// 执行 TCP 补充探测
|
// 执行 TCP 补充探测
|
||||||
tcpAliveHosts := runTcpProbeForHosts(ctx, unrespondedHosts, session)
|
tcpAliveHosts := runTcpProbeForHosts(ctx, unrespondedHosts, session)
|
||||||
@@ -114,7 +114,7 @@ func tcpSupplementaryProbe(ctx context.Context, allHosts []string, aliveHosts []
|
|||||||
// 合并结果
|
// 合并结果
|
||||||
if len(tcpAliveHosts) > 0 {
|
if len(tcpAliveHosts) > 0 {
|
||||||
aliveHosts = append(aliveHosts, tcpAliveHosts...)
|
aliveHosts = append(aliveHosts, tcpAliveHosts...)
|
||||||
common.LogInfo(i18n.Tr("tcp_probe_found", len(tcpAliveHosts)))
|
session.LogInfo(i18n.Tr("tcp_probe_found", len(tcpAliveHosts)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return aliveHosts
|
return aliveHosts
|
||||||
@@ -157,10 +157,7 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool, al
|
|||||||
}
|
}
|
||||||
_ = session.SaveResult(result)
|
_ = session.SaveResult(result)
|
||||||
|
|
||||||
// 保留原有的控制台输出
|
session.LogInfo(i18n.Tr("host_alive", ip, protocol))
|
||||||
if !config.Output.Silent {
|
|
||||||
common.LogInfo(i18n.Tr("host_alive", ip, protocol))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
livewg.Done()
|
livewg.Done()
|
||||||
}
|
}
|
||||||
@@ -730,7 +727,6 @@ func tcpProbeAlive(ctx context.Context, session *common.ScanSession, host string
|
|||||||
// runTcpProbeForHosts 对指定主机列表进行 TCP 补充探测
|
// runTcpProbeForHosts 对指定主机列表进行 TCP 补充探测
|
||||||
// 返回存活的主机列表
|
// 返回存活的主机列表
|
||||||
func runTcpProbeForHosts(ctx context.Context, hosts []string, session *common.ScanSession) []string {
|
func runTcpProbeForHosts(ctx context.Context, hosts []string, session *common.ScanSession) []string {
|
||||||
config := session.Config
|
|
||||||
if len(hosts) == 0 {
|
if len(hosts) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -773,9 +769,7 @@ func runTcpProbeForHosts(ctx context.Context, hosts []string, session *common.Sc
|
|||||||
}
|
}
|
||||||
_ = session.SaveResult(result)
|
_ = session.SaveResult(result)
|
||||||
|
|
||||||
if !config.Output.Silent {
|
session.LogInfo(i18n.Tr("host_alive", h, "TCP"))
|
||||||
common.LogInfo(i18n.Tr("host_alive", h, "TCP"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}(host)
|
}(host)
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-27
@@ -143,13 +143,13 @@ func (f *failedPortCollector) Count() int {
|
|||||||
func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout int64, session *common.ScanSession, stream chan<- string) []string {
|
func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout int64, session *common.ScanSession, stream chan<- string) []string {
|
||||||
config := session.Config
|
config := session.Config
|
||||||
state := session.State
|
state := session.State
|
||||||
common.LogDebug(fmt.Sprintf("[PortScan] 开始: %d个主机, 线程数=%d", len(hosts), config.ThreadNum))
|
session.LogDebug(fmt.Sprintf("[PortScan] 开始: %d个主机, 线程数=%d", len(hosts), config.ThreadNum))
|
||||||
|
|
||||||
// 大规模扫描预筛:跨多个 /24 时先做网段探活,跳过空网段
|
// 大规模扫描预筛:跨多个 /24 时先做网段探活,跳过空网段
|
||||||
if len(hosts) > subnetProbeThreshold {
|
if len(hosts) > subnetProbeThreshold {
|
||||||
hosts = probeSubnets(ctx, hosts, time.Duration(timeout)*time.Second, session)
|
hosts = probeSubnets(ctx, hosts, time.Duration(timeout)*time.Second, session)
|
||||||
if len(hosts) == 0 {
|
if len(hosts) == 0 {
|
||||||
common.LogInfo(i18n.GetText("port_scan_no_alive_subnet"))
|
session.LogInfo(i18n.GetText("port_scan_no_alive_subnet"))
|
||||||
if stream != nil {
|
if stream != nil {
|
||||||
close(stream)
|
close(stream)
|
||||||
}
|
}
|
||||||
@@ -160,13 +160,13 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
|
|||||||
// 解析端口和排除端口
|
// 解析端口和排除端口
|
||||||
portList := parsers.ParsePort(ports)
|
portList := parsers.ParsePort(ports)
|
||||||
if len(portList) == 0 {
|
if len(portList) == 0 {
|
||||||
common.LogError(i18n.Tr("invalid_port", ports))
|
session.LogError(i18n.Tr("invalid_port", ports))
|
||||||
if stream != nil {
|
if stream != nil {
|
||||||
close(stream)
|
close(stream)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
common.LogDebug(fmt.Sprintf("[PortScan] 端口解析完成: %d个端口", len(portList)))
|
session.LogDebug(fmt.Sprintf("[PortScan] 端口解析完成: %d个端口", len(portList)))
|
||||||
|
|
||||||
// 使用config中的排除端口配置
|
// 使用config中的排除端口配置
|
||||||
excludePorts := parsers.ParsePort(config.Target.ExcludePorts)
|
excludePorts := parsers.ParsePort(config.Target.ExcludePorts)
|
||||||
@@ -177,25 +177,25 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
|
|||||||
|
|
||||||
// 检查代理可靠性,如果存在全回显问题则警告
|
// 检查代理可靠性,如果存在全回显问题则警告
|
||||||
if common.IsProxyEnabled() && !common.IsProxyReliable() {
|
if common.IsProxyEnabled() && !common.IsProxyReliable() {
|
||||||
common.LogError("检测到代理存在全回显问题,端口扫描结果可能不准确")
|
session.LogError("检测到代理存在全回显问题,端口扫描结果可能不准确")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建流式迭代器(O(1) 内存,端口喷洒策略)
|
// 创建流式迭代器(O(1) 内存,端口喷洒策略)
|
||||||
iter := NewSocketIterator(hosts, portList, exclude)
|
iter := NewSocketIterator(hosts, portList, exclude)
|
||||||
totalTasks := iter.Total()
|
totalTasks := iter.Total()
|
||||||
common.LogDebug(fmt.Sprintf("[PortScan] 总任务数: %d", totalTasks))
|
session.LogDebug(fmt.Sprintf("[PortScan] 总任务数: %d", totalTasks))
|
||||||
|
|
||||||
// 使用传入的配置
|
// 使用传入的配置
|
||||||
threadNum := config.ThreadNum
|
threadNum := config.ThreadNum
|
||||||
|
|
||||||
// 大规模扫描警告和线程数自动调整
|
// 大规模扫描警告和线程数自动调整
|
||||||
if totalTasks > 100000 {
|
if totalTasks > 100000 {
|
||||||
common.LogInfo(fmt.Sprintf("大规模扫描: %d 个目标 (%d主机 × %d端口)", totalTasks, len(hosts), len(portList)))
|
session.LogInfo(fmt.Sprintf("大规模扫描: %d 个目标 (%d主机 × %d端口)", totalTasks, len(hosts), len(portList)))
|
||||||
// 如果任务数超过100万且线程数大于300,自动降低线程数
|
// 如果任务数超过100万且线程数大于300,自动降低线程数
|
||||||
if totalTasks > 1000000 && threadNum > 300 {
|
if totalTasks > 1000000 && threadNum > 300 {
|
||||||
oldThreadNum := threadNum
|
oldThreadNum := threadNum
|
||||||
threadNum = 300
|
threadNum = 300
|
||||||
common.LogInfo(fmt.Sprintf("自动调整线程数: %d -> %d (大规模扫描优化)", oldThreadNum, threadNum))
|
session.LogInfo(fmt.Sprintf("自动调整线程数: %d -> %d (大规模扫描优化)", oldThreadNum, threadNum))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
|
|||||||
description := fmt.Sprintf("端口扫描中(%d线程)", threadNum)
|
description := fmt.Sprintf("端口扫描中(%d线程)", threadNum)
|
||||||
common.InitProgressBar(int64(totalTasks), description)
|
common.InitProgressBar(int64(totalTasks), description)
|
||||||
}
|
}
|
||||||
common.LogDebug("[PortScan] 进度条初始化完成")
|
session.LogDebug("[PortScan] 进度条初始化完成")
|
||||||
|
|
||||||
// 初始化并发控制
|
// 初始化并发控制
|
||||||
to := time.Duration(timeout) * time.Second
|
to := time.Duration(timeout) * time.Second
|
||||||
@@ -214,7 +214,7 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
|
|||||||
failedCollector := &failedPortCollector{}
|
failedCollector := &failedPortCollector{}
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
common.LogDebug(fmt.Sprintf("[PortScan] 开始创建线程池, size=%d", threadNum))
|
session.LogDebug(fmt.Sprintf("[PortScan] 开始创建线程池, size=%d", threadNum))
|
||||||
// 创建自适应线程池(支持动态调整)
|
// 创建自适应线程池(支持动态调整)
|
||||||
pool, err := NewAdaptivePool(threadNum, func(task interface{}) {
|
pool, err := NewAdaptivePool(threadNum, func(task interface{}) {
|
||||||
taskInfo, ok := task.(portScanTask)
|
taskInfo, ok := task.(portScanTask)
|
||||||
@@ -230,19 +230,19 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
|
|||||||
common.UpdateProgressBar(1)
|
common.UpdateProgressBar(1)
|
||||||
}, state)
|
}, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogError(i18n.Tr("thread_pool_create_failed", err))
|
session.LogError(i18n.Tr("thread_pool_create_failed", err))
|
||||||
if stream != nil {
|
if stream != nil {
|
||||||
close(stream)
|
close(stream)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
common.LogDebug("[PortScan] 线程池创建成功")
|
session.LogDebug("[PortScan] 线程池创建成功")
|
||||||
defer pool.Release()
|
defer pool.Release()
|
||||||
|
|
||||||
common.LogDebug("[PortScan] 开始滑动窗口调度")
|
session.LogDebug("[PortScan] 开始滑动窗口调度")
|
||||||
// 滑动窗口调度:维护固定数量的"飞行中"任务
|
// 滑动窗口调度:维护固定数量的"飞行中"任务
|
||||||
slidingWindowSchedule(iter, pool, &wg, threadNum)
|
slidingWindowSchedule(iter, pool, &wg, threadNum)
|
||||||
common.LogDebug("[PortScan] 滑动窗口调度完成")
|
session.LogDebug("[PortScan] 滑动窗口调度完成")
|
||||||
|
|
||||||
// 收集结果
|
// 收集结果
|
||||||
aliveAddrs := collector.GetAll()
|
aliveAddrs := collector.GetAll()
|
||||||
@@ -257,7 +257,7 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
|
|||||||
common.FinishProgressBar()
|
common.FinishProgressBar()
|
||||||
}
|
}
|
||||||
|
|
||||||
common.LogInfo(i18n.Tr("port_scan_complete", count))
|
session.LogInfo(i18n.Tr("port_scan_complete", count))
|
||||||
|
|
||||||
// 检查扫描失败率,如果过高则警告用户
|
// 检查扫描失败率,如果过高则警告用户
|
||||||
resourceErrors := state.GetResourceExhaustedCount()
|
resourceErrors := state.GetResourceExhaustedCount()
|
||||||
@@ -268,18 +268,18 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
|
|||||||
|
|
||||||
if failureRate > 20 {
|
if failureRate > 20 {
|
||||||
// 失败率超过20%,严重警告
|
// 失败率超过20%,严重警告
|
||||||
common.LogError(i18n.Tr("scan_failure_rate_high", fmt.Sprintf("%.1f%%", failureRate), failedCount, totalTasks))
|
session.LogError(i18n.Tr("scan_failure_rate_high", fmt.Sprintf("%.1f%%", failureRate), failedCount, totalTasks))
|
||||||
common.LogError(i18n.GetText("scan_failure_reason"))
|
session.LogError(i18n.GetText("scan_failure_reason"))
|
||||||
common.LogError(i18n.Tr("scan_reduce_threads_suggestion", threadNum))
|
session.LogError(i18n.Tr("scan_reduce_threads_suggestion", threadNum))
|
||||||
} else if failureRate > 5 {
|
} else if failureRate > 5 {
|
||||||
// 失败率5-20%,一般警告
|
// 失败率5-20%,一般警告
|
||||||
common.LogInfo(i18n.Tr("scan_partial_failure", fmt.Sprintf("%.1f%%", failureRate), failedCount, totalTasks))
|
session.LogInfo(i18n.Tr("scan_partial_failure", fmt.Sprintf("%.1f%%", failureRate), failedCount, totalTasks))
|
||||||
common.LogInfo(i18n.Tr("scan_reduce_threads_accuracy", threadNum))
|
session.LogInfo(i18n.Tr("scan_reduce_threads_accuracy", threadNum))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resourceErrors > 0 {
|
if resourceErrors > 0 {
|
||||||
common.LogError(i18n.Tr("resource_exhausted_warning", resourceErrors))
|
session.LogError(i18n.Tr("resource_exhausted_warning", resourceErrors))
|
||||||
}
|
}
|
||||||
|
|
||||||
return aliveAddrs
|
return aliveAddrs
|
||||||
@@ -467,7 +467,7 @@ func scanSinglePort(ctx context.Context, host string, port int, addr string, ada
|
|||||||
// 步骤1.5:代理连接深度验证(防止透明代理/全回显代理的假连接问题)
|
// 步骤1.5:代理连接深度验证(防止透明代理/全回显代理的假连接问题)
|
||||||
valid, verifyMethod := verifyProxyConnectionDeep(conn, addr)
|
valid, verifyMethod := verifyProxyConnectionDeep(conn, addr)
|
||||||
if !valid {
|
if !valid {
|
||||||
common.LogDebug(fmt.Sprintf("代理验证失败 %s: %s", addr, verifyMethod))
|
session.LogDebug(fmt.Sprintf("代理验证失败 %s: %s", addr, verifyMethod))
|
||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -655,7 +655,7 @@ func processServiceResult(host string, port int, addr string, serviceInfo *Servi
|
|||||||
if serviceInfo == nil {
|
if serviceInfo == nil {
|
||||||
// 服务识别失败,尝试 HTTP 回退探测
|
// 服务识别失败,尝试 HTTP 回退探测
|
||||||
if !tryHTTPFallbackDetection(host, port, addr, config, session) {
|
if !tryHTTPFallbackDetection(host, port, addr, config, session) {
|
||||||
common.LogInfo(i18n.Tr("port_open", addr))
|
session.LogInfo(i18n.Tr("port_open", addr))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -677,7 +677,7 @@ func processServiceResult(host string, port int, addr string, serviceInfo *Servi
|
|||||||
Details: details,
|
Details: details,
|
||||||
})
|
})
|
||||||
|
|
||||||
common.LogInfo(buildServiceLogMessage(addr, serviceInfo, isWeb))
|
session.LogInfo(buildServiceLogMessage(addr, serviceInfo, isWeb))
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildServiceDetails 构建服务详情 map
|
// buildServiceDetails 构建服务详情 map
|
||||||
@@ -745,7 +745,7 @@ func tryHTTPFallbackDetection(host string, port int, addr string, config *common
|
|||||||
Details: details,
|
Details: details,
|
||||||
})
|
})
|
||||||
|
|
||||||
common.LogInfo(i18n.Tr("port_open_http", addr))
|
session.LogInfo(i18n.Tr("port_open_http", addr))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,7 +790,7 @@ func probeSubnets(ctx context.Context, hosts []string, timeout time.Duration, se
|
|||||||
return hosts
|
return hosts
|
||||||
}
|
}
|
||||||
|
|
||||||
common.LogInfo(fmt.Sprintf("网段预筛: %d 个 /24 子网, %d 个主机", len(subnets), len(hosts)))
|
session.LogInfo(fmt.Sprintf("网段预筛: %d 个 /24 子网, %d 个主机", len(subnets), len(hosts)))
|
||||||
|
|
||||||
aliveSubnets := sync.Map{}
|
aliveSubnets := sync.Map{}
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@@ -872,7 +872,7 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
skipped := len(subnets) - aliveCount
|
skipped := len(subnets) - aliveCount
|
||||||
common.LogInfo(fmt.Sprintf("网段预筛完成: %d 个存活 (网关命中 %d), %d 个跳过, 剩余 %d 主机",
|
session.LogInfo(fmt.Sprintf("网段预筛完成: %d 个存活 (网关命中 %d), %d 个跳过, 剩余 %d 主机",
|
||||||
aliveCount, gwHits, skipped, len(result)))
|
aliveCount, gwHits, skipped, len(result)))
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-12
@@ -87,7 +87,7 @@ func RunScan(ctx context.Context, info common.HostInfo, session *common.ScanSess
|
|||||||
|
|
||||||
// 初始化HTTP客户端(静默,无需日志)
|
// 初始化HTTP客户端(静默,无需日志)
|
||||||
if err := lib.Inithttp(config); err != nil {
|
if err := lib.Inithttp(config); err != nil {
|
||||||
common.LogError(i18n.Tr("http_client_init_failed", err))
|
session.LogError(i18n.Tr("http_client_init_failed", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,22 +107,22 @@ func RunScan(ctx context.Context, info common.HostInfo, session *common.ScanSess
|
|||||||
// 检查是否有活跃的连接需要维持
|
// 检查是否有活跃的连接需要维持
|
||||||
if state.IsReverseShellActive() || state.IsSocks5ProxyActive() || state.IsForwardShellActive() {
|
if state.IsReverseShellActive() || state.IsSocks5ProxyActive() || state.IsForwardShellActive() {
|
||||||
if state.IsReverseShellActive() {
|
if state.IsReverseShellActive() {
|
||||||
common.LogInfo(i18n.GetText("active_reverse_shell"))
|
session.LogInfo(i18n.GetText("active_reverse_shell"))
|
||||||
}
|
}
|
||||||
if state.IsSocks5ProxyActive() {
|
if state.IsSocks5ProxyActive() {
|
||||||
common.LogInfo(i18n.GetText("active_socks5_proxy"))
|
session.LogInfo(i18n.GetText("active_socks5_proxy"))
|
||||||
}
|
}
|
||||||
if state.IsForwardShellActive() {
|
if state.IsForwardShellActive() {
|
||||||
common.LogInfo(i18n.GetText("active_forward_shell"))
|
session.LogInfo(i18n.GetText("active_forward_shell"))
|
||||||
}
|
}
|
||||||
common.LogInfo(i18n.GetText("press_ctrl_c_exit"))
|
session.LogInfo(i18n.GetText("press_ctrl_c_exit"))
|
||||||
|
|
||||||
// 优雅等待信号或 context 取消(Web Stop)
|
// 优雅等待信号或 context 取消(Web Stop)
|
||||||
sigChan := make(chan os.Signal, 1)
|
sigChan := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||||
select {
|
select {
|
||||||
case <-sigChan:
|
case <-sigChan:
|
||||||
common.LogInfo(i18n.GetText("received_exit_signal"))
|
session.LogInfo(i18n.GetText("received_exit_signal"))
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
}
|
}
|
||||||
cancel()
|
cancel()
|
||||||
@@ -130,18 +130,21 @@ func RunScan(ctx context.Context, info common.HostInfo, session *common.ScanSess
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 完成扫描
|
// 完成扫描
|
||||||
finishScan(config, state)
|
finishScan(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
// finishScan 完成扫描并输出结果
|
// finishScan 完成扫描并输出结果
|
||||||
func finishScan(config *common.Config, state *common.State) {
|
func finishScan(session *common.ScanSession) {
|
||||||
|
config := session.Config
|
||||||
|
state := session.State
|
||||||
|
|
||||||
// 确保进度条正确完成
|
// 确保进度条正确完成
|
||||||
if common.IsProgressActive() {
|
if common.IsProgressActive() {
|
||||||
common.FinishProgressBar()
|
common.FinishProgressBar()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 输出扫描完成信息
|
// 输出扫描完成信息
|
||||||
common.LogInfo(i18n.Tr("scan_task_complete", time.Since(state.GetStartTime()).Round(time.Millisecond), state.GetNum()))
|
session.LogInfo(i18n.Tr("scan_task_complete", time.Since(state.GetStartTime()).Round(time.Millisecond), state.GetNum()))
|
||||||
|
|
||||||
// 输出性能统计 JSON(如果启用)
|
// 输出性能统计 JSON(如果启用)
|
||||||
if config.Output.PerfStats {
|
if config.Output.PerfStats {
|
||||||
@@ -262,7 +265,7 @@ func executeScanTask(ctx context.Context, session *common.ScanSession, pluginNam
|
|||||||
defer func() {
|
defer func() {
|
||||||
// 捕获并记录任何可能的panic
|
// 捕获并记录任何可能的panic
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
common.LogError(i18n.Tr("plugin_panic", pluginName, target.Host, target.Port, r))
|
session.LogError(i18n.Tr("plugin_panic", pluginName, target.Host, target.Port, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新统计和进度(任务真正完成时才更新)
|
// 更新统计和进度(任务真正完成时才更新)
|
||||||
@@ -284,10 +287,10 @@ func executeScanTask(ctx context.Context, session *common.ScanSession, pluginNam
|
|||||||
savePluginResult(session, &target, pluginName, result)
|
savePluginResult(session, &target, pluginName, result)
|
||||||
} else if result.Type == plugins.ResultTypeCredential {
|
} else if result.Type == plugins.ResultTypeCredential {
|
||||||
// 凭据测试完成但未发现弱密码,在error级别输出提示
|
// 凭据测试完成但未发现弱密码,在error级别输出提示
|
||||||
common.LogError(i18n.Tr("brute_no_weak_pass", target.Host, target.Port, pluginName))
|
session.LogError(i18n.Tr("brute_no_weak_pass", target.Host, target.Port, pluginName))
|
||||||
} else if result.Error != nil {
|
} else if result.Error != nil {
|
||||||
// 其他类型的错误
|
// 其他类型的错误
|
||||||
common.LogError(i18n.Tr("plugin_scan_error", target.Host, target.Port, result.Error))
|
session.LogError(i18n.Tr("plugin_scan_error", target.Host, target.Port, result.Error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-7
@@ -28,13 +28,13 @@ func (p *FTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
|
|||||||
config := session.Config
|
config := session.Config
|
||||||
state := session.State
|
state := session.State
|
||||||
if config.DisableBrute {
|
if config.DisableBrute {
|
||||||
return p.identifyService(info, config, state)
|
return p.identifyService(info, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
target := info.Target()
|
target := info.Target()
|
||||||
|
|
||||||
// 优先检测匿名访问
|
// 优先检测匿名访问
|
||||||
if result := p.testAnonymousAccess(ctx, info, config, state); result != nil && result.Success {
|
if result := p.testAnonymousAccess(ctx, info, session); result != nil && result.Success {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ func (p *FTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
|
|||||||
output.WriteString(fmt.Sprintf("\n [->] %s", file))
|
output.WriteString(fmt.Sprintf("\n [->] %s", file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
common.LogVuln(output.String())
|
session.LogVuln(output.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -144,7 +144,9 @@ func classifyFTPErrorType(err error) ErrorType {
|
|||||||
return ClassifyError(err, ftpAuthErrors, ftpNetworkErrors)
|
return ClassifyError(err, ftpAuthErrors, ftpNetworkErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *FTPPlugin) identifyService(info *common.HostInfo, config *common.Config, state *common.State) *ScanResult {
|
func (p *FTPPlugin) identifyService(info *common.HostInfo, session *common.ScanSession) *ScanResult {
|
||||||
|
config := session.Config
|
||||||
|
state := session.State
|
||||||
target := info.Target()
|
target := info.Target()
|
||||||
|
|
||||||
conn, err := ftplib.Dial(target, ftplib.DialWithTimeout(config.Timeout))
|
conn, err := ftplib.Dial(target, ftplib.DialWithTimeout(config.Timeout))
|
||||||
@@ -160,7 +162,7 @@ func (p *FTPPlugin) identifyService(info *common.HostInfo, config *common.Config
|
|||||||
defer func() { _ = conn.Quit() }()
|
defer func() { _ = conn.Quit() }()
|
||||||
|
|
||||||
banner := "FTP"
|
banner := "FTP"
|
||||||
common.LogSuccess(i18n.Tr("ftp_service", target, banner))
|
session.LogSuccess(i18n.Tr("ftp_service", target, banner))
|
||||||
return &ScanResult{
|
return &ScanResult{
|
||||||
Type: plugins.ResultTypeService,
|
Type: plugins.ResultTypeService,
|
||||||
Success: true,
|
Success: true,
|
||||||
@@ -170,7 +172,9 @@ func (p *FTPPlugin) identifyService(info *common.HostInfo, config *common.Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
// testAnonymousAccess 测试FTP匿名访问
|
// testAnonymousAccess 测试FTP匿名访问
|
||||||
func (p *FTPPlugin) testAnonymousAccess(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *ScanResult {
|
func (p *FTPPlugin) testAnonymousAccess(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
|
||||||
|
config := session.Config
|
||||||
|
state := session.State
|
||||||
target := info.Target()
|
target := info.Target()
|
||||||
|
|
||||||
anonymousCreds := []Credential{
|
anonymousCreds := []Credential{
|
||||||
@@ -204,7 +208,7 @@ func (p *FTPPlugin) testAnonymousAccess(ctx context.Context, info *common.HostIn
|
|||||||
output.WriteString(fmt.Sprintf("\n [->] %s", file))
|
output.WriteString(fmt.Sprintf("\n [->] %s", file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
common.LogVuln(output.String())
|
session.LogVuln(output.String())
|
||||||
|
|
||||||
return &ScanResult{
|
return &ScanResult{
|
||||||
Type: plugins.ResultTypeCredential,
|
Type: plugins.ResultTypeCredential,
|
||||||
|
|||||||
Reference in New Issue
Block a user