refactor: 输出格式重构,去掉所有插件的多线程,因为多线程会导致结果不准确,加入进度条

This commit is contained in:
ZacharyZcR 2025-01-01 07:18:36 +08:00
parent 277ea5d332
commit ceede3cd68
49 changed files with 1448 additions and 2911 deletions

View File

@ -1,5 +1,10 @@
package Common
import (
"github.com/schollz/progressbar/v3"
"sync"
)
var version = "2.0.0"
var Userdict = map[string][]string{
"ftp": {"ftp", "admin", "www", "web", "root", "db", "wwwroot", "data"},
@ -29,7 +34,12 @@ var Userdict = map[string][]string{
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
// 添加一个全局的进度条变量
var ProgressBar *progressbar.ProgressBar
// 添加一个全局互斥锁来控制输出
var OutputMutex sync.Mutex
type PocInfo struct {
Target string

View File

@ -113,7 +113,6 @@ func Flag(Info *HostInfo) {
// 暴力破解配置
flag.BoolVar(&DisableBrute, "nobr", false, "禁用密码暴力破解")
flag.IntVar(&BruteThreads, "br", 1, "设置密码破解线程数")
flag.IntVar(&MaxRetries, "retry", 3, "设置最大重试次数")
// 其他配置
@ -128,7 +127,7 @@ func Flag(Info *HostInfo) {
flag.BoolVar(&Silent, "silent", false, "启用静默扫描模式(减少屏幕输出)")
flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示")
flag.BoolVar(&JsonFormat, "json", false, "以JSON格式输出结果")
flag.StringVar(&LogLevel, "log", LogLevelAll, "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)")
flag.StringVar(&LogLevel, "log", LogLevelInfo, "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)")
flag.Parse()
}

View File

@ -18,19 +18,14 @@ import (
var (
// 全局变量
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
results = make(chan *LogEntry, 1000) // 使用缓冲通道
logWG sync.WaitGroup
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
// 扫描计数
Num int64 // 总任务数
End int64 // 已完成任务数
)
// 将 results 改名为 Results 使其可导出
var (
Results = results // 使 results 可导出
LogWG = logWG // 使 logWG 可导出
// 文件写入器
fileWriter *bufferedFileWriter
)
// ScanStatus 记录扫描状态
@ -66,16 +61,18 @@ var logColors = map[string]color.Attribute{
LogLevelDebug: color.FgBlue,
}
// bufferedFileWriter 文件写入器
type bufferedFileWriter struct {
file *os.File
writer *bufio.Writer
jsonEnc *json.Encoder
// JsonOutput JSON输出的结构体
type JsonOutput struct {
Level string `json:"level"`
Timestamp time.Time `json:"timestamp"`
Message string `json:"message"`
}
func init() {
func InitLogger() {
log.SetOutput(io.Discard)
go processLogs()
if !DisableSave {
fileWriter = newBufferedFileWriter()
}
}
// formatLogMessage 格式化日志消息
@ -85,124 +82,108 @@ func formatLogMessage(entry *LogEntry) string {
}
func printLog(entry *LogEntry) {
// 根据配置的日志级别过滤
if LogLevel != LogLevelAll && entry.Level != LogLevel {
// 先检查日志级别
if LogLevel != LogLevelAll &&
entry.Level != LogLevel &&
!(LogLevel == LogLevelInfo && (entry.Level == LogLevelInfo || entry.Level == LogLevelSuccess)) {
return
}
OutputMutex.Lock()
defer OutputMutex.Unlock()
logMsg := formatLogMessage(entry)
if NoColor {
fmt.Println(logMsg)
return
}
if colorAttr, ok := logColors[entry.Level]; ok {
color.New(colorAttr).Println(logMsg)
// 只在输出到终端时处理进度条
if !NoColor {
// 清除当前行
fmt.Print("\033[2K\r")
if colorAttr, ok := logColors[entry.Level]; ok {
color.New(colorAttr).Println(logMsg)
} else {
fmt.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{
if ProgressBar != nil {
ProgressBar.Clear()
}
entry := &LogEntry{
Level: LogLevelError,
Time: time.Now(),
Content: errorMsg,
}:
logWG.Add(1)
default:
printLog(&LogEntry{
Level: LogLevelError,
Time: time.Now(),
Content: errorMsg,
})
}
printLog(entry)
if fileWriter != nil {
fileWriter.write(entry)
}
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
}
func LogInfo(msg string) {
select {
case Results <- &LogEntry{
if ProgressBar != nil {
ProgressBar.Clear()
}
entry := &LogEntry{
Level: LogLevelInfo,
Time: time.Now(),
Content: msg,
}:
logWG.Add(1)
default:
printLog(&LogEntry{
Level: LogLevelInfo,
Time: time.Now(),
Content: msg,
})
}
printLog(entry)
if fileWriter != nil {
fileWriter.write(entry)
}
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
}
// LogSuccess 记录成功信息
func LogSuccess(result string) {
// 添加通道关闭检查
select {
case Results <- &LogEntry{
if ProgressBar != nil {
ProgressBar.Clear()
}
entry := &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,
})
}
}
// JsonOutput JSON输出的结构体
type JsonOutput struct {
Level string `json:"level"`
Timestamp time.Time `json:"timestamp"`
Message string `json:"message"`
}
printLog(entry)
if fileWriter != nil {
fileWriter.write(entry)
}
// processLogs 处理日志信息
func processLogs() {
writer := newBufferedFileWriter()
defer writer.close()
status.mu.Lock()
status.lastSuccess = time.Now()
status.mu.Unlock()
for entry := range results {
if !Silent {
printLog(entry)
}
if writer != nil {
writer.write(entry)
}
logWG.Done()
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
}
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("[ERROR] 打开输出文件失败 %s: %v\n", Outputfile, err)
@ -217,28 +198,67 @@ func newBufferedFileWriter() *bufferedFileWriter {
}
}
type bufferedFileWriter struct {
file *os.File
writer *bufio.Writer
jsonEnc *json.Encoder
mu sync.Mutex // 添加互斥锁保护写入
}
func (w *bufferedFileWriter) write(entry *LogEntry) {
if w == nil {
return
}
w.mu.Lock()
defer w.mu.Unlock()
var err error
if JsonFormat {
output := JsonOutput{
Level: entry.Level,
Timestamp: entry.Time,
Message: entry.Content,
}
if err := w.jsonEnc.Encode(output); err != nil {
fmt.Printf("[ERROR] JSON编码失败: %v\n", err)
}
err = w.jsonEnc.Encode(output)
} else {
logMsg := formatLogMessage(entry) + "\n"
if _, err := w.writer.WriteString(logMsg); err != nil {
fmt.Printf("[ERROR] 写入文件失败: %v\n", err)
}
_, err = w.writer.WriteString(logMsg)
}
w.writer.Flush()
if err != nil {
fmt.Printf("[ERROR] 写入日志失败: %v\n", err)
// 尝试重新打开文件
if err := w.reopen(); err != nil {
fmt.Printf("[ERROR] 重新打开文件失败: %v\n", err)
return
}
return
}
// 每隔一定数量的写入才进行一次Flush
if err := w.writer.Flush(); err != nil {
fmt.Printf("[ERROR] 刷新缓冲区失败: %v\n", err)
if err := w.reopen(); err != nil {
fmt.Printf("[ERROR] 重新打开文件失败: %v\n", err)
}
}
}
func (w *bufferedFileWriter) reopen() error {
if w.file != nil {
w.file.Close()
}
file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return err
}
w.file = file
w.writer = bufio.NewWriter(file)
w.jsonEnc = json.NewEncoder(w.writer)
return nil
}
func (w *bufferedFileWriter) close() {
@ -248,6 +268,12 @@ func (w *bufferedFileWriter) close() {
}
}
func CloseLogger() {
if fileWriter != nil {
fileWriter.close()
}
}
// CheckErrs 检查是否为需要重试的错误
func CheckErrs(err error) error {
if err == nil {

View File

@ -223,10 +223,10 @@ func ParseInput(Info *HostInfo) error {
LogInfo(fmt.Sprintf("暴力破解线程数: %d", BruteThreads))
}
if DisableSave {
IsSave = false
LogInfo("已启用临时保存模式")
}
//if DisableSave {
// IsSave = false
// LogInfo("已启用临时保存模式")
//}
// 处理端口配置
if Ports == MainPorts {

View File

@ -21,7 +21,7 @@ var pluginGroups = map[string][]string{
"web", "fcgi", // web类
"mysql", "mssql", "redis", "mongodb", "postgres", // 数据库类
"oracle", "memcached", "elasticsearch", "rabbitmq", "kafka", "activemq", "cassandra", "neo4j", // 数据库类
"ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "snmp", "zabbix", "modbus", "rsync", // 服务类
"ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "snmp", "modbus", "rsync", // 服务类
"ms17010", "smbghost", "smb2", // 漏洞类
"findnet", // 其他
},
@ -36,7 +36,7 @@ var pluginGroups = map[string][]string{
"web", "fcgi",
},
ModeService: {
"ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "zabbix", "modbus", "rsync",
"ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "modbus", "rsync",
},
ModeVul: {
"ms17010", "smbghost", "smb2",

View File

@ -57,7 +57,7 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
if isPing {
protocol = "PING"
}
fmt.Printf("[+] 目标 %-15s 存活 (%s)\n", ip, protocol)
fmt.Printf("目标 %-15s 存活 (%s)\n", ip, protocol)
}
AliveHosts = append(AliveHosts, ip)
@ -76,7 +76,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
}
Common.LogError(fmt.Sprintf("ICMP监听失败: %v", err))
fmt.Println("[-] 正在尝试无监听ICMP探测...")
fmt.Println("正在尝试无监听ICMP探测...")
// 尝试无监听ICMP探测
conn2, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
@ -87,8 +87,8 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
}
Common.LogError(fmt.Sprintf("ICMP连接失败: %v", err))
fmt.Println("[-] 当前用户权限不足,无法发送ICMP包")
fmt.Println("[*] 切换为PING方式探测...")
fmt.Println("当前用户权限不足,无法发送ICMP包")
fmt.Println("切换为PING方式探测...")
// 降级使用ping探测
RunPing(hostslist, chanHosts)
@ -100,7 +100,7 @@ func printAliveStats(hostslist []string) {
if len(hostslist) > 1000 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true)
for i := 0; i < len(arrTop); i++ {
output := fmt.Sprintf("[*] B段 %-16s 存活主机数: %d", arrTop[i]+".0.0/16", arrLen[i])
output := fmt.Sprintf("B段 %-16s 存活主机数: %d", arrTop[i]+".0.0/16", arrLen[i])
Common.LogSuccess(output)
}
}
@ -109,7 +109,7 @@ func printAliveStats(hostslist []string) {
if len(hostslist) > 256 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
for i := 0; i < len(arrTop); i++ {
output := fmt.Sprintf("[*] C段 %-16s 存活主机数: %d", arrTop[i]+".0/24", arrLen[i])
output := fmt.Sprintf("C段 %-16s 存活主机数: %d", arrTop[i]+".0/24", arrLen[i])
Common.LogSuccess(output)
}
}

View File

@ -81,7 +81,7 @@ func init() {
Common.RegisterPlugin("activemq", Common.ScanPlugin{
Name: "ActiveMQ",
Ports: []int{61616, 61613},
Ports: []int{61613},
ScanFunc: Plugins.ActiveMQScan,
})
@ -115,12 +115,6 @@ func init() {
ScanFunc: Plugins.SNMPScan,
})
Common.RegisterPlugin("zabbix", Common.ScanPlugin{
Name: "Zabbix",
Ports: []int{80, 443, 8080, 8443, 10051}, // Zabbix常用端口
ScanFunc: Plugins.ZabbixScan,
})
Common.RegisterPlugin("modbus", Common.ScanPlugin{
Name: "Modbus",
Ports: []int{502, 5020}, // Modbus 默认端口

View File

@ -2,12 +2,15 @@ package Core
import (
"fmt"
"github.com/schollz/progressbar/v3"
"github.com/shadow1ng/fscan/Common"
"github.com/shadow1ng/fscan/WebScan/lib"
"sort"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
)
// Scan 执行扫描主流程
@ -108,13 +111,68 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
if plugins := Common.GetPluginsForMode(mode); plugins != nil {
pluginsToRun = plugins
Common.LogInfo(fmt.Sprintf("加载插件组: %s", mode))
} else {
pluginsToRun = []string{mode}
isSinglePlugin = true
Common.LogInfo(fmt.Sprintf("使用单个插件: %s", mode))
}
loadedPlugins := make([]string, 0)
// 先遍历一遍计算实际要执行的任务数
actualTasks := 0
for _, target := range targets {
targetPort, _ := strconv.Atoi(target.Ports)
for _, pluginName := range pluginsToRun {
plugin, exists := Common.PluginManager[pluginName]
if !exists {
continue
}
if Common.LocalScan {
if len(plugin.Ports) == 0 {
actualTasks++
}
continue
}
if isSinglePlugin {
actualTasks++
continue
}
if len(plugin.Ports) > 0 {
if plugin.HasPort(targetPort) {
actualTasks++
}
} else {
actualTasks++
}
}
}
// 初始化进度条
Common.ProgressBar = progressbar.NewOptions(actualTasks,
progressbar.OptionEnableColorCodes(true),
progressbar.OptionShowCount(),
progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("[cyan]扫描进度:[reset]"),
progressbar.OptionSetTheme(progressbar.Theme{
Saucer: "[green]=[reset]",
SaucerHead: "[green]>[reset]",
SaucerPadding: " ",
BarStart: "[",
BarEnd: "]",
}),
progressbar.OptionUseANSICodes(true),
progressbar.OptionSetRenderBlankState(true),
// 设置更新频率
progressbar.OptionThrottle(65*time.Millisecond),
)
// 确保进度条首次渲染
Common.ProgressBar.RenderBlank()
time.Sleep(100 * time.Millisecond) // 给进度条一个短暂的初始化时间
for _, target := range targets {
targetPort, _ := strconv.Atoi(target.Ports)
@ -127,66 +185,82 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
if Common.LocalScan {
if len(plugin.Ports) == 0 {
loadedPlugins = append(loadedPlugins, pluginName)
AddScan(pluginName, target, ch, wg)
}
continue
}
if isSinglePlugin {
loadedPlugins = append(loadedPlugins, pluginName)
AddScan(pluginName, target, ch, wg)
continue
}
if len(plugin.Ports) > 0 {
if plugin.HasPort(targetPort) {
loadedPlugins = append(loadedPlugins, pluginName)
AddScan(pluginName, target, ch, wg)
}
} else {
loadedPlugins = append(loadedPlugins, pluginName)
AddScan(pluginName, target, ch, wg)
}
}
}
// 去重并输出实际加载的插件
uniquePlugins := make(map[string]struct{})
for _, p := range loadedPlugins {
uniquePlugins[p] = struct{}{}
}
finalPlugins := make([]string, 0, len(uniquePlugins))
for p := range uniquePlugins {
finalPlugins = append(finalPlugins, p)
}
sort.Strings(finalPlugins)
Common.LogInfo(fmt.Sprintf("加载的插件: %s", strings.Join(finalPlugins, ", ")))
}
// finishScan 完成扫描任务
func finishScan(wg *sync.WaitGroup) {
wg.Wait()
// 先发送最后的成功消息
// 确保进度条完成
Common.ProgressBar.Finish()
fmt.Println() // 添加一个换行
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
// 等待日志处理完成后再关闭通道
Common.LogWG.Wait()
close(Common.Results)
}
// Mutex用于保护共享资源的并发访问
var Mutex = &sync.Mutex{}
// AddScan 添加扫描任务到并发队列
// AddScan 也需要修改
func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
// 获取信号量,控制并发数
*ch <- struct{}{}
// 添加等待组计数
wg.Add(1)
// 启动goroutine执行扫描任务
go func() {
defer func() {
wg.Done() // 完成任务后减少等待组计数
<-*ch // 释放信号量
wg.Done()
<-*ch
}()
// 增加总任务数
Mutex.Lock()
atomic.AddInt64(&Common.Num, 1)
Mutex.Unlock()
// 执行扫描
ScanFunc(&plugin, &info)
// 增加已完成任务数
Mutex.Lock()
Common.OutputMutex.Lock()
atomic.AddInt64(&Common.End, 1)
Mutex.Unlock()
if Common.ProgressBar != nil {
// 清除当前行
fmt.Print("\033[2K\r")
Common.ProgressBar.Add(1)
}
Common.OutputMutex.Unlock()
}()
}

View File

@ -24,7 +24,7 @@ func MyPluginScan(info *Common.HostInfo) error {
// 3. 处理结果
if result.Vulnerable {
Common.LogSuccess(fmt.Sprintf("[+] Found vulnerability in %s:%d", info.Host, info.Port))
Common.LogSuccess(fmt.Sprintf("Found vulnerability in %s:%d", info.Host, info.Port))
}
return nil

View File

@ -5,7 +5,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"net"
"strings"
"sync"
"time"
)
@ -16,7 +15,6 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 首先测试默认账户
for retryCount := 0; retryCount < maxRetries; retryCount++ {
@ -35,103 +33,60 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
break
}
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["activemq"])*len(Common.Passwords))
starttime := time.Now().Unix()
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行连接测试
done := make(chan struct {
success bool
err error
})
// 执行连接测试
done := make(chan struct {
go func(user, pass string) {
flag, err := ActiveMQConn(info, user, pass)
done <- struct {
success bool
err error
})
}{flag, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success {
return nil
}
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
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
if err != nil {
errlog := fmt.Sprintf("ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue
}
}
break
}
}
}
@ -171,7 +126,7 @@ func ActiveMQConn(info *Common.HostInfo, user string, pass string) (bool, error)
response := string(respBuf[:n])
if strings.Contains(response, "CONNECTED") {
result := fmt.Sprintf("[+] ActiveMQ服务 %v:%v 爆破成功 用户名: %v 密码: %v",
result := fmt.Sprintf("ActiveMQ服务 %v:%v 爆破成功 用户名: %v 密码: %v",
info.Host, info.Ports, user, pass)
Common.LogSuccess(result)
return true, nil

View File

@ -6,7 +6,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"strconv"
"strings"
"sync"
"time"
)
@ -16,7 +15,6 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
// 首先测试无认证访问
@ -34,103 +32,60 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
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)
// 启动工作线程
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
}
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
// 执行连接
done := make(chan struct {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行连接
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}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -541,7 +541,7 @@ func (d *DomainInfo) GetSPNs() (map[string][]string, error) {
_ = entry.GetAttributeValue("cn")
spnList := entry.GetAttributeValues("servicePrincipalName")
if len(spnList) > 0 {
key := fmt.Sprintf("[*] SPN%s", dn)
key := fmt.Sprintf("SPN%s", dn)
spns[key] = spnList
}
}
@ -708,7 +708,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
for _, category := range categories {
if computers, ok := specialComputers[category]; ok {
fmt.Printf("[*] %s:\n", category)
fmt.Printf("%s:\n", category)
for _, computer := range computers {
fmt.Printf("\t%s\n", computer)
}
@ -724,7 +724,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
}
// 打印用户信息
fmt.Println("[*] 域用户:")
fmt.Println("域用户:")
for _, user := range users {
fmt.Println("\t" + user)
}
@ -737,7 +737,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
}
// 打印域管理员信息
fmt.Println("[*] 域管理员:")
fmt.Println("域管理员:")
for _, admin := range admins {
fmt.Println("\t" + admin)
}
@ -750,7 +750,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
}
// 打印组织单位信息
fmt.Println("[*] 组织单位:")
fmt.Println("组织单位:")
for _, ou := range ous {
fmt.Println("\t" + ou)
}
@ -763,7 +763,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
}
// 打印域计算机信息
fmt.Println("[*] 域计算机:")
fmt.Println("域计算机:")
for _, computer := range computers {
fmt.Printf("\t%s", computer.Name)
if computer.OperatingSystem != "" {
@ -775,7 +775,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
// 获取并显示信任域关系
trustDomains, err := di.GetTrustDomains()
if err == nil {
fmt.Println("[*] 信任域关系:")
fmt.Println("信任域关系:")
for _, domain := range trustDomains {
fmt.Printf("\t%s\n", domain)
}
@ -786,7 +786,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
adminGroups, err := di.GetAdminGroups()
if err == nil {
for groupName, members := range adminGroups {
fmt.Printf("[*] %s成员:\n", groupName)
fmt.Printf("%s成员:\n", groupName)
for _, member := range members {
fmt.Printf("\t%s\n", member)
}
@ -798,7 +798,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
delegations, err := di.GetDelegation()
if err == nil {
for delegationType, entries := range delegations {
fmt.Printf("[*] %s:\n", delegationType)
fmt.Printf("%s:\n", delegationType)
for _, entry := range entries {
fmt.Printf("\t%s\n", entry)
}
@ -809,7 +809,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
// 获取并显示AS-REP Roasting漏洞用户
asrepUsers, err := di.GetAsrepRoastUsers()
if err == nil {
fmt.Println("[*] AS-REP弱口令账户:")
fmt.Println("AS-REP弱口令账户:")
for _, user := range asrepUsers {
fmt.Printf("\t%s\n", user)
}
@ -819,7 +819,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
// 获取并显示域密码策略
passwordPolicy, err := di.GetPasswordPolicy()
if err == nil {
fmt.Println("[*] 域密码策略:")
fmt.Println("域密码策略:")
for key, value := range passwordPolicy {
fmt.Printf("\t%s: %s\n", key, value)
}
@ -843,7 +843,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
fmt.Println()
}
} else {
fmt.Println("[*] 未发现SPN信息\n")
fmt.Println("未发现SPN信息\n")
}
return nil
}

View File

@ -7,7 +7,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"net/http"
"strings"
"sync"
"time"
)
@ -18,7 +17,6 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 首先测试无认证访问
for retryCount := 0; retryCount < maxRetries; retryCount++ {
@ -35,105 +33,62 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
break
}
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["elastic"])*len(Common.Passwords))
starttime := time.Now().Unix()
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行连接尝试
done := make(chan struct {
success bool
err error
})
// 执行连接尝试
done := make(chan struct {
go func(user, pass string) {
flag, err := ElasticConn(info, user, pass)
done <- struct {
success bool
err error
})
}{flag, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -1,12 +1,10 @@
package Plugins
import (
"context"
"fmt"
"github.com/jlaffaye/ftp"
"github.com/shadow1ng/fscan/Common"
"strings"
"sync"
"time"
)
@ -17,11 +15,6 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 创建带取消功能的context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 先尝试匿名登录
for retryCount := 0; retryCount < maxRetries; retryCount++ {
@ -29,152 +22,74 @@ 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") {
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue
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))
starttime := time.Now().Unix()
// 任务分发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}
}
// 遍历所有用户名密码组合
for _, user := range Common.Userdict["ftp"] {
for _, pass := range Common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1)
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
}
}()
var wg sync.WaitGroup
resultChan := make(chan error, threads)
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行FTP连接
done := make(chan struct {
success bool
err error
})
// 启动工作线程
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for task := range taskChan {
select {
case <-ctx.Done():
resultChan <- nil
return
default:
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
done := make(chan struct {
go func(user, pass string) {
success, err := FtpConn(info, user, pass)
done <- struct {
success bool
err error
}, 1)
}{success, err}
}(user, pass)
connCtx, connCancel := context.WithTimeout(ctx, time.Duration(Common.Timeout)*time.Second)
go func(user, pass string) {
success, err := FtpConn(info, user, pass)
select {
case <-connCtx.Done():
case done <- struct {
success bool
err error
}{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 {
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 <-connCtx.Done():
err = fmt.Errorf("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
connCancel()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
if err != nil {
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
}
}
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
continue
}
continue
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
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
}
break // 如果不需要重试,跳出重试循环
}
}
}
@ -191,12 +106,6 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
if err != nil {
return false, err
}
// 确保连接被关闭
defer func() {
if conn != nil {
conn.Quit() // 发送QUIT命令关闭连接
}
}()
// 尝试登录
if err = conn.Login(Username, Password); err != nil {
@ -204,7 +113,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个目录
@ -217,5 +126,6 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
}
}
Common.LogSuccess(result)
return true, nil
}

View File

@ -71,14 +71,14 @@ func FcgiScan(info *Common.HostInfo) error {
}
}()
if err != nil {
fmt.Printf("[-] FastCGI连接失败 %v:%v - %v\n", info.Host, info.Ports, err)
fmt.Printf("FastCGI连接失败 %v:%v - %v\n", info.Host, info.Ports, err)
return err
}
// 发送FastCGI请求
stdout, stderr, err := fcgi.Request(env, reqParams)
if err != nil {
fmt.Printf("[-] FastCGI请求失败 %v:%v - %v\n", info.Host, info.Ports, err)
fmt.Printf("FastCGI请求失败 %v:%v - %v\n", info.Host, info.Ports, err)
return err
}
@ -90,10 +90,10 @@ func FcgiScan(info *Common.HostInfo) error {
// 命令执行成功,提取输出结果
output = strings.SplitN(output, cutLine, 2)[0]
if len(stderr) > 0 {
result = fmt.Sprintf("[+] FastCGI漏洞确认 %v:%v\n命令输出:\n%v\n错误信息:\n%v\n建议尝试其他路径例如: -path /www/wwwroot/index.php",
result = fmt.Sprintf("FastCGI漏洞确认 %v:%v\n命令输出:\n%v\n错误信息:\n%v\n建议尝试其他路径例如: -path /www/wwwroot/index.php",
info.Host, info.Ports, output, string(stderr))
} else {
result = fmt.Sprintf("[+] FastCGI漏洞确认 %v:%v\n命令输出:\n%v",
result = fmt.Sprintf("FastCGI漏洞确认 %v:%v\n命令输出:\n%v",
info.Host, info.Ports, output)
}
Common.LogSuccess(result)
@ -102,10 +102,10 @@ func FcgiScan(info *Common.HostInfo) error {
strings.Contains(output, "Status") {
// 目标存在FastCGI服务但可能路径错误
if len(stderr) > 0 {
result = fmt.Sprintf("[*] FastCGI服务确认 %v:%v\n响应:\n%v\n错误信息:\n%v\n建议尝试其他路径例如: -path /www/wwwroot/index.php",
result = fmt.Sprintf("FastCGI服务确认 %v:%v\n响应:\n%v\n错误信息:\n%v\n建议尝试其他路径例如: -path /www/wwwroot/index.php",
info.Host, info.Ports, output, string(stderr))
} else {
result = fmt.Sprintf("[*] FastCGI服务确认 %v:%v\n响应:\n%v",
result = fmt.Sprintf("FastCGI服务确认 %v:%v\n响应:\n%v",
info.Host, info.Ports, output)
}
Common.LogSuccess(result)

View File

@ -149,12 +149,12 @@ func read(text []byte, host string) error {
}
// 构建基础结果
result := fmt.Sprintf("[*] NetInfo 扫描结果")
result += fmt.Sprintf("\n[*] 目标主机: %s", host)
result := fmt.Sprintf("NetInfo 扫描结果")
result += fmt.Sprintf("\n目标主机: %s", host)
if name != "" {
result += fmt.Sprintf("\n[*] 主机名: %s", name)
result += fmt.Sprintf("\n主机名: %s", name)
}
result += "\n[*] 发现的网络接口:"
result += "\n发现的网络接口:"
// 用于分类存储地址
var ipv4Addrs []string

View File

@ -8,7 +8,6 @@ import (
"io"
"net"
"strings"
"sync"
"time"
)
@ -18,102 +17,61 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
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)
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行IMAP连接
done := make(chan struct {
success bool
err error
})
// 执行IMAP连接
done := make(chan struct {
go func(user, pass string) {
success, err := IMAPConn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue
}
}
break
}
}
}

View File

@ -5,18 +5,15 @@ import (
"github.com/IBM/sarama"
"github.com/shadow1ng/fscan/Common"
"strings"
"sync"
"time"
)
// KafkaScan 执行 Kafka 服务扫描
func KafkaScan(info *Common.HostInfo) (tmperr error) {
if Common.DisableBrute {
return
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 首先测试无认证访问
for retryCount := 0; retryCount < maxRetries; retryCount++ {
@ -33,105 +30,62 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
break
}
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["kafka"])*len(Common.Passwords))
starttime := time.Now().Unix()
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行Kafka连接
done := make(chan struct {
success bool
err error
})
// 执行Kafka连接
done := make(chan struct {
go func(user, pass string) {
success, err := KafkaConn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -5,7 +5,6 @@ import (
"github.com/go-ldap/ldap/v3"
"github.com/shadow1ng/fscan/Common"
"strings"
"sync"
"time"
)
@ -16,7 +15,6 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 首先尝试匿名访问
flag, err := LDAPConn(info, "", "")
@ -24,105 +22,62 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
return err
}
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["ldap"])*len(Common.Passwords))
starttime := time.Now().Unix()
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行LDAP连接
done := make(chan struct {
success bool
err error
})
// 执行LDAP连接
done := make(chan struct {
go func(user, pass string) {
success, err := LDAPConn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -89,10 +89,10 @@ var (
)
func LocalInfoScan(info *Common.HostInfo) (err error) {
fmt.Println("[+] LocalInfo扫描模块开始...")
fmt.Println("LocalInfo扫描模块开始...")
home, err := os.UserHomeDir()
if err != nil {
errlog := fmt.Sprintf("[-] Get UserHomeDir error: %v", err)
errlog := fmt.Sprintf("Get UserHomeDir error: %v", err)
Common.LogError(errlog)
return err
}
@ -103,7 +103,7 @@ func LocalInfoScan(info *Common.HostInfo) (err error) {
// 规则搜索
searchSensitiveFiles()
fmt.Println("[+] LocalInfo扫描模块结束...")
fmt.Println("LocalInfo扫描模块结束...")
return nil
}
@ -148,7 +148,7 @@ func scanFixedLocations(home string) {
func checkAndLogFile(path string) {
if _, err := os.Stat(path); err == nil {
result := fmt.Sprintf("[+] Found sensitive file: %s", path)
result := fmt.Sprintf("Found sensitive file: %s", path)
Common.LogSuccess(result)
}
}
@ -202,7 +202,7 @@ func searchSensitiveFiles() {
for _, white := range whitelist {
fileName := strings.ToLower(info.Name())
if strings.Contains(fileName, white) {
result := fmt.Sprintf("[+] Found potential sensitive file: %s", path)
result := fmt.Sprintf("Found potential sensitive file: %s", path)
Common.LogSuccess(result)
break
}

View File

@ -6,7 +6,6 @@ import (
_ "github.com/denisenkom/go-mssqldb"
"github.com/shadow1ng/fscan/Common"
"strings"
"sync"
"time"
)
@ -17,103 +16,61 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
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)
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行MSSQL连接
done := make(chan struct {
success bool
err error
})
// 执行MSSQL连接
done := make(chan struct {
go func(user, pass string) {
success, err := MssqlConn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
go func() {
wg.Wait()
close(resultChan)
}()
if err != nil {
errlog := fmt.Sprintf("MSSQL %v:%v %v %v %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}
@ -150,7 +107,7 @@ func MssqlConn(info *Common.HostInfo, user string, pass string) (bool, error) {
}
// 连接成功
result := fmt.Sprintf("[+] MSSQL %v:%v:%v %v", host, port, username, password)
result := fmt.Sprintf("MSSQL %v:%v:%v %v", host, port, username, password)
Common.LogSuccess(result)
return true, nil
}

View File

@ -6,7 +6,6 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/shadow1ng/fscan/Common"
"strings"
"sync"
"time"
)
@ -17,132 +16,72 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
// 添加成功标志通道
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 检查是否已经成功
select {
case <-successChan:
resultChan <- nil
return
default:
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行MySQL连接
done := make(chan struct {
success bool
err error
})
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 执行MySQL连接
done := make(chan struct {
go func(user, pass string) {
success, err := MysqlConn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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 // 如果不需要重试,跳出重试循环
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
// 连接成功
successLog := fmt.Sprintf("MySQL %v:%v %v %v",
info.Host, info.Ports, user, pass)
Common.LogSuccess(successLog)
return nil
}
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("MySQL %v:%v %v %v %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if !strings.Contains(err.Error(), "Access denied") {
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 特殊处理认证失败的情况
if strings.Contains(err.Error(), "Access denied") {
break // 跳出重试循环,继续下一个密码
}
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
tmperr = err
if !strings.Contains(err.Error(), "Access denied") {
return err
}
}
continue // 继续重试
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -5,7 +5,6 @@ import (
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
"github.com/shadow1ng/fscan/Common"
"strings"
"sync"
"time"
)
@ -16,7 +15,6 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 首先测试无认证访问和默认凭证
initialChecks := []struct {
@ -34,105 +32,62 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
}
}
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["neo4j"])*len(Common.Passwords))
starttime := time.Now().Unix()
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行Neo4j连接
done := make(chan struct {
success bool
err error
})
// 执行Neo4j连接
done := make(chan struct {
go func(user, pass string) {
flag, err := Neo4jConn(info, user, pass)
done <- struct {
success bool
err error
})
}{flag, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -229,7 +229,7 @@ func (info *NetBiosInfo) String() (output string) {
}
if text == "" {
} else if info.DomainControllers != "" {
output = fmt.Sprintf("[+] DC:%-24s", text)
output = fmt.Sprintf("DC:%-24s", text)
} else {
output = fmt.Sprintf("%-30s", text)
}

View File

@ -6,7 +6,6 @@ import (
"github.com/shadow1ng/fscan/Common"
_ "github.com/sijms/go-ora/v2"
"strings"
"sync"
"time"
)
@ -17,107 +16,62 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
// 创建任务通道
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行Oracle连接
done := make(chan struct {
success bool
err error
})
// 执行Oracle连接
done := make(chan struct {
go func(user, pass string) {
success, err := OracleConn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("Oracle %v:%v %v %v %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -7,7 +7,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"net"
"strings"
"sync"
"time"
)
@ -17,111 +16,66 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
// 创建任务通道
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行POP3连接
done := make(chan struct {
success bool
err error
})
// 执行POP3连接
done := make(chan struct {
go func(user, pass string) {
success, err := POP3Conn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
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, user, pass)
Common.LogSuccess(successLog)
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -6,7 +6,6 @@ import (
_ "github.com/lib/pq"
"github.com/shadow1ng/fscan/Common"
"strings"
"sync"
"time"
)
@ -17,107 +16,62 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
// 创建任务通道
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行PostgreSQL连接
done := make(chan struct {
success bool
err error
})
// 执行PostgreSQL连接
done := make(chan struct {
go func(user, pass string) {
success, err := PostgresConn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("PostgreSQL %v:%v %v %v %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -37,130 +37,40 @@ func RdpScan(info *Common.HostInfo) (tmperr error) {
return
}
var (
wg sync.WaitGroup
num = 0
all = len(Common.Userdict["rdp"]) * len(Common.Passwords)
mutex sync.Mutex
)
// 创建任务通道和结果通道
brlist := make(chan Brutelist)
resultChan := make(chan bool)
port, _ := strconv.Atoi(info.Ports)
total := len(Common.Userdict["rdp"]) * len(Common.Passwords)
num := 0
// 启动工作协程
for i := 0; i < Common.BruteThreads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for one := range brlist {
select {
case <-resultChan: // 检查是否已经找到有效凭据
return
default:
// 遍历用户名密码组合
for _, user := range Common.Userdict["rdp"] {
for _, pass := range Common.Passwords {
num++
pass = strings.Replace(pass, "{user}", user, -1)
// 尝试连接
flag, err := RdpConn(info.Host, Common.Domain, user, pass, port, Common.Timeout)
if flag && err == nil {
// 连接成功
var result string
if Common.Domain != "" {
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)
}
mutex.Lock()
num++
mutex.Unlock()
user, pass := one.user, one.pass
flag, err := RdpConn(info.Host, Common.Domain, user, pass, port, Common.Timeout)
if flag && err == nil {
// 连接成功
var result string
if Common.Domain != "" {
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)
}
Common.LogSuccess(result)
select {
case resultChan <- true: // 通知其他goroutine找到了有效凭据
default:
}
return
}
// 连接失败
errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", num, all, info.Host, port, user, pass, err)
Common.LogError(errlog)
Common.LogSuccess(result)
return nil
}
}()
}
// 分发扫描任务
go func() {
for _, user := range Common.Userdict["rdp"] {
for _, pass := range Common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1)
select {
case <-resultChan: // 如果已经找到有效凭据,停止分发任务
return
case brlist <- Brutelist{user, pass}:
}
}
// 连接失败
errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", num, total, info.Host, port, user, pass, err)
Common.LogError(errlog)
}
close(brlist)
}()
// 等待任务完成或找到有效凭据
go func() {
wg.Wait()
close(resultChan)
}()
// 等待结果
if <-resultChan {
return nil
}
return tmperr
}
// worker RDP扫描工作协程
func worker(host, domain string, port int, wg *sync.WaitGroup, brlist chan Brutelist,
signal *bool, num *int, all int, mutex *sync.Mutex, timeout int64) {
defer wg.Done()
for one := range brlist {
if *signal {
return
}
go incrNum(num, mutex)
user, pass := one.user, one.pass
flag, err := RdpConn(host, domain, user, pass, port, timeout)
if flag && err == nil {
// 连接成功
var result string
if domain != "" {
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)
}
Common.LogSuccess(result)
*signal = true
return
}
// 连接失败
errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", *num, all, host, port, user, pass, err)
Common.LogError(errlog)
}
}
// incrNum 线程安全地增加计数器
func incrNum(num *int, mutex *sync.Mutex) {
mutex.Lock()
*num++
mutex.Unlock()
}
// RdpConn 尝试RDP连接
func RdpConn(ip, domain, user, password string, port int, timeout int64) (bool, error) {
defer func() {

View File

@ -6,7 +6,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"net"
"strings"
"sync"
"time"
)
@ -17,116 +16,114 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["rabbitmq"])*len(Common.Passwords)+1) // +1 是为了加入guest账号
// 先测试默认账号 guest/guest
user, pass := "guest", "guest"
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
resultChan := make(chan error, threads)
// 执行RabbitMQ连接
done := make(chan struct {
success bool
err error
})
// 先加入默认账号guest/guest
taskChan <- struct {
user string
pass string
}{"guest", "guest"}
go func() {
success, err := RabbitMQConn(info, user, pass)
done <- struct {
success bool
err error
}{success, err}
}()
// 生成其他用户名密码组合任务
// 等待结果或超时
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, user, pass)
Common.LogSuccess(result)
return nil
}
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, user, pass, err)
Common.LogError(errlog)
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue
}
}
break
}
// 遍历其他用户名密码组合
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行RabbitMQ连接
done := make(chan struct {
success bool
err error
})
// 执行RabbitMQ连接
done := make(chan struct {
go func(user, pass string) {
success, err := RabbitMQConn(info, user, pass)
done <- struct {
success bool
err error
})
}{success, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
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, user, pass)
Common.LogSuccess(result)
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
if err != nil {
errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue
}
}
break
}
}
}

View File

@ -489,10 +489,10 @@ func readreply(conn net.Conn) (string, error) {
// testwrite 测试Redis写入权限
func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
fmt.Println("[*] 开始测试Redis写入权限...")
fmt.Println("开始测试Redis写入权限...")
// 测试SSH目录写入权限
fmt.Println("[*] 正在测试 /root/.ssh/ 目录写入权限...")
fmt.Println("正在测试 /root/.ssh/ 目录写入权限...")
_, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n"))
if err != nil {
fmt.Printf("发送SSH目录测试命令失败: %v\n", err)
@ -503,7 +503,7 @@ func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
fmt.Printf("读取SSH目录测试响应失败: %v\n", err)
return flag, flagCron, err
}
fmt.Printf("[*] SSH目录测试响应: %s\n", text)
fmt.Printf("SSH目录测试响应: %s\n", text)
if strings.Contains(text, "OK") {
flag = true
fmt.Println("SSH目录写入权限测试成功")
@ -512,7 +512,7 @@ func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
}
// 测试定时任务目录写入权限
fmt.Println("[*] 正在测试 /var/spool/cron/ 目录写入权限...")
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)
@ -523,7 +523,7 @@ func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
fmt.Printf("读取定时任务目录测试响应失败: %v\n", err)
return flag, flagCron, err
}
fmt.Printf("[*] 定时任务目录测试响应: %s\n", text)
fmt.Printf("定时任务目录测试响应: %s\n", text)
if strings.Contains(text, "OK") {
flagCron = true
fmt.Println("定时任务目录写入权限测试成功")
@ -531,7 +531,7 @@ func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
fmt.Println("定时任务目录写入权限测试失败")
}
fmt.Printf("[*] 写入权限测试完成 - SSH权限: %v, Cron权限: %v\n", flag, flagCron)
fmt.Printf("写入权限测试完成 - SSH权限: %v, Cron权限: %v\n", flag, flagCron)
return flag, flagCron, err
}

View File

@ -5,7 +5,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"net"
"strings"
"sync"
"time"
)
@ -16,7 +15,6 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 首先测试匿名访问
for retryCount := 0; retryCount < maxRetries; retryCount++ {
@ -36,105 +34,62 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
break
}
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["rsync"])*len(Common.Passwords))
starttime := time.Now().Unix()
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行Rsync连接
done := make(chan struct {
success bool
err error
})
// 执行Rsync连接
done := make(chan struct {
go func(user, pass string) {
flag, err := RsyncConn(info, user, pass)
done <- struct {
success bool
err error
})
}{flag && err == nil, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -5,7 +5,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"github.com/stacktitan/smb/smb"
"strings"
"sync"
"time"
)
@ -14,83 +13,39 @@ func SmbScan(info *Common.HostInfo) (tmperr error) {
return nil
}
threads := Common.BruteThreads
var wg sync.WaitGroup
successChan := make(chan struct{}, 1)
// 按用户分组处理
// 遍历所有用户
for _, user := range Common.Userdict["smb"] {
taskChan := make(chan string, len(Common.Passwords))
// 遍历该用户的所有密码
for _, pass := range Common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1)
taskChan <- pass
}
close(taskChan)
for i := 0; i < threads; i++ {
wg.Add(1)
go func(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
}
}
success, err := doWithTimeOut(info, user, pass)
if success {
if Common.Domain != "" {
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s\\%s:%s",
info.Host, info.Ports, Common.Domain, user, pass))
} else {
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s:%s",
info.Host, info.Ports, user, pass))
}
}(user)
}
return nil
}
wg.Wait()
if err != nil {
Common.LogError(fmt.Sprintf("SMB认证失败 %s:%s %s:%s %v",
info.Host, info.Ports, user, pass, err))
select {
case <-successChan:
// 等待日志打印完成
time.Sleep(500 * time.Millisecond)
Common.LogWG.Wait()
return nil
default:
// 等待失败日志打印完成
time.Sleep(100 * time.Millisecond)
if strings.Contains(err.Error(), "账号锁定") {
// 账号锁定时跳过当前用户的剩余密码
break // 跳出密码循环,继续下一个用户
}
}
}
}
// 主函数结束前多等待一会
time.Sleep(500 * time.Millisecond)
Common.LogWG.Wait()
// 最后再等待一下,确保所有日志都打印完成
time.Sleep(500 * time.Millisecond)
return nil
}

View File

@ -6,7 +6,6 @@ import (
"net"
"os"
"strings"
"sync"
"time"
"github.com/hirochachacha/go-smb2"
@ -27,110 +26,59 @@ func SmbScan2(info *Common.HostInfo) (tmperr error) {
return smbPasswordScan(info)
}
// smbPasswordScan 使用密码进行认证扫描
func smbPasswordScan(info *Common.HostInfo) error {
if Common.DisableBrute {
return nil
}
threads := Common.BruteThreads
var wg sync.WaitGroup
successChan := make(chan struct{}, 1)
hasprint := false
var hasPrintMutex sync.Mutex
// 改成按用户分组处理
// 遍历每个用户
for _, user := range Common.Userdict["smb"] {
// 为每个用户创建密码任务通道
taskChan := make(chan string, len(Common.Passwords))
// 生成该用户的所有密码任务
// 遍历该用户的所有密码
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 retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
success, err, printed := Smb2Con(info, user, pass, []byte{}, hasprint)
for pass := range taskChan {
select {
case <-successChan:
return
default:
time.Sleep(100 * time.Millisecond)
}
if printed {
hasprint = true
}
// 重试循环
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
hasPrintMutex.Lock()
currentHasPrint := hasprint
hasPrintMutex.Unlock()
if success {
logSuccessfulAuth(info, user, pass, []byte{})
return nil
}
success, err, printed := Smb2Con(info, username, pass, []byte{}, currentHasPrint)
if err != nil {
logFailedAuth(info, user, pass, []byte{}, err)
if printed {
hasPrintMutex.Lock()
hasprint = true
hasPrintMutex.Unlock()
time.Sleep(100 * time.Millisecond)
}
if success {
logSuccessfulAuth(info, username, pass, []byte{})
time.Sleep(100 * time.Millisecond)
successChan <- struct{}{}
return
}
if err != nil {
logFailedAuth(info, username, pass, []byte{}, err)
time.Sleep(100 * time.Millisecond)
// 检查是否账户锁定
if strings.Contains(err.Error(), "user account has been automatically locked") {
// 发现账户锁定,清空任务通道并返回
for range taskChan {
// 清空通道
}
return
}
// 其他登录失败情况
if strings.Contains(err.Error(), "LOGIN_FAILED") ||
strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "attempted logon is invalid") ||
strings.Contains(err.Error(), "bad username or authentication") {
break
}
if retryCount < Common.MaxRetries-1 {
time.Sleep(time.Second * time.Duration(retryCount+2))
continue
}
}
// 检查是否账户锁定
if strings.Contains(err.Error(), "user account has been automatically locked") {
// 账户锁定,跳过该用户的剩余密码
break
}
// 其他登录失败情况
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
}
}
}(user)
}
wg.Wait() // 等待当前用户的所有密码尝试完成
// 检查是否已经找到正确密码
select {
case <-successChan:
return nil
default:
break
}
}
}
time.Sleep(200 * time.Millisecond)
return nil
}
@ -139,94 +87,49 @@ func smbHashScan(info *Common.HostInfo) error {
return nil
}
threads := Common.BruteThreads
var wg sync.WaitGroup
successChan := make(chan struct{}, 1)
hasprint := false
var hasPrintMutex sync.Mutex
// 按用户分组处理
// 遍历每个用户
for _, user := range Common.Userdict["smb"] {
// 为每个用户创建hash任务通道
taskChan := make(chan []byte, len(Common.HashBytes))
// 生成该用户的所有hash任务
// 遍历该用户的所有hash
for _, hash := range Common.HashBytes {
taskChan <- hash
}
close(taskChan)
// 重试循环
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
success, err, printed := Smb2Con(info, user, "", hash, hasprint)
// 启动工作线程
for i := 0; i < threads; i++ {
wg.Add(1)
go func(username string) {
defer wg.Done()
if printed {
hasprint = true
}
for hash := range taskChan {
select {
case <-successChan:
return
default:
}
if success {
logSuccessfulAuth(info, user, "", hash)
return nil
}
// 重试循环
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
hasPrintMutex.Lock()
currentHasPrint := hasprint
hasPrintMutex.Unlock()
if err != nil {
logFailedAuth(info, user, "", hash, err)
success, err, printed := Smb2Con(info, username, "", hash, currentHasPrint)
if printed {
hasPrintMutex.Lock()
hasprint = true
hasPrintMutex.Unlock()
}
if success {
logSuccessfulAuth(info, username, "", hash)
successChan <- struct{}{}
return
}
if err != nil {
logFailedAuth(info, username, "", hash, err)
// 检查是否账户锁定
if strings.Contains(err.Error(), "user account has been automatically locked") {
// 发现账户锁定,清空任务通道并返回
for range taskChan {
// 清空通道
}
return
}
// 其他登录失败情况
if strings.Contains(err.Error(), "LOGIN_FAILED") ||
strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "attempted logon is invalid") ||
strings.Contains(err.Error(), "bad username or authentication") {
break
}
if retryCount < Common.MaxRetries-1 {
time.Sleep(time.Second * time.Duration(retryCount+1))
continue
}
}
// 检查是否账户锁定
if strings.Contains(err.Error(), "user account has been automatically locked") {
// 账户锁定跳过该用户的剩余hash
break
}
// 其他登录失败情况
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
}
}
}(user)
}
wg.Wait() // 等待当前用户的所有hash尝试完成
// 检查是否已经找到正确凭据
select {
case <-successChan:
return nil
default:
break
}
}
}

View File

@ -6,7 +6,6 @@ import (
"net"
"net/smtp"
"strings"
"sync"
"time"
)
@ -17,7 +16,6 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 先测试匿名访问
for retryCount := 0; retryCount < maxRetries; retryCount++ {
@ -36,105 +34,62 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
break
}
// 创建任务通道
taskChan := make(chan struct {
user string
pass string
}, len(Common.Userdict["smtp"])*len(Common.Passwords))
starttime := time.Now().Unix()
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行SMTP连接
done := make(chan struct {
success bool
err error
})
// 执行SMTP连接
done := make(chan struct {
go func(user, pass string) {
flag, err := SmtpConn(info, user, pass)
done <- struct {
success bool
err error
})
}{flag, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
var err error
select {
case result := <-done:
err = result.err
if result.success && err == nil {
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -6,7 +6,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"strconv"
"strings"
"sync"
"time"
)
@ -17,106 +16,66 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
portNum, _ := strconv.Atoi(info.Ports)
defaultCommunities := []string{"public", "private", "cisco", "community"}
starttime := time.Now().Unix()
timeout := time.Duration(Common.Timeout) * time.Second
// 创建任务通道
taskChan := make(chan string, len(defaultCommunities))
resultChan := make(chan error, threads)
// 生成所有community任务
// 遍历所有 community
for _, community := range defaultCommunities {
taskChan <- community
}
close(taskChan)
// 检查是否超时
if time.Now().Unix()-starttime > int64(timeout.Seconds()) {
return fmt.Errorf("扫描超时")
}
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行SNMP连接
done := make(chan struct {
success bool
err error
})
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
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)
return nil
}
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 {
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 // 如果不需要重试,跳出重试循环
continue // 继续重试
}
}
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
}
break // 如果不需要重试,跳出重试循环
}
}

View File

@ -1,13 +1,13 @@
package Plugins
import (
"context"
"fmt"
"github.com/shadow1ng/fscan/Common"
"golang.org/x/crypto/ssh"
"io/ioutil"
"net"
"strings"
"sync"
"time"
)
@ -17,97 +17,67 @@ func SshScan(info *Common.HostInfo) (tmperr error) {
}
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)
// 生成所有任务
// 遍历所有用户名密码组合
for _, user := range Common.Userdict["ssh"] {
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 {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
done := make(chan struct {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Common.Timeout)*time.Second)
done := make(chan struct {
success bool
err error
}, 1)
go func(user, pass string) {
success, err := SshConn(info, user, pass)
select {
case <-ctx.Done():
case done <- struct {
success bool
err error
})
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("连接超时")
}{success, err}:
}
}(user, pass)
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)
// 检查是否是已知错误如果是则等待3秒后重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
resultChan <- err
return
}
continue // 继续重试
}
var err error
select {
case result := <-done:
err = result.err
if result.success {
successLog := fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v",
info.Host, info.Ports, user, pass)
Common.LogSuccess(successLog)
time.Sleep(100 * time.Millisecond)
cancel()
return nil
}
if Common.SshKeyPath != "" {
resultChan <- err
return
}
break // 如果不需要重试,跳出重试循环
case <-ctx.Done():
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
go func() {
wg.Wait()
close(resultChan)
}()
cancel()
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
if err != nil {
errlog := fmt.Sprintf("SSH认证失败 %v:%v User:%v Pass:%v Err:%v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue
}
}
if Common.SshKeyPath != "" {
return err
}
break
}
}
}
@ -153,29 +123,13 @@ func SshConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
}
defer session.Close()
flag = true
// 如果需要执行命令
if Common.Command != "" {
output, err := session.CombinedOutput(Common.Command)
_, err := session.CombinedOutput(Common.Command)
if err != nil {
return true, err
}
if Common.SshKeyPath != "" {
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",
info.Host, info.Ports, user, pass, string(output)))
}
} else {
if Common.SshKeyPath != "" {
Common.LogSuccess(fmt.Sprintf("SSH密钥认证成功 %v:%v",
info.Host, info.Ports))
} else {
Common.LogSuccess(fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v",
info.Host, info.Ports, user, pass))
}
}
return flag, nil
return true, nil
}

View File

@ -153,7 +153,7 @@ func SmbGhostScan(info *Common.HostInfo) error {
bytes.Equal(buff[74:76], []byte{0x02, 0x00}) {
// 发现漏洞,记录结果
result := fmt.Sprintf("[+] %v CVE-2020-0796 SmbGhost Vulnerable", ip)
result := fmt.Sprintf("%v CVE-2020-0796 SmbGhost Vulnerable", ip)
Common.LogSuccess(result)
}

View File

@ -8,7 +8,6 @@ import (
"net"
"regexp"
"strings"
"sync"
"time"
)
@ -19,120 +18,74 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
// 创建任务通道
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)
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
for task := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行Telnet连接
done := make(chan struct {
success bool
noAuth bool
err error
})
// 执行Telnet连接
done := make(chan struct {
go func(user, pass string) {
flag, err := telnetConn(info, user, pass)
done <- struct {
success bool
noAuth bool
err error
})
}{err == nil, flag, err}
}(user, pass)
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("连接超时")
// 等待结果或超时
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)
return nil
} else if result.success {
// 成功爆破
result := fmt.Sprintf("Telnet服务 %v:%v 用户名:%v 密码:%v",
info.Host, info.Ports, user, pass)
Common.LogSuccess(result)
return nil
}
// 处理错误情况
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 // 如果不需要重试,跳出重试循环
case <-time.After(time.Duration(Common.Timeout) * time.Second):
err = fmt.Errorf("连接超时")
}
}
resultChan <- nil
}()
}
// 等待所有线程完成
go func() {
wg.Wait()
close(resultChan)
}()
// 处理错误情况
if err != nil {
errlog := fmt.Sprintf("Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v",
info.Host, info.Ports, user, pass, err)
Common.LogError(errlog)
// 检查结果
for err := range resultChan {
if err != nil {
tmperr = err
if retryErr := Common.CheckErrs(err); retryErr != nil {
return err
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
}
}

View File

@ -1,177 +0,0 @@
package Plugins
import (
"crypto/tls"
"encoding/base64"
"fmt"
"github.com/shadow1ng/fscan/Common"
"net/http"
"strings"
"sync"
"time"
)
// TomcatScan 执行 Tomcat Manager 服务扫描
func TomcatScan(info *Common.HostInfo) (tmperr error) {
if Common.DisableBrute {
return
}
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)
// 启动工作线程
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
}()
}
// 等待所有线程完成
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
}
// TomcatConn 尝试 Tomcat Manager 连接
func TomcatConn(info *Common.HostInfo, user string, pass string) (bool, error) {
host, port := info.Host, info.Ports
timeout := time.Duration(Common.Timeout) * time.Second
client := &http.Client{
Timeout: timeout,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
// 尝试不同的管理路径
paths := []string{
"/manager/html",
"/manager/status",
"/manager/text",
"/host-manager/html",
}
for _, path := range paths {
baseURL := fmt.Sprintf("http://%s:%s%s", host, port, path)
req, err := http.NewRequest("GET", baseURL, nil)
if err != nil {
continue
}
// 添加Basic认证
auth := base64.StdEncoding.EncodeToString([]byte(user + ":" + pass))
req.Header.Add("Authorization", "Basic "+auth)
resp, err := client.Do(req)
if err != nil {
continue
}
defer resp.Body.Close()
// 检查响应状态
if resp.StatusCode == 200 {
result := fmt.Sprintf("[+] Tomcat Manager %v:%v %s 爆破成功 用户名: %v 密码: %v",
host, port, path, user, pass)
Common.LogSuccess(result)
return true, nil
}
}
return false, fmt.Errorf("认证失败")
}

View File

@ -5,7 +5,6 @@ import (
"github.com/mitchellh/go-vnc"
"github.com/shadow1ng/fscan/Common"
"net"
"sync"
"time"
)
@ -16,103 +15,64 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
}
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 {
taskChan <- pass
}
close(taskChan)
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
// 启动工作线程
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
starttime := time.Now().Unix()
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行VNC连接
done := make(chan struct {
success bool
err error
})
for pass := range taskChan {
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
resultChan <- fmt.Errorf("扫描超时")
return
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)
return nil
}
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 {
return err
}
// 执行VNC连接
done := make(chan struct {
success bool
err error
})
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 // 如果不需要重试,跳出重试循环
continue // 继续重试
}
}
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
}
break // 如果不需要重试,跳出重试循环
}
}

View File

@ -7,7 +7,6 @@ import (
"github.com/shadow1ng/fscan/Common"
"os"
"strings"
"sync"
"time"
)
@ -34,130 +33,87 @@ func WmiExec(info *Common.HostInfo) (tmperr error) {
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
starttime := time.Now().Unix()
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}
// 检查是否超时
if time.Now().Unix()-starttime > int64(Common.Timeout) {
return fmt.Errorf("扫描超时")
}
// 重试循环
for retryCount := 0; retryCount < maxRetries; retryCount++ {
// 执行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}
}(user, 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, user)
} else {
successLog = fmt.Sprintf("WmiExec %v:%v:%v ",
info.Host, info.Ports, user)
}
if Common.HashValue != "" {
successLog += "hash: " + Common.HashValue
} else {
successLog += pass
}
Common.LogSuccess(successLog)
return nil
}
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, user, pass, err)
errlog = strings.Replace(errlog, "\n", "", -1)
Common.LogError(errlog)
// 检查是否需要重试
if retryErr := Common.CheckErrs(err); retryErr != nil {
if retryCount == maxRetries-1 {
return err
}
continue // 继续重试
}
}
break // 如果不需要重试,跳出重试循环
}
// 如果是32位hash值,只尝试一次密码
if len(Common.HashValue) == 32 {
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
}

View File

@ -1,209 +0,0 @@
package Plugins
import (
"encoding/json"
"fmt"
"github.com/go-resty/resty/v2"
"github.com/shadow1ng/fscan/Common"
"net"
"strings"
"sync"
"time"
)
// ZabbixScan 执行 Zabbix 服务扫描
func ZabbixScan(info *Common.HostInfo) (tmperr error) {
if Common.DisableBrute {
return
}
maxRetries := Common.MaxRetries
threads := Common.BruteThreads
// 先测试默认账号
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)
// 启动工作线程
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
}()
}
// 等待所有线程完成
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
}
// ZabbixConn 尝试 Zabbix API 连接
func ZabbixConn(info *Common.HostInfo, user string, pass string) (bool, error) {
host, port := info.Host, info.Ports
timeout := time.Duration(Common.Timeout) * time.Second
// 构造 API URL
apiURL := fmt.Sprintf("http://%s:%s/api_jsonrpc.php", host, port)
// 构造认证请求
authRequest := map[string]interface{}{
"jsonrpc": "2.0",
"method": "user.login",
"params": map[string]string{
"user": user,
"password": pass,
},
"id": 1,
}
// 创建HTTP客户端
client := resty.New()
client.SetTimeout(timeout)
// 发送认证请求
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody(authRequest).
Post(apiURL)
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
return false, fmt.Errorf("连接超时")
}
return false, err
}
// 解析响应
var result struct {
Result string `json:"result"`
Error struct {
Code int `json:"code"`
Message string `json:"message"`
Data string `json:"data"`
} `json:"error"`
}
if err := json.Unmarshal(resp.Body(), &result); err != nil {
return false, fmt.Errorf("响应解析失败")
}
// 检查是否认证成功
if result.Result != "" {
success := fmt.Sprintf("[+] Zabbix服务 %v:%v 爆破成功 用户名: %v 密码: %v", host, port, user, pass)
Common.LogSuccess(success)
return true, nil
}
return false, fmt.Errorf("认证失败: %v", result.Error.Message)
}

View File

@ -227,34 +227,34 @@ https://github.com/jjf012/gopoc
# 10. Dynamics
[+] 2022/11/19 Add hash collision, wmiexec echo free command execution function
[+] 2022/7/14 Add -hf parameter, support host: port and host/xx: port formats, rule.Search regular matching range is changed from body to header+body, and -nobr no longer includes -nopoc. Optimize webtitle output format.
[+] 2022/7/6 Add manual gc recycling to try to save useless memory, -Urls support comma separation. Fix a poc module bug- Nobr no longer contains nopoc.
[+] 2022/7/2 Strengthen the poc fuzzy module to support running backup files, directories, shiro keys (10 keys by default, 100 keys with the -full parameter), etc.Add ms17017 (use parameter: -sc add), which can be used in ms17010 exp Go defines the shell code, and built-in functions such as adding users.
2022/11/19 Add hash collision, wmiexec echo free command execution function
2022/7/14 Add -hf parameter, support host: port and host/xx: port formats, rule.Search regular matching range is changed from body to header+body, and -nobr no longer includes -nopoc. Optimize webtitle output format.
2022/7/6 Add manual gc recycling to try to save useless memory, -Urls support comma separation. Fix a poc module bug- Nobr no longer contains nopoc.
2022/7/2 Strengthen the poc fuzzy module to support running backup files, directories, shiro keys (10 keys by default, 100 keys with the -full parameter), etc.Add ms17017 (use parameter: -sc add), which can be used in ms17010 exp Go defines the shell code, and built-in functions such as adding users.
Add poc and fingerprint. Socks5 proxy is supported. Because the body fingerprint is more complete, the icon icon is no longer running by default.
[+] 2022/4/20 The poc module adds the specified directory or file -path poc path, the port can specify the file -portf port.txt, the rdp module adds the multi-threaded explosion demo, and -br xx specifies the thread.
[+] 2022/2/25 Add - m webonly to skip port scanning and directly access http. Thanks @ AgeloVito
[+] 2022/1/11 Add oracle password explosion.
[+] 2022/1/7 When scanning IP/8, each C segment gateway and several random IPs will be scanned by default. Recommended parameter: -h ip/8 -m icmp. The LiveTop function is added. When detecting the survival, the number of B and C segment IPs of top10 will be output by default.
[+] 2021/12/7 Add rdp scanning and port parameter -pa 3389 (the port will be added based on the original port list)
[+] 2021/12/1 Optimize the xray parsing module, support groups, add poc, add https judgment (tls handshake package), optimize the ip parsing module (support all ip/xx), add the blasting shutdown parameter nobr, add the skip certain ip scanning function -hn 192.168.1.1, add the skip certain port scanning function - pn 21445, and add the scan Docker unauthorized vulnerability.
[+] 2021/6/18 Improve the poc mechanism. If the fingerprint is identified, the poc will be sent according to the fingerprint information. If the fingerprint is not identified, all poc will be printed once.
[+] 2021/5/29 Adding the fcgi protocol to execute the scan of unauthorized commands, optimizing the poc module, optimizing the icmp module, and adding the ssh module to the private key connection.
[+] 2021/5/15 Added win03 version (deleted xray_poc module), added silent scanning mode, added web fingerprint, fixed netbios module array overrun, added a CheckErrs dictionary, and added gzip decoding to webtitle.
[+] 2021/5/6 Update mod library, poc and fingerprint. Modify thread processing mechanism, netbios detection, domain control identification module, webtitle encoding module, etc.
[+] 2021/4/22 Modify webtitle module and add gbk decoding.
[+] 2021/4/21 Add netbios detection and domain control identification functions.
[+] 2021/3/4 Support -u url and -uf parameters, support batch scan URLs.
[+] 2021/2/25 Modify the yaml parsing module to support password explosion, such as tomcat weak password. The new sets parameter in yaml is an array, which is used to store passwords. See tomcat-manager-week.yaml for details.
[+] 2021/2/8 Add fingerprint identification function to identify common CMS and frameworks, such as Zhiyuan OA and Tongda OA.
[+] 2021/2/5 Modify the icmp packet mode, which is more suitable for large-scale detection.
2022/4/20 The poc module adds the specified directory or file -path poc path, the port can specify the file -portf port.txt, the rdp module adds the multi-threaded explosion demo, and -br xx specifies the thread.
2022/2/25 Add - m webonly to skip port scanning and directly access http. Thanks @ AgeloVito
2022/1/11 Add oracle password explosion.
2022/1/7 When scanning IP/8, each C segment gateway and several random IPs will be scanned by default. Recommended parameter: -h ip/8 -m icmp. The LiveTop function is added. When detecting the survival, the number of B and C segment IPs of top10 will be output by default.
2021/12/7 Add rdp scanning and port parameter -pa 3389 (the port will be added based on the original port list)
2021/12/1 Optimize the xray parsing module, support groups, add poc, add https judgment (tls handshake package), optimize the ip parsing module (support all ip/xx), add the blasting shutdown parameter nobr, add the skip certain ip scanning function -hn 192.168.1.1, add the skip certain port scanning function - pn 21445, and add the scan Docker unauthorized vulnerability.
2021/6/18 Improve the poc mechanism. If the fingerprint is identified, the poc will be sent according to the fingerprint information. If the fingerprint is not identified, all poc will be printed once.
2021/5/29 Adding the fcgi protocol to execute the scan of unauthorized commands, optimizing the poc module, optimizing the icmp module, and adding the ssh module to the private key connection.
2021/5/15 Added win03 version (deleted xray_poc module), added silent scanning mode, added web fingerprint, fixed netbios module array overrun, added a CheckErrs dictionary, and added gzip decoding to webtitle.
2021/5/6 Update mod library, poc and fingerprint. Modify thread processing mechanism, netbios detection, domain control identification module, webtitle encoding module, etc.
2021/4/22 Modify webtitle module and add gbk decoding.
2021/4/21 Add netbios detection and domain control identification functions.
2021/3/4 Support -u url and -uf parameters, support batch scan URLs.
2021/2/25 Modify the yaml parsing module to support password explosion, such as tomcat weak password. The new sets parameter in yaml is an array, which is used to store passwords. See tomcat-manager-week.yaml for details.
2021/2/8 Add fingerprint identification function to identify common CMS and frameworks, such as Zhiyuan OA and Tongda OA.
2021/2/5 Modify the icmp packet mode, which is more suitable for large-scale detection.
Modify the error prompt. If there is no new progress in - debug within 10 seconds, the current progress will be printed every 10 seconds.
[+] 2020/12/12 The yaml parsing engine has been added to support the poc of xray. By default, all the poc are used (the poc of xray has been filtered). You can use - pocname weblogic, and only one or some poc is used. Need go version 1.16 or above, and can only compile the latest version of go for testing.
[+] 2020/12/6 Optimize the icmp module and add the -domain parameter (for the smb blasting module, applicable to domain users)
[+] 2020/12/03 Optimize the ip segment processing module, icmp, port scanning module. 192.168.1.1-192.168.255.255 is supported.
[+] 2020/11/17 The -ping parameter is added to replace icmp packets with ping in the survival detection module.
[+] 2020/11/17 WebScan module and shiro simple recognition are added. Skip certificate authentication during https access. Separate the timeout of the service module and the web module, and add the -wt parameter (WebTimeout).
[+] 2020/11/16 Optimize the icmp module and add the -it parameter (IcmpThreads). The default value is 11000, which is suitable for scanning section B.
[+] 2020/11/15 Support importt ip from file, -hf ip.txt, and process de duplication ips.
2020/12/12 The yaml parsing engine has been added to support the poc of xray. By default, all the poc are used (the poc of xray has been filtered). You can use - pocname weblogic, and only one or some poc is used. Need go version 1.16 or above, and can only compile the latest version of go for testing.
2020/12/6 Optimize the icmp module and add the -domain parameter (for the smb blasting module, applicable to domain users)
2020/12/03 Optimize the ip segment processing module, icmp, port scanning module. 192.168.1.1-192.168.255.255 is supported.
2020/11/17 The -ping parameter is added to replace icmp packets with ping in the survival detection module.
2020/11/17 WebScan module and shiro simple recognition are added. Skip certificate authentication during https access. Separate the timeout of the service module and the web module, and add the -wt parameter (WebTimeout).
2020/11/16 Optimize the icmp module and add the -it parameter (IcmpThreads). The default value is 11000, which is suitable for scanning section B.
2020/11/15 Support importt ip from file, -hf ip.txt, and process de duplication ips.
[url-doczh]: README.md

View File

@ -58,7 +58,7 @@ func InfoCheck(Url string, CheckData *[]CheckDatas) []string {
// 输出结果
if len(matchedInfos) > 0 {
result := fmt.Sprintf("[+] 发现指纹 目标: %-25v 指纹: %s", Url, matchedInfos)
result := fmt.Sprintf("发现指纹 目标: %-25v 指纹: %s", Url, matchedInfos)
Common.LogSuccess(result)
return matchedInfos
}

View File

@ -83,7 +83,7 @@ func initpoc() {
}
} else {
// 从指定目录加载POC
Common.LogSuccess(fmt.Sprintf("[*] 从目录加载POC: %s", Common.PocPath))
Common.LogSuccess(fmt.Sprintf("从目录加载POC: %s", Common.PocPath))
err := filepath.Walk(Common.PocPath, func(path string, info os.FileInfo, err error) error {
if err != nil || info == nil {
return err
@ -98,7 +98,7 @@ func initpoc() {
})
if err != nil {
Common.LogError(fmt.Sprintf("[-] 加载外部POC失败: %v", err))
Common.LogError(fmt.Sprintf("加载外部POC失败: %v", err))
}
}
}

View File

@ -256,7 +256,7 @@ func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc {
if p, err := LoadPoc(f, Pocs); err == nil {
pocs = append(pocs, p)
} else {
fmt.Printf("[-] POC加载失败 %s: %v\n", f, err)
fmt.Printf("POC加载失败 %s: %v\n", f, err)
}
}
return pocs
@ -268,14 +268,14 @@ func LoadPoc(fileName string, Pocs embed.FS) (*Poc, error) {
// 读取POC文件内容
yamlFile, err := Pocs.ReadFile("pocs/" + fileName)
if err != nil {
fmt.Printf("[-] POC文件读取失败 %s: %v\n", fileName, err)
fmt.Printf("POC文件读取失败 %s: %v\n", fileName, err)
return nil, err
}
// 解析YAML内容
err = yaml.Unmarshal(yamlFile, p)
if err != nil {
fmt.Printf("[-] POC解析失败 %s: %v\n", fileName, err)
fmt.Printf("POC解析失败 %s: %v\n", fileName, err)
return nil, err
}
return p, err
@ -285,7 +285,7 @@ func LoadPoc(fileName string, Pocs embed.FS) (*Poc, error) {
func SelectPoc(Pocs embed.FS, pocname string) []string {
entries, err := Pocs.ReadDir("pocs")
if err != nil {
fmt.Printf("[-] 读取POC目录失败: %v\n", err)
fmt.Printf("读取POC目录失败: %v\n", err)
}
var foundFiles []string
@ -304,14 +304,14 @@ func LoadPocbyPath(fileName string) (*Poc, error) {
// 读取POC文件内容
data, err := os.ReadFile(fileName)
if err != nil {
fmt.Printf("[-] POC文件读取失败 %s: %v\n", fileName, err)
fmt.Printf("POC文件读取失败 %s: %v\n", fileName, err)
return nil, err
}
// 解析YAML内容
err = yaml.Unmarshal(data, p)
if err != nil {
fmt.Printf("[-] POC解析失败 %s: %v\n", fileName, err)
fmt.Printf("POC解析失败 %s: %v\n", fileName, err)
return nil, err
}
return p, err

4
go.mod
View File

@ -68,10 +68,14 @@ require (
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/schollz/progressbar/v3 v3.17.1 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
golang.org/x/term v0.27.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
)

6
go.sum
View File

@ -247,6 +247,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
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=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
@ -297,6 +299,8 @@ github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzuk
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
@ -305,6 +309,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/schollz/progressbar/v3 v3.17.1 h1:bI1MTaoQO+v5kzklBjYNRQLoVpe0zbyRZNK6DFkVC5U=
github.com/schollz/progressbar/v3 v3.17.1/go.mod h1:RzqpnsPQNjUyIgdglUjRLgD7sVnxN1wpmBMV+UiEbL4=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shadow1ng/grdp v1.0.3 h1:d29xgHDK4aa3ljm/e/yThdJxygf26zJyRPBunrWT65k=
github.com/shadow1ng/grdp v1.0.3/go.mod h1:3ZMSLWUvPOwoRr6IwpAQCzKbLEZqT80sbyxxe6YgcTg=

View File

@ -1,21 +1,19 @@
package main
import (
"fmt"
"github.com/shadow1ng/fscan/Common"
"github.com/shadow1ng/fscan/Core"
"os"
"time"
)
func main() {
Common.InitLogger()
defer Common.CloseLogger() // 确保程序退出时关闭日志文件
start := time.Now()
var Info Common.HostInfo
Common.Flag(&Info)
if err := Common.Parse(&Info); err != nil {
os.Exit(1) // 或者其他错误处理
os.Exit(1) // 直接退出即可,日志已经同步写入
}
Core.Scan(Info)
fmt.Printf("[*] 扫描结束,耗时: %s\n", time.Since(start))
}