mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 05:56:46 +08:00
Compare commits
17 Commits
a7ea2f5198
...
4054c767dd
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4054c767dd | ||
![]() |
2385a730eb | ||
![]() |
5bf3f7a2d9 | ||
![]() |
53ab64669a | ||
![]() |
767cb2dd21 | ||
![]() |
f806a186e4 | ||
![]() |
9e9485814d | ||
![]() |
36f0e5076d | ||
![]() |
98a9a4e1c2 | ||
![]() |
d9d0271d5b | ||
![]() |
1febb54fe6 | ||
![]() |
f8c8f3d1eb | ||
![]() |
622795740f | ||
![]() |
a23c82142d | ||
![]() |
5f7669a537 | ||
![]() |
d19abcac36 | ||
![]() |
a36767c158 |
@ -63,6 +63,10 @@ var (
|
||||
DownloadURL string // 下载文件的URL
|
||||
DownloadSavePath string // 下载文件保存路径
|
||||
|
||||
// 发包频率控制相关变量
|
||||
PacketRateLimit int64 // 每分钟最大发包次数 (0表示不限制)
|
||||
MaxPacketCount int64 // 整个程序最大发包总数 (0表示不限制)
|
||||
|
||||
// Parse.go 使用的变量
|
||||
HostPort []string
|
||||
URLs []string
|
||||
@ -199,6 +203,12 @@ func Flag(Info *HostInfo) {
|
||||
flag.BoolVar(&DisableBrute, "nobr", false, i18n.GetText("flag_disable_brute"))
|
||||
flag.IntVar(&MaxRetries, "retry", 3, i18n.GetText("flag_max_retries"))
|
||||
|
||||
// ═════════════════════════════════════════════════
|
||||
// 发包频率控制参数
|
||||
// ═════════════════════════════════════════════════
|
||||
flag.Int64Var(&PacketRateLimit, "rate", 0, i18n.GetText("flag_packet_rate_limit"))
|
||||
flag.Int64Var(&MaxPacketCount, "maxpkts", 0, i18n.GetText("flag_max_packet_count"))
|
||||
|
||||
// ═════════════════════════════════════════════════
|
||||
// 输出与显示控制参数
|
||||
// ═════════════════════════════════════════════════
|
||||
|
@ -1,7 +1,10 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common/config"
|
||||
@ -101,6 +104,19 @@ var (
|
||||
End int64 // 结束计数器
|
||||
Num int64 // 数量计数器
|
||||
|
||||
// 网络包计数器 - 使用原子操作确保线程安全
|
||||
PacketCount int64 // 总发包数量
|
||||
TCPPacketCount int64 // TCP包数量总计
|
||||
TCPSuccessPacketCount int64 // TCP成功连接包数量
|
||||
TCPFailedPacketCount int64 // TCP失败连接包数量
|
||||
UDPPacketCount int64 // UDP包数量
|
||||
HTTPPacketCount int64 // HTTP请求数量
|
||||
|
||||
// 发包频率控制变量
|
||||
PacketRateStartTime int64 // 当前分钟的开始时间戳
|
||||
PacketRateCurrentCount int64 // 当前分钟内的发包数量
|
||||
PacketRateMutex sync.Mutex // 发包频率控制互斥锁
|
||||
|
||||
// =============================================================================
|
||||
// 初始化控制
|
||||
// =============================================================================
|
||||
@ -173,3 +189,145 @@ const (
|
||||
|
||||
|
||||
// LogWithProgress 已在progressmanager.go中定义,此处不重复
|
||||
|
||||
// =============================================================================
|
||||
// 网络包计数器功能
|
||||
// =============================================================================
|
||||
|
||||
// IncrementPacketCount 增加总包计数(原子操作)
|
||||
func IncrementPacketCount() int64 {
|
||||
return atomic.AddInt64(&PacketCount, 1)
|
||||
}
|
||||
|
||||
// IncrementTCPSuccessPacketCount 增加TCP成功连接包计数(原子操作)
|
||||
func IncrementTCPSuccessPacketCount() int64 {
|
||||
atomic.AddInt64(&TCPSuccessPacketCount, 1)
|
||||
atomic.AddInt64(&TCPPacketCount, 1)
|
||||
return atomic.AddInt64(&PacketCount, 1)
|
||||
}
|
||||
|
||||
// IncrementTCPFailedPacketCount 增加TCP失败连接包计数(原子操作)
|
||||
func IncrementTCPFailedPacketCount() int64 {
|
||||
atomic.AddInt64(&TCPFailedPacketCount, 1)
|
||||
atomic.AddInt64(&TCPPacketCount, 1)
|
||||
return atomic.AddInt64(&PacketCount, 1)
|
||||
}
|
||||
|
||||
// IncrementUDPPacketCount 增加UDP包计数(原子操作)
|
||||
func IncrementUDPPacketCount() int64 {
|
||||
atomic.AddInt64(&UDPPacketCount, 1)
|
||||
return atomic.AddInt64(&PacketCount, 1)
|
||||
}
|
||||
|
||||
// IncrementHTTPPacketCount 增加HTTP包计数(原子操作)
|
||||
func IncrementHTTPPacketCount() int64 {
|
||||
atomic.AddInt64(&HTTPPacketCount, 1)
|
||||
return atomic.AddInt64(&PacketCount, 1)
|
||||
}
|
||||
|
||||
// GetPacketCount 获取总包计数(原子操作)
|
||||
func GetPacketCount() int64 {
|
||||
return atomic.LoadInt64(&PacketCount)
|
||||
}
|
||||
|
||||
// GetTCPPacketCount 获取TCP包计数(原子操作)
|
||||
func GetTCPPacketCount() int64 {
|
||||
return atomic.LoadInt64(&TCPPacketCount)
|
||||
}
|
||||
|
||||
// GetTCPSuccessPacketCount 获取TCP成功连接包计数(原子操作)
|
||||
func GetTCPSuccessPacketCount() int64 {
|
||||
return atomic.LoadInt64(&TCPSuccessPacketCount)
|
||||
}
|
||||
|
||||
// GetTCPFailedPacketCount 获取TCP失败连接包计数(原子操作)
|
||||
func GetTCPFailedPacketCount() int64 {
|
||||
return atomic.LoadInt64(&TCPFailedPacketCount)
|
||||
}
|
||||
|
||||
// GetUDPPacketCount 获取UDP包计数(原子操作)
|
||||
func GetUDPPacketCount() int64 {
|
||||
return atomic.LoadInt64(&UDPPacketCount)
|
||||
}
|
||||
|
||||
// GetHTTPPacketCount 获取HTTP包计数(原子操作)
|
||||
func GetHTTPPacketCount() int64 {
|
||||
return atomic.LoadInt64(&HTTPPacketCount)
|
||||
}
|
||||
|
||||
// ResetPacketCounters 重置所有包计数器(原子操作)
|
||||
func ResetPacketCounters() {
|
||||
atomic.StoreInt64(&PacketCount, 0)
|
||||
atomic.StoreInt64(&TCPPacketCount, 0)
|
||||
atomic.StoreInt64(&TCPSuccessPacketCount, 0)
|
||||
atomic.StoreInt64(&TCPFailedPacketCount, 0)
|
||||
atomic.StoreInt64(&UDPPacketCount, 0)
|
||||
atomic.StoreInt64(&HTTPPacketCount, 0)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 发包频率控制功能
|
||||
// =============================================================================
|
||||
|
||||
// CanSendPacket 检查是否可以发包 - 同时检查频率限制和总数限制
|
||||
// 返回值: (可以发包, 错误信息)
|
||||
func CanSendPacket() (bool, string) {
|
||||
// 检查总数限制
|
||||
if MaxPacketCount > 0 {
|
||||
currentTotal := atomic.LoadInt64(&PacketCount)
|
||||
if currentTotal >= MaxPacketCount {
|
||||
return false, fmt.Sprintf("已达到最大发包数量限制: %d", MaxPacketCount)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查频率限制
|
||||
if PacketRateLimit > 0 {
|
||||
PacketRateMutex.Lock()
|
||||
defer PacketRateMutex.Unlock()
|
||||
|
||||
currentTime := time.Now().Unix() / 60 // 当前分钟
|
||||
|
||||
// 如果是新的分钟,重置计数器
|
||||
if PacketRateStartTime != currentTime {
|
||||
PacketRateStartTime = currentTime
|
||||
atomic.StoreInt64(&PacketRateCurrentCount, 0)
|
||||
}
|
||||
|
||||
// 检查当前分钟的发包数是否超限
|
||||
currentCount := atomic.LoadInt64(&PacketRateCurrentCount)
|
||||
if currentCount >= PacketRateLimit {
|
||||
return false, fmt.Sprintf("已达到每分钟发包频率限制: %d", PacketRateLimit)
|
||||
}
|
||||
|
||||
// 增加当前分钟的发包计数
|
||||
atomic.AddInt64(&PacketRateCurrentCount, 1)
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// WaitForPacketLimit 等待直到可以发包 - 智能等待策略
|
||||
func WaitForPacketLimit() error {
|
||||
maxWaitTime := 60 * time.Second // 最大等待1分钟
|
||||
startWait := time.Now()
|
||||
|
||||
for {
|
||||
canSend, reason := CanSendPacket()
|
||||
if canSend {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 如果是总数限制,直接返回错误
|
||||
if MaxPacketCount > 0 && strings.Contains(reason, "最大发包数量") {
|
||||
return fmt.Errorf(reason)
|
||||
}
|
||||
|
||||
// 如果等待超时,返回错误
|
||||
if time.Since(startWait) > maxWaitTime {
|
||||
return fmt.Errorf("等待发包权限超时: %s", reason)
|
||||
}
|
||||
|
||||
// 短暂休眠后重试
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
@ -187,6 +187,14 @@ var FlagMessages = map[string]map[string]string{
|
||||
LangZH: "最大重试次数",
|
||||
LangEN: "Maximum retries",
|
||||
},
|
||||
"flag_packet_rate_limit": {
|
||||
LangZH: "每分钟最大发包次数 (0表示不限制)",
|
||||
LangEN: "Maximum packets per minute (0 means no limit)",
|
||||
},
|
||||
"flag_max_packet_count": {
|
||||
LangZH: "整个程序最大发包总数 (0表示不限制)",
|
||||
LangEN: "Maximum total packet count for entire program (0 means no limit)",
|
||||
},
|
||||
"flag_output_file": {
|
||||
LangZH: "输出文件",
|
||||
LangEN: "Output file",
|
||||
|
90
common/network.go
Normal file
90
common/network.go
Normal file
@ -0,0 +1,90 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
network.go - 统一网络操作包装器
|
||||
|
||||
提供带发包控制、统计和代理支持的统一网络操作接口。
|
||||
消除在每个插件中重复添加发包控制检查的需要。
|
||||
*/
|
||||
|
||||
// =============================================================================
|
||||
// 统一网络连接包装器
|
||||
// =============================================================================
|
||||
|
||||
// SafeDialTimeout 带发包控制的TCP连接
|
||||
// 自动处理发包限制检查和统计计数
|
||||
func SafeDialTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
|
||||
// 检查发包限制
|
||||
if canSend, reason := CanSendPacket(); !canSend {
|
||||
LogError(fmt.Sprintf("网络连接 %s 受限: %s", address, reason))
|
||||
return nil, fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
// 建立连接 - 支持SOCKS5代理
|
||||
// 注意:WrapperTcpWithTimeout内部已经有计数逻辑,这里不重复计数
|
||||
conn, err := WrapperTcpWithTimeout(network, address, timeout)
|
||||
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// SafeUDPDial 带发包控制的UDP连接
|
||||
func SafeUDPDial(network, address string, timeout time.Duration) (net.Conn, error) {
|
||||
// 检查发包限制
|
||||
if canSend, reason := CanSendPacket(); !canSend {
|
||||
LogError(fmt.Sprintf("UDP连接 %s 受限: %s", address, reason))
|
||||
return nil, fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
// 建立UDP连接
|
||||
conn, err := net.DialTimeout(network, address, timeout)
|
||||
|
||||
// 统计UDP包数量
|
||||
if err == nil {
|
||||
IncrementUDPPacketCount()
|
||||
}
|
||||
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// SafeHTTPDo 带发包控制的HTTP请求
|
||||
func SafeHTTPDo(client *http.Client, req *http.Request) (*http.Response, error) {
|
||||
// 检查发包限制
|
||||
if canSend, reason := CanSendPacket(); !canSend {
|
||||
LogError(fmt.Sprintf("HTTP请求 %s 受限: %s", req.URL.String(), reason))
|
||||
return nil, fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
// 执行HTTP请求
|
||||
resp, err := client.Do(req)
|
||||
|
||||
// 统计TCP包数量 (HTTP本质上是TCP)
|
||||
if err != nil {
|
||||
IncrementTCPFailedPacketCount()
|
||||
} else {
|
||||
IncrementTCPSuccessPacketCount()
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 便捷函数封装
|
||||
// =============================================================================
|
||||
|
||||
// SafeTCPDial TCP连接的便捷封装
|
||||
func SafeTCPDial(address string, timeout time.Duration) (net.Conn, error) {
|
||||
return SafeDialTimeout("tcp", address, timeout)
|
||||
}
|
||||
|
||||
// SafeTCPDialContext 带Context的TCP连接
|
||||
func SafeTCPDialContext(network, address string, timeout time.Duration) (net.Conn, error) {
|
||||
// 这个函数为将来扩展Context支持预留
|
||||
return SafeDialTimeout(network, address, timeout)
|
||||
}
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -171,7 +172,32 @@ func (pm *ProgressManager) generateProgressBar() string {
|
||||
if pm.total == 0 {
|
||||
spinner := pm.getActivityIndicator()
|
||||
memInfo := pm.getMemoryInfo()
|
||||
return fmt.Sprintf("%s %s 等待中... %s", pm.description, spinner, memInfo)
|
||||
|
||||
// 获取TCP包统计(包含原HTTP请求)
|
||||
packetCount := GetPacketCount()
|
||||
tcpSuccess := GetTCPSuccessPacketCount()
|
||||
tcpFailed := GetTCPFailedPacketCount()
|
||||
udpCount := GetUDPPacketCount()
|
||||
|
||||
packetInfo := ""
|
||||
if packetCount > 0 {
|
||||
// 构建简化的包统计信息:只显示TCP和UDP
|
||||
details := make([]string, 0, 2)
|
||||
if tcpSuccess > 0 || tcpFailed > 0 {
|
||||
details = append(details, fmt.Sprintf("TCP:%d✓%d✗", tcpSuccess, tcpFailed))
|
||||
}
|
||||
if udpCount > 0 {
|
||||
details = append(details, fmt.Sprintf("UDP:%d", udpCount))
|
||||
}
|
||||
|
||||
if len(details) > 0 {
|
||||
packetInfo = fmt.Sprintf(" 发包:%d[%s]", packetCount, strings.Join(details, ","))
|
||||
} else {
|
||||
packetInfo = fmt.Sprintf(" 发包:%d", packetCount)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s %s 等待中...%s %s", pm.description, spinner, packetInfo, memInfo)
|
||||
}
|
||||
|
||||
percentage := float64(pm.current) / float64(pm.total) * 100
|
||||
@ -231,9 +257,33 @@ func (pm *ProgressManager) generateProgressBar() string {
|
||||
// 生成活跃指示器
|
||||
spinner := pm.getActivityIndicator()
|
||||
|
||||
// 获取TCP包统计(包含原HTTP请求)
|
||||
packetCount := GetPacketCount()
|
||||
tcpSuccess := GetTCPSuccessPacketCount()
|
||||
tcpFailed := GetTCPFailedPacketCount()
|
||||
udpCount := GetUDPPacketCount()
|
||||
|
||||
packetInfo := ""
|
||||
if packetCount > 0 {
|
||||
// 构建简化的包统计信息:只显示TCP和UDP
|
||||
details := make([]string, 0, 2)
|
||||
if tcpSuccess > 0 || tcpFailed > 0 {
|
||||
details = append(details, fmt.Sprintf("TCP:%d✓%d✗", tcpSuccess, tcpFailed))
|
||||
}
|
||||
if udpCount > 0 {
|
||||
details = append(details, fmt.Sprintf("UDP:%d", udpCount))
|
||||
}
|
||||
|
||||
if len(details) > 0 {
|
||||
packetInfo = fmt.Sprintf(" 发包:%d[%s]", packetCount, strings.Join(details, ","))
|
||||
} else {
|
||||
packetInfo = fmt.Sprintf(" 发包:%d", packetCount)
|
||||
}
|
||||
}
|
||||
|
||||
// 构建基础进度条
|
||||
baseProgress := fmt.Sprintf("%s %s %6.1f%% %s (%d/%d)%s%s",
|
||||
pm.description, spinner, percentage, bar, pm.current, pm.total, speedStr, eta)
|
||||
baseProgress := fmt.Sprintf("%s %s %6.1f%% %s (%d/%d)%s%s%s",
|
||||
pm.description, spinner, percentage, bar, pm.current, pm.total, speedStr, eta, packetInfo)
|
||||
|
||||
// 添加内存信息
|
||||
memInfo := pm.getMemoryInfo()
|
||||
|
@ -77,13 +77,25 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
|
||||
common.UpdateProgressBar(1)
|
||||
}()
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("端口扫描 %s 受限: %s", addr, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 连接测试 - 支持SOCKS5代理
|
||||
conn, err := common.WrapperTcpWithTimeout("tcp", addr, to)
|
||||
|
||||
if err != nil {
|
||||
// 计数TCP连接失败包
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 计数TCP连接成功包
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
|
||||
// 记录开放端口(先记录到内存,延迟输出直到服务识别完成)
|
||||
atomic.AddInt64(&count, 1)
|
||||
aliveMap.Store(addr, struct{}{})
|
||||
|
@ -253,13 +253,25 @@ func (w *WebPortDetector) tryHTTPConnectionDirect(ctx context.Context, host stri
|
||||
req.Header.Set("User-Agent", "fscan-web-detector/2.2")
|
||||
req.Header.Set("Accept", "*/*")
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("HTTP请求 %s 受限: %s", req.URL.String(), reason))
|
||||
return false
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
// HTTP请求失败,计为TCP失败
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
// 检查错误类型,某些错误也表明是HTTP服务
|
||||
return w.analyzeHTTPError(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// HTTP请求成功,计为TCP成功
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
|
||||
// 分析HTTP响应
|
||||
return w.analyzeHTTPResponse(resp, url)
|
||||
}
|
||||
|
@ -61,6 +61,12 @@ func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanR
|
||||
}
|
||||
|
||||
func (p *ActiveMQPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("ActiveMQ连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
@ -104,6 +110,17 @@ func (p *ActiveMQPlugin) authenticateSTOMP(conn net.Conn, username, password str
|
||||
|
||||
func (p *ActiveMQPlugin) identifyService(info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("ActiveMQ识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "activemq",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout)
|
||||
|
@ -61,6 +61,12 @@ func (p *CassandraPlugin) Scan(ctx context.Context, info *common.HostInfo) *Scan
|
||||
}
|
||||
|
||||
func (p *CassandraPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Cassandra连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(info.Ports)
|
||||
if err != nil {
|
||||
return false
|
||||
@ -81,8 +87,10 @@ func (p *CassandraPlugin) testCredential(ctx context.Context, info *common.HostI
|
||||
|
||||
session, err := cluster.CreateSession()
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer session.Close()
|
||||
|
||||
var dummy interface{}
|
||||
@ -94,6 +102,17 @@ func (p *CassandraPlugin) testCredential(ctx context.Context, info *common.HostI
|
||||
|
||||
func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Cassandra识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "cassandra",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(info.Ports)
|
||||
if err != nil {
|
||||
return &ScanResult{
|
||||
@ -111,6 +130,7 @@ func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.Host
|
||||
|
||||
session, err := cluster.CreateSession()
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
if strings.Contains(strings.ToLower(err.Error()), "authentication") {
|
||||
banner := "Cassandra (需要认证)"
|
||||
common.LogSuccess(fmt.Sprintf("Cassandra %s %s", target, banner))
|
||||
@ -126,6 +146,7 @@ func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.Host
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer session.Close()
|
||||
|
||||
banner := "Cassandra"
|
||||
|
@ -63,6 +63,12 @@ func (p *ElasticsearchPlugin) Scan(ctx context.Context, info *common.HostInfo) *
|
||||
|
||||
|
||||
func (p *ElasticsearchPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Elasticsearch连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: time.Duration(common.Timeout) * time.Second,
|
||||
Transport: &http.Transport{
|
||||
@ -89,8 +95,10 @@ func (p *ElasticsearchPlugin) testCredential(ctx context.Context, info *common.H
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == 200 {
|
||||
@ -110,6 +118,17 @@ func (p *ElasticsearchPlugin) testCredential(ctx context.Context, info *common.H
|
||||
|
||||
|
||||
func (p *ElasticsearchPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
common.LogError(fmt.Sprintf("Elasticsearch识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "elasticsearch",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
if p.testCredential(ctx, info, Credential{Username: "", Password: ""}) {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
banner := "Elasticsearch"
|
||||
|
@ -44,15 +44,27 @@ func (p *FindNetPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRe
|
||||
}
|
||||
}
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("FindNet连接 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "findnet",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
// 建立连接
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "findnet",
|
||||
Error: fmt.Errorf("连接RPC端口失败: %v", err),
|
||||
}
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
// 设置超时
|
||||
|
@ -63,7 +63,20 @@ func (p *FTPPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("FTP连接 %s 受限: %s", target, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
conn, err := ftplib.DialTimeout(target, timeout)
|
||||
if err == nil {
|
||||
// 计数成功连接
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
} else {
|
||||
// 计数失败连接
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
}
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@ -83,7 +96,24 @@ func (p *FTPPlugin) identifyService(info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("FTP服务识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "ftp",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := ftplib.DialTimeout(target, timeout)
|
||||
if err == nil {
|
||||
// 计数成功连接
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
} else {
|
||||
// 计数失败连接
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
}
|
||||
if err != nil {
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
|
@ -72,6 +72,12 @@ func (p *KafkaPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugins.
|
||||
|
||||
|
||||
func (p *KafkaPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) sarama.Client {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Kafka连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
@ -92,8 +98,10 @@ func (p *KafkaPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
brokers := []string{target}
|
||||
client, err := sarama.NewClient(brokers, config)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
return client
|
||||
}
|
||||
|
||||
@ -102,6 +110,16 @@ func (p *KafkaPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Kafka识别 %s 受限: %s", target, reason))
|
||||
return &plugins.Result{
|
||||
Success: false,
|
||||
Service: "kafka",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试无认证连接
|
||||
emptyCred := plugins.Credential{Username: "", Password: ""}
|
||||
client := p.testCredential(ctx, info, emptyCred)
|
||||
@ -124,6 +142,7 @@ func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo
|
||||
brokers := []string{target}
|
||||
client, err := sarama.NewClient(brokers, config)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
// 如果连接失败,尝试检查是否是Kafka协议错误
|
||||
if p.isKafkaProtocolError(err) {
|
||||
banner := "Kafka (需要认证)"
|
||||
@ -140,6 +159,7 @@ func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo
|
||||
Error: fmt.Errorf("无法识别为Kafka服务: %v", err),
|
||||
}
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer client.Close()
|
||||
|
||||
banner := "Kafka"
|
||||
|
@ -84,17 +84,46 @@ func (p *LDAPPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
}
|
||||
|
||||
func (p *LDAPPlugin) connectLDAP(ctx context.Context, info *common.HostInfo, creds plugins.Credential) (*ldaplib.Conn, error) {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("LDAP连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return nil, fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
var conn *ldaplib.Conn
|
||||
var err error
|
||||
|
||||
if info.Ports == "636" {
|
||||
return ldaplib.DialTLS("tcp", target, nil)
|
||||
conn, err = ldaplib.DialTLS("tcp", target, nil)
|
||||
} else {
|
||||
conn, err = ldaplib.Dial("tcp", target)
|
||||
}
|
||||
return ldaplib.Dial("tcp", target)
|
||||
|
||||
// 统计包数量
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
} else {
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
}
|
||||
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (p *LDAPPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("LDAP识别 %s 受限: %s", target, reason))
|
||||
return &plugins.Result{
|
||||
Success: false,
|
||||
Service: "ldap",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := p.connectLDAP(ctx, info, plugins.Credential{})
|
||||
if err != nil {
|
||||
return &plugins.Result{
|
||||
|
@ -59,12 +59,21 @@ func (p *MemcachedPlugin) Scan(ctx context.Context, info *common.HostInfo) *Scan
|
||||
|
||||
func (p *MemcachedPlugin) connectToMemcached(ctx context.Context, info *common.HostInfo) net.Conn {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Memcached连接 %s 受限: %s", target, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, timeout)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(timeout))
|
||||
|
||||
@ -100,6 +109,16 @@ func (p *MemcachedPlugin) testBasicCommand(conn net.Conn) bool {
|
||||
func (p *MemcachedPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Memcached识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "memcached",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
conn := p.connectToMemcached(ctx, info)
|
||||
if conn == nil {
|
||||
return &ScanResult{
|
||||
|
@ -135,6 +135,12 @@ func (p *MongoDBPlugin) mongodbUnauth(ctx context.Context, info *common.HostInfo
|
||||
|
||||
// checkMongoAuth 检查MongoDB认证状态 - 基于原始工作版本
|
||||
func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, packet []byte) (string, error) {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("MongoDB连接 %s 受限: %s", address, reason))
|
||||
return "", fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
// 创建连接超时上下文
|
||||
connCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second)
|
||||
defer cancel()
|
||||
@ -143,8 +149,11 @@ func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, pack
|
||||
var d net.Dialer
|
||||
conn, err := d.DialContext(connCtx, "tcp", address)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return "", fmt.Errorf("连接失败: %v", err)
|
||||
}
|
||||
// 连接成功,计数TCP成功包
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
// 检查上下文是否已取消
|
||||
@ -216,6 +225,12 @@ func (p *MongoDBPlugin) createOpQueryPacket() []byte {
|
||||
|
||||
// testMongoCredential 使用官方MongoDB驱动测试凭据
|
||||
func (p *MongoDBPlugin) testMongoCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("MongoDB认证测试 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
// 构建MongoDB连接URI
|
||||
var uri string
|
||||
if cred.Username != "" && cred.Password != "" {
|
||||
@ -242,13 +257,17 @@ func (p *MongoDBPlugin) testMongoCredential(ctx context.Context, info *common.Ho
|
||||
// 连接到MongoDB
|
||||
client, err := mongo.Connect(authCtx, clientOptions)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
// 连接成功,计数TCP成功包
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer client.Disconnect(authCtx)
|
||||
|
||||
// 测试连接 - 尝试ping数据库
|
||||
err = client.Ping(authCtx, nil)
|
||||
if err != nil {
|
||||
// ping失败,但已经连接成功了,不需要额外计数
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -296,11 +296,18 @@ func init() {
|
||||
|
||||
// checkMS17010Vulnerability 检测MS17-010漏洞 (从原始MS17010.go复制和适配)
|
||||
func (p *MS17010Plugin) checkMS17010Vulnerability(ip string) (bool, string, error) {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
return false, "", fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
// 连接目标
|
||||
conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false, "", fmt.Errorf("连接错误: %v", err)
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
if err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)); err != nil {
|
||||
@ -401,10 +408,17 @@ func (p *MS17010Plugin) checkMS17010Vulnerability(ip string) (bool, string, erro
|
||||
|
||||
// checkDoublePulsar 检测DOUBLEPULSAR后门
|
||||
func (p *MS17010Plugin) checkDoublePulsar(ip string) bool {
|
||||
conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
// 检查发包限制
|
||||
if canSend, _ := common.CanSendPacket(); !canSend {
|
||||
return false
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
// 简化的后门检测逻辑
|
||||
|
@ -64,6 +64,12 @@ func (p *MSSQLPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResu
|
||||
|
||||
|
||||
func (p *MSSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) *sql.DB {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("MSSQL连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
connStr := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%s;database=master;connection timeout=%d",
|
||||
info.Host, cred.Username, cred.Password, info.Ports, common.Timeout)
|
||||
|
||||
@ -81,10 +87,14 @@ func (p *MSSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
|
||||
err = db.PingContext(pingCtx)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
db.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 连接成功,计数TCP成功包
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
@ -97,6 +107,16 @@ func (p *MSSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("MSSQL识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "mssql",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
connStr := fmt.Sprintf("server=%s;user id=invalid;password=invalid;port=%s;database=master;connection timeout=%d",
|
||||
info.Host, info.Ports, common.Timeout)
|
||||
|
||||
@ -115,6 +135,13 @@ func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo
|
||||
|
||||
err = db.PingContext(pingCtx)
|
||||
|
||||
// 统计包数量
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
} else {
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
}
|
||||
|
||||
var banner string
|
||||
if err != nil && (strings.Contains(strings.ToLower(err.Error()), "login failed") ||
|
||||
strings.Contains(strings.ToLower(err.Error()), "mssql") ||
|
||||
|
@ -61,6 +61,13 @@ func (p *MySQLPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResu
|
||||
}
|
||||
|
||||
func (p *MySQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("MySQL连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
// 建立MySQL连接
|
||||
connStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/mysql?charset=utf8&timeout=%ds",
|
||||
cred.Username, cred.Password, info.Host, info.Ports, common.Timeout)
|
||||
|
||||
@ -75,6 +82,12 @@ func (p *MySQLPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
db.SetMaxIdleConns(0)
|
||||
|
||||
err = db.PingContext(ctx)
|
||||
// 统计MySQL连接结果
|
||||
if err == nil {
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
} else {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
}
|
||||
return err == nil
|
||||
}
|
||||
|
||||
@ -82,7 +95,7 @@ func (p *MySQLPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
func (p *MySQLPlugin) identifyService(info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
conn, err := common.WrapperTcpWithTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
|
@ -67,6 +67,12 @@ func (p *Neo4jPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResu
|
||||
|
||||
|
||||
func (p *Neo4jPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Neo4j未授权检测 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
|
||||
|
||||
client := &http.Client{
|
||||
@ -80,8 +86,10 @@ func (p *Neo4jPlugin) testUnauthorizedAccess(ctx context.Context, info *common.H
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == 200 {
|
||||
@ -96,6 +104,12 @@ func (p *Neo4jPlugin) testUnauthorizedAccess(ctx context.Context, info *common.H
|
||||
}
|
||||
|
||||
func (p *Neo4jPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Neo4j凭据测试 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
|
||||
|
||||
client := &http.Client{
|
||||
@ -112,8 +126,10 @@ func (p *Neo4jPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer resp.Body.Close()
|
||||
|
||||
return resp.StatusCode == 200
|
||||
@ -127,6 +143,17 @@ func (p *Neo4jPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
|
||||
func (p *Neo4jPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Neo4j识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "neo4j",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
|
||||
|
||||
client := &http.Client{
|
||||
@ -144,12 +171,14 @@ func (p *Neo4jPlugin) identifyService(ctx context.Context, info *common.HostInfo
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "neo4j",
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer resp.Body.Close()
|
||||
|
||||
var banner string
|
||||
|
@ -158,10 +158,19 @@ func (p *NetBIOSPlugin) queryNetBIOSNames(host string) (*NetBIOSInfo, error) {
|
||||
}
|
||||
|
||||
target := fmt.Sprintf("%s:137", host)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("NetBIOS UDP连接 %s 受限: %s", target, reason))
|
||||
return nil, fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("udp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementUDPPacketCount()
|
||||
return nil, fmt.Errorf("连接NetBIOS名称服务失败: %v", err)
|
||||
}
|
||||
common.IncrementUDPPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
@ -183,10 +192,19 @@ func (p *NetBIOSPlugin) queryNetBIOSNames(host string) (*NetBIOSInfo, error) {
|
||||
// queryNetBIOSSession 查询NetBIOS会话服务(TCP 139)
|
||||
func (p *NetBIOSPlugin) queryNetBIOSSession(host string) (*NetBIOSInfo, error) {
|
||||
target := fmt.Sprintf("%s:139", host)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("NetBIOS TCP连接 %s 受限: %s", target, reason))
|
||||
return nil, fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil, fmt.Errorf("连接NetBIOS会话服务失败: %v", err)
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
|
@ -25,6 +25,16 @@ func (p *OraclePlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRes
|
||||
return p.identifyService(ctx, info)
|
||||
}
|
||||
|
||||
// Oracle驱动未安装,但保持与其他插件一致的发包检查
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Oracle连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "oracle",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "oracle",
|
||||
@ -41,6 +51,16 @@ func (p *OraclePlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRes
|
||||
|
||||
|
||||
func (p *OraclePlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
// 保持与其他插件一致的发包检查
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Oracle识别 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "oracle",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "oracle",
|
||||
|
@ -64,6 +64,12 @@ func (p *PostgreSQLPlugin) Scan(ctx context.Context, info *common.HostInfo) *Sca
|
||||
|
||||
|
||||
func (p *PostgreSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) *sql.DB {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("PostgreSQL连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
connStr := fmt.Sprintf("postgres://%s:%s@%s:%s/postgres?sslmode=disable&connect_timeout=%d",
|
||||
cred.Username, cred.Password, info.Host, info.Ports, common.Timeout)
|
||||
|
||||
@ -81,10 +87,14 @@ func (p *PostgreSQLPlugin) testCredential(ctx context.Context, info *common.Host
|
||||
|
||||
err = db.PingContext(pingCtx)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
db.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 连接成功,计数TCP成功包
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
@ -96,6 +106,16 @@ func (p *PostgreSQLPlugin) testCredential(ctx context.Context, info *common.Host
|
||||
func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("PostgreSQL识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "postgresql",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
connStr := fmt.Sprintf("postgres://invalid:invalid@%s:%s/postgres?sslmode=disable&connect_timeout=%d",
|
||||
info.Host, info.Ports, common.Timeout)
|
||||
|
||||
@ -114,6 +134,13 @@ func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.Hos
|
||||
|
||||
err = db.PingContext(pingCtx)
|
||||
|
||||
// 统计包数量
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
} else {
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
}
|
||||
|
||||
// 改进识别逻辑:任何PostgreSQL相关的响应都认为是有效服务
|
||||
var banner string
|
||||
if err != nil {
|
||||
|
@ -90,15 +90,27 @@ func (p *RabbitMQPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugi
|
||||
func (p *RabbitMQPlugin) testAMQPProtocol(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("RabbitMQ AMQP连接 %s 受限: %s", target, reason))
|
||||
return &plugins.Result{
|
||||
Success: false,
|
||||
Service: "rabbitmq",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
// 连接到AMQP端口
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return &plugins.Result{
|
||||
Success: false,
|
||||
Service: "rabbitmq",
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
// 设置超时
|
||||
@ -174,6 +186,12 @@ func min(a, b int) int {
|
||||
}
|
||||
|
||||
func (p *RabbitMQPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("RabbitMQ HTTP连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
|
||||
|
||||
client := &http.Client{
|
||||
@ -190,8 +208,10 @@ func (p *RabbitMQPlugin) testCredential(ctx context.Context, info *common.HostIn
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer resp.Body.Close()
|
||||
|
||||
return resp.StatusCode == 200
|
||||
@ -217,6 +237,17 @@ func (p *RabbitMQPlugin) identifyService(ctx context.Context, info *common.HostI
|
||||
// testManagementInterface 检测RabbitMQ管理界面
|
||||
func (p *RabbitMQPlugin) testManagementInterface(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("RabbitMQ管理接口 %s 受限: %s", target, reason))
|
||||
return &plugins.Result{
|
||||
Success: false,
|
||||
Service: "rabbitmq",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
|
||||
|
||||
client := &http.Client{
|
||||
@ -234,12 +265,14 @@ func (p *RabbitMQPlugin) testManagementInterface(ctx context.Context, info *comm
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return &plugins.Result{
|
||||
Success: false,
|
||||
Service: "rabbitmq",
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer resp.Body.Close()
|
||||
|
||||
var banner string
|
||||
|
@ -100,10 +100,18 @@ func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult
|
||||
func (p *RDPPlugin) testRDPConnection(ctx context.Context, info *common.HostInfo) bool {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("RDP连接 %s 受限: %s", target, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
@ -136,13 +144,19 @@ func (p *RDPPlugin) testRDPConnection(ctx context.Context, info *common.HostInfo
|
||||
|
||||
// checkNLAStatus 检查网络级别身份验证状态
|
||||
func (p *RDPPlugin) checkNLAStatus(ctx context.Context, info *common.HostInfo) string {
|
||||
// 简化实现,实际需要解析RDP协商响应
|
||||
// 检查发包限制
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("RDP NLA检测 %s 受限: %s", target, reason))
|
||||
return "检测失败"
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return "检测失败"
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
|
@ -121,16 +121,27 @@ func (p *RedisPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
err error
|
||||
}
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Redis连接 %s 受限: %s", target, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
connChan := make(chan connResult, 1)
|
||||
|
||||
go func() {
|
||||
// 建立TCP连接
|
||||
conn, err := net.DialTimeout("tcp", target, timeout)
|
||||
if err != nil {
|
||||
// 计数TCP连接失败包
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
connChan <- connResult{nil, err}
|
||||
return
|
||||
}
|
||||
|
||||
// 计数TCP连接成功包
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
|
||||
// 如果有密码,进行认证
|
||||
if cred.Password != "" {
|
||||
authCmd := fmt.Sprintf("AUTH %s\r\n", cred.Password)
|
||||
@ -350,9 +361,21 @@ func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Redis服务识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "redis",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试连接Redis服务
|
||||
conn, err := net.DialTimeout("tcp", target, timeout)
|
||||
if err != nil {
|
||||
// 计数TCP连接失败包
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "redis",
|
||||
@ -361,6 +384,9 @@ func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 计数TCP连接成功包
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
|
||||
// 发送PING命令识别
|
||||
pingCmd := "PING\r\n"
|
||||
conn.SetWriteDeadline(time.Now().Add(timeout))
|
||||
|
@ -91,12 +91,21 @@ func (p *RsyncPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
|
||||
func (p *RsyncPlugin) connectToRsync(ctx context.Context, info *common.HostInfo) net.Conn {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Rsync连接 %s 受限: %s", target, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, timeout)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(timeout))
|
||||
return conn
|
||||
@ -137,6 +146,16 @@ func (p *RsyncPlugin) getModules(conn net.Conn) []string {
|
||||
func (p *RsyncPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Rsync识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "rsync",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
conn := p.connectToRsync(ctx, info)
|
||||
if conn == nil {
|
||||
return &ScanResult{
|
||||
|
@ -105,6 +105,12 @@ func (p *SmbPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult
|
||||
|
||||
// testCredential 测试单个凭据
|
||||
func (p *SmbPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("SMB连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
options := smb.Options{
|
||||
Host: info.Host,
|
||||
Port: 445,
|
||||
@ -124,8 +130,10 @@ func (p *SmbPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
|
||||
session, err := smb.NewSession(options, false)
|
||||
if err == nil {
|
||||
defer session.Close()
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
resultChan <- session.IsAuthenticated
|
||||
} else {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
resultChan <- false
|
||||
}
|
||||
}()
|
||||
@ -199,6 +207,17 @@ func (p *SmbPlugin) testShareAccess(ctx context.Context, info *common.HostInfo,
|
||||
|
||||
// identifyService 服务识别
|
||||
func (p *SmbPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
common.LogError(fmt.Sprintf("SMB识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "smb",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
if p.testCredential(ctx, info, Credential{Username: "", Password: ""}) {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
banner := "SMB文件共享服务"
|
||||
|
@ -105,6 +105,11 @@ func (p *Smb2Plugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResul
|
||||
|
||||
// testCredential 测试单个凭据 - 简化的SMB2协议检测
|
||||
func (p *Smb2Plugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
// 检查发包限制
|
||||
if canSend, _ := common.CanSendPacket(); !canSend {
|
||||
return false
|
||||
}
|
||||
|
||||
// 基于TCP连接的简单SMB2检测
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second)
|
||||
defer cancel()
|
||||
@ -112,8 +117,10 @@ func (p *Smb2Plugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
dialer := &net.Dialer{}
|
||||
conn, err := dialer.DialContext(timeoutCtx, "tcp", fmt.Sprintf("%s:445", info.Host))
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
// 发送SMB2协商请求
|
||||
@ -153,10 +160,17 @@ func (p *Smb2Plugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
|
||||
// detectProtocol 检测SMB2协议信息
|
||||
func (p *Smb2Plugin) detectProtocol(ctx context.Context, info *common.HostInfo) string {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:445", info.Host), 5*time.Second)
|
||||
if err != nil {
|
||||
// 检查发包限制
|
||||
if canSend, _ := common.CanSendPacket(); !canSend {
|
||||
return ""
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:445", info.Host), 5*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return ""
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
// 发送SMB2协商请求获取版本信息
|
||||
|
@ -156,11 +156,18 @@ func (p *SmbGhostPlugin) detectVulnerability(ctx context.Context, info *common.H
|
||||
addr := fmt.Sprintf("%s:445", info.Host)
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
return false, fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
// 建立TCP连接
|
||||
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false, fmt.Errorf("连接失败: %v", err)
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
// 设置连接超时
|
||||
@ -200,10 +207,17 @@ func (p *SmbGhostPlugin) gatherSystemInfo(ctx context.Context, info *common.Host
|
||||
addr := fmt.Sprintf("%s:445", info.Host)
|
||||
timeout := time.Duration(common.Timeout) * time.Second
|
||||
|
||||
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout)
|
||||
if err != nil {
|
||||
// 检查发包限制
|
||||
if canSend, _ := common.CanSendPacket(); !canSend {
|
||||
return ""
|
||||
}
|
||||
|
||||
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return ""
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
// 发送标准SMB协商请求获取系统信息
|
||||
|
@ -41,15 +41,27 @@ func (p *SMBInfoPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRe
|
||||
}
|
||||
}
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("SMBInfo连接 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "smbinfo",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
// 建立连接
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "smbinfo",
|
||||
Error: fmt.Errorf("连接失败: %v", err),
|
||||
}
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
@ -253,11 +265,18 @@ func (p *SMBInfoPlugin) handleSMBv1(conn net.Conn, target string) (*SMBInfo, err
|
||||
|
||||
// handleSMBv2 处理SMBv2协议信息收集
|
||||
func (p *SMBInfoPlugin) handleSMBv2(target string) (*SMBInfo, error) {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
return nil, fmt.Errorf("SMBv2连接受限: %s", reason)
|
||||
}
|
||||
|
||||
// 重新建立连接处理SMBv2
|
||||
conn2, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil, fmt.Errorf("SMBv2连接失败: %v", err)
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn2.Close()
|
||||
|
||||
conn2.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
|
@ -90,12 +90,23 @@ func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugins.R
|
||||
func (p *SMTPPlugin) testOpenRelay(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("SMTP连接 %s 受限: %s", target, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置超时的Dialer
|
||||
dialer := &net.Dialer{
|
||||
Timeout: time.Duration(common.Timeout) * time.Second,
|
||||
}
|
||||
|
||||
conn, err := dialer.DialContext(ctx, "tcp", target)
|
||||
if err == nil {
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
} else {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
}
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@ -132,12 +143,23 @@ func (p *SMTPPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
|
||||
common.LogDebug(fmt.Sprintf("SMTP测试凭据: %s:%s", cred.Username, cred.Password))
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("SMTP凭据测试 %s 受限: %s", target, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
// 设置连接超时
|
||||
dialer := &net.Dialer{
|
||||
Timeout: timeout,
|
||||
}
|
||||
|
||||
conn, err := dialer.DialContext(ctx, "tcp", target)
|
||||
if err == nil {
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
} else {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
}
|
||||
if err != nil {
|
||||
common.LogDebug(fmt.Sprintf("SMTP连接失败: %v", err))
|
||||
return false
|
||||
@ -177,7 +199,8 @@ func (p *SMTPPlugin) testCredential(ctx context.Context, info *common.HostInfo,
|
||||
func (p *SMTPPlugin) getServerInfo(ctx context.Context, info *common.HostInfo) string {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
// 使用统一TCP包装器
|
||||
conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
@ -207,11 +230,8 @@ func (p *SMTPPlugin) identifyService(ctx context.Context, info *common.HostInfo)
|
||||
if serverInfo != "" {
|
||||
banner = fmt.Sprintf("SMTP邮件服务 (%s)", serverInfo)
|
||||
} else {
|
||||
// 简单连接测试
|
||||
dialer := &net.Dialer{
|
||||
Timeout: time.Duration(common.Timeout) * time.Second,
|
||||
}
|
||||
conn, err := dialer.DialContext(ctx, "tcp", target)
|
||||
// 使用统一TCP包装器进行简单连接测试
|
||||
conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
return &plugins.Result{
|
||||
Success: false,
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
@ -62,7 +61,8 @@ func (p *SNMPPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResul
|
||||
func (p *SNMPPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
conn, err := net.DialTimeout("udp", target, time.Duration(common.Timeout)*time.Second)
|
||||
// 使用统一UDP包装器
|
||||
conn, err := common.SafeUDPDial("udp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -120,7 +120,8 @@ func (p *SNMPPlugin) identifyService(ctx context.Context, info *common.HostInfo)
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("udp", target, time.Duration(common.Timeout)*time.Second)
|
||||
// 使用统一UDP包装器
|
||||
conn, err := common.SafeUDPDial("udp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
|
@ -164,6 +164,12 @@ func (p *SSHPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
|
||||
err error
|
||||
}
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("SSH连接 %s 受限: %s", target, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
resultChan := make(chan sshResult, 1)
|
||||
go func() {
|
||||
client, err := ssh.Dial("tcp", target, config)
|
||||
@ -173,8 +179,12 @@ func (p *SSHPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
if result.err != nil {
|
||||
// 计数TCP连接失败包
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil
|
||||
}
|
||||
// 计数TCP连接成功包
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
return result.client
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
@ -197,8 +207,8 @@ func (p *SSHPlugin) executeCommand(client *ssh.Client, cmd string) (string, erro
|
||||
func (p *SSHPlugin) identifyService(info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 尝试连接获取SSH Banner
|
||||
conn, err := common.WrapperTcpWithTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
// 使用统一TCP包装器获取SSH Banner
|
||||
conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
|
@ -65,8 +65,19 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugins
|
||||
func (p *TelnetPlugin) testTelnetCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool {
|
||||
address := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("Telnet连接 %s 受限: %s", address, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
// 创建带超时的连接
|
||||
conn, err := net.DialTimeout("tcp", address, time.Duration(common.Timeout)*time.Second)
|
||||
if err == nil {
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
} else {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
}
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -304,7 +315,8 @@ func (p *TelnetPlugin) isLoginFailed(data string) bool {
|
||||
func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
// 使用统一TCP包装器
|
||||
conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
return &plugins.Result{
|
||||
Success: false,
|
||||
|
@ -70,10 +70,18 @@ func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult
|
||||
func (p *VNCPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("VNC未授权检测 %s 受限: %s", target, reason))
|
||||
return nil
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
@ -105,10 +113,18 @@ func (p *VNCPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo)
|
||||
func (p *VNCPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("VNC认证测试 %s 受限: %s", target, reason))
|
||||
return false
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return false
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
@ -229,14 +245,26 @@ func (p *VNCPlugin) reverseBits(b byte) byte {
|
||||
func (p *VNCPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("VNC识别 %s 受限: %s", target, reason))
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "vnc",
|
||||
Error: fmt.Errorf("发包受限: %s", reason),
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return &ScanResult{
|
||||
Success: false,
|
||||
Service: "vnc",
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
||||
|
@ -675,6 +675,12 @@ func DoRequest(req *http.Request, redirect bool) (*Response, error) {
|
||||
}
|
||||
|
||||
// 执行请求
|
||||
// 检查发包限制
|
||||
if canSend, reason := common.CanSendPacket(); !canSend {
|
||||
common.LogError(fmt.Sprintf("POC HTTP请求 %s 受限: %s", req.URL.String(), reason))
|
||||
return nil, fmt.Errorf("发包受限: %s", reason)
|
||||
}
|
||||
|
||||
var (
|
||||
oResp *http.Response
|
||||
err error
|
||||
@ -687,8 +693,13 @@ func DoRequest(req *http.Request, redirect bool) (*Response, error) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// HTTP请求失败,计为TCP失败
|
||||
common.IncrementTCPFailedPacketCount()
|
||||
return nil, fmt.Errorf("请求执行失败: %w", err)
|
||||
}
|
||||
|
||||
// HTTP请求成功,计为TCP成功
|
||||
common.IncrementTCPSuccessPacketCount()
|
||||
defer oResp.Body.Close()
|
||||
|
||||
// 解析响应
|
||||
|
Loading…
Reference in New Issue
Block a user