refactor: 输出格式重构,重构SMB、SMB2、FTP的一些验证逻辑

This commit is contained in:
ZacharyZcR
2025-01-01 05:24:49 +08:00
parent d13e1952e9
commit 277ea5d332
47 changed files with 879 additions and 867 deletions

View File

@@ -104,7 +104,11 @@ var (
EnableWmi bool // 原IsWmi
// 输出配置
DisableSave bool // 原TmpSave
DisableSave bool // 禁止保存结果
Silent bool // 静默模式
NoColor bool // 禁用彩色输出
JsonFormat bool // JSON格式输出
LogLevel string // 日志输出级别
)
var (

View File

@@ -73,7 +73,7 @@ func Flag(Info *HostInfo) {
" 漏洞类: ms17010, smbghost, smb2\n"+
" 其他: findnet, wmiexec, localinfo")
flag.BoolVar(&UseSynScan, "sS", false, "使用SYN扫描替代TCP全连接扫描(需要root/管理员权限)")
flag.IntVar(&ThreadNum, "t", 600, "设置扫描线程数")
flag.IntVar(&ThreadNum, "t", 60, "设置扫描线程数")
flag.Int64Var(&Timeout, "time", 3, "设置连接超时时间(单位:秒)")
flag.IntVar(&LiveTop, "top", 10, "仅显示指定数量的存活主机")
flag.BoolVar(&DisablePing, "np", false, "禁用主机存活探测")
@@ -126,9 +126,9 @@ func Flag(Info *HostInfo) {
flag.StringVar(&Outputfile, "o", "result.txt", "指定结果输出文件名")
flag.BoolVar(&DisableSave, "no", false, "禁止保存扫描结果")
flag.BoolVar(&Silent, "silent", false, "启用静默扫描模式(减少屏幕输出)")
flag.BoolVar(&Nocolor, "nocolor", false, "禁用彩色输出显示")
flag.BoolVar(&JsonOutput, "json", false, "以JSON格式输出结果")
flag.Int64Var(&WaitTime, "debug", 60, "设置错误日志输出时间间隔(单位:秒)")
flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示")
flag.BoolVar(&JsonFormat, "json", false, "以JSON格式输出结果")
flag.StringVar(&LogLevel, "log", LogLevelAll, "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)")
flag.Parse()
}

View File

@@ -1,139 +1,250 @@
package Common
import (
"bufio"
"encoding/json"
"fmt"
"github.com/fatih/color"
"io"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
"github.com/fatih/color"
)
// 记录扫描状态的全局变量
var (
Num int64 // 总任务数
End int64 // 已完成数
Results = make(chan *string) // 结果通道
LogSucTime int64 // 最近成功日志时间
LogErrTime int64 // 最近错误日志时间
WaitTime int64 // 等待时间
Silent bool // 静默模式
Nocolor bool // 禁用颜色
JsonOutput bool // JSON输出
LogWG sync.WaitGroup // 日志同步等待组
// 全局变量
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
results = make(chan *LogEntry, 1000) // 使用缓冲通道
logWG sync.WaitGroup
// 扫描计数
Num int64 // 总任务数
End int64 // 已完成任务数
)
// JsonText JSON输出的结构体
type JsonText struct {
Type string `json:"type"` // 消息类型
Text string `json:"text"` // 消息内容
// 将 results 改名为 Results 使其可导出
var (
Results = results // 使 results 可导出
LogWG = logWG // 使 logWG 可导出
)
// ScanStatus 记录扫描状态
type ScanStatus struct {
mu sync.RWMutex
total int64
completed int64
lastSuccess time.Time
lastError time.Time
}
// LogEntry 日志条目
type LogEntry struct {
Level string // "ERROR", "INFO", "SUCCESS", "DEBUG"
Time time.Time
Content string
}
// LogLevel 定义日志等级常量
const (
LogLevelAll = "ALL" // 输出所有日志
LogLevelError = "ERROR" // 错误日志
LogLevelInfo = "INFO" // 信息日志
LogLevelSuccess = "SUCCESS" // 成功日志
LogLevelDebug = "DEBUG" // 调试日志
)
// 定义日志颜色映射
var logColors = map[string]color.Attribute{
LogLevelError: color.FgRed,
LogLevelInfo: color.FgYellow,
LogLevelSuccess: color.FgGreen,
LogLevelDebug: color.FgBlue,
}
// bufferedFileWriter 文件写入器
type bufferedFileWriter struct {
file *os.File
writer *bufio.Writer
jsonEnc *json.Encoder
}
// init 初始化日志配置
func init() {
log.SetOutput(io.Discard)
LogSucTime = time.Now().Unix()
go SaveLog()
go processLogs()
}
// formatLogMessage 格式化日志消息
func formatLogMessage(entry *LogEntry) string {
timeStr := entry.Time.Format("2006-01-02 15:04:05")
return fmt.Sprintf("[%s] [%s] %s", timeStr, entry.Level, entry.Content)
}
func printLog(entry *LogEntry) {
// 根据配置的日志级别过滤
if LogLevel != LogLevelAll && entry.Level != LogLevel {
return
}
logMsg := formatLogMessage(entry)
if NoColor {
fmt.Println(logMsg)
return
}
if colorAttr, ok := logColors[entry.Level]; ok {
color.New(colorAttr).Println(logMsg)
} else {
fmt.Println(logMsg)
}
}
// 同样修改 LogError 和 LogInfo
func LogError(errMsg string) {
// 获取调用者信息
_, file, line, ok := runtime.Caller(1)
if !ok {
file = "unknown"
line = 0
}
// 只获取文件名
file = filepath.Base(file)
// 格式化错误消息
errorMsg := fmt.Sprintf("%s:%d - %s", file, line, errMsg)
select {
case Results <- &LogEntry{
Level: LogLevelError,
Time: time.Now(),
Content: errorMsg,
}:
logWG.Add(1)
default:
printLog(&LogEntry{
Level: LogLevelError,
Time: time.Now(),
Content: errorMsg,
})
}
}
func LogInfo(msg string) {
select {
case Results <- &LogEntry{
Level: LogLevelInfo,
Time: time.Now(),
Content: msg,
}:
logWG.Add(1)
default:
printLog(&LogEntry{
Level: LogLevelInfo,
Time: time.Now(),
Content: msg,
})
}
}
// LogSuccess 记录成功信息
func LogSuccess(result string) {
LogWG.Add(1)
LogSucTime = time.Now().Unix()
Results <- &result
}
// SaveLog 保存日志信息
func SaveLog() {
for result := range Results {
// 打印日志
if !Silent {
if Nocolor {
fmt.Println(*result)
} else {
switch {
case strings.HasPrefix(*result, "[+] 信息扫描"):
color.Green(*result)
case strings.HasPrefix(*result, "[+]"):
color.Red(*result)
default:
fmt.Println(*result)
}
}
}
// 保存到文件
if IsSave {
WriteFile(*result, Outputfile)
}
LogWG.Done()
// 添加通道关闭检查
select {
case Results <- &LogEntry{
Level: LogLevelSuccess,
Time: time.Now(),
Content: result,
}:
logWG.Add(1)
status.mu.Lock()
status.lastSuccess = time.Now()
status.mu.Unlock()
default:
// 如果通道已关闭或已满,直接打印
printLog(&LogEntry{
Level: LogLevelSuccess,
Time: time.Now(),
Content: result,
})
}
}
// WriteFile 写入文件
func WriteFile(result string, filename string) {
// 打开文件
fl, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
// JsonOutput JSON输出的结构体
type JsonOutput struct {
Level string `json:"level"`
Timestamp time.Time `json:"timestamp"`
Message string `json:"message"`
}
// processLogs 处理日志信息
func processLogs() {
writer := newBufferedFileWriter()
defer writer.close()
for entry := range results {
if !Silent {
printLog(entry)
}
if writer != nil {
writer.write(entry)
}
logWG.Done()
}
}
func newBufferedFileWriter() *bufferedFileWriter {
if DisableSave {
return nil
}
file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("[-] 打开文件失败 %s: %v\n", filename, err)
fmt.Printf("[ERROR] 打开输出文件失败 %s: %v\n", Outputfile, err)
return nil
}
writer := bufio.NewWriter(file)
return &bufferedFileWriter{
file: file,
writer: writer,
jsonEnc: json.NewEncoder(writer),
}
}
func (w *bufferedFileWriter) write(entry *LogEntry) {
if w == nil {
return
}
defer fl.Close()
if JsonOutput {
// 解析JSON格式
var scantype, text string
if strings.HasPrefix(result, "[+]") || strings.HasPrefix(result, "[*]") || strings.HasPrefix(result, "[-]") {
index := strings.Index(result[4:], " ")
if index == -1 {
scantype = "msg"
text = result[4:]
} else {
scantype = result[4 : 4+index]
text = result[4+index+1:]
}
} else {
scantype = "msg"
text = result
if JsonFormat {
output := JsonOutput{
Level: entry.Level,
Timestamp: entry.Time,
Message: entry.Content,
}
// 构造JSON对象
jsonText := JsonText{
Type: scantype,
Text: text,
if err := w.jsonEnc.Encode(output); err != nil {
fmt.Printf("[ERROR] JSON编码失败: %v\n", err)
}
// 序列化JSON
jsonData, err := json.Marshal(jsonText)
if err != nil {
fmt.Printf("[-] JSON序列化失败: %v\n", err)
jsonText = JsonText{
Type: "msg",
Text: result,
}
jsonData, _ = json.Marshal(jsonText)
}
jsonData = append(jsonData, []byte(",\n")...)
_, err = fl.Write(jsonData)
} else {
_, err = fl.Write([]byte(result + "\n"))
logMsg := formatLogMessage(entry) + "\n"
if _, err := w.writer.WriteString(logMsg); err != nil {
fmt.Printf("[ERROR] 写入文件失败: %v\n", err)
}
}
if err != nil {
fmt.Printf("[-] 写入文件失败 %s: %v\n", filename, err)
}
w.writer.Flush()
}
// LogError 记录错误信息
func LogError(errinfo interface{}) {
if WaitTime == 0 {
fmt.Printf("[*] 已完成 %v/%v %v\n", End, Num, errinfo)
} else if (time.Now().Unix()-LogSucTime) > WaitTime && (time.Now().Unix()-LogErrTime) > WaitTime {
fmt.Printf("[*] 已完成 %v/%v %v\n", End, Num, errinfo)
LogErrTime = time.Now().Unix()
func (w *bufferedFileWriter) close() {
if w != nil {
w.writer.Flush()
w.file.Close()
}
}

View File

@@ -19,7 +19,7 @@ func Parse(Info *HostInfo) error {
return nil
}
// ParseUser 解析用户名配置,支持直接指定用户名列表或从文件读取
// ParseUser 解析用户名配置
func ParseUser() error {
// 如果未指定用户名和用户名文件,直接返回
if Username == "" && UsersFile == "" {
@@ -31,7 +31,7 @@ func ParseUser() error {
// 处理直接指定的用户名列表
if Username != "" {
usernames = strings.Split(Username, ",")
fmt.Printf("[*] 已加载直接指定的用户名: %d 个\n", len(usernames))
LogInfo(fmt.Sprintf("加载用户名: %d 个", len(usernames)))
}
// 从文件加载用户名列表
@@ -47,12 +47,12 @@ func ParseUser() error {
usernames = append(usernames, user)
}
}
fmt.Printf("[*] 已从文件加载用户名: %d 个\n", len(users))
LogInfo(fmt.Sprintf("从文件加载用户名: %d 个", len(users)))
}
// 去重处理
usernames = RemoveDuplicate(usernames)
fmt.Printf("[*] 去重后用户名总数: %d 个\n", len(usernames))
LogInfo(fmt.Sprintf("用户名总数: %d 个", len(usernames)))
// 更新用户字典
for name := range Userdict {
@@ -74,7 +74,7 @@ func ParsePass(Info *HostInfo) error {
}
}
Passwords = pwdList
fmt.Printf("[*] 已加载直接指定的密码: %d 个\n", len(pwdList))
LogInfo(fmt.Sprintf("加载密码: %d 个", len(pwdList)))
}
// 从文件加载密码列表
@@ -89,7 +89,7 @@ func ParsePass(Info *HostInfo) error {
}
}
Passwords = pwdList
fmt.Printf("[*] 已从文件加载密码: %d 个\n", len(passes))
LogInfo(fmt.Sprintf("从文件加载密码: %d 个", len(passes)))
}
// 处理哈希文件
@@ -108,10 +108,10 @@ func ParsePass(Info *HostInfo) error {
HashValues = append(HashValues, line)
validCount++
} else {
fmt.Printf("[-] 无效的哈希值(长度!=32): %s\n", line)
LogError(fmt.Sprintf("无效的哈希值: %s (长度!=32)", line))
}
}
fmt.Printf("[*] 已加载有效哈希值: %d 个\n", validCount)
LogInfo(fmt.Sprintf("加载有效哈希值: %d 个", validCount))
}
// 处理直接指定的URL列表
@@ -126,7 +126,7 @@ func ParsePass(Info *HostInfo) error {
}
}
}
fmt.Printf("[*] 已加载直接指定的URL: %d 个\n", len(URLs))
LogInfo(fmt.Sprintf("加载URL: %d 个", len(URLs)))
}
// 从文件加载URL列表
@@ -145,7 +145,7 @@ func ParsePass(Info *HostInfo) error {
}
}
}
fmt.Printf("[*] 已从文件加载URL: %d 个\n", len(urls))
LogInfo(fmt.Sprintf("从文件加载URL: %d 个", len(urls)))
}
// 从文件加载端口列表
@@ -163,7 +163,7 @@ func ParsePass(Info *HostInfo) error {
}
}
Ports = newport.String()
fmt.Printf("[*] 已从文件加载端口配置\n")
LogInfo("从文件加载端口配置")
}
return nil
@@ -174,7 +174,7 @@ func Readfile(filename string) ([]string, error) {
// 打开文件
file, err := os.Open(filename)
if err != nil {
fmt.Printf("[-] 打开文件 %s 失败: %v\n", filename, err)
LogError(fmt.Sprintf("打开文件失败 %s: %v", filename, err))
return nil, err
}
defer file.Close()
@@ -195,11 +195,11 @@ func Readfile(filename string) ([]string, error) {
// 检查扫描过程中是否有错误
if err := scanner.Err(); err != nil {
fmt.Printf("[- 读取文件 %s 时出错: %v\n", filename, err)
LogError(fmt.Sprintf("读取文件错误 %s: %v", filename, err))
return nil, err
}
fmt.Printf("[*] 成功读取文件 %s: %d 行\n", filename, lineCount)
LogInfo(fmt.Sprintf("读取文件成功 %s: %d 行", filename, lineCount))
return content, nil
}
@@ -207,25 +207,25 @@ func Readfile(filename string) ([]string, error) {
func ParseInput(Info *HostInfo) error {
// 检查必要的目标参数
if Info.Host == "" && HostsFile == "" && TargetURL == "" && URLsFile == "" {
fmt.Println("[-] 未指定扫描目标")
LogError("未指定扫描目标")
flag.Usage()
return fmt.Errorf("必须指定扫描目标")
}
// 如果是本地扫描模式,输出提示
if LocalScan {
fmt.Println("[*] 已启用本地扫描模式")
LogInfo("已启用本地扫描模式")
}
// 配置基本参数
if BruteThreads <= 0 {
BruteThreads = 1
fmt.Printf("[*] 已将暴力破解线程数设置为: %d\n", BruteThreads)
LogInfo(fmt.Sprintf("暴力破解线程数: %d", BruteThreads))
}
if DisableSave {
IsSave = false
fmt.Println("[*] 已启用临时保存模式")
LogInfo("已启用临时保存模式")
}
// 处理端口配置
@@ -239,7 +239,7 @@ func ParseInput(Info *HostInfo) error {
} else {
Ports += "," + AddPorts
}
fmt.Printf("[*] 已添加额外端口: %s\n", AddPorts)
LogInfo(fmt.Sprintf("额外端口: %s", AddPorts))
}
// 处理用户名配置
@@ -249,7 +249,7 @@ func ParseInput(Info *HostInfo) error {
Userdict[dict] = append(Userdict[dict], users...)
Userdict[dict] = RemoveDuplicate(Userdict[dict])
}
fmt.Printf("[*] 已添加额外用户名: %s\n", AddUsers)
LogInfo(fmt.Sprintf("额外用户名: %s", AddUsers))
}
// 处理密码配置
@@ -257,7 +257,7 @@ func ParseInput(Info *HostInfo) error {
passes := strings.Split(AddPasswords, ",")
Passwords = append(Passwords, passes...)
Passwords = RemoveDuplicate(Passwords)
fmt.Printf("[*] 已添加额外密码: %s\n", AddPasswords)
LogInfo(fmt.Sprintf("额外密码: %s", AddPasswords))
}
// 处理Socks5代理配置
@@ -275,7 +275,7 @@ func ParseInput(Info *HostInfo) error {
return fmt.Errorf("Socks5代理格式错误: %v", err)
}
DisablePing = true
fmt.Printf("[*] 使用Socks5代理: %s\n", Socks5Proxy)
LogInfo(fmt.Sprintf("Socks5代理: %s", Socks5Proxy))
}
// 处理HTTP代理配置
@@ -299,7 +299,7 @@ func ParseInput(Info *HostInfo) error {
if err != nil {
return fmt.Errorf("代理格式错误: %v", err)
}
fmt.Printf("[*] 使用代理: %s\n", HttpProxy)
LogInfo(fmt.Sprintf("HTTP代理: %s", HttpProxy))
}
// 处理Hash配置
@@ -315,7 +315,7 @@ func ParseInput(Info *HostInfo) error {
for _, hash := range HashValues {
hashByte, err := hex.DecodeString(hash)
if err != nil {
fmt.Printf("[-] Hash解码失败: %s\n", hash)
LogError(fmt.Sprintf("Hash解码失败: %s", hash))
continue
}
HashBytes = append(HashBytes, hashByte)

View File

@@ -23,16 +23,16 @@ var ParseIPErr = errors.New("主机解析错误\n" +
"192.168.1.1-192.168.255.255 (IP范围)\n" +
"192.168.1.1-255 (最后一位简写范围)")
// ParseIP 解析IP地址配置,支持从主机字符串和文件读取
// ParseIP 解析IP地址配置
func ParseIP(host string, filename string, nohosts ...string) (hosts []string, err error) {
// 处理主机和端口组合的情况 (192.168.0.0/16:80)
// 处理主机和端口组合的情况
if filename == "" && strings.Contains(host, ":") {
hostport := strings.Split(host, ":")
if len(hostport) == 2 {
host = hostport[0]
hosts = ParseIPs(host)
Ports = hostport[1]
fmt.Printf("[*] 已解析主机端口组合,端口设置为: %s\n", Ports)
LogInfo(fmt.Sprintf("已解析主机端口组合,端口设置为: %s", Ports))
}
} else {
// 解析主机地址
@@ -42,10 +42,10 @@ func ParseIP(host string, filename string, nohosts ...string) (hosts []string, e
if filename != "" {
fileHosts, err := Readipfile(filename)
if err != nil {
fmt.Printf("[-] 读取主机文件失败: %v\n", err)
LogError(fmt.Sprintf("读取主机文件失败: %v", err))
} else {
hosts = append(hosts, fileHosts...)
fmt.Printf("[*] 已从文件加载额外主机: %d 个\n", len(fileHosts))
LogInfo(fmt.Sprintf("从文件加载额外主机: %d 个", len(fileHosts)))
}
}
}
@@ -72,13 +72,13 @@ func ParseIP(host string, filename string, nohosts ...string) (hosts []string, e
}
hosts = newHosts
sort.Strings(hosts)
fmt.Printf("[*] 已排除指定主机: %d 个\n", len(excludeHosts))
LogInfo(fmt.Sprintf("已排除指定主机: %d 个", len(excludeHosts)))
}
}
// 去重处理
hosts = RemoveDuplicate(hosts)
fmt.Printf("[*] 最终有效主机数量: %d\n", len(hosts))
LogInfo(fmt.Sprintf("最终有效主机数量: %d", len(hosts)))
// 检查解析结果
if len(hosts) == 0 && len(HostPort) == 0 && (host != "" || filename != "") {
@@ -102,40 +102,28 @@ func ParseIPs(ip string) (hosts []string) {
return hosts
}
// parseIP 解析不同格式的IP地址,返回解析后的IP列表
func parseIP(ip string) []string {
reg := regexp.MustCompile(`[a-zA-Z]+`)
switch {
// 处理常用内网IP段简写
case ip == "192":
return parseIP("192.168.0.0/8")
case ip == "172":
return parseIP("172.16.0.0/12")
case ip == "10":
return parseIP("10.0.0.0/8")
// 处理/8网段 - 仅扫描网关和随机IP以避免过多扫描
case strings.HasSuffix(ip, "/8"):
return parseIP8(ip)
// 处理CIDR格式 (/24 /16 /8等)
case strings.Contains(ip, "/"):
return parseIP2(ip)
// 处理域名 - 保留域名格式
case reg.MatchString(ip):
return []string{ip}
// 处理IP范围格式 (192.168.1.1-192.168.1.100)
case strings.Contains(ip, "-"):
return parseIP1(ip)
// 处理单个IP地址
default:
testIP := net.ParseIP(ip)
if testIP == nil {
fmt.Printf("[-] 无效的IP地址格式: %s\n", ip)
LogError(fmt.Sprintf("无效的IP格式: %s", ip))
return nil
}
return []string{ip}
@@ -144,18 +132,15 @@ func parseIP(ip string) []string {
// parseIP2 解析CIDR格式的IP地址段
func parseIP2(host string) []string {
// 解析CIDR
_, ipNet, err := net.ParseCIDR(host)
if err != nil {
fmt.Printf("[-] CIDR格式解析失败: %s, %v\n", host, err)
LogError(fmt.Sprintf("CIDR格式解析失败: %s, %v", host, err))
return nil
}
// 转换为IP范围并解析
ipRange := IPRange(ipNet)
hosts := parseIP1(ipRange)
fmt.Printf("[*] 已解析CIDR %s -> IP范围 %s\n", host, ipRange)
LogInfo(fmt.Sprintf("解析CIDR %s -> IP范围 %s", host, ipRange))
return hosts
}
@@ -169,50 +154,46 @@ func parseIP1(ip string) []string {
if len(ipRange[1]) < 4 {
endNum, err := strconv.Atoi(ipRange[1])
if testIP == nil || endNum > 255 || err != nil {
fmt.Printf("[-] IP范围格式错误: %s\n", ip)
LogError(fmt.Sprintf("IP范围格式错误: %s", ip))
return nil
}
// 解析IP段
splitIP := strings.Split(ipRange[0], ".")
startNum, err1 := strconv.Atoi(splitIP[3])
endNum, err2 := strconv.Atoi(ipRange[1])
prefixIP := strings.Join(splitIP[0:3], ".")
if startNum > endNum || err1 != nil || err2 != nil {
fmt.Printf("[-] IP范围无效: %d-%d\n", startNum, endNum)
LogError(fmt.Sprintf("IP范围无效: %d-%d", startNum, endNum))
return nil
}
// 生成IP列表
for i := startNum; i <= endNum; i++ {
allIP = append(allIP, prefixIP+"."+strconv.Itoa(i))
}
fmt.Printf("[*] 已生成IP范围: %s.%d - %s.%d\n", prefixIP, startNum, prefixIP, endNum)
LogInfo(fmt.Sprintf("生成IP范围: %s.%d - %s.%d", prefixIP, startNum, prefixIP, endNum))
} else {
// 处理完整IP范围格式 (192.168.111.1-192.168.112.255)
// 处理完整IP范围格式
splitIP1 := strings.Split(ipRange[0], ".")
splitIP2 := strings.Split(ipRange[1], ".")
if len(splitIP1) != 4 || len(splitIP2) != 4 {
fmt.Printf("[-] IP格式错误: %s\n", ip)
LogError(fmt.Sprintf("IP格式错误: %s", ip))
return nil
}
// 解析起始和结束IP
start, end := [4]int{}, [4]int{}
for i := 0; i < 4; i++ {
ip1, err1 := strconv.Atoi(splitIP1[i])
ip2, err2 := strconv.Atoi(splitIP2[i])
if ip1 > ip2 || err1 != nil || err2 != nil {
fmt.Printf("[-] IP范围无效: %s-%s\n", ipRange[0], ipRange[1])
LogError(fmt.Sprintf("IP范围无效: %s-%s", ipRange[0], ipRange[1]))
return nil
}
start[i], end[i] = ip1, ip2
}
// 将IP转换为数值并生成范围内的所有IP
startNum := start[0]<<24 | start[1]<<16 | start[2]<<8 | start[3]
endNum := end[0]<<24 | end[1]<<16 | end[2]<<8 | end[3]
@@ -224,7 +205,7 @@ func parseIP1(ip string) []string {
allIP = append(allIP, ip)
}
fmt.Printf("[*] 已生成IP范围: %s - %s\n", ipRange[0], ipRange[1])
LogInfo(fmt.Sprintf("生成IP范围: %s - %s", ipRange[0], ipRange[1]))
}
return allIP
@@ -232,36 +213,27 @@ func parseIP1(ip string) []string {
// IPRange 计算CIDR的起始IP和结束IP
func IPRange(c *net.IPNet) string {
// 获取起始IP
start := c.IP.String()
// 获取子网掩码
mask := c.Mask
// 计算广播地址(结束IP)
bcst := make(net.IP, len(c.IP))
copy(bcst, c.IP)
// 通过位运算计算最大IP地址
for i := 0; i < len(mask); i++ {
ipIdx := len(bcst) - i - 1
bcst[ipIdx] = c.IP[ipIdx] | ^mask[len(mask)-i-1]
}
end := bcst.String()
// 返回"起始IP-结束IP"格式的字符串
result := fmt.Sprintf("%s-%s", start, end)
fmt.Printf("[*] CIDR范围: %s\n", result)
LogInfo(fmt.Sprintf("CIDR范围: %s", result))
return result
}
// Readipfile 从文件中按行读取IP地址
func Readipfile(filename string) ([]string, error) {
// 打开文件
file, err := os.Open(filename)
if err != nil {
fmt.Printf("[-] 打开文件失败 %s: %v\n", filename, err)
LogError(fmt.Sprintf("打开文件失败 %s: %v", filename, err))
return nil, err
}
defer file.Close()
@@ -270,54 +242,47 @@ func Readipfile(filename string) ([]string, error) {
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
// 逐行处理IP
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" {
continue
}
// 解析IP:端口格式
text := strings.Split(line, ":")
if len(text) == 2 {
port := strings.Split(text[1], " ")[0]
num, err := strconv.Atoi(port)
if err != nil || num < 1 || num > 65535 {
fmt.Printf("[-] 忽略无效端口: %s\n", line)
LogError(fmt.Sprintf("忽略无效端口: %s", line))
continue
}
// 解析带端口的IP地址
hosts := ParseIPs(text[0])
for _, host := range hosts {
HostPort = append(HostPort, fmt.Sprintf("%s:%s", host, port))
}
fmt.Printf("[*] 已解析IP端口组合: %s\n", line)
LogInfo(fmt.Sprintf("解析IP端口组合: %s", line))
} else {
// 解析纯IP地址
hosts := ParseIPs(line)
content = append(content, hosts...)
fmt.Printf("[*] 已解析IP地址: %s\n", line)
LogInfo(fmt.Sprintf("解析IP地址: %s", line))
}
}
// 检查扫描过程中是否有错误
if err := scanner.Err(); err != nil {
fmt.Printf("[-] 读取文件时出错: %v\n", err)
LogError(fmt.Sprintf("读取文件错: %v", err))
return content, err
}
fmt.Printf("[*] 从文件加载完成,共解析 %d 个IP地址\n", len(content))
LogInfo(fmt.Sprintf("从文件解析完成: %d 个IP地址", len(content)))
return content, nil
}
// RemoveDuplicate 对字符串切片进行去重
func RemoveDuplicate(old []string) []string {
// 使用map存储不重复的元素
temp := make(map[string]struct{})
var result []string
// 遍历并去重
for _, item := range old {
if _, exists := temp[item]; !exists {
temp[item] = struct{}{}
@@ -335,7 +300,7 @@ func parseIP8(ip string) []string {
testIP := net.ParseIP(realIP)
if testIP == nil {
fmt.Printf("[-] 无效的IP地址格式: %s\n", realIP)
LogError(fmt.Sprintf("无效的IP格式: %s", realIP))
return nil
}
@@ -343,7 +308,7 @@ func parseIP8(ip string) []string {
ipRange := strings.Split(ip, ".")[0]
var allIP []string
fmt.Printf("[*] 开始解析 %s.0.0.0/8 网段\n", ipRange)
LogInfo(fmt.Sprintf("解析网段: %s.0.0.0/8", ipRange))
// 遍历所有可能的第二、三段
for a := 0; a <= 255; a++ {
@@ -364,17 +329,14 @@ func parseIP8(ip string) []string {
}
}
fmt.Printf("[*] 已生成 %d 个采样IP地址\n", len(allIP))
LogInfo(fmt.Sprintf("生成采样IP: %d 个", len(allIP)))
return allIP
}
// RandInt 生成指定范围内的随机整数
func RandInt(min, max int) int {
// 参数验证
if min >= max || min == 0 || max == 0 {
return max
}
// 生成随机数
return rand.Intn(max-min) + min
}

View File

@@ -42,7 +42,7 @@ func ParsePort(ports string) []int {
if strings.Contains(port, "-") {
ranges := strings.Split(port, "-")
if len(ranges) < 2 {
fmt.Printf("[-] 无效的端口范围格式: %s\n", port)
LogError(fmt.Sprintf("端口范围格式错误: %s", port))
continue
}
@@ -63,7 +63,7 @@ func ParsePort(ports string) []int {
end, _ := strconv.Atoi(upper)
for i := start; i <= end; i++ {
if i > 65535 || i < 1 {
fmt.Printf("[-] 忽略无效端口: %d\n", i)
LogError(fmt.Sprintf("忽略无效端口: %d", i))
continue
}
scanPorts = append(scanPorts, i)
@@ -74,17 +74,15 @@ func ParsePort(ports string) []int {
scanPorts = removeDuplicate(scanPorts)
sort.Ints(scanPorts)
fmt.Printf("[*] 共解析 %d 个有效端口\n", len(scanPorts))
LogInfo(fmt.Sprintf("有效端口数量: %d", len(scanPorts)))
return scanPorts
}
// removeDuplicate 对整数切片进行去重
func removeDuplicate(old []int) []int {
// 使用map存储不重复的元素
temp := make(map[int]struct{})
var result []int
// 遍历并去重
for _, item := range old {
if _, exists := temp[item]; !exists {
temp[item] = struct{}{}

View File

@@ -48,7 +48,7 @@ var pluginGroups = map[string][]string{
// ParseScanMode 解析扫描模式
func ParseScanMode(mode string) {
fmt.Printf("[*] 解析扫描模式: %s\n", mode)
LogInfo(fmt.Sprintf("解析扫描模式: %s", mode))
// 检查是否是预设模式
presetModes := []string{
@@ -60,9 +60,9 @@ func ParseScanMode(mode string) {
if mode == presetMode {
ScanMode = mode
if plugins := GetPluginsForMode(mode); plugins != nil {
fmt.Printf("[+] 使用预设模式: %s, 包含插件: %v\n", mode, plugins)
LogInfo(fmt.Sprintf("使用预设模式: %s, 包含插件: %v", mode, plugins))
} else {
fmt.Printf("[+] 使用预设模式: %s\n", mode)
LogInfo(fmt.Sprintf("使用预设模式: %s", mode))
}
return
}
@@ -71,14 +71,14 @@ func ParseScanMode(mode string) {
// 检查是否是有效的插件名
if _, exists := PluginManager[mode]; exists {
ScanMode = mode
fmt.Printf("[+] 使用单个插件: %s\n", mode)
LogInfo(fmt.Sprintf("使用单个插件: %s", mode))
return
}
// 默认使用All模式
ScanMode = ModeAll
fmt.Printf("[*] 未识别的模式,使用默认模式: %s\n", ModeAll)
fmt.Printf("[+] 包含插件: %v\n", pluginGroups[ModeAll])
LogInfo(fmt.Sprintf("未识别的模式,使用默认模式: %s", ModeAll))
LogInfo(fmt.Sprintf("包含插件: %v", pluginGroups[ModeAll]))
}
// GetPluginsForMode 获取指定模式下的插件列表