diff --git a/.gitignore b/.gitignore index 8bd5e0a..a6e63a1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ result.txt main .idea fscan.exe +fscan diff --git a/Common/Config.go b/Common/Config.go index 9037854..ffbe57d 100644 --- a/Common/Config.go +++ b/Common/Config.go @@ -26,7 +26,7 @@ var Userdict = map[string][]string{ "neo4j": {"neo4j", "admin", "root", "test"}, } -var Passwords = []string{"123456", "admin", "admin123", "root", "", "pass123", "pass@123", "password", "P@ssword123", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456", "1q2w3e", "Charge123", "Aa123456789", "elastic123"} +var Passwords = []string{"123456", "admin", "admin123", "root", "", "pass123", "pass@123", "password", "Password", "P@ssword123", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456", "1q2w3e", "Charge123", "Aa123456789", "elastic123"} var Outputfile = "result.txt" var IsSave = true @@ -92,6 +92,7 @@ var ( // 爆破配置 DisableBrute bool // 原IsBrute BruteThreads int // 原BruteThread + MaxRetries int // 最大重试次数 // 其他配置 RemotePath string // 原Path diff --git a/Common/Flag.go b/Common/Flag.go index 8f04032..be655ce 100644 --- a/Common/Flag.go +++ b/Common/Flag.go @@ -114,6 +114,7 @@ func Flag(Info *HostInfo) { // 暴力破解配置 flag.BoolVar(&DisableBrute, "nobr", false, "禁用密码暴力破解") flag.IntVar(&BruteThreads, "br", 1, "设置密码破解线程数") + flag.IntVar(&MaxRetries, "retry", 3, "设置最大重试次数") // 其他配置 flag.StringVar(&RemotePath, "path", "", "指定FCG/SMB远程文件路径") diff --git a/Common/Log.go b/Common/Log.go index c7e0dae..bfa6f96 100644 --- a/Common/Log.go +++ b/Common/Log.go @@ -137,13 +137,13 @@ func LogError(errinfo interface{}) { } } -// CheckErrs 检查是否为已知错误 -func CheckErrs(err error) bool { +// CheckErrs 检查是否为需要重试的错误 +func CheckErrs(err error) error { if err == nil { - return false + return nil } - // 已知错误列表 + // 已知需要重试的错误列表 errs := []string{ "closed by the remote host", "too many connections", "EOF", "A connection attempt failed", @@ -159,9 +159,10 @@ func CheckErrs(err error) bool { errLower := strings.ToLower(err.Error()) for _, key := range errs { if strings.Contains(errLower, strings.ToLower(key)) { - return true + time.Sleep(3 * time.Second) + return err } } - return false + return nil } diff --git a/Plugins/ActiveMQ.go b/Plugins/ActiveMQ.go index 31b1ed6..7110199 100644 --- a/Plugins/ActiveMQ.go +++ b/Plugins/ActiveMQ.go @@ -5,6 +5,7 @@ import ( "github.com/shadow1ng/fscan/Common" "net" "strings" + "sync" "time" ) @@ -14,39 +15,127 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads // 首先测试默认账户 - flag, err := ActiveMQConn(info, "admin", "admin") - if flag { - return nil + for retryCount := 0; retryCount < maxRetries; retryCount++ { + flag, err := ActiveMQConn(info, "admin", "admin") + if flag { + return nil + } + if err != nil { + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + return err + } + continue + } + } + break } - tmperr = err - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["activemq"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["activemq"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := ActiveMQConn(info, user, pass) - if flag { - return nil + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行连接测试 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + flag, err := ActiveMQConn(info, user, pass) + done <- struct { + success bool + err error + }{flag, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + if err != nil { + errlog := fmt.Sprintf("[-] ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue + } + } + + break + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["activemq"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/Cassandra.go b/Plugins/Cassandra.go index ea4c4da..efe6285 100644 --- a/Plugins/Cassandra.go +++ b/Plugins/Cassandra.go @@ -6,6 +6,7 @@ import ( "github.com/shadow1ng/fscan/Common" "strconv" "strings" + "sync" "time" ) @@ -14,37 +15,126 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) { return } + maxRetries := Common.MaxRetries + threads := Common.BruteThreads starttime := time.Now().Unix() // 首先测试无认证访问 - flag, err := CassandraConn(info, "", "") - if flag && err == nil { - return err + for retryCount := 0; retryCount < maxRetries; retryCount++ { + flag, err := CassandraConn(info, "", "") + if flag && err == nil { + return err + } + if err != nil && Common.CheckErrs(err) != nil { + if retryCount == maxRetries-1 { + return err + } + continue + } + break } - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["cassandra"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["cassandra"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := CassandraConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := CassandraConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["cassandra"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/Elasticsearch.go b/Plugins/Elasticsearch.go index 2536265..a5a3371 100644 --- a/Plugins/Elasticsearch.go +++ b/Plugins/Elasticsearch.go @@ -7,6 +7,7 @@ import ( "github.com/shadow1ng/fscan/Common" "net/http" "strings" + "sync" "time" ) @@ -16,40 +17,127 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads // 首先测试无认证访问 - flag, err := ElasticConn(info, "", "") - if flag && err == nil { - return err + for retryCount := 0; retryCount < maxRetries; retryCount++ { + flag, err := ElasticConn(info, "", "") + if flag && err == nil { + return err + } + if err != nil && Common.CheckErrs(err) != nil { + if retryCount == maxRetries-1 { + return err + } + continue + } + break } - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["elastic"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["elastic"] { for _, pass := range Common.Passwords { - // 替换密码中的用户名占位符 pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := ElasticConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行连接尝试 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + flag, err := ElasticConn(info, user, pass) + done <- struct { + success bool + err error + }{flag, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - // 记录错误信息 - errlog := fmt.Sprintf("[-] Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - // 超时检查 - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["elastic"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/FTP.go b/Plugins/FTP.go index 960ba4b..3993a62 100644 --- a/Plugins/FTP.go +++ b/Plugins/FTP.go @@ -5,57 +5,140 @@ import ( "github.com/jlaffaye/ftp" "github.com/shadow1ng/fscan/Common" "strings" + "sync" "time" ) // FtpScan 执行FTP服务扫描 func FtpScan(info *Common.HostInfo) (tmperr error) { - // 如果已开启暴力破解则直接返回 if Common.DisableBrute { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 尝试匿名登录 - flag, err := FtpConn(info, "anonymous", "") - if flag && err == nil { - // 匿名登录成功,不需要继续尝试其他密码 - return nil - } - errlog := fmt.Sprintf("[-] ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err) - Common.LogError(errlog) - tmperr = err - if Common.CheckErrs(err) { - return err + // 先尝试匿名登录 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + flag, err := FtpConn(info, "anonymous", "") + if flag && err == nil { + return nil + } + errlog := fmt.Sprintf("[-] ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err) + Common.LogError(errlog) + + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + return err + } + continue + } + break } - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["ftp"])*len(Common.Passwords)) + + 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) - flag, err := FtpConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行FTP连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := FtpConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - // 记录错误信息 - errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - // 超时检查 - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["ftp"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/IMAP.go b/Plugins/IMAP.go index fb6e269..f877d96 100644 --- a/Plugins/IMAP.go +++ b/Plugins/IMAP.go @@ -8,6 +8,7 @@ import ( "io" "net" "strings" + "sync" "time" ) @@ -16,31 +17,107 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 尝试用户名密码组合 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["imap"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["imap"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := IMAPConn(info, user, pass) - if flag && err == nil { - return err + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行IMAP连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := IMAPConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue + } + } + + break + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + go func() { + wg.Wait() + close(resultChan) + }() + + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["imap"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/Kafka.go b/Plugins/Kafka.go index 698dcf1..d4d4047 100644 --- a/Plugins/Kafka.go +++ b/Plugins/Kafka.go @@ -5,6 +5,7 @@ import ( "github.com/IBM/sarama" "github.com/shadow1ng/fscan/Common" "strings" + "sync" "time" ) @@ -14,37 +15,127 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads // 首先测试无认证访问 - flag, err := KafkaConn(info, "", "") - if flag && err == nil { - return err + for retryCount := 0; retryCount < maxRetries; retryCount++ { + flag, err := KafkaConn(info, "", "") + if flag && err == nil { + return nil + } + if err != nil && Common.CheckErrs(err) != nil { + if retryCount < maxRetries-1 { + continue + } + return err + } + break } - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["kafka"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["kafka"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := KafkaConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行Kafka连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := KafkaConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["kafka"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/LDAP.go b/Plugins/LDAP.go index 23b6531..1a2e84f 100644 --- a/Plugins/LDAP.go +++ b/Plugins/LDAP.go @@ -5,6 +5,7 @@ import ( "github.com/go-ldap/ldap/v3" "github.com/shadow1ng/fscan/Common" "strings" + "sync" "time" ) @@ -14,38 +15,118 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 尝试匿名访问 + // 首先尝试匿名访问 flag, err := LDAPConn(info, "", "") if flag && err == nil { return err } - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["ldap"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["ldap"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := LDAPConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行LDAP连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := LDAPConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["ldap"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/MSSQL.go b/Plugins/MSSQL.go index c4ea972..6066ab1 100644 --- a/Plugins/MSSQL.go +++ b/Plugins/MSSQL.go @@ -6,6 +6,7 @@ import ( _ "github.com/denisenkom/go-mssqldb" "github.com/shadow1ng/fscan/Common" "strings" + "sync" "time" ) @@ -15,34 +16,108 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 尝试用户名密码组合 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["mssql"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["mssql"] { for _, pass := range Common.Passwords { - // 替换密码中的用户名占位符 pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := MssqlConn(info, user, pass) - if flag && err == nil { - return err + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行MSSQL连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := MssqlConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + if err != nil { + errlog := fmt.Sprintf("[-] MSSQL %v:%v %v %v %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - // 记录错误信息 - errlog := fmt.Sprintf("[-] MSSQL %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - // 超时检查 - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["mssql"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/MySQL.go b/Plugins/MySQL.go index 1b03a37..2d909dc 100644 --- a/Plugins/MySQL.go +++ b/Plugins/MySQL.go @@ -6,6 +6,7 @@ import ( _ "github.com/go-sql-driver/mysql" "github.com/shadow1ng/fscan/Common" "strings" + "sync" "time" ) @@ -15,34 +16,138 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 尝试用户名密码组合 + // 添加成功标志通道 + successChan := make(chan struct{}, 1) + defer close(successChan) + + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["mysql"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["mysql"] { for _, pass := range Common.Passwords { - // 替换密码中的用户名占位符 pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := MysqlConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 检查是否已经成功 + select { + case <-successChan: + resultChan <- nil + return + default: + } + + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行MySQL连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := MysqlConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + // 连接成功 + select { + case successChan <- struct{}{}: // 标记成功 + successLog := fmt.Sprintf("[+] MySQL %v:%v %v %v", + info.Host, info.Ports, task.user, task.pass) + Common.LogSuccess(successLog) + default: + } + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] MySQL %v:%v %v %v %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 特殊处理认证失败的情况 + if strings.Contains(err.Error(), "Access denied") { + break // 跳出重试循环,继续下一个密码 + } + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + break // 如果不需要重试,跳出重试循环 + } + } } + resultChan <- nil + }() + } - // 记录错误信息 - errlog := fmt.Sprintf("[-] MySQL %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - // 超时检查 - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["mysql"])*len(Common.Passwords)) * Common.Timeout) { - return err + if !strings.Contains(err.Error(), "Access denied") { + if retryErr := Common.CheckErrs(err); retryErr != nil { + return err + } } } } + return tmperr } @@ -74,8 +179,6 @@ func MysqlConn(info *Common.HostInfo, user string, pass string) (bool, error) { return false, err } - // 连接成功 - result := fmt.Sprintf("[+] MySQL %v:%v:%v %v", host, port, username, password) - Common.LogSuccess(result) + // 连接成功,只返回结果,不打印日志 return true, nil } diff --git a/Plugins/Neo4j.go b/Plugins/Neo4j.go index f8d0753..e7135b7 100644 --- a/Plugins/Neo4j.go +++ b/Plugins/Neo4j.go @@ -5,6 +5,7 @@ import ( "github.com/neo4j/neo4j-go-driver/v4/neo4j" "github.com/shadow1ng/fscan/Common" "strings" + "sync" "time" ) @@ -14,43 +15,128 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 首先测试无认证访问 - flag, err := Neo4jConn(info, "", "") - if flag && err == nil { - return err + // 首先测试无认证访问和默认凭证 + initialChecks := []struct { + user string + pass string + }{ + {"", ""}, // 无认证 + {"neo4j", "neo4j"}, // 默认凭证 } - // 测试默认凭证 - flag, err = Neo4jConn(info, "neo4j", "neo4j") - if flag && err == nil { - return err + for _, check := range initialChecks { + flag, err := Neo4jConn(info, check.user, check.pass) + if flag && err == nil { + return err + } } - // 尝试其他用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["neo4j"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["neo4j"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := Neo4jConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行Neo4j连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + flag, err := Neo4jConn(info, user, pass) + done <- struct { + success bool + err error + }{flag, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["neo4j"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } @@ -78,7 +164,7 @@ func Neo4jConn(info *Common.HostInfo, user string, pass string) (bool, error) { // 无认证时使用NoAuth driver, err = neo4j.NewDriver(uri, neo4j.NoAuth(), config) } - + if err != nil { return false, err } diff --git a/Plugins/Oracle.go b/Plugins/Oracle.go index ddab0e9..d90c94f 100644 --- a/Plugins/Oracle.go +++ b/Plugins/Oracle.go @@ -6,6 +6,7 @@ import ( "github.com/shadow1ng/fscan/Common" _ "github.com/sijms/go-ora/v2" "strings" + "sync" "time" ) @@ -15,34 +16,112 @@ func OracleScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["oracle"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["oracle"] { for _, pass := range Common.Passwords { - // 替换密码中的用户名占位符 pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := OracleConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行Oracle连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := OracleConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Oracle %v:%v %v %v %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - // 记录错误信息 - errlog := fmt.Sprintf("[-] Oracle %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - // 超时检查 - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["oracle"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/POP3.go b/Plugins/POP3.go index ee6d334..306b09a 100644 --- a/Plugins/POP3.go +++ b/Plugins/POP3.go @@ -7,6 +7,7 @@ import ( "github.com/shadow1ng/fscan/Common" "net" "strings" + "sync" "time" ) @@ -15,30 +16,116 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["pop3"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["pop3"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := POP3Conn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行POP3连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := POP3Conn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + // 连接成功 + successLog := fmt.Sprintf("[+] POP3服务 %v:%v 用户名: %v 密码: %v", + info.Host, info.Ports, task.user, task.pass) + Common.LogSuccess(successLog) + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["pop3"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/Postgres.go b/Plugins/Postgres.go index 0fa446b..cb10f55 100644 --- a/Plugins/Postgres.go +++ b/Plugins/Postgres.go @@ -6,6 +6,7 @@ import ( _ "github.com/lib/pq" "github.com/shadow1ng/fscan/Common" "strings" + "sync" "time" ) @@ -15,34 +16,112 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["postgresql"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["postgresql"] { for _, pass := range Common.Passwords { - // 替换密码中的用户名占位符 pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := PostgresConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行PostgreSQL连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := PostgresConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] PostgreSQL %v:%v %v %v %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - // 记录错误信息 - errlog := fmt.Sprintf("[-] PostgreSQL %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - // 超时检查 - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["postgresql"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/RabbitMQ.go b/Plugins/RabbitMQ.go index 8e2d3a3..01af0df 100644 --- a/Plugins/RabbitMQ.go +++ b/Plugins/RabbitMQ.go @@ -6,6 +6,7 @@ import ( "github.com/shadow1ng/fscan/Common" "net" "strings" + "sync" "time" ) @@ -15,37 +16,121 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 首先测试默认账户 guest/guest - flag, err := RabbitMQConn(info, "guest", "guest") - if flag && err == nil { - return err - } + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["rabbitmq"])*len(Common.Passwords)+1) // +1 是为了加入guest账号 - // 尝试用户名密码组合 + resultChan := make(chan error, threads) + + // 先加入默认账号guest/guest + taskChan <- struct { + user string + pass string + }{"guest", "guest"} + + // 生成其他用户名密码组合任务 for _, user := range Common.Userdict["rabbitmq"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := RabbitMQConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行RabbitMQ连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := RabbitMQConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + result := fmt.Sprintf("[+] RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v", + info.Host, info.Ports, task.user, task.pass) + Common.LogSuccess(result) + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["rabbitmq"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/Redis.go b/Plugins/Redis.go index 3f68b82..7d79395 100644 --- a/Plugins/Redis.go +++ b/Plugins/Redis.go @@ -8,6 +8,7 @@ import ( "net" "os" "strings" + "sync" "time" ) @@ -20,7 +21,7 @@ var ( func RedisScan(info *Common.HostInfo) (tmperr error) { starttime := time.Now().Unix() - // 尝试无密码连接 + // 先尝试无密码连接 flag, err := RedisUnauth(info) if flag && err == nil { return err @@ -30,30 +31,102 @@ func RedisScan(info *Common.HostInfo) (tmperr error) { return } - // 尝试密码暴力破解 + maxRetries := Common.MaxRetries + threads := Common.BruteThreads + + // 创建任务通道 + taskChan := make(chan string, len(Common.Passwords)) + resultChan := make(chan error, threads) + + // 生成所有密码任务 for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", "redis", -1) + taskChan <- pass + } + close(taskChan) - flag, err := RedisConn(info, pass) - if flag && err == nil { - return err - } + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() - // 记录错误信息 - errlog := fmt.Sprintf("[-] Redis %v:%v %v %v", info.Host, info.Ports, pass, err) - Common.LogError(errlog) - tmperr = err + for pass := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } - if Common.CheckErrs(err) { - return err - } + // 执行Redis连接 + done := make(chan struct { + success bool + err error + }) - // 超时检查 - if time.Now().Unix()-starttime > (int64(len(Common.Passwords)) * Common.Timeout) { - return err + go func(pass string) { + success, err := RedisConn(info, pass) + done <- struct { + success bool + err error + }{success, err} + }(pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Redis %v:%v %v %v", + info.Host, info.Ports, pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } + } + resultChan <- nil + }() + } + + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { + tmperr = err + if retryErr := Common.CheckErrs(err); retryErr != nil { + return err + } } } - fmt.Println("[+] Redis扫描模块结束...") + return tmperr } diff --git a/Plugins/Rsync.go b/Plugins/Rsync.go index a76d14c..582c5d2 100644 --- a/Plugins/Rsync.go +++ b/Plugins/Rsync.go @@ -5,6 +5,7 @@ import ( "github.com/shadow1ng/fscan/Common" "net" "strings" + "sync" "time" ) @@ -14,38 +15,130 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads // 首先测试匿名访问 - flag, err := RsyncConn(info, "", "") - if flag && err == nil { - return err + for retryCount := 0; retryCount < maxRetries; retryCount++ { + flag, err := RsyncConn(info, "", "") + if flag && err == nil { + return err + } + + if err != nil { + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + return err + } + continue + } + } + break } - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["rsync"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["rsync"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := RsyncConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行Rsync连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + flag, err := RsyncConn(info, user, pass) + done <- struct { + success bool + err error + }{flag && err == nil, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["rsync"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/SMB.go b/Plugins/SMB.go index 99f7ff9..f9e036b 100644 --- a/Plugins/SMB.go +++ b/Plugins/SMB.go @@ -6,60 +6,133 @@ import ( "github.com/shadow1ng/fscan/Common" "github.com/stacktitan/smb/smb" "strings" + "sync" "time" ) // SmbScan 执行SMB服务的认证扫描 func SmbScan(info *Common.HostInfo) (tmperr error) { - // 如果未启用暴力破解则直接返回 if Common.DisableBrute { return nil } - startTime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 遍历用户名和密码字典进行认证尝试 + // 创建任务通道 + 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.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - // 执行带超时的认证 - success, err := doWithTimeOut(info, user, pass) + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + startTime := time.Now().Unix() - if success && err == nil { - // 认证成功,记录结果 - var result string - if Common.Domain != "" { - result = fmt.Sprintf("[✓] SMB认证成功 %v:%v Domain:%v\\%v Pass:%v", - info.Host, info.Ports, Common.Domain, user, pass) - } else { - result = fmt.Sprintf("[✓] SMB认证成功 %v:%v User:%v Pass:%v", - info.Host, info.Ports, user, pass) + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-startTime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行SMB认证 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := doWithTimeOut(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + // 认证成功 + var successLog string + if Common.Domain != "" { + successLog = fmt.Sprintf("[✓] SMB认证成功 %v:%v Domain:%v\\%v Pass:%v", + info.Host, info.Ports, Common.Domain, task.user, task.pass) + } else { + successLog = fmt.Sprintf("[✓] SMB认证成功 %v:%v User:%v Pass:%v", + info.Host, info.Ports, task.user, task.pass) + } + Common.LogSuccess(successLog) + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[x] SMB认证失败 %v:%v User:%v Pass:%v Err:%v", + info.Host, info.Ports, task.user, task.pass, + strings.ReplaceAll(err.Error(), "\n", "")) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 } - Common.LogSuccess(result) + } + resultChan <- nil + }() + } + + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { + tmperr = err + if retryErr := Common.CheckErrs(err); retryErr != nil { return err - } else { - // 认证失败,记录错误 - errorMsg := fmt.Sprintf("[x] SMB认证失败 %v:%v User:%v Pass:%v Err:%v", - info.Host, info.Ports, user, pass, - strings.ReplaceAll(err.Error(), "\n", "")) - Common.LogError(errorMsg) - tmperr = err - - // 检查是否需要中断扫描 - if Common.CheckErrs(err) { - return err - } - - // 检查是否超时 - timeoutLimit := int64(len(Common.Userdict["smb"])*len(Common.Passwords)) * Common.Timeout - if time.Now().Unix()-startTime > timeoutLimit { - return err - } } } } + return tmperr } diff --git a/Plugins/SMB2.go b/Plugins/SMB2.go index e636673..c133a52 100644 --- a/Plugins/SMB2.go +++ b/Plugins/SMB2.go @@ -6,6 +6,7 @@ import ( "net" "os" "strings" + "sync" "time" "github.com/hirochachacha/go-smb2" @@ -13,79 +14,269 @@ import ( // SmbScan2 执行SMB2服务的认证扫描,支持密码和哈希两种认证方式 func SmbScan2(info *Common.HostInfo) (tmperr error) { - - // 如果未启用暴力破解则直接返回 if Common.DisableBrute { return nil } - hasprint := false - startTime := time.Now().Unix() - // 使用哈希认证模式 if len(Common.HashBytes) > 0 { - return smbHashScan(info, hasprint, startTime) + return smbHashScan(info) } // 使用密码认证模式 - return smbPasswordScan(info, hasprint, startTime) + return smbPasswordScan(info) } // smbHashScan 使用哈希进行认证扫描 -func smbHashScan(info *Common.HostInfo, hasprint bool, startTime int64) error { +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 { - success, err, printed := Smb2Con(info, user, "", hash, hasprint) - if printed { - hasprint = true - } + taskChan <- struct { + user string + hash []byte + }{user, hash} + } + } + close(taskChan) - if success { - logSuccessfulAuth(info, user, "", hash) + // 启动工作线程 + var wg sync.WaitGroup + var hasPrintMutex sync.Mutex + + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + startTime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-startTime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行SMB2认证 + done := make(chan struct { + success bool + err error + printed bool + }) + + go func(user string, hash []byte) { + hasPrintMutex.Lock() + currentHasPrint := hasprint + hasPrintMutex.Unlock() + + success, err, printed := Smb2Con(info, user, "", hash, currentHasPrint) + + if printed { + hasPrintMutex.Lock() + hasprint = true + hasPrintMutex.Unlock() + } + + done <- struct { + success bool + err error + printed bool + }{success, err, printed} + }(task.user, task.hash) + + // 等待结果或超时 + select { + case result := <-done: + if result.success { + logSuccessfulAuth(info, task.user, "", task.hash) + resultChan <- nil + return + } + + if result.err != nil { + logFailedAuth(info, task.user, "", task.hash, result.err) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(result.err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- result.err + return + } + continue // 继续重试 + } + } + + case <-time.After(time.Duration(Common.Timeout) * time.Second): + logFailedAuth(info, task.user, "", task.hash, fmt.Errorf("连接超时")) + } + + break // 如果不需要重试,跳出重试循环 + } + + if len(Common.HashValue) > 0 { + break + } + } + resultChan <- nil + }() + } + + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } - - logFailedAuth(info, user, "", hash, err) - - if shouldStopScan(err, startTime, len(Common.Userdict["smb"])*len(Common.HashBytes)) { - return err - } - - if len(Common.HashValue) > 0 { - break - } } } + return nil } // smbPasswordScan 使用密码进行认证扫描 -func smbPasswordScan(info *Common.HostInfo, hasprint bool, startTime int64) error { +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) - success, err, printed := Smb2Con(info, user, pass, []byte{}, hasprint) - if printed { - hasprint = true - } + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - if success { - logSuccessfulAuth(info, user, pass, []byte{}) + // 启动工作线程 + var wg sync.WaitGroup + var hasPrintMutex sync.Mutex + + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + startTime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-startTime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行SMB2认证 + done := make(chan struct { + success bool + err error + printed bool + }) + + go func(user, pass string) { + hasPrintMutex.Lock() + currentHasPrint := hasprint + hasPrintMutex.Unlock() + + success, err, printed := Smb2Con(info, user, pass, []byte{}, currentHasPrint) + + if printed { + hasPrintMutex.Lock() + hasprint = true + 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 + return + } + + if result.err != nil { + logFailedAuth(info, task.user, task.pass, []byte{}, result.err) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(result.err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- result.err + return + } + continue // 继续重试 + } + } + + case <-time.After(time.Duration(Common.Timeout) * time.Second): + logFailedAuth(info, task.user, task.pass, []byte{}, fmt.Errorf("连接超时")) + } + + break // 如果不需要重试,跳出重试循环 + } + + if len(Common.HashValue) > 0 { + break + } + } + resultChan <- nil + }() + } + + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } - - logFailedAuth(info, user, pass, []byte{}, err) - - if shouldStopScan(err, startTime, len(Common.Userdict["smb"])*len(Common.Passwords)) { - return err - } - - if len(Common.HashValue) > 0 { - break - } } } - fmt.Println("[+] Smb2扫描模块结束...") + return nil } @@ -93,10 +284,10 @@ func smbPasswordScan(info *Common.HostInfo, hasprint bool, startTime int64) erro 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认证成功 %v:%v Domain:%v\\%v ", info.Host, info.Ports, Common.Domain, user) } else { - result = fmt.Sprintf("[✓] SMB2认证成功 %v:%v User:%v ", + result = fmt.Sprintf("[+] SMB2认证成功 %v:%v User:%v ", info.Host, info.Ports, user) } @@ -112,29 +303,16 @@ 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("[x] SMB2认证失败 %v:%v User:%v HashValue:%v Err:%v", + errlog = fmt.Sprintf("[-] SMB2认证失败 %v:%v User:%v HashValue:%v Err:%v", info.Host, info.Ports, user, Common.HashValue, err) } else { - errlog = fmt.Sprintf("[x] SMB2认证失败 %v:%v User:%v Pass:%v Err:%v", + errlog = fmt.Sprintf("[-] SMB2认证失败 %v:%v User:%v Pass:%v Err:%v", info.Host, info.Ports, user, pass, err) } errlog = strings.ReplaceAll(errlog, "\n", " ") Common.LogError(errlog) } -// shouldStopScan 检查是否应该停止扫描 -func shouldStopScan(err error, startTime int64, totalAttempts int) bool { - if Common.CheckErrs(err) { - return true - } - - if time.Now().Unix()-startTime > (int64(totalAttempts) * Common.Timeout) { - return true - } - - return false -} - // Smb2Con 尝试SMB2连接并进行认证,检查共享访问权限 func Smb2Con(info *Common.HostInfo, user string, pass string, hash []byte, hasprint bool) (flag bool, err error, flag2 bool) { // 建立TCP连接 diff --git a/Plugins/SMTP.go b/Plugins/SMTP.go index 19502ec..5ed3ec1 100644 --- a/Plugins/SMTP.go +++ b/Plugins/SMTP.go @@ -6,6 +6,7 @@ import ( "net" "net/smtp" "strings" + "sync" "time" ) @@ -15,39 +16,129 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 首先测试匿名访问 - flag, err := SmtpConn(info, "", "") - if flag && err == nil { - return err + // 先测试匿名访问 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + flag, err := SmtpConn(info, "", "") + if flag && err == nil { + return err + } + if err != nil { + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + return err + } + continue + } + } + break } - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["smtp"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["smtp"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := SmtpConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行SMTP连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + flag, err := SmtpConn(info, user, pass) + done <- struct { + success bool + err error + }{flag, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - // 超时检查 - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["smtp"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/SNMP.go b/Plugins/SNMP.go index f9ab158..80a3ec2 100644 --- a/Plugins/SNMP.go +++ b/Plugins/SNMP.go @@ -6,6 +6,7 @@ import ( "github.com/shadow1ng/fscan/Common" "strconv" "strings" + "sync" "time" ) @@ -15,31 +16,107 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() - portNum, _ := strconv.Atoi(info.Ports) // 添加端口转换 + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 首先尝试默认community strings + portNum, _ := strconv.Atoi(info.Ports) defaultCommunities := []string{"public", "private", "cisco", "community"} + // 创建任务通道 + taskChan := make(chan string, len(defaultCommunities)) + resultChan := make(chan error, threads) + + // 生成所有community任务 for _, community := range defaultCommunities { - flag, err := SNMPConnect(info, community, portNum) // 传入转换后的端口 - if flag && err == nil { - return err - } + taskChan <- community + } + close(taskChan) - if Common.CheckErrs(err) { - return err - } + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() - errlog := fmt.Sprintf("[-] SNMP服务 %v:%v 尝试失败 community: %v 错误: %v", - info.Host, info.Ports, community, err) - Common.LogError(errlog) - tmperr = err + for community := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + timeout := time.Duration(Common.Timeout) * time.Second + if time.Now().Unix()-starttime > int64(timeout.Seconds()) { + resultChan <- fmt.Errorf("扫描超时") + return + } - // 修正超时计算 - timeout := time.Duration(Common.Timeout) * time.Second - if time.Now().Unix()-starttime > int64(timeout.Seconds())*int64(len(defaultCommunities)) { - return err + // 执行SNMP连接 + done := make(chan struct { + success bool + err error + }) + + go func(community string) { + success, err := SNMPConnect(info, community, portNum) + done <- struct { + success bool + err error + }{success, err} + }(community) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + // 连接成功 + successLog := fmt.Sprintf("[+] SNMP服务 %v:%v community: %v 连接成功", + info.Host, info.Ports, community) + Common.LogSuccess(successLog) + resultChan <- nil + return + } + case <-time.After(timeout): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] SNMP服务 %v:%v 尝试失败 community: %v 错误: %v", + info.Host, info.Ports, community, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } + } + resultChan <- nil + }() + } + + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { + tmperr = err + if retryErr := Common.CheckErrs(err); retryErr != nil { + return err + } } } diff --git a/Plugins/SSH.go b/Plugins/SSH.go index 960a46e..b305d53 100644 --- a/Plugins/SSH.go +++ b/Plugins/SSH.go @@ -16,13 +16,13 @@ func SshScan(info *Common.HostInfo) (tmperr error) { return } - threads := Common.BruteThreads // 使用 BruteThreads 来控制线程数 + maxRetries := Common.MaxRetries + threads := Common.BruteThreads taskChan := make(chan struct { user string pass string }, len(Common.Userdict["ssh"])*len(Common.Passwords)) - // 创建结果通道 resultChan := make(chan error, threads) // 生成所有任务 @@ -37,62 +37,66 @@ func SshScan(info *Common.HostInfo) (tmperr error) { } close(taskChan) - // 启动工作线程 var wg sync.WaitGroup for i := 0; i < threads; i++ { wg.Add(1) go func() { defer wg.Done() for task := range taskChan { - // 为每个任务创建结果通道 - done := make(chan struct { - success bool - err error - }) - - // 执行SSH连接 - go func(user, pass string) { - success, err := SshConn(info, user, pass) - done <- struct { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + done := make(chan struct { success bool err error - }{success, err} - }(task.user, task.pass) + }) - // 等待结果或超时 - var err error - select { - case result := <-done: - err = result.err - if result.success { - resultChan <- nil - return + go func(user, pass string) { + success, err := SshConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + var err error + select { + case result := <-done: + err = result.err + if result.success { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") } - case <-time.After(time.Duration(Common.Timeout) * time.Second): - err = fmt.Errorf("连接超时") - } - if err != nil { - errlog := fmt.Sprintf("[-] SSH认证失败 %v:%v User:%v Pass:%v Err:%v", - info.Host, info.Ports, task.user, task.pass, err) - Common.LogError(errlog) + if err != nil { + errlog := fmt.Sprintf("[-] SSH认证失败 %v:%v User:%v Pass:%v Err:%v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) - if Common.CheckErrs(err) { + // 检查是否是已知错误,如果是则等待3秒后重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + if Common.SshKeyPath != "" { resultChan <- err return } - } - if Common.SshKeyPath != "" { - resultChan <- err - return + break // 如果不需要重试,跳出重试循环 } } resultChan <- nil }() } - // 等待所有线程完成 go func() { wg.Wait() close(resultChan) @@ -102,7 +106,7 @@ func SshScan(info *Common.HostInfo) (tmperr error) { for err := range resultChan { if err != nil { tmperr = err - if Common.CheckErrs(err) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } diff --git a/Plugins/Telnet.go b/Plugins/Telnet.go index 3e35431..5f6a9ed 100644 --- a/Plugins/Telnet.go +++ b/Plugins/Telnet.go @@ -8,55 +8,132 @@ import ( "net" "regexp" "strings" + "sync" "time" ) // TelnetScan 执行Telnet服务扫描和密码爆破 func TelnetScan(info *Common.HostInfo) (tmperr error) { - // 检查是否禁用暴力破解 if Common.DisableBrute { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 遍历用户名密码字典进行尝试 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["telnet"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["telnet"] { for _, pass := range Common.Passwords { - // 替换密码中的用户名占位符 pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - // 尝试Telnet连接 - flag, err := telnetConn(info, user, pass) + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() - // 处理连接结果 - if flag { - // 无需认证的情况 - result := fmt.Sprintf("[+] Telnet服务 %v:%v 无需认证", info.Host, info.Ports) - Common.LogSuccess(result) - return nil - } else if err == nil { - // 成功爆破到密码 - result := fmt.Sprintf("[+] Telnet服务 %v:%v 用户名:%v 密码:%v", info.Host, info.Ports, user, pass) - Common.LogSuccess(result) - return nil + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行Telnet连接 + done := make(chan struct { + success bool + noAuth bool + err error + }) + + go func(user, pass string) { + flag, err := telnetConn(info, user, pass) + done <- struct { + success bool + noAuth bool + err error + }{err == nil, flag, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.noAuth { + // 无需认证 + 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", + info.Host, info.Ports, task.user, task.pass) + Common.LogSuccess(result) + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - // 处理错误情况 - errlog := fmt.Sprintf("[-] Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v", - info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - // 检查是否存在严重错误需要中断 - if Common.CheckErrs(err) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } - - // 检查是否超时 - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["telnet"])*len(Common.Passwords)) * Common.Timeout) { - return fmt.Errorf("扫描超时") - } } } diff --git a/Plugins/Tomcat.go b/Plugins/Tomcat.go index 7f4c7bc..27275a4 100644 --- a/Plugins/Tomcat.go +++ b/Plugins/Tomcat.go @@ -7,6 +7,7 @@ import ( "github.com/shadow1ng/fscan/Common" "net/http" "strings" + "sync" "time" ) @@ -16,31 +17,112 @@ func TomcatScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["tomcat"])*len(Common.Passwords)) + + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["tomcat"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := TomcatConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行Tomcat连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := TomcatConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Tomcat Manager %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] Tomcat Manager %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["tomcat"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/Plugins/VNC.go b/Plugins/VNC.go index 74bcb1d..ae71d74 100644 --- a/Plugins/VNC.go +++ b/Plugins/VNC.go @@ -5,46 +5,117 @@ import ( "github.com/mitchellh/go-vnc" "github.com/shadow1ng/fscan/Common" "net" + "sync" "time" ) // VncScan 执行VNC服务扫描及密码尝试 func VncScan(info *Common.HostInfo) (tmperr error) { - // 如果已开启暴力破解则直接返回 if Common.DisableBrute { return } + maxRetries := Common.MaxRetries + threads := Common.BruteThreads modename := "vnc" - starttime := time.Now().Unix() - // 遍历密码字典尝试连接 + // 创建任务通道 + taskChan := make(chan string, len(Common.Passwords)) + resultChan := make(chan error, threads) + + // 生成所有密码任务 for _, pass := range Common.Passwords { - flag, err := VncConn(info, pass) + taskChan <- pass + } + close(taskChan) - if flag && err == nil { - // 连接成功,记录结果 - result := fmt.Sprintf("[+] %s://%v:%v 密码: %v", modename, info.Host, info.Ports, pass) - Common.LogSuccess(result) - return err - } + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() - // 连接失败,记录错误信息 - errlog := fmt.Sprintf("[-] %s://%v:%v 尝试密码: %v 错误: %v", - modename, info.Host, info.Ports, pass, err) - Common.LogError(errlog) - tmperr = err + for pass := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } - // 检查是否需要中断扫描 - if Common.CheckErrs(err) { - return err - } + // 执行VNC连接 + done := make(chan struct { + success bool + err error + }) - // 检查是否超时 - if time.Now().Unix()-starttime > (int64(len(Common.Passwords)) * Common.Timeout) { - return fmt.Errorf("扫描超时") + go func(pass string) { + success, err := VncConn(info, pass) + done <- struct { + success bool + err error + }{success, err} + }(pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + // 连接成功 + successLog := fmt.Sprintf("[+] %s://%v:%v 密码: %v", + modename, info.Host, info.Ports, pass) + Common.LogSuccess(successLog) + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] %s://%v:%v 尝试密码: %v 错误: %v", + modename, info.Host, info.Ports, pass, err) + Common.LogError(errlog) + + // 检查是否是需要重试的错误 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } + } + resultChan <- nil + }() + } + + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { + tmperr = err + if retryErr := Common.CheckErrs(err); retryErr != nil { + return err + } } } + return tmperr } diff --git a/Plugins/WMIExec.go b/Plugins/WMIExec.go index 262c1fd..1c70a75 100644 --- a/Plugins/WMIExec.go +++ b/Plugins/WMIExec.go @@ -7,6 +7,7 @@ import ( "github.com/shadow1ng/fscan/Common" "os" "strings" + "sync" "time" ) @@ -32,49 +33,132 @@ func WmiExec(info *Common.HostInfo) (tmperr error) { return nil } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads + 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"] { - PASS: for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) - - flag, err := Wmiexec(info, user, pass, Common.HashValue) - - errlog := fmt.Sprintf("[-] WmiExec %v:%v %v %v %v", info.Host, 445, user, pass, err) - errlog = strings.Replace(errlog, "\n", "", -1) - Common.LogError(errlog) - - if flag { - var result string - if Common.Domain != "" { - result = fmt.Sprintf("[+] WmiExec %v:%v:%v\\%v ", info.Host, info.Ports, Common.Domain, user) - } else { - result = fmt.Sprintf("[+] WmiExec %v:%v:%v ", info.Host, info.Ports, user) - } - - if Common.HashValue != "" { - result += "hash: " + Common.HashValue - } else { - result += pass - } - Common.LogSuccess(result) - return err - } else { - tmperr = err - if Common.CheckErrs(err) { - return err - } - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["smb"])*len(Common.Passwords)) * Common.Timeout) { - return err - } - } - + taskChan <- struct { + user string + pass string + }{user, pass} + // 如果是32位hash值,只尝试一次密码 if len(Common.HashValue) == 32 { - break PASS + break } } } + close(taskChan) + + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行WMI连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := Wmiexec(info, user, pass, Common.HashValue) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success { + // 成功连接 + var successLog string + if Common.Domain != "" { + successLog = fmt.Sprintf("[+] WmiExec %v:%v:%v\\%v ", + info.Host, info.Ports, Common.Domain, task.user) + } else { + successLog = fmt.Sprintf("[+] WmiExec %v:%v:%v ", + info.Host, info.Ports, task.user) + } + + if Common.HashValue != "" { + successLog += "hash: " + Common.HashValue + } else { + successLog += task.pass + } + Common.LogSuccess(successLog) + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] WmiExec %v:%v %v %v %v", + info.Host, 445, task.user, task.pass, err) + errlog = strings.Replace(errlog, "\n", "", -1) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } + } + resultChan <- nil + }() + } + + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { + tmperr = err + if retryErr := Common.CheckErrs(err); retryErr != nil { + return err + } + } + } + return tmperr } diff --git a/Plugins/Zabbix.go b/Plugins/Zabbix.go index dbe564e..a9eeca6 100644 --- a/Plugins/Zabbix.go +++ b/Plugins/Zabbix.go @@ -7,6 +7,7 @@ import ( "github.com/shadow1ng/fscan/Common" "net" "strings" + "sync" "time" ) @@ -16,37 +17,134 @@ func ZabbixScan(info *Common.HostInfo) (tmperr error) { return } - starttime := time.Now().Unix() + maxRetries := Common.MaxRetries + threads := Common.BruteThreads - // 首先测试默认账户 - flag, err := ZabbixConn(info, "Admin", "zabbix") - if flag && err == nil { - return err + // 先测试默认账号 + defaultDone := make(chan struct { + success bool + err error + }) + + go func() { + success, err := ZabbixConn(info, "Admin", "zabbix") + defaultDone <- struct { + success bool + err error + }{success, err} + }() + + select { + case result := <-defaultDone: + if result.success && result.err == nil { + return result.err + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + Common.LogError(fmt.Sprintf("[-] Zabbix默认账号连接超时 %v:%v", info.Host, info.Ports)) } - // 尝试用户名密码组合 + // 创建任务通道 + taskChan := make(chan struct { + user string + pass string + }, len(Common.Userdict["zabbix"])*len(Common.Passwords)) + resultChan := make(chan error, threads) + + // 生成所有用户名密码组合任务 for _, user := range Common.Userdict["zabbix"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) + taskChan <- struct { + user string + pass string + }{user, pass} + } + } + close(taskChan) - flag, err := ZabbixConn(info, user, pass) - if flag && err == nil { - return err + // 启动工作线程 + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + defer wg.Done() + starttime := time.Now().Unix() + + for task := range taskChan { + // 重试循环 + for retryCount := 0; retryCount < maxRetries; retryCount++ { + // 检查是否超时 + if time.Now().Unix()-starttime > int64(Common.Timeout) { + resultChan <- fmt.Errorf("扫描超时") + return + } + + // 执行Zabbix连接 + done := make(chan struct { + success bool + err error + }) + + go func(user, pass string) { + success, err := ZabbixConn(info, user, pass) + done <- struct { + success bool + err error + }{success, err} + }(task.user, task.pass) + + // 等待结果或超时 + var err error + select { + case result := <-done: + err = result.err + if result.success && err == nil { + resultChan <- nil + return + } + case <-time.After(time.Duration(Common.Timeout) * time.Second): + err = fmt.Errorf("连接超时") + } + + // 处理错误情况 + if err != nil { + errlog := fmt.Sprintf("[-] Zabbix服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", + info.Host, info.Ports, task.user, task.pass, err) + Common.LogError(errlog) + + // 检查是否需要重试 + if retryErr := Common.CheckErrs(err); retryErr != nil { + if retryCount == maxRetries-1 { + resultChan <- err + return + } + continue // 继续重试 + } + } + + break // 如果不需要重试,跳出重试循环 + } } + resultChan <- nil + }() + } - errlog := fmt.Sprintf("[-] Zabbix服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v", info.Host, info.Ports, user, pass, err) - Common.LogError(errlog) + // 等待所有线程完成 + go func() { + wg.Wait() + close(resultChan) + }() + + // 检查结果 + for err := range resultChan { + if err != nil { tmperr = err - - if Common.CheckErrs(err) { - return err - } - - if time.Now().Unix()-starttime > (int64(len(Common.Userdict["zabbix"])*len(Common.Passwords)) * Common.Timeout) { + if retryErr := Common.CheckErrs(err); retryErr != nil { return err } } } + return tmperr } diff --git a/TestDocker/MySQL/Dockerfile b/TestDocker/MySQL/Dockerfile index 5b14e00..0320f93 100644 --- a/TestDocker/MySQL/Dockerfile +++ b/TestDocker/MySQL/Dockerfile @@ -2,7 +2,7 @@ FROM mysql:latest # 设置环境变量 -ENV MYSQL_ROOT_PASSWORD=123456 +ENV MYSQL_ROOT_PASSWORD=Password ENV MYSQL_DATABASE=mydb # 开放3306端口 diff --git a/TestDocker/MySQL/README.txt b/TestDocker/MySQL/README.txt index e0a25fd..dbd446d 100644 --- a/TestDocker/MySQL/README.txt +++ b/TestDocker/MySQL/README.txt @@ -1,5 +1,2 @@ docker build -t mysql-server . -docker run -d \ - -p 3306:3306 \ - --name mysql-container \ - mysql-server \ No newline at end of file +docker run -d -p 3306:3306 --name mysql-container mysql-server \ No newline at end of file