mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-07-13 12:52:44 +08:00
CN to EN from Core
This commit is contained in:
parent
968064c240
commit
50a53e1fd8
148
Core/ICMP.go
148
Core/ICMP.go
@ -14,38 +14,38 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
AliveHosts []string // 存活主机列表
|
||||
ExistHosts = make(map[string]struct{}) // 已发现主机记录
|
||||
livewg sync.WaitGroup // 存活检测等待组
|
||||
AliveHosts []string // List of alive hosts
|
||||
ExistHosts = make(map[string]struct{}) // Record of discovered hosts
|
||||
livewg sync.WaitGroup // Wait group for live detection
|
||||
)
|
||||
|
||||
// CheckLive 检测主机存活状态
|
||||
// CheckLive checks the live status of hosts
|
||||
func CheckLive(hostslist []string, Ping bool) []string {
|
||||
// 创建主机通道
|
||||
// Create host channel
|
||||
chanHosts := make(chan string, len(hostslist))
|
||||
|
||||
// 处理存活主机
|
||||
// Handle alive hosts
|
||||
go handleAliveHosts(chanHosts, hostslist, Ping)
|
||||
|
||||
// 根据Ping参数选择检测方式
|
||||
// Choose detection method based on Ping parameter
|
||||
if Ping {
|
||||
// 使用ping方式探测
|
||||
// Use ping method
|
||||
RunPing(hostslist, chanHosts)
|
||||
} else {
|
||||
probeWithICMP(hostslist, chanHosts)
|
||||
}
|
||||
|
||||
// 等待所有检测完成
|
||||
// Wait for all detections to complete
|
||||
livewg.Wait()
|
||||
close(chanHosts)
|
||||
|
||||
// 输出存活统计信息
|
||||
// Print alive statistics
|
||||
printAliveStats(hostslist)
|
||||
|
||||
return AliveHosts
|
||||
}
|
||||
|
||||
// IsContain 检查切片中是否包含指定元素
|
||||
// IsContain checks if the slice contains the specified element
|
||||
func IsContain(items []string, item string) bool {
|
||||
for _, eachItem := range items {
|
||||
if eachItem == item {
|
||||
@ -61,7 +61,7 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
||||
ExistHosts[ip] = struct{}{}
|
||||
AliveHosts = append(AliveHosts, ip)
|
||||
|
||||
// 使用Output系统保存存活主机信息
|
||||
// Use Output system to save alive host information
|
||||
protocol := "ICMP"
|
||||
if isPing {
|
||||
protocol = "PING"
|
||||
@ -78,7 +78,7 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
||||
}
|
||||
Common.SaveResult(result)
|
||||
|
||||
// 保留原有的控制台输出
|
||||
// Keep original console output
|
||||
if !Common.Silent {
|
||||
Common.LogSuccess(Common.GetText("target_alive", ip, protocol))
|
||||
}
|
||||
@ -87,9 +87,9 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// probeWithICMP 使用ICMP方式探测
|
||||
// probeWithICMP probes using ICMP method
|
||||
func probeWithICMP(hostslist []string, chanHosts chan string) {
|
||||
// 尝试监听本地ICMP
|
||||
// Try to listen on local ICMP
|
||||
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||
if err == nil {
|
||||
RunIcmp1(hostslist, conn, chanHosts)
|
||||
@ -99,7 +99,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
|
||||
Common.LogError(Common.GetText("icmp_listen_failed", err))
|
||||
Common.LogInfo(Common.GetText("trying_no_listen_icmp"))
|
||||
|
||||
// 尝试无监听ICMP探测
|
||||
// Try no-listen ICMP probe
|
||||
conn2, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
|
||||
if err == nil {
|
||||
defer conn2.Close()
|
||||
@ -111,22 +111,22 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
|
||||
Common.LogInfo(Common.GetText("insufficient_privileges"))
|
||||
Common.LogInfo(Common.GetText("switching_to_ping"))
|
||||
|
||||
// 降级使用ping探测
|
||||
// Fallback to ping probe
|
||||
RunPing(hostslist, chanHosts)
|
||||
}
|
||||
|
||||
// printAliveStats 打印存活统计信息
|
||||
// printAliveStats prints alive statistics
|
||||
func printAliveStats(hostslist []string) {
|
||||
// 大规模扫描时输出 /16 网段统计
|
||||
if len(hostslist) > 1000 {
|
||||
// Output /16 subnet statistics for large-scale scans
|
||||
if (len(hostslist) > 1000) {
|
||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true)
|
||||
for i := 0; i < len(arrTop); i++ {
|
||||
Common.LogSuccess(Common.GetText("subnet_16_alive", arrTop[i], arrLen[i]))
|
||||
}
|
||||
}
|
||||
|
||||
// 输出 /24 网段统计
|
||||
if len(hostslist) > 256 {
|
||||
// Output /24 subnet statistics
|
||||
if (len(hostslist) > 256) {
|
||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
|
||||
for i := 0; i < len(arrTop); i++ {
|
||||
Common.LogSuccess(Common.GetText("subnet_24_alive", arrTop[i], arrLen[i]))
|
||||
@ -134,17 +134,17 @@ func printAliveStats(hostslist []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// RunIcmp1 使用ICMP批量探测主机存活(监听模式)
|
||||
// RunIcmp1 uses ICMP to probe host liveliness (listen mode)
|
||||
func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) {
|
||||
endflag := false
|
||||
|
||||
// 启动监听协程
|
||||
// Start listening goroutine
|
||||
go func() {
|
||||
for {
|
||||
if endflag {
|
||||
return
|
||||
}
|
||||
// 接收ICMP响应
|
||||
// Receive ICMP response
|
||||
msg := make([]byte, 100)
|
||||
_, sourceIP, _ := conn.ReadFrom(msg)
|
||||
if sourceIP != nil {
|
||||
@ -154,22 +154,22 @@ func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string)
|
||||
}
|
||||
}()
|
||||
|
||||
// 发送ICMP请求
|
||||
// Send ICMP requests
|
||||
for _, host := range hostslist {
|
||||
dst, _ := net.ResolveIPAddr("ip", host)
|
||||
IcmpByte := makemsg(host)
|
||||
conn.WriteTo(IcmpByte, dst)
|
||||
}
|
||||
|
||||
// 等待响应
|
||||
// Wait for responses
|
||||
start := time.Now()
|
||||
for {
|
||||
// 所有主机都已响应则退出
|
||||
// Exit if all hosts have responded
|
||||
if len(AliveHosts) == len(hostslist) {
|
||||
break
|
||||
}
|
||||
|
||||
// 根据主机数量设置超时时间
|
||||
// Set timeout based on number of hosts
|
||||
since := time.Since(start)
|
||||
wait := time.Second * 6
|
||||
if len(hostslist) <= 256 {
|
||||
@ -185,9 +185,9 @@ func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string)
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
// RunIcmp2 使用ICMP并发探测主机存活(无监听模式)
|
||||
// RunIcmp2 uses ICMP to probe host liveliness (no-listen mode)
|
||||
func RunIcmp2(hostslist []string, chanHosts chan string) {
|
||||
// 控制并发数
|
||||
// Control concurrency
|
||||
num := 1000
|
||||
if len(hostslist) < num {
|
||||
num = len(hostslist)
|
||||
@ -196,7 +196,7 @@ func RunIcmp2(hostslist []string, chanHosts chan string) {
|
||||
var wg sync.WaitGroup
|
||||
limiter := make(chan struct{}, num)
|
||||
|
||||
// 并发探测
|
||||
// Concurrent probing
|
||||
for _, host := range hostslist {
|
||||
wg.Add(1)
|
||||
limiter <- struct{}{}
|
||||
@ -218,29 +218,29 @@ func RunIcmp2(hostslist []string, chanHosts chan string) {
|
||||
close(limiter)
|
||||
}
|
||||
|
||||
// icmpalive 检测主机ICMP是否存活
|
||||
// icmpalive checks if the host is alive using ICMP
|
||||
func icmpalive(host string) bool {
|
||||
startTime := time.Now()
|
||||
|
||||
// 建立ICMP连接
|
||||
// Establish ICMP connection
|
||||
conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 设置超时时间
|
||||
// Set timeout
|
||||
if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// 构造并发送ICMP请求
|
||||
// Construct and send ICMP request
|
||||
msg := makemsg(host)
|
||||
if _, err := conn.Write(msg); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// 接收ICMP响应
|
||||
// Receive ICMP response
|
||||
receive := make([]byte, 60)
|
||||
if _, err := conn.Read(receive); err != nil {
|
||||
return false
|
||||
@ -249,13 +249,13 @@ func icmpalive(host string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// RunPing 使用系统Ping命令并发探测主机存活
|
||||
// RunPing uses system ping command to probe host liveliness concurrently
|
||||
func RunPing(hostslist []string, chanHosts chan string) {
|
||||
var wg sync.WaitGroup
|
||||
// 限制并发数为50
|
||||
// Limit concurrency to 50
|
||||
limiter := make(chan struct{}, 50)
|
||||
|
||||
// 并发探测
|
||||
// Concurrent probing
|
||||
for _, host := range hostslist {
|
||||
wg.Add(1)
|
||||
limiter <- struct{}{}
|
||||
@ -276,9 +276,9 @@ func RunPing(hostslist []string, chanHosts chan string) {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// ExecCommandPing 执行系统Ping命令检测主机存活
|
||||
// ExecCommandPing executes system ping command to check host liveliness
|
||||
func ExecCommandPing(ip string) bool {
|
||||
// 过滤黑名单字符
|
||||
// Filter blacklist characters
|
||||
forbiddenChars := []string{";", "&", "|", "`", "$", "\\", "'", "%", "\"", "\n"}
|
||||
for _, char := range forbiddenChars {
|
||||
if strings.Contains(ip, char) {
|
||||
@ -287,7 +287,7 @@ func ExecCommandPing(ip string) bool {
|
||||
}
|
||||
|
||||
var command *exec.Cmd
|
||||
// 根据操作系统选择不同的ping命令
|
||||
// Choose different ping commands based on OS
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false")
|
||||
@ -297,11 +297,11 @@ func ExecCommandPing(ip string) bool {
|
||||
command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false")
|
||||
}
|
||||
|
||||
// 捕获命令输出
|
||||
// Capture command output
|
||||
var outinfo bytes.Buffer
|
||||
command.Stdout = &outinfo
|
||||
|
||||
// 执行命令
|
||||
// Execute command
|
||||
if err := command.Start(); err != nil {
|
||||
return false
|
||||
}
|
||||
@ -310,76 +310,76 @@ func ExecCommandPing(ip string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 分析输出结果
|
||||
// Analyze output result
|
||||
output := outinfo.String()
|
||||
return strings.Contains(output, "true") && strings.Count(output, ip) > 2
|
||||
}
|
||||
|
||||
// makemsg 构造ICMP echo请求消息
|
||||
// makemsg constructs ICMP echo request message
|
||||
func makemsg(host string) []byte {
|
||||
msg := make([]byte, 40)
|
||||
|
||||
// 获取标识符
|
||||
// Get identifier
|
||||
id0, id1 := genIdentifier(host)
|
||||
|
||||
// 设置ICMP头部
|
||||
// Set ICMP header
|
||||
msg[0] = 8 // Type: Echo Request
|
||||
msg[1] = 0 // Code: 0
|
||||
msg[2] = 0 // Checksum高位(待计算)
|
||||
msg[3] = 0 // Checksum低位(待计算)
|
||||
msg[2] = 0 // Checksum high byte (to be calculated)
|
||||
msg[3] = 0 // Checksum low byte (to be calculated)
|
||||
msg[4], msg[5] = id0, id1 // Identifier
|
||||
msg[6], msg[7] = genSequence(1) // Sequence Number
|
||||
|
||||
// 计算校验和
|
||||
// Calculate checksum
|
||||
check := checkSum(msg[0:40])
|
||||
msg[2] = byte(check >> 8) // 设置校验和高位
|
||||
msg[3] = byte(check & 255) // 设置校验和低位
|
||||
msg[2] = byte(check >> 8) // Set checksum high byte
|
||||
msg[3] = byte(check & 255) // Set checksum low byte
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
// checkSum 计算ICMP校验和
|
||||
// checkSum calculates ICMP checksum
|
||||
func checkSum(msg []byte) uint16 {
|
||||
sum := 0
|
||||
length := len(msg)
|
||||
|
||||
// 按16位累加
|
||||
// Accumulate in 16-bit units
|
||||
for i := 0; i < length-1; i += 2 {
|
||||
sum += int(msg[i])*256 + int(msg[i+1])
|
||||
}
|
||||
|
||||
// 处理奇数长度情况
|
||||
// Handle odd length case
|
||||
if length%2 == 1 {
|
||||
sum += int(msg[length-1]) * 256
|
||||
}
|
||||
|
||||
// 将高16位加到低16位
|
||||
// Add high 16 bits to low 16 bits
|
||||
sum = (sum >> 16) + (sum & 0xffff)
|
||||
sum = sum + (sum >> 16)
|
||||
|
||||
// 取反得到校验和
|
||||
// Take one's complement to get checksum
|
||||
return uint16(^sum)
|
||||
}
|
||||
|
||||
// genSequence 生成ICMP序列号
|
||||
// genSequence generates ICMP sequence number
|
||||
func genSequence(v int16) (byte, byte) {
|
||||
ret1 := byte(v >> 8) // 高8位
|
||||
ret2 := byte(v & 255) // 低8位
|
||||
ret1 := byte(v >> 8) // High 8 bits
|
||||
ret2 := byte(v & 255) // Low 8 bits
|
||||
return ret1, ret2
|
||||
}
|
||||
|
||||
// genIdentifier 根据主机地址生成标识符
|
||||
// genIdentifier generates identifier based on host address
|
||||
func genIdentifier(host string) (byte, byte) {
|
||||
return host[0], host[1] // 使用主机地址前两个字节
|
||||
return host[0], host[1] // Use first two bytes of host address
|
||||
}
|
||||
|
||||
// ArrayCountValueTop 统计IP地址段存活数量并返回TOP N结果
|
||||
// ArrayCountValueTop counts the number of alive IP segments and returns the top N results
|
||||
func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) {
|
||||
if len(arrInit) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 统计各网段出现次数
|
||||
// Count occurrences of each segment
|
||||
segmentCounts := make(map[string]int)
|
||||
for _, ip := range arrInit {
|
||||
segments := strings.Split(ip, ".")
|
||||
@ -387,29 +387,29 @@ func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []strin
|
||||
continue
|
||||
}
|
||||
|
||||
// 根据flag确定统计B段还是C段
|
||||
// Determine whether to count B segment or C segment based on flag
|
||||
var segment string
|
||||
if flag {
|
||||
segment = fmt.Sprintf("%s.%s", segments[0], segments[1]) // B段
|
||||
segment = fmt.Sprintf("%s.%s", segments[0], segments[1]) // B segment
|
||||
} else {
|
||||
segment = fmt.Sprintf("%s.%s.%s", segments[0], segments[1], segments[2]) // C段
|
||||
segment = fmt.Sprintf("%s.%s.%s", segments[0], segments[1], segments[2]) // C segment
|
||||
}
|
||||
|
||||
segmentCounts[segment]++
|
||||
}
|
||||
|
||||
// 创建副本用于排序
|
||||
// Create a copy for sorting
|
||||
sortMap := make(map[string]int)
|
||||
for k, v := range segmentCounts {
|
||||
sortMap[k] = v
|
||||
}
|
||||
|
||||
// 获取TOP N结果
|
||||
// Get top N results
|
||||
for i := 0; i < length && len(sortMap) > 0; i++ {
|
||||
maxSegment := ""
|
||||
maxCount := 0
|
||||
|
||||
// 查找当前最大值
|
||||
// Find current maximum value
|
||||
for segment, count := range sortMap {
|
||||
if count > maxCount {
|
||||
maxCount = count
|
||||
@ -417,11 +417,11 @@ func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []strin
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到结果集
|
||||
// Add to result set
|
||||
arrTop = append(arrTop, maxSegment)
|
||||
arrLen = append(arrLen, maxCount)
|
||||
|
||||
// 从待处理map中删除已处理项
|
||||
// Remove processed item from map
|
||||
delete(sortMap, maxSegment)
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
//go:embed nmap-service-probes.txt
|
||||
var ProbeString string
|
||||
|
||||
var v VScan // 改为VScan类型而不是指针
|
||||
var v VScan // Changed to VScan type instead of pointer
|
||||
|
||||
type VScan struct {
|
||||
Exclude string
|
||||
@ -24,27 +24,27 @@ type VScan struct {
|
||||
}
|
||||
|
||||
type Probe struct {
|
||||
Name string // 探测器名称
|
||||
Data string // 探测数据
|
||||
Protocol string // 协议
|
||||
Ports string // 端口范围
|
||||
SSLPorts string // SSL端口范围
|
||||
Name string // Probe name
|
||||
Data string // Probe data
|
||||
Protocol string // Protocol
|
||||
Ports string // Port range
|
||||
SSLPorts string // SSL port range
|
||||
|
||||
TotalWaitMS int // 总等待时间
|
||||
TCPWrappedMS int // TCP包装等待时间
|
||||
Rarity int // 稀有度
|
||||
Fallback string // 回退探测器名称
|
||||
TotalWaitMS int // Total wait time
|
||||
TCPWrappedMS int // TCP wrapped wait time
|
||||
Rarity int // Rarity
|
||||
Fallback string // Fallback probe name
|
||||
|
||||
Matchs *[]Match // 匹配规则列表
|
||||
Matchs *[]Match // Match rules list
|
||||
}
|
||||
|
||||
type Match struct {
|
||||
IsSoft bool // 是否为软匹配
|
||||
Service string // 服务名称
|
||||
Pattern string // 匹配模式
|
||||
VersionInfo string // 版本信息格式
|
||||
FoundItems []string // 找到的项目
|
||||
PatternCompiled *regexp.Regexp // 编译后的正则表达式
|
||||
IsSoft bool // Whether it's a soft match
|
||||
Service string // Service name
|
||||
Pattern string // Match pattern
|
||||
VersionInfo string // Version info format
|
||||
FoundItems []string // Found items
|
||||
PatternCompiled *regexp.Regexp // Compiled regular expression
|
||||
}
|
||||
|
||||
type Directive struct {
|
||||
@ -65,43 +65,43 @@ type Extras struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
Common.LogDebug("开始初始化全局变量")
|
||||
Common.LogDebug("Starting to initialize global variables")
|
||||
|
||||
v = VScan{} // 直接初始化VScan结构体
|
||||
v = VScan{} // Directly initialize VScan struct
|
||||
v.Init()
|
||||
|
||||
// 获取并检查 NULL 探测器
|
||||
// Get and check NULL probe
|
||||
if nullProbe, ok := v.ProbesMapKName["NULL"]; ok {
|
||||
Common.LogDebug(fmt.Sprintf("成功获取NULL探测器,Data长度: %d", len(nullProbe.Data)))
|
||||
Common.LogDebug(fmt.Sprintf("Successfully obtained NULL probe, Data length: %d", len(nullProbe.Data)))
|
||||
null = &nullProbe
|
||||
} else {
|
||||
Common.LogDebug("警告: 未找到NULL探测器")
|
||||
Common.LogDebug("Warning: NULL probe not found")
|
||||
}
|
||||
|
||||
// 获取并检查 GenericLines 探测器
|
||||
// Get and check GenericLines probe
|
||||
if commonProbe, ok := v.ProbesMapKName["GenericLines"]; ok {
|
||||
Common.LogDebug(fmt.Sprintf("成功获取GenericLines探测器,Data长度: %d", len(commonProbe.Data)))
|
||||
Common.LogDebug(fmt.Sprintf("Successfully obtained GenericLines probe, Data length: %d", len(commonProbe.Data)))
|
||||
common = &commonProbe
|
||||
} else {
|
||||
Common.LogDebug("警告: 未找到GenericLines探测器")
|
||||
Common.LogDebug("Warning: GenericLines probe not found")
|
||||
}
|
||||
|
||||
Common.LogDebug("全局变量初始化完成")
|
||||
Common.LogDebug("Global variables initialization complete")
|
||||
}
|
||||
|
||||
// 解析指令语法,返回指令结构
|
||||
// Parse directive syntax, return directive structure
|
||||
func (p *Probe) getDirectiveSyntax(data string) (directive Directive) {
|
||||
Common.LogDebug("开始解析指令语法,输入数据: " + data)
|
||||
Common.LogDebug("Starting to parse directive syntax, input data: " + data)
|
||||
|
||||
directive = Directive{}
|
||||
// 查找第一个空格的位置
|
||||
// Find the position of the first space
|
||||
blankIndex := strings.Index(data, " ")
|
||||
if blankIndex == -1 {
|
||||
Common.LogDebug("未找到空格分隔符")
|
||||
Common.LogDebug("Space separator not found")
|
||||
return directive
|
||||
}
|
||||
|
||||
// 解析各个字段
|
||||
// Parse each field
|
||||
directiveName := data[:blankIndex]
|
||||
Flag := data[blankIndex+1 : blankIndex+2]
|
||||
delimiter := data[blankIndex+2 : blankIndex+3]
|
||||
@ -112,70 +112,70 @@ func (p *Probe) getDirectiveSyntax(data string) (directive Directive) {
|
||||
directive.Delimiter = delimiter
|
||||
directive.DirectiveStr = directiveStr
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("指令解析结果: 名称=%s, 标志=%s, 分隔符=%s, 内容=%s",
|
||||
Common.LogDebug(fmt.Sprintf("Directive parsing result: Name=%s, Flag=%s, Delimiter=%s, Content=%s",
|
||||
directiveName, Flag, delimiter, directiveStr))
|
||||
|
||||
return directive
|
||||
}
|
||||
|
||||
// 解析探测器信息
|
||||
// Parse probe information
|
||||
func (p *Probe) parseProbeInfo(probeStr string) {
|
||||
Common.LogDebug("开始解析探测器信息,输入字符串: " + probeStr)
|
||||
Common.LogDebug("Starting to parse probe information, input string: " + probeStr)
|
||||
|
||||
// 提取协议和其他信息
|
||||
// Extract protocol and other information
|
||||
proto := probeStr[:4]
|
||||
other := probeStr[4:]
|
||||
|
||||
// 验证协议类型
|
||||
// Validate protocol type
|
||||
if !(proto == "TCP " || proto == "UDP ") {
|
||||
errMsg := "探测器协议必须是 TCP 或 UDP"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
errMsg := "Probe protocol must be TCP or UDP"
|
||||
Common.LogDebug("Error: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
|
||||
// 验证其他信息不为空
|
||||
// Validate other information is not empty
|
||||
if len(other) == 0 {
|
||||
errMsg := "nmap-service-probes - 探测器名称无效"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
errMsg := "nmap-service-probes - Invalid probe name"
|
||||
Common.LogDebug("Error: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
|
||||
// 解析指令
|
||||
// Parse directive
|
||||
directive := p.getDirectiveSyntax(other)
|
||||
|
||||
// 设置探测器属性
|
||||
// Set probe attributes
|
||||
p.Name = directive.DirectiveName
|
||||
p.Data = strings.Split(directive.DirectiveStr, directive.Delimiter)[0]
|
||||
p.Protocol = strings.ToLower(strings.TrimSpace(proto))
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("探测器解析完成: 名称=%s, 数据=%s, 协议=%s",
|
||||
Common.LogDebug(fmt.Sprintf("Probe parsing completed: Name=%s, Data=%s, Protocol=%s",
|
||||
p.Name, p.Data, p.Protocol))
|
||||
}
|
||||
|
||||
// 从字符串解析探测器信息
|
||||
// Parse probe information from string
|
||||
func (p *Probe) fromString(data string) error {
|
||||
Common.LogDebug("开始解析探测器字符串数据")
|
||||
Common.LogDebug("Starting to parse probe string data")
|
||||
var err error
|
||||
|
||||
// 预处理数据
|
||||
// Preprocess data
|
||||
data = strings.TrimSpace(data)
|
||||
lines := strings.Split(data, "\n")
|
||||
if len(lines) == 0 {
|
||||
return fmt.Errorf("输入数据为空")
|
||||
return fmt.Errorf("Input data is empty")
|
||||
}
|
||||
|
||||
probeStr := lines[0]
|
||||
p.parseProbeInfo(probeStr)
|
||||
|
||||
// 解析匹配规则和其他配置
|
||||
// Parse match rules and other configurations
|
||||
var matchs []Match
|
||||
for _, line := range lines {
|
||||
Common.LogDebug("处理行: " + line)
|
||||
Common.LogDebug("Processing line: " + line)
|
||||
switch {
|
||||
case strings.HasPrefix(line, "match "):
|
||||
match, err := p.getMatch(line)
|
||||
if err != nil {
|
||||
Common.LogDebug("解析match失败: " + err.Error())
|
||||
Common.LogDebug("Failed to parse match: " + err.Error())
|
||||
continue
|
||||
}
|
||||
matchs = append(matchs, match)
|
||||
@ -183,7 +183,7 @@ func (p *Probe) fromString(data string) error {
|
||||
case strings.HasPrefix(line, "softmatch "):
|
||||
softMatch, err := p.getSoftMatch(line)
|
||||
if err != nil {
|
||||
Common.LogDebug("解析softmatch失败: " + err.Error())
|
||||
Common.LogDebug("Failed to parse softmatch: " + err.Error())
|
||||
continue
|
||||
}
|
||||
matchs = append(matchs, softMatch)
|
||||
@ -208,80 +208,80 @@ func (p *Probe) fromString(data string) error {
|
||||
}
|
||||
}
|
||||
p.Matchs = &matchs
|
||||
Common.LogDebug(fmt.Sprintf("解析完成,共有 %d 个匹配规则", len(matchs)))
|
||||
Common.LogDebug(fmt.Sprintf("Parsing completed, total of %d match rules", len(matchs)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析端口配置
|
||||
// Parse port configuration
|
||||
func (p *Probe) parsePorts(data string) {
|
||||
p.Ports = data[len("ports")+1:]
|
||||
Common.LogDebug("解析端口: " + p.Ports)
|
||||
Common.LogDebug("Parsing ports: " + p.Ports)
|
||||
}
|
||||
|
||||
// 解析SSL端口配置
|
||||
// Parse SSL port configuration
|
||||
func (p *Probe) parseSSLPorts(data string) {
|
||||
p.SSLPorts = data[len("sslports")+1:]
|
||||
Common.LogDebug("解析SSL端口: " + p.SSLPorts)
|
||||
Common.LogDebug("Parsing SSL ports: " + p.SSLPorts)
|
||||
}
|
||||
|
||||
// 解析总等待时间
|
||||
// Parse total wait time
|
||||
func (p *Probe) parseTotalWaitMS(data string) {
|
||||
waitMS, err := strconv.Atoi(strings.TrimSpace(data[len("totalwaitms")+1:]))
|
||||
if err != nil {
|
||||
Common.LogDebug("解析总等待时间失败: " + err.Error())
|
||||
Common.LogDebug("Failed to parse total wait time: " + err.Error())
|
||||
return
|
||||
}
|
||||
p.TotalWaitMS = waitMS
|
||||
Common.LogDebug(fmt.Sprintf("总等待时间: %d ms", waitMS))
|
||||
Common.LogDebug(fmt.Sprintf("Total wait time: %d ms", waitMS))
|
||||
}
|
||||
|
||||
// 解析TCP包装等待时间
|
||||
// Parse TCP wrapped wait time
|
||||
func (p *Probe) parseTCPWrappedMS(data string) {
|
||||
wrappedMS, err := strconv.Atoi(strings.TrimSpace(data[len("tcpwrappedms")+1:]))
|
||||
if err != nil {
|
||||
Common.LogDebug("解析TCP包装等待时间失败: " + err.Error())
|
||||
Common.LogDebug("Failed to parse TCP wrapped wait time: " + err.Error())
|
||||
return
|
||||
}
|
||||
p.TCPWrappedMS = wrappedMS
|
||||
Common.LogDebug(fmt.Sprintf("TCP包装等待时间: %d ms", wrappedMS))
|
||||
Common.LogDebug(fmt.Sprintf("TCP wrapped wait time: %d ms", wrappedMS))
|
||||
}
|
||||
|
||||
// 解析稀有度
|
||||
// Parse rarity
|
||||
func (p *Probe) parseRarity(data string) {
|
||||
rarity, err := strconv.Atoi(strings.TrimSpace(data[len("rarity")+1:]))
|
||||
if err != nil {
|
||||
Common.LogDebug("解析稀有度失败: " + err.Error())
|
||||
Common.LogDebug("Failed to parse rarity: " + err.Error())
|
||||
return
|
||||
}
|
||||
p.Rarity = rarity
|
||||
Common.LogDebug(fmt.Sprintf("稀有度: %d", rarity))
|
||||
Common.LogDebug(fmt.Sprintf("Rarity: %d", rarity))
|
||||
}
|
||||
|
||||
// 解析回退配置
|
||||
// Parse fallback configuration
|
||||
func (p *Probe) parseFallback(data string) {
|
||||
p.Fallback = data[len("fallback")+1:]
|
||||
Common.LogDebug("回退配置: " + p.Fallback)
|
||||
Common.LogDebug("Fallback configuration: " + p.Fallback)
|
||||
}
|
||||
|
||||
// 判断是否为十六进制编码
|
||||
// Check if it's a hexadecimal code
|
||||
func isHexCode(b []byte) bool {
|
||||
matchRe := regexp.MustCompile(`\\x[0-9a-fA-F]{2}`)
|
||||
return matchRe.Match(b)
|
||||
}
|
||||
|
||||
// 判断是否为八进制编码
|
||||
// Check if it's an octal code
|
||||
func isOctalCode(b []byte) bool {
|
||||
matchRe := regexp.MustCompile(`\\[0-7]{1,3}`)
|
||||
return matchRe.Match(b)
|
||||
}
|
||||
|
||||
// 判断是否为结构化转义字符
|
||||
// Check if it's a structured escape character
|
||||
func isStructCode(b []byte) bool {
|
||||
matchRe := regexp.MustCompile(`\\[aftnrv]`)
|
||||
return matchRe.Match(b)
|
||||
}
|
||||
|
||||
// 判断是否为正则表达式特殊字符
|
||||
// Check if it's a regular expression special character
|
||||
func isReChar(n int64) bool {
|
||||
reChars := `.*?+{}()^$|\`
|
||||
for _, char := range reChars {
|
||||
@ -292,19 +292,19 @@ func isReChar(n int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断是否为其他转义序列
|
||||
// Check if it's another escape sequence
|
||||
func isOtherEscapeCode(b []byte) bool {
|
||||
matchRe := regexp.MustCompile(`\\[^\\]`)
|
||||
return matchRe.Match(b)
|
||||
}
|
||||
|
||||
// 从内容解析探测器规则
|
||||
// Parse probe rules from content
|
||||
func (v *VScan) parseProbesFromContent(content string) {
|
||||
Common.LogDebug("开始解析探测器规则文件内容")
|
||||
Common.LogDebug("Starting to parse probe rules from file content")
|
||||
var probes []Probe
|
||||
var lines []string
|
||||
|
||||
// 过滤注释和空行
|
||||
// Filter comments and empty lines
|
||||
linesTemp := strings.Split(content, "\n")
|
||||
for _, lineTemp := range linesTemp {
|
||||
lineTemp = strings.TrimSpace(lineTemp)
|
||||
@ -314,196 +314,196 @@ func (v *VScan) parseProbesFromContent(content string) {
|
||||
lines = append(lines, lineTemp)
|
||||
}
|
||||
|
||||
// 验证文件内容
|
||||
// Validate file content
|
||||
if len(lines) == 0 {
|
||||
errMsg := "读取nmap-service-probes文件失败: 内容为空"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
errMsg := "Failed to read nmap-service-probes file: Content is empty"
|
||||
Common.LogDebug("Error: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
|
||||
// 检查Exclude指令
|
||||
// Check Exclude directive
|
||||
excludeCount := 0
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "Exclude ") {
|
||||
excludeCount++
|
||||
}
|
||||
if excludeCount > 1 {
|
||||
errMsg := "nmap-service-probes文件中只允许有一个Exclude指令"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
errMsg := "Only one Exclude directive is allowed in nmap-service-probes file"
|
||||
Common.LogDebug("Error: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// 验证第一行格式
|
||||
// Validate first line format
|
||||
firstLine := lines[0]
|
||||
if !(strings.HasPrefix(firstLine, "Exclude ") || strings.HasPrefix(firstLine, "Probe ")) {
|
||||
errMsg := "解析错误: 首行必须以\"Probe \"或\"Exclude \"开头"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
errMsg := "Parsing error: First line must start with \"Probe \" or \"Exclude \""
|
||||
Common.LogDebug("Error: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
|
||||
// 处理Exclude指令
|
||||
// Process Exclude directive
|
||||
if excludeCount == 1 {
|
||||
v.Exclude = firstLine[len("Exclude")+1:]
|
||||
lines = lines[1:]
|
||||
Common.LogDebug("解析到Exclude规则: " + v.Exclude)
|
||||
Common.LogDebug("Parsed Exclude rule: " + v.Exclude)
|
||||
}
|
||||
|
||||
// 合并内容并分割探测器
|
||||
// Merge content and split probes
|
||||
content = "\n" + strings.Join(lines, "\n")
|
||||
probeParts := strings.Split(content, "\nProbe")[1:]
|
||||
|
||||
// 解析每个探测器
|
||||
// Parse each probe
|
||||
for _, probePart := range probeParts {
|
||||
probe := Probe{}
|
||||
if err := probe.fromString(probePart); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("解析探测器失败: %v", err))
|
||||
Common.LogDebug(fmt.Sprintf("Failed to parse probe: %v", err))
|
||||
continue
|
||||
}
|
||||
probes = append(probes, probe)
|
||||
}
|
||||
|
||||
v.AllProbes = probes
|
||||
Common.LogDebug(fmt.Sprintf("成功解析 %d 个探测器规则", len(probes)))
|
||||
Common.LogDebug(fmt.Sprintf("Successfully parsed %d probe rules", len(probes)))
|
||||
}
|
||||
|
||||
// 将探测器转换为名称映射
|
||||
// Convert probes to name mapping
|
||||
func (v *VScan) parseProbesToMapKName() {
|
||||
Common.LogDebug("开始构建探测器名称映射")
|
||||
Common.LogDebug("Starting to build probe name mapping")
|
||||
v.ProbesMapKName = map[string]Probe{}
|
||||
for _, probe := range v.AllProbes {
|
||||
v.ProbesMapKName[probe.Name] = probe
|
||||
Common.LogDebug("添加探测器映射: " + probe.Name)
|
||||
Common.LogDebug("Added probe mapping: " + probe.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置使用的探测器
|
||||
// Set probes to be used
|
||||
func (v *VScan) SetusedProbes() {
|
||||
Common.LogDebug("开始设置要使用的探测器")
|
||||
Common.LogDebug("Starting to set probes to be used")
|
||||
|
||||
for _, probe := range v.AllProbes {
|
||||
if strings.ToLower(probe.Protocol) == "tcp" {
|
||||
if probe.Name == "SSLSessionReq" {
|
||||
Common.LogDebug("跳过 SSLSessionReq 探测器")
|
||||
Common.LogDebug("Skipping SSLSessionReq probe")
|
||||
continue
|
||||
}
|
||||
|
||||
v.Probes = append(v.Probes, probe)
|
||||
Common.LogDebug("添加TCP探测器: " + probe.Name)
|
||||
Common.LogDebug("Added TCP probe: " + probe.Name)
|
||||
|
||||
// 特殊处理TLS会话请求
|
||||
// Special handling for TLS session request
|
||||
if probe.Name == "TLSSessionReq" {
|
||||
sslProbe := v.ProbesMapKName["SSLSessionReq"]
|
||||
v.Probes = append(v.Probes, sslProbe)
|
||||
Common.LogDebug("为TLSSessionReq添加SSL探测器")
|
||||
Common.LogDebug("Added SSL probe for TLSSessionReq")
|
||||
}
|
||||
} else {
|
||||
v.UdpProbes = append(v.UdpProbes, probe)
|
||||
Common.LogDebug("添加UDP探测器: " + probe.Name)
|
||||
Common.LogDebug("Added UDP probe: " + probe.Name)
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("探测器设置完成,TCP: %d个, UDP: %d个",
|
||||
Common.LogDebug(fmt.Sprintf("Probe setting completed, TCP: %d, UDP: %d",
|
||||
len(v.Probes), len(v.UdpProbes)))
|
||||
}
|
||||
|
||||
// 解析match指令获取匹配规则
|
||||
// Parse match directive to get match rule
|
||||
func (p *Probe) getMatch(data string) (match Match, err error) {
|
||||
Common.LogDebug("开始解析match指令:" + data)
|
||||
Common.LogDebug("Starting to parse match directive: " + data)
|
||||
match = Match{}
|
||||
|
||||
// 提取match文本并解析指令语法
|
||||
// Extract match text and parse directive syntax
|
||||
matchText := data[len("match")+1:]
|
||||
directive := p.getDirectiveSyntax(matchText)
|
||||
|
||||
// 分割文本获取pattern和版本信息
|
||||
// Split text to get pattern and version info
|
||||
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
|
||||
if len(textSplited) == 0 {
|
||||
return match, fmt.Errorf("无效的match指令格式")
|
||||
return match, fmt.Errorf("Invalid match directive format")
|
||||
}
|
||||
|
||||
pattern := textSplited[0]
|
||||
versionInfo := strings.Join(textSplited[1:], "")
|
||||
|
||||
// 解码并编译正则表达式
|
||||
// Decode and compile regular expression
|
||||
patternUnescaped, decodeErr := DecodePattern(pattern)
|
||||
if decodeErr != nil {
|
||||
Common.LogDebug("解码pattern失败: " + decodeErr.Error())
|
||||
Common.LogDebug("Failed to decode pattern: " + decodeErr.Error())
|
||||
return match, decodeErr
|
||||
}
|
||||
|
||||
patternUnescapedStr := string([]rune(string(patternUnescaped)))
|
||||
patternCompiled, compileErr := regexp.Compile(patternUnescapedStr)
|
||||
if compileErr != nil {
|
||||
Common.LogDebug("编译正则表达式失败: " + compileErr.Error())
|
||||
Common.LogDebug("Failed to compile regular expression: " + compileErr.Error())
|
||||
return match, compileErr
|
||||
}
|
||||
|
||||
// 设置match对象属性
|
||||
// Set match object attributes
|
||||
match.Service = directive.DirectiveName
|
||||
match.Pattern = pattern
|
||||
match.PatternCompiled = patternCompiled
|
||||
match.VersionInfo = versionInfo
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("解析match成功: 服务=%s, Pattern=%s",
|
||||
Common.LogDebug(fmt.Sprintf("Match parsing successful: Service=%s, Pattern=%s",
|
||||
match.Service, match.Pattern))
|
||||
return match, nil
|
||||
}
|
||||
|
||||
// 解析softmatch指令获取软匹配规则
|
||||
// Parse softmatch directive to get soft match rule
|
||||
func (p *Probe) getSoftMatch(data string) (softMatch Match, err error) {
|
||||
Common.LogDebug("开始解析softmatch指令:" + data)
|
||||
Common.LogDebug("Starting to parse softmatch directive: " + data)
|
||||
softMatch = Match{IsSoft: true}
|
||||
|
||||
// 提取softmatch文本并解析指令语法
|
||||
// Extract softmatch text and parse directive syntax
|
||||
matchText := data[len("softmatch")+1:]
|
||||
directive := p.getDirectiveSyntax(matchText)
|
||||
|
||||
// 分割文本获取pattern和版本信息
|
||||
// Split text to get pattern and version info
|
||||
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
|
||||
if len(textSplited) == 0 {
|
||||
return softMatch, fmt.Errorf("无效的softmatch指令格式")
|
||||
return softMatch, fmt.Errorf("Invalid softmatch directive format")
|
||||
}
|
||||
|
||||
pattern := textSplited[0]
|
||||
versionInfo := strings.Join(textSplited[1:], "")
|
||||
|
||||
// 解码并编译正则表达式
|
||||
// Decode and compile regular expression
|
||||
patternUnescaped, decodeErr := DecodePattern(pattern)
|
||||
if decodeErr != nil {
|
||||
Common.LogDebug("解码pattern失败: " + decodeErr.Error())
|
||||
Common.LogDebug("Failed to decode pattern: " + decodeErr.Error())
|
||||
return softMatch, decodeErr
|
||||
}
|
||||
|
||||
patternUnescapedStr := string([]rune(string(patternUnescaped)))
|
||||
patternCompiled, compileErr := regexp.Compile(patternUnescapedStr)
|
||||
if compileErr != nil {
|
||||
Common.LogDebug("编译正则表达式失败: " + compileErr.Error())
|
||||
Common.LogDebug("Failed to compile regular expression: " + compileErr.Error())
|
||||
return softMatch, compileErr
|
||||
}
|
||||
|
||||
// 设置softMatch对象属性
|
||||
// Set softMatch object attributes
|
||||
softMatch.Service = directive.DirectiveName
|
||||
softMatch.Pattern = pattern
|
||||
softMatch.PatternCompiled = patternCompiled
|
||||
softMatch.VersionInfo = versionInfo
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("解析softmatch成功: 服务=%s, Pattern=%s",
|
||||
Common.LogDebug(fmt.Sprintf("Softmatch parsing successful: Service=%s, Pattern=%s",
|
||||
softMatch.Service, softMatch.Pattern))
|
||||
return softMatch, nil
|
||||
}
|
||||
|
||||
// 解码模式字符串,处理转义序列
|
||||
// Decode pattern string, handle escape sequences
|
||||
func DecodePattern(s string) ([]byte, error) {
|
||||
Common.LogDebug("开始解码pattern: " + s)
|
||||
Common.LogDebug("Starting to decode pattern: " + s)
|
||||
sByteOrigin := []byte(s)
|
||||
|
||||
// 处理十六进制、八进制和结构化转义序列
|
||||
// Handle hexadecimal, octal, and structured escape sequences
|
||||
matchRe := regexp.MustCompile(`\\(x[0-9a-fA-F]{2}|[0-7]{1,3}|[aftnrv])`)
|
||||
sByteDec := matchRe.ReplaceAllFunc(sByteOrigin, func(match []byte) (v []byte) {
|
||||
var replace []byte
|
||||
|
||||
// 处理十六进制转义
|
||||
// Handle hexadecimal escape
|
||||
if isHexCode(match) {
|
||||
hexNum := match[2:]
|
||||
byteNum, _ := strconv.ParseInt(string(hexNum), 16, 32)
|
||||
@ -514,20 +514,20 @@ func DecodePattern(s string) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理结构化转义字符
|
||||
// Handle structured escape characters
|
||||
if isStructCode(match) {
|
||||
structCodeMap := map[int][]byte{
|
||||
97: []byte{0x07}, // \a 响铃
|
||||
102: []byte{0x0c}, // \f 换页
|
||||
116: []byte{0x09}, // \t 制表符
|
||||
110: []byte{0x0a}, // \n 换行
|
||||
114: []byte{0x0d}, // \r 回车
|
||||
118: []byte{0x0b}, // \v 垂直制表符
|
||||
97: []byte{0x07}, // \a bell
|
||||
102: []byte{0x0c}, // \f form feed
|
||||
116: []byte{0x09}, // \t tab
|
||||
110: []byte{0x0a}, // \n newline
|
||||
114: []byte{0x0d}, // \r carriage return
|
||||
118: []byte{0x0b}, // \v vertical tab
|
||||
}
|
||||
replace = structCodeMap[int(match[1])]
|
||||
}
|
||||
|
||||
// 处理八进制转义
|
||||
// Handle octal escape
|
||||
if isOctalCode(match) {
|
||||
octalNum := match[2:]
|
||||
byteNum, _ := strconv.ParseInt(string(octalNum), 8, 32)
|
||||
@ -536,7 +536,7 @@ func DecodePattern(s string) ([]byte, error) {
|
||||
return replace
|
||||
})
|
||||
|
||||
// 处理其他转义序列
|
||||
// Handle other escape sequences
|
||||
matchRe2 := regexp.MustCompile(`\\([^\\])`)
|
||||
sByteDec2 := matchRe2.ReplaceAllFunc(sByteDec, func(match []byte) (v []byte) {
|
||||
if isOtherEscapeCode(match) {
|
||||
@ -545,57 +545,57 @@ func DecodePattern(s string) ([]byte, error) {
|
||||
return match
|
||||
})
|
||||
|
||||
Common.LogDebug("pattern解码完成")
|
||||
Common.LogDebug("Pattern decoding completed")
|
||||
return sByteDec2, nil
|
||||
}
|
||||
|
||||
// ProbesRarity 用于按稀有度排序的探测器切片
|
||||
// ProbesRarity is a slice of probes for sorting by rarity
|
||||
type ProbesRarity []Probe
|
||||
|
||||
// Len 返回切片长度,实现 sort.Interface 接口
|
||||
// Len returns slice length, implements sort.Interface
|
||||
func (ps ProbesRarity) Len() int {
|
||||
return len(ps)
|
||||
}
|
||||
|
||||
// Swap 交换切片中的两个元素,实现 sort.Interface 接口
|
||||
// Swap exchanges two elements in the slice, implements sort.Interface
|
||||
func (ps ProbesRarity) Swap(i, j int) {
|
||||
ps[i], ps[j] = ps[j], ps[i]
|
||||
}
|
||||
|
||||
// Less 比较函数,按稀有度升序排序,实现 sort.Interface 接口
|
||||
// Less comparison function, sorts by rarity in ascending order, implements sort.Interface
|
||||
func (ps ProbesRarity) Less(i, j int) bool {
|
||||
return ps[i].Rarity < ps[j].Rarity
|
||||
}
|
||||
|
||||
// Target 定义目标结构体
|
||||
// Target defines target structure
|
||||
type Target struct {
|
||||
IP string // 目标IP地址
|
||||
Port int // 目标端口
|
||||
Protocol string // 协议类型
|
||||
IP string // Target IP address
|
||||
Port int // Target port
|
||||
Protocol string // Protocol type
|
||||
}
|
||||
|
||||
// ContainsPort 检查指定端口是否在探测器的端口范围内
|
||||
// ContainsPort checks if the specified port is within the probe's port range
|
||||
func (p *Probe) ContainsPort(testPort int) bool {
|
||||
Common.LogDebug(fmt.Sprintf("检查端口 %d 是否在探测器端口范围内: %s", testPort, p.Ports))
|
||||
Common.LogDebug(fmt.Sprintf("Checking if port %d is within probe port range: %s", testPort, p.Ports))
|
||||
|
||||
// 检查单个端口
|
||||
// Check individual ports
|
||||
ports := strings.Split(p.Ports, ",")
|
||||
for _, port := range ports {
|
||||
port = strings.TrimSpace(port)
|
||||
cmpPort, err := strconv.Atoi(port)
|
||||
if err == nil && testPort == cmpPort {
|
||||
Common.LogDebug(fmt.Sprintf("端口 %d 匹配单个端口", testPort))
|
||||
Common.LogDebug(fmt.Sprintf("Port %d matches individual port", testPort))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 检查端口范围
|
||||
// Check port ranges
|
||||
for _, port := range ports {
|
||||
port = strings.TrimSpace(port)
|
||||
if strings.Contains(port, "-") {
|
||||
portRange := strings.Split(port, "-")
|
||||
if len(portRange) != 2 {
|
||||
Common.LogDebug("无效的端口范围格式: " + port)
|
||||
Common.LogDebug("Invalid port range format: " + port)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -603,62 +603,62 @@ func (p *Probe) ContainsPort(testPort int) bool {
|
||||
end, err2 := strconv.Atoi(strings.TrimSpace(portRange[1]))
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
Common.LogDebug(fmt.Sprintf("解析端口范围失败: %s", port))
|
||||
Common.LogDebug(fmt.Sprintf("Failed to parse port range: %s", port))
|
||||
continue
|
||||
}
|
||||
|
||||
if testPort >= start && testPort <= end {
|
||||
Common.LogDebug(fmt.Sprintf("端口 %d 在范围 %d-%d 内", testPort, start, end))
|
||||
Common.LogDebug(fmt.Sprintf("Port %d is within range %d-%d", testPort, start, end))
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("端口 %d 不在探测器端口范围内", testPort))
|
||||
Common.LogDebug(fmt.Sprintf("Port %d is not within probe port range", testPort))
|
||||
return false
|
||||
}
|
||||
|
||||
// MatchPattern 使用正则表达式匹配响应内容
|
||||
// MatchPattern uses regular expression to match response content
|
||||
func (m *Match) MatchPattern(response []byte) bool {
|
||||
// 将响应转换为字符串并进行匹配
|
||||
// Convert response to string and match
|
||||
responseStr := string([]rune(string(response)))
|
||||
foundItems := m.PatternCompiled.FindStringSubmatch(responseStr)
|
||||
|
||||
if len(foundItems) > 0 {
|
||||
m.FoundItems = foundItems
|
||||
Common.LogDebug(fmt.Sprintf("匹配成功,找到 %d 个匹配项", len(foundItems)))
|
||||
Common.LogDebug(fmt.Sprintf("Match successful, found %d matching items", len(foundItems)))
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// ParseVersionInfo 解析版本信息并返回额外信息结构
|
||||
// ParseVersionInfo parses version information and returns extra information structure
|
||||
func (m *Match) ParseVersionInfo(response []byte) Extras {
|
||||
Common.LogDebug("开始解析版本信息")
|
||||
Common.LogDebug("Starting to parse version information")
|
||||
var extras = Extras{}
|
||||
|
||||
// 替换版本信息中的占位符
|
||||
foundItems := m.FoundItems[1:] // 跳过第一个完整匹配项
|
||||
// Replace placeholders in version info
|
||||
foundItems := m.FoundItems[1:] // Skip the first complete match item
|
||||
versionInfo := m.VersionInfo
|
||||
for index, value := range foundItems {
|
||||
dollarName := "$" + strconv.Itoa(index+1)
|
||||
versionInfo = strings.Replace(versionInfo, dollarName, value, -1)
|
||||
}
|
||||
Common.LogDebug("替换后的版本信息: " + versionInfo)
|
||||
Common.LogDebug("Version info after replacement: " + versionInfo)
|
||||
|
||||
// 定义解析函数
|
||||
// Define parsing function
|
||||
parseField := func(field, pattern string) string {
|
||||
patterns := []string{
|
||||
pattern + `/([^/]*)/`, // 斜线分隔
|
||||
pattern + `\|([^|]*)\|`, // 竖线分隔
|
||||
pattern + `/([^/]*)/`, // Slash delimiter
|
||||
pattern + `\|([^|]*)\|`, // Pipe delimiter
|
||||
}
|
||||
|
||||
for _, p := range patterns {
|
||||
if strings.Contains(versionInfo, pattern) {
|
||||
regex := regexp.MustCompile(p)
|
||||
if matches := regex.FindStringSubmatch(versionInfo); len(matches) > 1 {
|
||||
Common.LogDebug(fmt.Sprintf("解析到%s: %s", field, matches[1]))
|
||||
Common.LogDebug(fmt.Sprintf("Parsed %s: %s", field, matches[1]))
|
||||
return matches[1]
|
||||
}
|
||||
}
|
||||
@ -666,15 +666,15 @@ func (m *Match) ParseVersionInfo(response []byte) Extras {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 解析各个字段
|
||||
extras.VendorProduct = parseField("厂商产品", " p")
|
||||
extras.Version = parseField("版本", " v")
|
||||
extras.Info = parseField("信息", " i")
|
||||
extras.Hostname = parseField("主机名", " h")
|
||||
extras.OperatingSystem = parseField("操作系统", " o")
|
||||
extras.DeviceType = parseField("设备类型", " d")
|
||||
// Parse each field
|
||||
extras.VendorProduct = parseField("vendor product", " p")
|
||||
extras.Version = parseField("version", " v")
|
||||
extras.Info = parseField("info", " i")
|
||||
extras.Hostname = parseField("hostname", " h")
|
||||
extras.OperatingSystem = parseField("operating system", " o")
|
||||
extras.DeviceType = parseField("device type", " d")
|
||||
|
||||
// 特殊处理CPE
|
||||
// Special handling for CPE
|
||||
if strings.Contains(versionInfo, " cpe:/") || strings.Contains(versionInfo, " cpe:|") {
|
||||
cpePatterns := []string{`cpe:/([^/]*)`, `cpe:\|([^|]*)`}
|
||||
for _, pattern := range cpePatterns {
|
||||
@ -685,7 +685,7 @@ func (m *Match) ParseVersionInfo(response []byte) Extras {
|
||||
} else {
|
||||
extras.CPE = cpeName[0]
|
||||
}
|
||||
Common.LogDebug("解析到CPE: " + extras.CPE)
|
||||
Common.LogDebug("Parsed CPE: " + extras.CPE)
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -694,12 +694,12 @@ func (m *Match) ParseVersionInfo(response []byte) Extras {
|
||||
return extras
|
||||
}
|
||||
|
||||
// ToMap 将 Extras 转换为 map[string]string
|
||||
// ToMap converts Extras to map[string]string
|
||||
func (e *Extras) ToMap() map[string]string {
|
||||
Common.LogDebug("开始转换Extras为Map")
|
||||
Common.LogDebug("Starting to convert Extras to Map")
|
||||
result := make(map[string]string)
|
||||
|
||||
// 定义字段映射
|
||||
// Define field mapping
|
||||
fields := map[string]string{
|
||||
"vendor_product": e.VendorProduct,
|
||||
"version": e.Version,
|
||||
@ -710,31 +710,31 @@ func (e *Extras) ToMap() map[string]string {
|
||||
"cpe": e.CPE,
|
||||
}
|
||||
|
||||
// 添加非空字段到结果map
|
||||
// Add non-empty fields to result map
|
||||
for key, value := range fields {
|
||||
if value != "" {
|
||||
result[key] = value
|
||||
Common.LogDebug(fmt.Sprintf("添加字段 %s: %s", key, value))
|
||||
Common.LogDebug(fmt.Sprintf("Added field %s: %s", key, value))
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("转换完成,共有 %d 个字段", len(result)))
|
||||
Common.LogDebug(fmt.Sprintf("Conversion completed, total %d fields", len(result)))
|
||||
return result
|
||||
}
|
||||
|
||||
func DecodeData(s string) ([]byte, error) {
|
||||
if len(s) == 0 {
|
||||
Common.LogDebug("输入数据为空")
|
||||
Common.LogDebug("Input data is empty")
|
||||
return nil, fmt.Errorf("empty input")
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始解码数据,长度: %d, 内容: %q", len(s), s))
|
||||
Common.LogDebug(fmt.Sprintf("Starting to decode data, length: %d, content: %q", len(s), s))
|
||||
sByteOrigin := []byte(s)
|
||||
|
||||
// 处理十六进制、八进制和结构化转义序列
|
||||
// Handle hexadecimal, octal, and structured escape sequences
|
||||
matchRe := regexp.MustCompile(`\\(x[0-9a-fA-F]{2}|[0-7]{1,3}|[aftnrv])`)
|
||||
sByteDec := matchRe.ReplaceAllFunc(sByteOrigin, func(match []byte) []byte {
|
||||
// 处理十六进制转义
|
||||
// Handle hexadecimal escape
|
||||
if isHexCode(match) {
|
||||
hexNum := match[2:]
|
||||
byteNum, err := strconv.ParseInt(string(hexNum), 16, 32)
|
||||
@ -744,15 +744,15 @@ func DecodeData(s string) ([]byte, error) {
|
||||
return []byte{uint8(byteNum)}
|
||||
}
|
||||
|
||||
// 处理结构化转义字符
|
||||
// Handle structured escape characters
|
||||
if isStructCode(match) {
|
||||
structCodeMap := map[int][]byte{
|
||||
97: []byte{0x07}, // \a 响铃
|
||||
102: []byte{0x0c}, // \f 换页
|
||||
116: []byte{0x09}, // \t 制表符
|
||||
110: []byte{0x0a}, // \n 换行
|
||||
114: []byte{0x0d}, // \r 回车
|
||||
118: []byte{0x0b}, // \v 垂直制表符
|
||||
97: []byte{0x07}, // \a bell
|
||||
102: []byte{0x0c}, // \f form feed
|
||||
116: []byte{0x09}, // \t tab
|
||||
110: []byte{0x0a}, // \n newline
|
||||
114: []byte{0x0d}, // \r carriage return
|
||||
118: []byte{0x0b}, // \v vertical tab
|
||||
}
|
||||
if replace, ok := structCodeMap[int(match[1])]; ok {
|
||||
return replace
|
||||
@ -760,7 +760,7 @@ func DecodeData(s string) ([]byte, error) {
|
||||
return match
|
||||
}
|
||||
|
||||
// 处理八进制转义
|
||||
// Handle octal escape
|
||||
if isOctalCode(match) {
|
||||
octalNum := match[2:]
|
||||
byteNum, err := strconv.ParseInt(string(octalNum), 8, 32)
|
||||
@ -770,11 +770,11 @@ func DecodeData(s string) ([]byte, error) {
|
||||
return []byte{uint8(byteNum)}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("无法识别的转义序列: %s", string(match)))
|
||||
Common.LogDebug(fmt.Sprintf("Unrecognized escape sequence: %s", string(match)))
|
||||
return match
|
||||
})
|
||||
|
||||
// 处理其他转义序列
|
||||
// Handle other escape sequences
|
||||
matchRe2 := regexp.MustCompile(`\\([^\\])`)
|
||||
sByteDec2 := matchRe2.ReplaceAllFunc(sByteDec, func(match []byte) []byte {
|
||||
if len(match) < 2 {
|
||||
@ -787,39 +787,39 @@ func DecodeData(s string) ([]byte, error) {
|
||||
})
|
||||
|
||||
if len(sByteDec2) == 0 {
|
||||
Common.LogDebug("解码后数据为空")
|
||||
Common.LogDebug("Decoded data is empty")
|
||||
return nil, fmt.Errorf("decoded data is empty")
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("解码完成,结果长度: %d, 内容: %x", len(sByteDec2), sByteDec2))
|
||||
Common.LogDebug(fmt.Sprintf("Decoding completed, result length: %d, content: %x", len(sByteDec2), sByteDec2))
|
||||
return sByteDec2, nil
|
||||
}
|
||||
|
||||
// GetAddress 获取目标的完整地址(IP:端口)
|
||||
// GetAddress gets the target's full address (IP:port)
|
||||
func (t *Target) GetAddress() string {
|
||||
addr := t.IP + ":" + strconv.Itoa(t.Port)
|
||||
Common.LogDebug("获取目标地址: " + addr)
|
||||
Common.LogDebug("Getting target address: " + addr)
|
||||
return addr
|
||||
}
|
||||
|
||||
// trimBanner 处理和清理横幅数据
|
||||
// trimBanner processes and cleans banner data
|
||||
func trimBanner(buf []byte) string {
|
||||
Common.LogDebug("开始处理横幅数据")
|
||||
Common.LogDebug("Starting to process banner data")
|
||||
bufStr := string(buf)
|
||||
|
||||
// 特殊处理SMB协议
|
||||
// Special handling for SMB protocol
|
||||
if strings.Contains(bufStr, "SMB") {
|
||||
banner := hex.EncodeToString(buf)
|
||||
if len(banner) > 0xa+6 && banner[0xa:0xa+6] == "534d42" { // "SMB" in hex
|
||||
Common.LogDebug("检测到SMB协议数据")
|
||||
Common.LogDebug("Detected SMB protocol data")
|
||||
plain := banner[0xa2:]
|
||||
data, err := hex.DecodeString(plain)
|
||||
if err != nil {
|
||||
Common.LogDebug("SMB数据解码失败: " + err.Error())
|
||||
Common.LogDebug("Failed to decode SMB data: " + err.Error())
|
||||
return bufStr
|
||||
}
|
||||
|
||||
// 解析domain
|
||||
// Parse domain
|
||||
var domain string
|
||||
var index int
|
||||
for i, s := range data {
|
||||
@ -831,7 +831,7 @@ func trimBanner(buf []byte) string {
|
||||
}
|
||||
}
|
||||
|
||||
// 解析hostname
|
||||
// Parse hostname
|
||||
var hostname string
|
||||
remainData := data[index:]
|
||||
for i, h := range remainData {
|
||||
@ -844,12 +844,12 @@ func trimBanner(buf []byte) string {
|
||||
}
|
||||
|
||||
smbBanner := fmt.Sprintf("hostname: %s domain: %s", hostname, domain)
|
||||
Common.LogDebug("SMB横幅: " + smbBanner)
|
||||
Common.LogDebug("SMB banner: " + smbBanner)
|
||||
return smbBanner
|
||||
}
|
||||
}
|
||||
|
||||
// 处理常规数据
|
||||
// Process regular data
|
||||
var src string
|
||||
for _, ch := range bufStr {
|
||||
if ch > 32 && ch < 125 {
|
||||
@ -859,19 +859,19 @@ func trimBanner(buf []byte) string {
|
||||
}
|
||||
}
|
||||
|
||||
// 清理多余空白
|
||||
// Clean up extra whitespace
|
||||
re := regexp.MustCompile(`\s{2,}`)
|
||||
src = re.ReplaceAllString(src, ".")
|
||||
result := strings.TrimSpace(src)
|
||||
Common.LogDebug("处理后的横幅: " + result)
|
||||
Common.LogDebug("Processed banner: " + result)
|
||||
return result
|
||||
}
|
||||
|
||||
// Init 初始化VScan对象
|
||||
// Init initializes the VScan object
|
||||
func (v *VScan) Init() {
|
||||
Common.LogDebug("开始初始化VScan")
|
||||
Common.LogDebug("Starting to initialize VScan")
|
||||
v.parseProbesFromContent(ProbeString)
|
||||
v.parseProbesToMapKName()
|
||||
v.SetusedProbes()
|
||||
Common.LogDebug("VScan初始化完成")
|
||||
Common.LogDebug("VScan initialization completed")
|
||||
}
|
||||
|
242
Core/PortInfo.go
242
Core/PortInfo.go
@ -9,54 +9,54 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ServiceInfo 定义服务识别的结果信息
|
||||
// ServiceInfo defines the service identification result information
|
||||
type ServiceInfo struct {
|
||||
Name string // 服务名称,如 http、ssh 等
|
||||
Banner string // 服务返回的横幅信息
|
||||
Version string // 服务版本号
|
||||
Extras map[string]string // 其他额外信息,如操作系统、产品名等
|
||||
Name string // Service name, such as http, ssh, etc.
|
||||
Banner string // Banner information returned by the service
|
||||
Version string // Service version number
|
||||
Extras map[string]string // Other additional information, such as operating system, product name, etc.
|
||||
}
|
||||
|
||||
// Result 定义单次探测的结果
|
||||
// Result defines the result of a single detection
|
||||
type Result struct {
|
||||
Service Service // 识别出的服务信息
|
||||
Banner string // 服务横幅
|
||||
Extras map[string]string // 额外信息
|
||||
Send []byte // 发送的探测数据
|
||||
Recv []byte // 接收到的响应数据
|
||||
Service Service // Identified service information
|
||||
Banner string // Service banner
|
||||
Extras map[string]string // Additional information
|
||||
Send []byte // Probe data sent
|
||||
Recv []byte // Response data received
|
||||
}
|
||||
|
||||
// Service 定义服务的基本信息
|
||||
// Service defines the basic information of a service
|
||||
type Service struct {
|
||||
Name string // 服务名称
|
||||
Extras map[string]string // 服务的额外属性
|
||||
Name string // Service name
|
||||
Extras map[string]string // Additional service attributes
|
||||
}
|
||||
|
||||
// Info 定义单个端口探测的上下文信息
|
||||
// Info defines the context information for a single port probe
|
||||
type Info struct {
|
||||
Address string // 目标IP地址
|
||||
Port int // 目标端口
|
||||
Conn net.Conn // 网络连接
|
||||
Result Result // 探测结果
|
||||
Found bool // 是否成功识别服务
|
||||
Address string // Target IP address
|
||||
Port int // Target port
|
||||
Conn net.Conn // Network connection
|
||||
Result Result // Detection result
|
||||
Found bool // Whether the service was successfully identified
|
||||
}
|
||||
|
||||
// PortInfoScanner 定义端口服务识别器
|
||||
// PortInfoScanner defines a port service identifier
|
||||
type PortInfoScanner struct {
|
||||
Address string // 目标IP地址
|
||||
Port int // 目标端口
|
||||
Conn net.Conn // 网络连接
|
||||
Timeout time.Duration // 超时时间
|
||||
info *Info // 探测上下文
|
||||
Address string // Target IP address
|
||||
Port int // Target port
|
||||
Conn net.Conn // Network connection
|
||||
Timeout time.Duration // Timeout duration
|
||||
info *Info // Detection context
|
||||
}
|
||||
|
||||
// 预定义的基础探测器
|
||||
// Predefined basic probes
|
||||
var (
|
||||
null = new(Probe) // 空探测器,用于基本协议识别
|
||||
common = new(Probe) // 通用探测器,用于常见服务识别
|
||||
null = new(Probe) // Empty probe, used for basic protocol identification
|
||||
common = new(Probe) // Common probe, used for common service identification
|
||||
)
|
||||
|
||||
// NewPortInfoScanner 创建新的端口服务识别器实例
|
||||
// NewPortInfoScanner creates a new port service identifier instance
|
||||
func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Duration) *PortInfoScanner {
|
||||
return &PortInfoScanner{
|
||||
Address: addr,
|
||||
@ -74,12 +74,12 @@ func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Durat
|
||||
}
|
||||
}
|
||||
|
||||
// Identify 执行服务识别,返回识别结果
|
||||
// Identify performs service identification and returns the result
|
||||
func (s *PortInfoScanner) Identify() (*ServiceInfo, error) {
|
||||
Common.LogDebug(fmt.Sprintf("开始识别服务 %s:%d", s.Address, s.Port))
|
||||
Common.LogDebug(fmt.Sprintf("Starting to identify service %s:%d", s.Address, s.Port))
|
||||
s.info.PortInfo()
|
||||
|
||||
// 构造返回结果
|
||||
// Construct the return result
|
||||
serviceInfo := &ServiceInfo{
|
||||
Name: s.info.Result.Service.Name,
|
||||
Banner: s.info.Result.Banner,
|
||||
@ -87,104 +87,104 @@ func (s *PortInfoScanner) Identify() (*ServiceInfo, error) {
|
||||
Extras: make(map[string]string),
|
||||
}
|
||||
|
||||
// 复制额外信息
|
||||
// Copy additional information
|
||||
for k, v := range s.info.Result.Service.Extras {
|
||||
serviceInfo.Extras[k] = v
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("服务识别完成 %s:%d => %s", s.Address, s.Port, serviceInfo.Name))
|
||||
Common.LogDebug(fmt.Sprintf("Service identification completed %s:%d => %s", s.Address, s.Port, serviceInfo.Name))
|
||||
return serviceInfo, nil
|
||||
}
|
||||
|
||||
// PortInfo 执行端口服务识别的主要逻辑
|
||||
// PortInfo executes the main logic of port service identification
|
||||
func (i *Info) PortInfo() {
|
||||
// 1. 首先尝试读取服务的初始响应
|
||||
// 1. First try to read the initial response from the service
|
||||
if response, err := i.Read(); err == nil && len(response) > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("收到初始响应: %d 字节", len(response)))
|
||||
Common.LogDebug(fmt.Sprintf("Received initial response: %d bytes", len(response)))
|
||||
|
||||
// 使用基础探测器检查响应
|
||||
Common.LogDebug("尝试使用基础探测器(null/common)检查响应")
|
||||
// Check the response using basic probes
|
||||
Common.LogDebug("Attempting to check response using basic probes (null/common)")
|
||||
if i.tryProbes(response, []*Probe{null, common}) {
|
||||
Common.LogDebug("基础探测器匹配成功")
|
||||
Common.LogDebug("Basic probe matching successful")
|
||||
return
|
||||
}
|
||||
Common.LogDebug("基础探测器未匹配")
|
||||
Common.LogDebug("Basic probes did not match")
|
||||
} else if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取初始响应失败: %v", err))
|
||||
Common.LogDebug(fmt.Sprintf("Failed to read initial response: %v", err))
|
||||
}
|
||||
|
||||
// 记录已使用的探测器,避免重复使用
|
||||
// Record used probes to avoid duplication
|
||||
usedProbes := make(map[string]struct{})
|
||||
|
||||
// 2. 尝试使用端口专用探测器
|
||||
Common.LogDebug(fmt.Sprintf("尝试使用端口 %d 的专用探测器", i.Port))
|
||||
// 2. Try to use port-specific probes
|
||||
Common.LogDebug(fmt.Sprintf("Attempting to use dedicated probes for port %d", i.Port))
|
||||
if i.processPortMapProbes(usedProbes) {
|
||||
Common.LogDebug("端口专用探测器匹配成功")
|
||||
Common.LogDebug("Port-specific probe matching successful")
|
||||
return
|
||||
}
|
||||
Common.LogDebug("端口专用探测器未匹配")
|
||||
Common.LogDebug("Port-specific probes did not match")
|
||||
|
||||
// 3. 使用默认探测器列表
|
||||
Common.LogDebug("尝试使用默认探测器列表")
|
||||
// 3. Use the default probe list
|
||||
Common.LogDebug("Attempting to use default probe list")
|
||||
if i.processDefaultProbes(usedProbes) {
|
||||
Common.LogDebug("默认探测器匹配成功")
|
||||
Common.LogDebug("Default probe matching successful")
|
||||
return
|
||||
}
|
||||
Common.LogDebug("默认探测器未匹配")
|
||||
Common.LogDebug("Default probes did not match")
|
||||
|
||||
// 4. 如果所有探测都失败,标记为未知服务
|
||||
// 4. If all probes fail, mark as unknown service
|
||||
if strings.TrimSpace(i.Result.Service.Name) == "" {
|
||||
Common.LogDebug("未识别出服务,标记为 unknown")
|
||||
Common.LogDebug("Service not recognized, marking as unknown")
|
||||
i.Result.Service.Name = "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// tryProbes 尝试使用指定的探测器列表检查响应
|
||||
// tryProbes attempts to use the specified probe list to check the response
|
||||
func (i *Info) tryProbes(response []byte, probes []*Probe) bool {
|
||||
for _, probe := range probes {
|
||||
Common.LogDebug(fmt.Sprintf("尝试探测器: %s", probe.Name))
|
||||
Common.LogDebug(fmt.Sprintf("Attempting probe: %s", probe.Name))
|
||||
i.GetInfo(response, probe)
|
||||
if i.Found {
|
||||
Common.LogDebug(fmt.Sprintf("探测器 %s 匹配成功", probe.Name))
|
||||
Common.LogDebug(fmt.Sprintf("Probe %s matched successfully", probe.Name))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// processPortMapProbes 处理端口映射中的专用探测器
|
||||
// processPortMapProbes processes dedicated probes in the port mapping
|
||||
func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool {
|
||||
// 检查是否存在端口专用探测器
|
||||
// Check if port-specific probes exist
|
||||
if len(Common.PortMap[i.Port]) == 0 {
|
||||
Common.LogDebug(fmt.Sprintf("端口 %d 没有专用探测器", i.Port))
|
||||
Common.LogDebug(fmt.Sprintf("Port %d has no dedicated probes", i.Port))
|
||||
return false
|
||||
}
|
||||
|
||||
// 遍历端口专用探测器
|
||||
// Iterate through port-specific probes
|
||||
for _, name := range Common.PortMap[i.Port] {
|
||||
Common.LogDebug(fmt.Sprintf("尝试端口专用探测器: %s", name))
|
||||
Common.LogDebug(fmt.Sprintf("Attempting port-specific probe: %s", name))
|
||||
usedProbes[name] = struct{}{}
|
||||
probe := v.ProbesMapKName[name]
|
||||
|
||||
// 解码探测数据
|
||||
// Decode probe data
|
||||
probeData, err := DecodeData(probe.Data)
|
||||
if err != nil || len(probeData) == 0 {
|
||||
Common.LogDebug(fmt.Sprintf("探测器 %s 数据解码失败", name))
|
||||
Common.LogDebug(fmt.Sprintf("Failed to decode probe data for %s", name))
|
||||
continue
|
||||
}
|
||||
|
||||
// 发送探测数据并获取响应
|
||||
Common.LogDebug(fmt.Sprintf("发送探测数据: %d 字节", len(probeData)))
|
||||
// Send probe data and get response
|
||||
Common.LogDebug(fmt.Sprintf("Sending probe data: %d bytes", len(probeData)))
|
||||
if response := i.Connect(probeData); len(response) > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("收到响应: %d 字节", len(response)))
|
||||
Common.LogDebug(fmt.Sprintf("Received response: %d bytes", len(response)))
|
||||
|
||||
// 使用当前探测器检查响应
|
||||
// Check response with current probe
|
||||
i.GetInfo(response, &probe)
|
||||
if i.Found {
|
||||
return true
|
||||
}
|
||||
|
||||
// 根据探测器类型进行额外检查
|
||||
// Perform additional checks based on probe type
|
||||
switch name {
|
||||
case "GenericLines":
|
||||
if i.tryProbes(response, []*Probe{null}) {
|
||||
@ -202,14 +202,14 @@ func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// processDefaultProbes 处理默认探测器列表
|
||||
// processDefaultProbes processes the default probe list
|
||||
func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
|
||||
failCount := 0
|
||||
const maxFailures = 10 // 最大失败次数
|
||||
const maxFailures = 10 // Maximum failure count
|
||||
|
||||
// 遍历默认探测器列表
|
||||
// Iterate through the default probe list
|
||||
for _, name := range Common.DefaultMap {
|
||||
// 跳过已使用的探测器
|
||||
// Skip already used probes
|
||||
if _, used := usedProbes[name]; used {
|
||||
continue
|
||||
}
|
||||
@ -220,7 +220,7 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
|
||||
continue
|
||||
}
|
||||
|
||||
// 发送探测数据并获取响应
|
||||
// Send probe data and get response
|
||||
response := i.Connect(probeData)
|
||||
if len(response) == 0 {
|
||||
failCount++
|
||||
@ -230,13 +230,13 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
|
||||
continue
|
||||
}
|
||||
|
||||
// 使用当前探测器检查响应
|
||||
// Check response with current probe
|
||||
i.GetInfo(response, &probe)
|
||||
if i.Found {
|
||||
return true
|
||||
}
|
||||
|
||||
// 根据探测器类型进行额外检查
|
||||
// Perform additional checks based on probe type
|
||||
switch name {
|
||||
case "GenericLines":
|
||||
if i.tryProbes(response, []*Probe{null}) {
|
||||
@ -250,7 +250,7 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试使用端口映射中的其他探测器
|
||||
// Try to use other probes in the port mapping
|
||||
if len(Common.PortMap[i.Port]) > 0 {
|
||||
for _, mappedName := range Common.PortMap[i.Port] {
|
||||
usedProbes[mappedName] = struct{}{}
|
||||
@ -265,13 +265,13 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetInfo 分析响应数据并提取服务信息
|
||||
// GetInfo analyzes response data and extracts service information
|
||||
func (i *Info) GetInfo(response []byte, probe *Probe) {
|
||||
Common.LogDebug(fmt.Sprintf("开始分析响应数据,长度: %d", len(response)))
|
||||
Common.LogDebug(fmt.Sprintf("Starting to analyze response data, length: %d", len(response)))
|
||||
|
||||
// 响应数据有效性检查
|
||||
// Check response data validity
|
||||
if len(response) <= 0 {
|
||||
Common.LogDebug("响应数据为空")
|
||||
Common.LogDebug("Response data is empty")
|
||||
return
|
||||
}
|
||||
|
||||
@ -281,42 +281,42 @@ func (i *Info) GetInfo(response []byte, probe *Probe) {
|
||||
softFound bool
|
||||
)
|
||||
|
||||
// 处理主要匹配规则
|
||||
Common.LogDebug(fmt.Sprintf("处理探测器 %s 的主要匹配规则", probe.Name))
|
||||
// Process main matching rules
|
||||
Common.LogDebug(fmt.Sprintf("Processing main matching rules for probe %s", probe.Name))
|
||||
if matched, match := i.processMatches(response, probe.Matchs); matched {
|
||||
Common.LogDebug("找到硬匹配")
|
||||
Common.LogDebug("Hard match found")
|
||||
return
|
||||
} else if match != nil {
|
||||
Common.LogDebug("找到软匹配")
|
||||
Common.LogDebug("Soft match found")
|
||||
softFound = true
|
||||
softMatch = *match
|
||||
}
|
||||
|
||||
// 处理回退匹配规则
|
||||
// Process fallback matching rules
|
||||
if probe.Fallback != "" {
|
||||
Common.LogDebug(fmt.Sprintf("尝试回退匹配: %s", probe.Fallback))
|
||||
Common.LogDebug(fmt.Sprintf("Attempting fallback match: %s", probe.Fallback))
|
||||
if fbProbe, ok := v.ProbesMapKName[probe.Fallback]; ok {
|
||||
if matched, match := i.processMatches(response, fbProbe.Matchs); matched {
|
||||
Common.LogDebug("回退匹配成功")
|
||||
Common.LogDebug("Fallback match successful")
|
||||
return
|
||||
} else if match != nil {
|
||||
Common.LogDebug("找到回退软匹配")
|
||||
Common.LogDebug("Fallback soft match found")
|
||||
softFound = true
|
||||
softMatch = *match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理未找到匹配的情况
|
||||
// Handle case when no match is found
|
||||
if !i.Found {
|
||||
Common.LogDebug("未找到硬匹配,处理未匹配情况")
|
||||
Common.LogDebug("No hard match found, handling no match case")
|
||||
i.handleNoMatch(response, result, softFound, softMatch)
|
||||
}
|
||||
}
|
||||
|
||||
// processMatches 处理匹配规则集
|
||||
// processMatches processes the set of matching rules
|
||||
func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match) {
|
||||
Common.LogDebug(fmt.Sprintf("开始处理匹配规则,共 %d 条", len(*matches)))
|
||||
Common.LogDebug(fmt.Sprintf("Starting to process matching rules, total %d rules", len(*matches)))
|
||||
var softMatch *Match
|
||||
|
||||
for _, match := range *matches {
|
||||
@ -325,11 +325,11 @@ func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match)
|
||||
}
|
||||
|
||||
if !match.IsSoft {
|
||||
Common.LogDebug(fmt.Sprintf("找到硬匹配: %s", match.Service))
|
||||
Common.LogDebug(fmt.Sprintf("Hard match found: %s", match.Service))
|
||||
i.handleHardMatch(response, &match)
|
||||
return true, nil
|
||||
} else if softMatch == nil {
|
||||
Common.LogDebug(fmt.Sprintf("找到软匹配: %s", match.Service))
|
||||
Common.LogDebug(fmt.Sprintf("Soft match found: %s", match.Service))
|
||||
tmpMatch := match
|
||||
softMatch = &tmpMatch
|
||||
}
|
||||
@ -338,9 +338,9 @@ func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match)
|
||||
return false, softMatch
|
||||
}
|
||||
|
||||
// handleHardMatch 处理硬匹配结果
|
||||
// handleHardMatch handles hard match results
|
||||
func (i *Info) handleHardMatch(response []byte, match *Match) {
|
||||
Common.LogDebug(fmt.Sprintf("处理硬匹配结果: %s", match.Service))
|
||||
Common.LogDebug(fmt.Sprintf("Processing hard match result: %s", match.Service))
|
||||
result := &i.Result
|
||||
extras := match.ParseVersionInfo(response)
|
||||
extrasMap := extras.ToMap()
|
||||
@ -350,64 +350,64 @@ func (i *Info) handleHardMatch(response []byte, match *Match) {
|
||||
result.Banner = trimBanner(response)
|
||||
result.Service.Extras = extrasMap
|
||||
|
||||
// 特殊处理 microsoft-ds 服务
|
||||
// Special handling for microsoft-ds service
|
||||
if result.Service.Name == "microsoft-ds" {
|
||||
Common.LogDebug("特殊处理 microsoft-ds 服务")
|
||||
Common.LogDebug("Special handling for microsoft-ds service")
|
||||
result.Service.Extras["hostname"] = result.Banner
|
||||
}
|
||||
|
||||
i.Found = true
|
||||
Common.LogDebug(fmt.Sprintf("服务识别结果: %s, Banner: %s", result.Service.Name, result.Banner))
|
||||
Common.LogDebug(fmt.Sprintf("Service identification result: %s, Banner: %s", result.Service.Name, result.Banner))
|
||||
}
|
||||
|
||||
// handleNoMatch 处理未找到匹配的情况
|
||||
// handleNoMatch handles the case when no match is found
|
||||
func (i *Info) handleNoMatch(response []byte, result *Result, softFound bool, softMatch Match) {
|
||||
Common.LogDebug("处理未匹配情况")
|
||||
Common.LogDebug("Handling no match case")
|
||||
result.Banner = trimBanner(response)
|
||||
|
||||
if !softFound {
|
||||
// 尝试识别 HTTP 服务
|
||||
// Try to identify HTTP service
|
||||
if strings.Contains(result.Banner, "HTTP/") ||
|
||||
strings.Contains(result.Banner, "html") {
|
||||
Common.LogDebug("识别为HTTP服务")
|
||||
Common.LogDebug("Identified as HTTP service")
|
||||
result.Service.Name = "http"
|
||||
} else {
|
||||
Common.LogDebug("未知服务")
|
||||
Common.LogDebug("Unknown service")
|
||||
result.Service.Name = "unknown"
|
||||
}
|
||||
} else {
|
||||
Common.LogDebug("使用软匹配结果")
|
||||
Common.LogDebug("Using soft match result")
|
||||
extras := softMatch.ParseVersionInfo(response)
|
||||
result.Service.Extras = extras.ToMap()
|
||||
result.Service.Name = softMatch.Service
|
||||
i.Found = true
|
||||
Common.LogDebug(fmt.Sprintf("软匹配服务: %s", result.Service.Name))
|
||||
Common.LogDebug(fmt.Sprintf("Soft match service: %s", result.Service.Name))
|
||||
}
|
||||
}
|
||||
|
||||
// Connect 发送数据并获取响应
|
||||
// Connect sends data and gets response
|
||||
func (i *Info) Connect(msg []byte) []byte {
|
||||
i.Write(msg)
|
||||
reply, _ := i.Read()
|
||||
return reply
|
||||
}
|
||||
|
||||
const WrTimeout = 5 // 默认读写超时时间(秒)
|
||||
const WrTimeout = 5 // Default read/write timeout (seconds)
|
||||
|
||||
// Write 写入数据到连接
|
||||
// Write writes data to the connection
|
||||
func (i *Info) Write(msg []byte) error {
|
||||
if i.Conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置写入超时
|
||||
// Set write timeout
|
||||
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
|
||||
|
||||
// 写入数据
|
||||
// Write data
|
||||
_, err := i.Conn.Write(msg)
|
||||
if err != nil && strings.Contains(err.Error(), "close") {
|
||||
i.Conn.Close()
|
||||
// 连接关闭时重试
|
||||
// Retry when connection is closed
|
||||
i.Conn, err = net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second)
|
||||
if err == nil {
|
||||
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
|
||||
@ -415,7 +415,7 @@ func (i *Info) Write(msg []byte) error {
|
||||
}
|
||||
}
|
||||
|
||||
// 记录发送的数据
|
||||
// Record sent data
|
||||
if err == nil {
|
||||
i.Result.Send = msg
|
||||
}
|
||||
@ -423,22 +423,22 @@ func (i *Info) Write(msg []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read 从连接读取响应
|
||||
// Read reads response from the connection
|
||||
func (i *Info) Read() ([]byte, error) {
|
||||
if i.Conn == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 设置读取超时
|
||||
// Set read timeout
|
||||
i.Conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
|
||||
|
||||
// 读取数据
|
||||
// Read data
|
||||
result, err := readFromConn(i.Conn)
|
||||
if err != nil && strings.Contains(err.Error(), "close") {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 记录接收到的数据
|
||||
// Record received data
|
||||
if len(result) > 0 {
|
||||
i.Result.Recv = result
|
||||
}
|
||||
@ -446,9 +446,9 @@ func (i *Info) Read() ([]byte, error) {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// readFromConn 从连接读取数据的辅助函数
|
||||
// readFromConn helper function to read data from connection
|
||||
func readFromConn(conn net.Conn) ([]byte, error) {
|
||||
size := 2 * 1024 // 读取缓冲区大小
|
||||
size := 2 * 1024 // Read buffer size
|
||||
var result []byte
|
||||
|
||||
for {
|
||||
@ -473,4 +473,4 @@ func readFromConn(conn net.Conn) ([]byte, error) {
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
118
Core/PortScan.go
118
Core/PortScan.go
@ -10,47 +10,47 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Addr 表示待扫描的地址
|
||||
// Addr represents the address to be scanned
|
||||
type Addr struct {
|
||||
ip string // IP地址
|
||||
port int // 端口号
|
||||
ip string // IP address
|
||||
port int // Port number
|
||||
}
|
||||
|
||||
// ScanResult 扫描结果
|
||||
// ScanResult scanning result
|
||||
type ScanResult struct {
|
||||
Address string // IP地址
|
||||
Port int // 端口号
|
||||
Service *ServiceInfo // 服务信息
|
||||
Address string // IP address
|
||||
Port int // Port number
|
||||
Service *ServiceInfo // Service information
|
||||
}
|
||||
|
||||
// PortScan 执行端口扫描
|
||||
// hostslist: 待扫描的主机列表
|
||||
// ports: 待扫描的端口范围
|
||||
// timeout: 超时时间(秒)
|
||||
// 返回活跃地址列表
|
||||
// PortScan executes port scanning
|
||||
// hostslist: List of hosts to be scanned
|
||||
// ports: Port range to be scanned
|
||||
// timeout: Timeout in seconds
|
||||
// Returns list of active addresses
|
||||
func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
var results []ScanResult
|
||||
var aliveAddrs []string
|
||||
var mu sync.Mutex
|
||||
|
||||
// 解析并验证端口列表
|
||||
// Parse and validate port list
|
||||
probePorts := Common.ParsePort(ports)
|
||||
if len(probePorts) == 0 {
|
||||
Common.LogError(fmt.Sprintf("端口格式错误: %s", ports))
|
||||
Common.LogError(fmt.Sprintf("Invalid port format: %s", ports))
|
||||
return aliveAddrs
|
||||
}
|
||||
|
||||
// 排除指定端口
|
||||
// Exclude specified ports
|
||||
probePorts = excludeNoPorts(probePorts)
|
||||
|
||||
// 初始化并发控制
|
||||
// Initialize concurrency control
|
||||
workers := Common.ThreadNum
|
||||
addrs := make(chan Addr, 100) // 待扫描地址通道
|
||||
scanResults := make(chan ScanResult, 100) // 扫描结果通道
|
||||
addrs := make(chan Addr, 100) // Channel for addresses to be scanned
|
||||
scanResults := make(chan ScanResult, 100) // Channel for scan results
|
||||
var wg sync.WaitGroup
|
||||
var workerWg sync.WaitGroup
|
||||
|
||||
// 启动扫描工作协程
|
||||
// Start scanning worker goroutines
|
||||
for i := 0; i < workers; i++ {
|
||||
workerWg.Add(1)
|
||||
go func() {
|
||||
@ -61,7 +61,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
}()
|
||||
}
|
||||
|
||||
// 启动结果处理协程
|
||||
// Start result processing goroutine
|
||||
var resultWg sync.WaitGroup
|
||||
resultWg.Add(1)
|
||||
go func() {
|
||||
@ -75,7 +75,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
}
|
||||
}()
|
||||
|
||||
// 分发扫描任务
|
||||
// Distribute scanning tasks
|
||||
for _, port := range probePorts {
|
||||
for _, host := range hostslist {
|
||||
wg.Add(1)
|
||||
@ -83,7 +83,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
}
|
||||
}
|
||||
|
||||
// 等待所有任务完成
|
||||
// Wait for all tasks to complete
|
||||
close(addrs)
|
||||
workerWg.Wait()
|
||||
wg.Wait()
|
||||
@ -93,11 +93,11 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
return aliveAddrs
|
||||
}
|
||||
|
||||
// PortConnect 执行单个端口连接检测
|
||||
// addr: 待检测的地址
|
||||
// results: 结果通道
|
||||
// timeout: 超时时间
|
||||
// wg: 等待组
|
||||
// PortConnect performs connection detection for a single port
|
||||
// addr: Address to be detected
|
||||
// results: Results channel
|
||||
// timeout: Timeout duration
|
||||
// wg: Wait group
|
||||
func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
@ -105,7 +105,7 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
|
||||
var err error
|
||||
var conn net.Conn
|
||||
|
||||
// 尝试建立TCP连接
|
||||
// Try to establish TCP connection
|
||||
conn, err = Common.WrapperTcpWithTimeout("tcp4",
|
||||
fmt.Sprintf("%s:%v", addr.ip, addr.port),
|
||||
time.Duration(timeout)*time.Second)
|
||||
@ -118,11 +118,11 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
|
||||
return
|
||||
}
|
||||
|
||||
// 记录开放端口
|
||||
// Record open port
|
||||
address := fmt.Sprintf("%s:%d", addr.ip, addr.port)
|
||||
Common.LogSuccess(fmt.Sprintf("端口开放 %s", address))
|
||||
Common.LogSuccess(fmt.Sprintf("Port open %s", address))
|
||||
|
||||
// 保存端口扫描结果
|
||||
// Save port scan result
|
||||
portResult := &Common.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: Common.PORT,
|
||||
@ -134,66 +134,66 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
|
||||
}
|
||||
Common.SaveResult(portResult)
|
||||
|
||||
// 构造扫描结果
|
||||
// Construct scan result
|
||||
result := ScanResult{
|
||||
Address: addr.ip,
|
||||
Port: addr.port,
|
||||
}
|
||||
|
||||
// 执行服务识别
|
||||
// Perform service identification
|
||||
if !Common.SkipFingerprint && conn != nil {
|
||||
scanner := NewPortInfoScanner(addr.ip, addr.port, conn, time.Duration(timeout)*time.Second)
|
||||
if serviceInfo, err := scanner.Identify(); err == nil {
|
||||
result.Service = serviceInfo
|
||||
|
||||
// 构造服务识别日志
|
||||
// Construct service identification log
|
||||
var logMsg strings.Builder
|
||||
logMsg.WriteString(fmt.Sprintf("服务识别 %s => ", address))
|
||||
logMsg.WriteString(fmt.Sprintf("Service identification %s => ", address))
|
||||
|
||||
if serviceInfo.Name != "unknown" {
|
||||
logMsg.WriteString(fmt.Sprintf("[%s]", serviceInfo.Name))
|
||||
}
|
||||
|
||||
if serviceInfo.Version != "" {
|
||||
logMsg.WriteString(fmt.Sprintf(" 版本:%s", serviceInfo.Version))
|
||||
logMsg.WriteString(fmt.Sprintf(" Version:%s", serviceInfo.Version))
|
||||
}
|
||||
|
||||
// 收集服务详细信息
|
||||
// Collect service details
|
||||
details := map[string]interface{}{
|
||||
"port": addr.port,
|
||||
"service": serviceInfo.Name,
|
||||
}
|
||||
|
||||
// 添加版本信息
|
||||
// Add version information
|
||||
if serviceInfo.Version != "" {
|
||||
details["version"] = serviceInfo.Version
|
||||
}
|
||||
|
||||
// 添加产品信息
|
||||
// Add product information
|
||||
if v, ok := serviceInfo.Extras["vendor_product"]; ok && v != "" {
|
||||
details["product"] = v
|
||||
logMsg.WriteString(fmt.Sprintf(" 产品:%s", v))
|
||||
logMsg.WriteString(fmt.Sprintf(" Product:%s", v))
|
||||
}
|
||||
|
||||
// 添加操作系统信息
|
||||
// Add operating system information
|
||||
if v, ok := serviceInfo.Extras["os"]; ok && v != "" {
|
||||
details["os"] = v
|
||||
logMsg.WriteString(fmt.Sprintf(" 系统:%s", v))
|
||||
logMsg.WriteString(fmt.Sprintf(" OS:%s", v))
|
||||
}
|
||||
|
||||
// 添加额外信息
|
||||
// Add additional information
|
||||
if v, ok := serviceInfo.Extras["info"]; ok && v != "" {
|
||||
details["info"] = v
|
||||
logMsg.WriteString(fmt.Sprintf(" 信息:%s", v))
|
||||
logMsg.WriteString(fmt.Sprintf(" Info:%s", v))
|
||||
}
|
||||
|
||||
// 添加Banner信息
|
||||
// Add Banner information
|
||||
if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 {
|
||||
details["banner"] = strings.TrimSpace(serviceInfo.Banner)
|
||||
logMsg.WriteString(fmt.Sprintf(" Banner:[%s]", strings.TrimSpace(serviceInfo.Banner)))
|
||||
}
|
||||
|
||||
// 保存服务识别结果
|
||||
// Save service identification result
|
||||
serviceResult := &Common.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: Common.SERVICE,
|
||||
@ -210,17 +210,17 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
|
||||
results <- result
|
||||
}
|
||||
|
||||
// NoPortScan 生成端口列表(不进行扫描)
|
||||
// hostslist: 主机列表
|
||||
// ports: 端口范围
|
||||
// 返回地址列表
|
||||
// NoPortScan generates a port list (without scanning)
|
||||
// hostslist: Host list
|
||||
// ports: Port range
|
||||
// Returns address list
|
||||
func NoPortScan(hostslist []string, ports string) []string {
|
||||
var AliveAddress []string
|
||||
|
||||
// 解析并排除端口
|
||||
// Parse and exclude ports
|
||||
probePorts := excludeNoPorts(Common.ParsePort(ports))
|
||||
|
||||
// 生成地址列表
|
||||
// Generate address list
|
||||
for _, port := range probePorts {
|
||||
for _, host := range hostslist {
|
||||
address := fmt.Sprintf("%s:%d", host, port)
|
||||
@ -231,27 +231,27 @@ func NoPortScan(hostslist []string, ports string) []string {
|
||||
return AliveAddress
|
||||
}
|
||||
|
||||
// excludeNoPorts 排除指定的端口
|
||||
// ports: 原始端口列表
|
||||
// 返回过滤后的端口列表
|
||||
// excludeNoPorts excludes specified ports
|
||||
// ports: Original port list
|
||||
// Returns filtered port list
|
||||
func excludeNoPorts(ports []int) []int {
|
||||
noPorts := Common.ParsePort(Common.ExcludePorts)
|
||||
if len(noPorts) == 0 {
|
||||
return ports
|
||||
}
|
||||
|
||||
// 使用map过滤端口
|
||||
// Use map to filter ports
|
||||
temp := make(map[int]struct{})
|
||||
for _, port := range ports {
|
||||
temp[port] = struct{}{}
|
||||
}
|
||||
|
||||
// 移除需要排除的端口
|
||||
// Remove ports to be excluded
|
||||
for _, port := range noPorts {
|
||||
delete(temp, port)
|
||||
}
|
||||
|
||||
// 转换为有序切片
|
||||
// Convert to ordered slice
|
||||
var newPorts []int
|
||||
for port := range temp {
|
||||
newPorts = append(newPorts, port)
|
||||
@ -259,4 +259,4 @@ func excludeNoPorts(ports []int) []int {
|
||||
sort.Ints(newPorts)
|
||||
|
||||
return newPorts
|
||||
}
|
||||
}
|
@ -5,11 +5,11 @@ import (
|
||||
"github.com/shadow1ng/fscan/Plugins"
|
||||
)
|
||||
|
||||
// init 初始化并注册所有扫描插件
|
||||
// 包括标准端口服务扫描、特殊扫描类型和本地信息收集等
|
||||
// init initializes and registers all scan plugins
|
||||
// including standard port service scans, special scan types, and local information collection
|
||||
func init() {
|
||||
// 1. 标准网络服务扫描插件
|
||||
// 文件传输和远程访问服务
|
||||
// 1. Standard network service scan plugins
|
||||
// File transfer and remote access services
|
||||
Common.RegisterPlugin("ftp", Common.ScanPlugin{
|
||||
Name: "FTP",
|
||||
Ports: []int{21},
|
||||
@ -28,7 +28,7 @@ func init() {
|
||||
ScanFunc: Plugins.TelnetScan,
|
||||
})
|
||||
|
||||
// Windows网络服务
|
||||
// Windows network services
|
||||
Common.RegisterPlugin("findnet", Common.ScanPlugin{
|
||||
Name: "FindNet",
|
||||
Ports: []int{135},
|
||||
@ -47,7 +47,7 @@ func init() {
|
||||
ScanFunc: Plugins.SmbScan,
|
||||
})
|
||||
|
||||
// 数据库服务
|
||||
// Database services
|
||||
Common.RegisterPlugin("mssql", Common.ScanPlugin{
|
||||
Name: "MSSQL",
|
||||
Ports: []int{1433, 1434},
|
||||
@ -66,7 +66,7 @@ func init() {
|
||||
ScanFunc: Plugins.MysqlScan,
|
||||
})
|
||||
|
||||
// 中间件和消息队列服务
|
||||
// Middleware and message queue services
|
||||
Common.RegisterPlugin("elasticsearch", Common.ScanPlugin{
|
||||
Name: "Elasticsearch",
|
||||
Ports: []int{9200, 9300},
|
||||
@ -91,14 +91,14 @@ func init() {
|
||||
ScanFunc: Plugins.ActiveMQScan,
|
||||
})
|
||||
|
||||
// 目录和认证服务
|
||||
// Directory and authentication services
|
||||
Common.RegisterPlugin("ldap", Common.ScanPlugin{
|
||||
Name: "LDAP",
|
||||
Ports: []int{389, 636},
|
||||
ScanFunc: Plugins.LDAPScan,
|
||||
})
|
||||
|
||||
// 邮件服务
|
||||
// Mail services
|
||||
Common.RegisterPlugin("smtp", Common.ScanPlugin{
|
||||
Name: "SMTP",
|
||||
Ports: []int{25, 465, 587},
|
||||
@ -117,7 +117,7 @@ func init() {
|
||||
ScanFunc: Plugins.POP3Scan,
|
||||
})
|
||||
|
||||
// 网络管理和监控服务
|
||||
// Network management and monitoring services
|
||||
Common.RegisterPlugin("snmp", Common.ScanPlugin{
|
||||
Name: "SNMP",
|
||||
Ports: []int{161, 162},
|
||||
@ -130,14 +130,14 @@ func init() {
|
||||
ScanFunc: Plugins.ModbusScan,
|
||||
})
|
||||
|
||||
// 数据同步和备份服务
|
||||
// Data synchronization and backup services
|
||||
Common.RegisterPlugin("rsync", Common.ScanPlugin{
|
||||
Name: "Rsync",
|
||||
Ports: []int{873},
|
||||
ScanFunc: Plugins.RsyncScan,
|
||||
})
|
||||
|
||||
// NoSQL数据库
|
||||
// NoSQL databases
|
||||
Common.RegisterPlugin("cassandra", Common.ScanPlugin{
|
||||
Name: "Cassandra",
|
||||
Ports: []int{9042},
|
||||
@ -150,7 +150,7 @@ func init() {
|
||||
ScanFunc: Plugins.Neo4jScan,
|
||||
})
|
||||
|
||||
// 远程桌面和显示服务
|
||||
// Remote desktop and display services
|
||||
Common.RegisterPlugin("rdp", Common.ScanPlugin{
|
||||
Name: "RDP",
|
||||
Ports: []int{3389, 13389, 33389},
|
||||
@ -169,7 +169,7 @@ func init() {
|
||||
ScanFunc: Plugins.VncScan,
|
||||
})
|
||||
|
||||
// 缓存和键值存储服务
|
||||
// Cache and key-value storage services
|
||||
Common.RegisterPlugin("redis", Common.ScanPlugin{
|
||||
Name: "Redis",
|
||||
Ports: []int{6379, 6380, 16379},
|
||||
@ -194,7 +194,7 @@ func init() {
|
||||
ScanFunc: Plugins.MongodbScan,
|
||||
})
|
||||
|
||||
// 2. 特殊漏洞扫描插件
|
||||
// 2. Special vulnerability scan plugins
|
||||
Common.RegisterPlugin("ms17010", Common.ScanPlugin{
|
||||
Name: "MS17010",
|
||||
Ports: []int{445},
|
||||
@ -207,7 +207,7 @@ func init() {
|
||||
ScanFunc: Plugins.SmbGhost,
|
||||
})
|
||||
|
||||
// 3. Web应用扫描插件
|
||||
// 3. Web application scan plugins
|
||||
Common.RegisterPlugin("webtitle", Common.ScanPlugin{
|
||||
Name: "WebTitle",
|
||||
Ports: Common.ParsePortsFromString(Common.WebPorts),
|
||||
@ -220,7 +220,7 @@ func init() {
|
||||
ScanFunc: Plugins.WebPoc,
|
||||
})
|
||||
|
||||
// 4. Windows系统专用插件
|
||||
// 4. Windows system specific plugins
|
||||
Common.RegisterPlugin("smb2", Common.ScanPlugin{
|
||||
Name: "SMBScan2",
|
||||
Ports: []int{445},
|
||||
@ -233,7 +233,7 @@ func init() {
|
||||
ScanFunc: Plugins.WmiExec,
|
||||
})
|
||||
|
||||
// 5. 本地信息收集插件
|
||||
// 5. Local information collection plugins
|
||||
Common.RegisterPlugin("localinfo", Common.ScanPlugin{
|
||||
Name: "LocalInfo",
|
||||
Ports: []int{},
|
||||
|
264
Core/Scanner.go
264
Core/Scanner.go
@ -13,92 +13,92 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 全局变量定义
|
||||
// Global variable definitions
|
||||
var (
|
||||
LocalScan bool // 本地扫描模式标识
|
||||
WebScan bool // Web扫描模式标识
|
||||
LocalScan bool // Local scan mode identifier
|
||||
WebScan bool // Web scan mode identifier
|
||||
)
|
||||
|
||||
// Scan 执行扫描主流程
|
||||
// info: 主机信息结构体,包含扫描目标的基本信息
|
||||
// Scan executes the main scanning process
|
||||
// info: Host information structure, contains basic information about the scan target
|
||||
func Scan(info Common.HostInfo) {
|
||||
Common.LogInfo("开始信息扫描")
|
||||
Common.LogInfo("Starting information scan")
|
||||
|
||||
// 初始化HTTP客户端配置
|
||||
// Initialize HTTP client configuration
|
||||
lib.Inithttp()
|
||||
|
||||
// 初始化并发控制
|
||||
// Initialize concurrency control
|
||||
ch := make(chan struct{}, Common.ThreadNum)
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
// 根据扫描模式执行不同的扫描策略
|
||||
// Execute different scanning strategies based on scan mode
|
||||
switch {
|
||||
case Common.LocalMode:
|
||||
// 本地信息收集模式
|
||||
// Local information collection mode
|
||||
LocalScan = true
|
||||
executeLocalScan(info, &ch, &wg)
|
||||
case len(Common.URLs) > 0:
|
||||
// Web扫描模式
|
||||
// Web scanning mode
|
||||
WebScan = true
|
||||
executeWebScan(info, &ch, &wg)
|
||||
default:
|
||||
// 主机扫描模式
|
||||
// Host scanning mode
|
||||
executeHostScan(info, &ch, &wg)
|
||||
}
|
||||
|
||||
// 等待所有扫描任务完成
|
||||
// Wait for all scanning tasks to complete
|
||||
finishScan(&wg)
|
||||
}
|
||||
|
||||
// executeLocalScan 执行本地扫描
|
||||
// info: 主机信息
|
||||
// ch: 并发控制通道
|
||||
// wg: 等待组
|
||||
// executeLocalScan executes local scanning
|
||||
// info: Host information
|
||||
// ch: Concurrency control channel
|
||||
// wg: Wait group
|
||||
func executeLocalScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
Common.LogInfo("执行本地信息收集")
|
||||
Common.LogInfo("Executing local information collection")
|
||||
|
||||
// 获取本地模式支持的插件列表
|
||||
// Get list of plugins supported by local mode
|
||||
validLocalPlugins := getValidPlugins(Common.ModeLocal)
|
||||
|
||||
// 验证扫描模式的合法性
|
||||
// Validate scan mode legality
|
||||
if err := validateScanMode(validLocalPlugins, Common.ModeLocal); err != nil {
|
||||
Common.LogError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 输出使用的插件信息
|
||||
// Output plugin information being used
|
||||
if Common.ScanMode == Common.ModeLocal {
|
||||
Common.LogInfo("使用全部本地插件")
|
||||
Common.LogInfo("Using all local plugins")
|
||||
Common.ParseScanMode(Common.ScanMode)
|
||||
} else {
|
||||
Common.LogInfo(fmt.Sprintf("使用插件: %s", Common.ScanMode))
|
||||
Common.LogInfo(fmt.Sprintf("Using plugin: %s", Common.ScanMode))
|
||||
}
|
||||
|
||||
// 执行扫描任务
|
||||
// Execute scanning tasks
|
||||
executeScans([]Common.HostInfo{info}, ch, wg)
|
||||
}
|
||||
|
||||
// executeWebScan 执行Web扫描
|
||||
// info: 主机信息
|
||||
// ch: 并发控制通道
|
||||
// wg: 等待组
|
||||
// executeWebScan executes Web scanning
|
||||
// info: Host information
|
||||
// ch: Concurrency control channel
|
||||
// wg: Wait group
|
||||
func executeWebScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
Common.LogInfo("开始Web扫描")
|
||||
Common.LogInfo("Starting Web scanning")
|
||||
|
||||
// 获取Web模式支持的插件列表
|
||||
// Get list of plugins supported by Web mode
|
||||
validWebPlugins := getValidPlugins(Common.ModeWeb)
|
||||
|
||||
// 验证扫描模式的合法性
|
||||
// Validate scan mode legality
|
||||
if err := validateScanMode(validWebPlugins, Common.ModeWeb); err != nil {
|
||||
Common.LogError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 处理目标URL列表
|
||||
// Process target URL list
|
||||
var targetInfos []Common.HostInfo
|
||||
for _, url := range Common.URLs {
|
||||
urlInfo := info
|
||||
// 确保URL包含协议头
|
||||
// Ensure URL contains protocol header
|
||||
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
|
||||
url = "http://" + url
|
||||
}
|
||||
@ -106,43 +106,43 @@ func executeWebScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup)
|
||||
targetInfos = append(targetInfos, urlInfo)
|
||||
}
|
||||
|
||||
// 输出使用的插件信息
|
||||
// Output plugin information being used
|
||||
if Common.ScanMode == Common.ModeWeb {
|
||||
Common.LogInfo("使用全部Web插件")
|
||||
Common.LogInfo("Using all Web plugins")
|
||||
Common.ParseScanMode(Common.ScanMode)
|
||||
} else {
|
||||
Common.LogInfo(fmt.Sprintf("使用插件: %s", Common.ScanMode))
|
||||
Common.LogInfo(fmt.Sprintf("Using plugin: %s", Common.ScanMode))
|
||||
}
|
||||
|
||||
// 执行扫描任务
|
||||
// Execute scanning tasks
|
||||
executeScans(targetInfos, ch, wg)
|
||||
}
|
||||
|
||||
// executeHostScan 执行主机扫描
|
||||
// info: 主机信息
|
||||
// ch: 并发控制通道
|
||||
// wg: 等待组
|
||||
// executeHostScan executes host scanning
|
||||
// info: Host information
|
||||
// ch: Concurrency control channel
|
||||
// wg: Wait group
|
||||
func executeHostScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
// 验证扫描目标
|
||||
// Validate scan target
|
||||
if info.Host == "" {
|
||||
Common.LogError("未指定扫描目标")
|
||||
Common.LogError("Scan target not specified")
|
||||
return
|
||||
}
|
||||
|
||||
// 解析目标主机
|
||||
// Parse target host
|
||||
hosts, err := Common.ParseIP(info.Host, Common.HostsFile, Common.ExcludeHosts)
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("解析主机错误: %v", err))
|
||||
Common.LogError(fmt.Sprintf("Host parsing error: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
Common.LogInfo("开始主机扫描")
|
||||
Common.LogInfo("Starting host scanning")
|
||||
executeScan(hosts, info, ch, wg)
|
||||
}
|
||||
|
||||
// getValidPlugins 获取指定模式下的有效插件列表
|
||||
// mode: 扫描模式
|
||||
// 返回: 有效插件映射表
|
||||
// getValidPlugins gets list of valid plugins for the specified mode
|
||||
// mode: Scan mode
|
||||
// returns: Valid plugins mapping table
|
||||
func getValidPlugins(mode string) map[string]bool {
|
||||
validPlugins := make(map[string]bool)
|
||||
for _, plugin := range Common.PluginGroups[mode] {
|
||||
@ -151,94 +151,94 @@ func getValidPlugins(mode string) map[string]bool {
|
||||
return validPlugins
|
||||
}
|
||||
|
||||
// validateScanMode 验证扫描模式的合法性
|
||||
// validPlugins: 有效插件列表
|
||||
// mode: 扫描模式
|
||||
// 返回: 错误信息
|
||||
// validateScanMode validates the legality of scan mode
|
||||
// validPlugins: Valid plugin list
|
||||
// mode: Scan mode
|
||||
// returns: Error information
|
||||
func validateScanMode(validPlugins map[string]bool, mode string) error {
|
||||
if Common.ScanMode == "" || Common.ScanMode == "All" {
|
||||
Common.ScanMode = mode
|
||||
} else if _, exists := validPlugins[Common.ScanMode]; !exists {
|
||||
return fmt.Errorf("无效的%s插件: %s", mode, Common.ScanMode)
|
||||
return fmt.Errorf("Invalid %s plugin: %s", mode, Common.ScanMode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// executeScan 执行主扫描流程
|
||||
// hosts: 目标主机列表
|
||||
// info: 主机信息
|
||||
// ch: 并发控制通道
|
||||
// wg: 等待组
|
||||
// executeScan executes main scanning process
|
||||
// hosts: Target host list
|
||||
// info: Host information
|
||||
// ch: Concurrency control channel
|
||||
// wg: Wait group
|
||||
func executeScan(hosts []string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
var targetInfos []Common.HostInfo
|
||||
|
||||
// 处理主机和端口扫描
|
||||
// Process host and port scanning
|
||||
if len(hosts) > 0 || len(Common.HostPort) > 0 {
|
||||
// 检查主机存活性
|
||||
// Check host liveness
|
||||
if shouldPingScan(hosts) {
|
||||
hosts = CheckLive(hosts, Common.UsePing)
|
||||
Common.LogInfo(fmt.Sprintf("存活主机数量: %d", len(hosts)))
|
||||
Common.LogInfo(fmt.Sprintf("Number of live hosts: %d", len(hosts)))
|
||||
if Common.IsICMPScan() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 获取存活端口
|
||||
// Get alive ports
|
||||
alivePorts := getAlivePorts(hosts)
|
||||
if len(alivePorts) > 0 {
|
||||
targetInfos = prepareTargetInfos(alivePorts, info)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加URL扫描目标
|
||||
// Add URL scanning targets
|
||||
targetInfos = appendURLTargets(targetInfos, info)
|
||||
|
||||
// 执行漏洞扫描
|
||||
// Execute vulnerability scanning
|
||||
if len(targetInfos) > 0 {
|
||||
Common.LogInfo("开始漏洞扫描")
|
||||
Common.LogInfo("Starting vulnerability scanning")
|
||||
executeScans(targetInfos, ch, wg)
|
||||
}
|
||||
}
|
||||
|
||||
// shouldPingScan 判断是否需要执行ping扫描
|
||||
// hosts: 目标主机列表
|
||||
// 返回: 是否需要ping扫描
|
||||
// shouldPingScan determines if ping scanning should be executed
|
||||
// hosts: Target host list
|
||||
// returns: Whether ping scanning is needed
|
||||
func shouldPingScan(hosts []string) bool {
|
||||
return (Common.DisablePing == false && len(hosts) > 1) || Common.IsICMPScan()
|
||||
}
|
||||
|
||||
// getAlivePorts 获取存活端口列表
|
||||
// hosts: 目标主机列表
|
||||
// 返回: 存活端口列表
|
||||
// getAlivePorts gets list of alive ports
|
||||
// hosts: Target host list
|
||||
// returns: List of alive ports
|
||||
func getAlivePorts(hosts []string) []string {
|
||||
var alivePorts []string
|
||||
|
||||
// 根据扫描模式选择端口扫描方式
|
||||
// Choose port scanning method based on scan mode
|
||||
if Common.IsWebScan() {
|
||||
alivePorts = NoPortScan(hosts, Common.Ports)
|
||||
} else if len(hosts) > 0 {
|
||||
alivePorts = PortScan(hosts, Common.Ports, Common.Timeout)
|
||||
Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts)))
|
||||
Common.LogInfo(fmt.Sprintf("Number of alive ports: %d", len(alivePorts)))
|
||||
if Common.IsPortScan() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// 合并额外指定的端口
|
||||
// Merge additional specified ports
|
||||
if len(Common.HostPort) > 0 {
|
||||
alivePorts = append(alivePorts, Common.HostPort...)
|
||||
alivePorts = Common.RemoveDuplicate(alivePorts)
|
||||
Common.HostPort = nil
|
||||
Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts)))
|
||||
Common.LogInfo(fmt.Sprintf("Number of alive ports: %d", len(alivePorts)))
|
||||
}
|
||||
|
||||
return alivePorts
|
||||
}
|
||||
|
||||
// appendURLTargets 添加URL扫描目标
|
||||
// targetInfos: 现有目标列表
|
||||
// baseInfo: 基础主机信息
|
||||
// 返回: 更新后的目标列表
|
||||
// appendURLTargets adds URL scanning targets
|
||||
// targetInfos: Existing target list
|
||||
// baseInfo: Base host information
|
||||
// returns: Updated target list
|
||||
func appendURLTargets(targetInfos []Common.HostInfo, baseInfo Common.HostInfo) []Common.HostInfo {
|
||||
for _, url := range Common.URLs {
|
||||
urlInfo := baseInfo
|
||||
@ -248,16 +248,16 @@ func appendURLTargets(targetInfos []Common.HostInfo, baseInfo Common.HostInfo) [
|
||||
return targetInfos
|
||||
}
|
||||
|
||||
// prepareTargetInfos 准备扫描目标信息
|
||||
// alivePorts: 存活端口列表
|
||||
// baseInfo: 基础主机信息
|
||||
// 返回: 目标信息列表
|
||||
// prepareTargetInfos prepares scanning target information
|
||||
// alivePorts: Alive port list
|
||||
// baseInfo: Base host information
|
||||
// returns: Target information list
|
||||
func prepareTargetInfos(alivePorts []string, baseInfo Common.HostInfo) []Common.HostInfo {
|
||||
var infos []Common.HostInfo
|
||||
for _, targetIP := range alivePorts {
|
||||
hostParts := strings.Split(targetIP, ":")
|
||||
if len(hostParts) != 2 {
|
||||
Common.LogError(fmt.Sprintf("无效的目标地址格式: %s", targetIP))
|
||||
Common.LogError(fmt.Sprintf("Invalid target address format: %s", targetIP))
|
||||
continue
|
||||
}
|
||||
info := baseInfo
|
||||
@ -268,27 +268,27 @@ func prepareTargetInfos(alivePorts []string, baseInfo Common.HostInfo) []Common.
|
||||
return infos
|
||||
}
|
||||
|
||||
// ScanTask 扫描任务结构体
|
||||
// ScanTask scan task structure
|
||||
type ScanTask struct {
|
||||
pluginName string // 插件名称
|
||||
target Common.HostInfo // 目标信息
|
||||
pluginName string // Plugin name
|
||||
target Common.HostInfo // Target information
|
||||
}
|
||||
|
||||
// executeScans 执行扫描任务
|
||||
// targets: 目标列表
|
||||
// ch: 并发控制通道
|
||||
// wg: 等待组
|
||||
// executeScans executes scanning tasks
|
||||
// targets: Target list
|
||||
// ch: Concurrency control channel
|
||||
// wg: Wait group
|
||||
func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
mode := Common.GetScanMode()
|
||||
|
||||
// 获取要执行的插件列表
|
||||
// Get list of plugins to execute
|
||||
pluginsToRun, isSinglePlugin := getPluginsToRun(mode)
|
||||
|
||||
var tasks []ScanTask
|
||||
actualTasks := 0
|
||||
loadedPlugins := make([]string, 0)
|
||||
|
||||
// 收集扫描任务
|
||||
// Collect scanning tasks
|
||||
for _, target := range targets {
|
||||
targetPort, _ := strconv.Atoi(target.Ports)
|
||||
for _, pluginName := range pluginsToRun {
|
||||
@ -305,22 +305,22 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
|
||||
}
|
||||
}
|
||||
|
||||
// 处理插件列表
|
||||
// Process plugin list
|
||||
finalPlugins := getUniquePlugins(loadedPlugins)
|
||||
Common.LogInfo(fmt.Sprintf("加载的插件: %s", strings.Join(finalPlugins, ", ")))
|
||||
Common.LogInfo(fmt.Sprintf("Loaded plugins: %s", strings.Join(finalPlugins, ", ")))
|
||||
|
||||
// 初始化进度条
|
||||
// Initialize progress bar
|
||||
initializeProgressBar(actualTasks)
|
||||
|
||||
// 执行扫描任务
|
||||
// Execute scanning tasks
|
||||
for _, task := range tasks {
|
||||
AddScan(task.pluginName, task.target, ch, wg)
|
||||
}
|
||||
}
|
||||
|
||||
// getPluginsToRun 获取要执行的插件列表
|
||||
// mode: 扫描模式
|
||||
// 返回: 插件列表和是否为单插件模式
|
||||
// getPluginsToRun gets list of plugins to execute
|
||||
// mode: Scan mode
|
||||
// returns: Plugin list and whether it's single plugin mode
|
||||
func getPluginsToRun(mode string) ([]string, bool) {
|
||||
var pluginsToRun []string
|
||||
isSinglePlugin := false
|
||||
@ -335,13 +335,13 @@ func getPluginsToRun(mode string) ([]string, bool) {
|
||||
return pluginsToRun, isSinglePlugin
|
||||
}
|
||||
|
||||
// collectScanTasks 收集扫描任务
|
||||
// plugin: 插件信息
|
||||
// target: 目标信息
|
||||
// targetPort: 目标端口
|
||||
// pluginName: 插件名称
|
||||
// isSinglePlugin: 是否为单插件模式
|
||||
// 返回: 是否添加任务和任务列表
|
||||
// collectScanTasks collects scanning tasks
|
||||
// plugin: Plugin information
|
||||
// target: Target information
|
||||
// targetPort: Target port
|
||||
// pluginName: Plugin name
|
||||
// isSinglePlugin: Whether it's single plugin mode
|
||||
// returns: Whether task was added and task list
|
||||
func collectScanTasks(plugin Common.ScanPlugin, target Common.HostInfo, targetPort int, pluginName string, isSinglePlugin bool) (bool, []ScanTask) {
|
||||
var tasks []ScanTask
|
||||
taskAdded := false
|
||||
@ -357,9 +357,9 @@ func collectScanTasks(plugin Common.ScanPlugin, target Common.HostInfo, targetPo
|
||||
return taskAdded, tasks
|
||||
}
|
||||
|
||||
// getUniquePlugins 获取去重后的插件列表
|
||||
// loadedPlugins: 已加载的插件列表
|
||||
// 返回: 去重并排序后的插件列表
|
||||
// getUniquePlugins gets deduplicated plugin list
|
||||
// loadedPlugins: Already loaded plugin list
|
||||
// returns: Deduplicated and sorted plugin list
|
||||
func getUniquePlugins(loadedPlugins []string) []string {
|
||||
uniquePlugins := make(map[string]struct{})
|
||||
for _, p := range loadedPlugins {
|
||||
@ -375,15 +375,15 @@ func getUniquePlugins(loadedPlugins []string) []string {
|
||||
return finalPlugins
|
||||
}
|
||||
|
||||
// initializeProgressBar 初始化进度条
|
||||
// actualTasks: 实际任务数量
|
||||
// initializeProgressBar initializes progress bar
|
||||
// actualTasks: Actual number of tasks
|
||||
func initializeProgressBar(actualTasks int) {
|
||||
if Common.ShowProgress {
|
||||
Common.ProgressBar = progressbar.NewOptions(actualTasks,
|
||||
progressbar.OptionEnableColorCodes(true),
|
||||
progressbar.OptionShowCount(),
|
||||
progressbar.OptionSetWidth(15),
|
||||
progressbar.OptionSetDescription("[cyan]扫描进度:[reset]"),
|
||||
progressbar.OptionSetDescription("[cyan]Scanning progress:[reset]"),
|
||||
progressbar.OptionSetTheme(progressbar.Theme{
|
||||
Saucer: "[green]=[reset]",
|
||||
SaucerHead: "[green]>[reset]",
|
||||
@ -398,25 +398,25 @@ func initializeProgressBar(actualTasks int) {
|
||||
}
|
||||
}
|
||||
|
||||
// finishScan 完成扫描任务
|
||||
// wg: 等待组
|
||||
// finishScan completes scanning tasks
|
||||
// wg: Wait group
|
||||
func finishScan(wg *sync.WaitGroup) {
|
||||
wg.Wait()
|
||||
if Common.ProgressBar != nil {
|
||||
Common.ProgressBar.Finish()
|
||||
fmt.Println()
|
||||
}
|
||||
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
|
||||
Common.LogSuccess(fmt.Sprintf("Scanning completed: %v/%v", Common.End, Common.Num))
|
||||
}
|
||||
|
||||
// Mutex 用于保护共享资源的并发访问
|
||||
// Mutex for protecting concurrent access to shared resources
|
||||
var Mutex = &sync.Mutex{}
|
||||
|
||||
// AddScan 添加扫描任务并启动扫描
|
||||
// plugin: 插件名称
|
||||
// info: 目标信息
|
||||
// ch: 并发控制通道
|
||||
// wg: 等待组
|
||||
// AddScan adds scanning task and starts scanning
|
||||
// plugin: Plugin name
|
||||
// info: Target information
|
||||
// ch: Concurrency control channel
|
||||
// wg: Wait group
|
||||
func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
*ch <- struct{}{}
|
||||
wg.Add(1)
|
||||
@ -433,29 +433,29 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa
|
||||
}()
|
||||
}
|
||||
|
||||
// ScanFunc 执行扫描插件
|
||||
// name: 插件名称
|
||||
// info: 目标信息
|
||||
// ScanFunc executes scanning plugin
|
||||
// name: Plugin name
|
||||
// info: Target information
|
||||
func ScanFunc(name *string, info *Common.HostInfo) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
Common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err))
|
||||
Common.LogError(fmt.Sprintf("Scanning error %v:%v - %v", info.Host, info.Ports, err))
|
||||
}
|
||||
}()
|
||||
|
||||
plugin, exists := Common.PluginManager[*name]
|
||||
if !exists {
|
||||
Common.LogInfo(fmt.Sprintf("扫描类型 %v 无对应插件,已跳过", *name))
|
||||
Common.LogInfo(fmt.Sprintf("Scan type %v has no corresponding plugin, skipped", *name))
|
||||
return
|
||||
}
|
||||
|
||||
if err := plugin.ScanFunc(info); err != nil {
|
||||
Common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err))
|
||||
Common.LogError(fmt.Sprintf("Scanning error %v:%v - %v", info.Host, info.Ports, err))
|
||||
}
|
||||
}
|
||||
|
||||
// updateScanProgress 更新扫描进度
|
||||
// info: 目标信息
|
||||
// updateScanProgress updates scanning progress
|
||||
// info: Target information
|
||||
func updateScanProgress(info *Common.HostInfo) {
|
||||
Common.OutputMutex.Lock()
|
||||
atomic.AddInt64(&Common.End, 1)
|
||||
@ -464,4 +464,4 @@ func updateScanProgress(info *Common.HostInfo) {
|
||||
Common.ProgressBar.Add(1)
|
||||
}
|
||||
Common.OutputMutex.Unlock()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user